Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OpenSSL: improve MinGW support on Windows #6079

Merged
merged 21 commits into from
Dec 31, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
4a58502
openssl: enhance test
Doekin Dec 27, 2024
4556226
openssl: improve cross-build support on Windows
Doekin Dec 28, 2024
17ea9ac
openssl: Remove always-true `if` condition
Doekin Dec 29, 2024
abe12e9
openssl: handle mismatched Perl
Doekin Dec 29, 2024
79e98d4
openssl: fix Lua script
Doekin Dec 29, 2024
79c6f04
openssl: fix removing DLL import libraries unexpectedly
Doekin Dec 29, 2024
0e4066b
openssl: fix BSD platform
Doekin Dec 29, 2024
d5e12bc
openssl: fix wrong config
Doekin Dec 29, 2024
661f083
openssl: skip building tests
Doekin Dec 29, 2024
2121619
openssl: improve Perl dependency handling for Windows
Doekin Dec 29, 2024
2cf58d8
openssl: fix overlong make recipe
Doekin Dec 29, 2024
43c7fb9
openssl: trim trailing whitespace
Doekin Dec 29, 2024
0de6b83
openssl: improve Perl platform compatibility warning message
Doekin Dec 29, 2024
aeecc86
openssl: ensure ARFLAGS is not overridden with an empty string
Doekin Dec 30, 2024
a7144ca
openssl: restore the check for precompiled packages
Doekin Dec 30, 2024
409ef37
openssl: add LLVM resource compiler support for MinGW
Doekin Dec 30, 2024
6d5fbd8
openssl: remove temporary file after use
Doekin Dec 31, 2024
d6a3f76
openssl: add try-catch to configuration and Makefile patch functions
Doekin Dec 31, 2024
c86fa6e
openssl: improve compatibility with older versions
Doekin Dec 31, 2024
dbe0b01
openssl: add warning for building versions earlier than 1.1.1
Doekin Dec 31, 2024
977b69c
openssl: improve version checks
Doekin Dec 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions packages/o/openssl/configure/patch.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
function _remove_unused_modules()
io.replace("Configure", "use Pod::Usage;", "", {plain = true})
io.replace("Configure", "pod2usage.-;", "")
end

function main(package, opt)
if not package:is_plat("windows") and not opt.perl.use_unix_path then
os.tryrm("Configurations/unix*-checker.pm")
end
if package:is_plat("windows") and opt.perl.use_unix_path then
io.replace("Configurations/10-main.conf", "NUL", "null", {plain = true})
end
_remove_unused_modules()
end
14 changes: 14 additions & 0 deletions packages/o/openssl/makefile/patch.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
function main(package, opt)
if not package:is_plat("windows") and not opt.perl.use_unix_path then
local apps_openssl = io.readfile("Makefile"):match("APPS_OPENSSL=([^\r\n]*)")
io.gsub("Makefile", "\\([^%s\"\\])", "/%1")
io.replace("Makefile", "APPS_OPENSSL=([^\r\n]*)", "APPS_OPENSSL=" .. apps_openssl)
io.replace("Makefile", "$(APPS_OPENSSL)", [["$(APPS_OPENSSL)"]], {plain = true})
end

if package:is_plat("windows") then
io.replace("makefile", "PERL=([^\r\n]*)", "PERL=" .. opt.perl.program)
else
io.replace("Makefile", "PERL=([^\r\n]*)", ([[PERL="%s"]]):format(opt.perl.program))
end
end
172 changes: 115 additions & 57 deletions packages/o/openssl/xmake.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,25 @@ package("openssl")
on_fetch("fetch")

on_load(function (package)
if not package:is_precompiled() then
if package:is_plat("android") and is_subhost("windows") and os.arch() == "x64" then
-- when building for android on windows, use msys2 perl instead of strawberry-perl to avoid configure issue
package:add("deps", "msys2", {configs = {msystem = "MINGW64", base_devel = true}, private = true})
elseif is_subhost("windows") and not package:is_precompiled() then
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and why not remove not package:is_precompiled()?
If you are using the build-artifacts binary, you do not need to compile openssl and install its build dependencies.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and here

Copy link
Contributor Author

@Doekin Doekin Dec 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, there is no is_precompiled now

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, there is no is_precompiled now

but we need is_precompiled.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I misunderstood.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you are downloading a precompiled binary, then all build dependencies do not need to be installed.

https://github.com/xmake-mirror/build-artifacts/releases?q=openssl&expanded=true

Copy link
Contributor Author

@Doekin Doekin Dec 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the outer if not package:is_precompiled() then might work .

on_load(function (package)
if not package:is_precompiled() then

if package:is_plat("android") and is_subhost("windows") and os.arch() == "x64" then
-- when building for android on windows, use msys2 perl instead of strawberry-perl to avoid configure issue
package:add("deps", "msys2", {configs = {msystem = "MINGW64", base_devel = true}, private = true})
elseif is_subhost("windows") then
import("lib.detect.find_tool")
local perl = find_tool("perl", {paths={"$(env PERL)"}})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should not call find_tool in on_load

if not perl then
package:add("deps", "strawberry-perl", { private = true })
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why remove {system = false}, it will break some things. it will use incorrect perl in some systems and ci envs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please share more details about the scenarios where the system Perl might fail? There might be a workaround we can implement to address this issue. Using the system Perl helps save disk space.

For your reference, I tested with Perl installed via scoop, and it seemed to work as expected.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't reproduce it because I don't remember what happened before. But since there is a clear comment to fix this problem by passing system = false, we shouldn't just remove it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment indicated that Perl bundled with GitForWindows fails to build OpenSSL. I encountered this issue too at the beginning. The error message is as follows:

Can't locate Pod/Usage.pm in @INC (you may need to install the Pod::Usage module) (@INC entries checked: . /usr/lib/perl5/site_perl /usr/share/perl5/site_perl /usr/lib/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib/perl5/core_perl /usr/share/perl5/core_perl) at configdata.pm line 11398.
BEGIN failed--compilation aborted at configdata.pm line 11398.
Compilation failed in require.
BEGIN failed--compilation aborted.

I looked into the config script and found that Pod::Usage is only used to generate help messages, which are shown with the ./Configure help command. I guess that the help message is not needed when installing the package. So, I removed the use of the Pod::Usage module, and it builds successfully using Perl from GitForWindows.

end
if package:is_plat("windows") then
package:add("deps", "nasm", { private = true })
-- the perl executable found in GitForWindows will fail to build OpenSSL
-- see https://github.com/openssl/openssl/blob/master/NOTES-PERL.md#perl-on-windows
package:add("deps", "strawberry-perl", { system = false, private = true })
-- check xmake tool jom
import("package.tools.jom", {try = true})
if jom then
package:add("deps", "jom", {private = true})
end
else
wprint("package(openssl): OpenSSL should be built in a Unix-like shell (e.g., MSYS2, Git Bash) if not targeting MSVC. " ..
"It seems you are not in such an environment. If you encounter build errors, please consider trying again in a Unix-like shell.")
end
end

Expand All @@ -61,6 +66,20 @@ package("openssl")
end
end)

if on_check then
on_check(function (package)
import("lib.detect.find_tool")
local perl = assert(find_tool("perl", {paths={"$(env PERL)"}}), "package(openssl): perl not found!")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use package:find_tool and add spaces =

local working_dir = os.iorunv(perl.program, {"-MFile::Spec::Functions=rel2abs", "-e", "print rel2abs('.')"})
-- Check if Perl is using Unix-style paths
local use_unix_path = working_dir:find("/") == 1
if use_unix_path and package:is_plat("windows") or not use_unix_path and not package:is_plat("windows") then
wprint("package(openssl): The detected Perl may not match your build platform. While it should generally work, it could potentially cause issues. If you encounter any build problems, " ..
"please try installing a compatible version of Perl. If you already have a suitable Perl installed but still see this message, ensure it takes priority over other Perl installations in your system.")
end
end)
end

on_install("windows", function (package)
import("package.tools.jom", {try = true})
import("package.tools.nmake")
Expand All @@ -83,7 +102,13 @@ package("openssl")
table.insert(configs, "no-makedepend")
table.insert(configs, "/FS")
end
os.vrunv("perl", configs)
import("lib.detect.find_tool")
local perl = assert(find_tool("perl", {paths={"$(env PERL)"}}), "package(openssl): perl not found!")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should not call find_tool, we should use add_deps to bind perl path end and run perl

local working_dir = os.iorunv(perl.program, {"-MFile::Spec::Functions=rel2abs", "-e", "print rel2abs('.')"})
perl.use_unix_path = working_dir:find("/") == 1
import("configure.patch")(package, {perl = perl})
os.vrunv(perl.program, configs, {envs = {CONFIGURE_INSIST = 1}})
import("makefile.patch")(package, {perl = perl})

if jom then
jom.build(package)
Expand All @@ -94,39 +119,10 @@ package("openssl")
end
end)

on_install("mingw", function (package)
local configs = {"Configure", "no-tests"}
table.insert(configs, package:is_arch("i386", "x86") and "mingw" or "mingw64")
table.insert(configs, package:config("shared") and "shared" or "no-shared")
local installdir = package:installdir()
-- Use MSYS2 paths instead of Windows paths
if is_subhost("msys") then
installdir = installdir:gsub("(%a):[/\\](.+)", "/%1/%2"):gsub("\\", "/")
end
table.insert(configs, "--prefix=" .. installdir)
table.insert(configs, "--openssldir=" .. installdir)
local buildenvs = import("package.tools.autoconf").buildenvs(package)
buildenvs.RC = package:build_getenv("mrc")
if is_subhost("msys") then
local rc = buildenvs.RC
if rc then
rc = rc:gsub("(%a):[/\\](.+)", "/%1/%2"):gsub("\\", "/")
buildenvs.RC = rc
end
end
-- fix 'cp: directory fuzz does not exist'
if package:config("shared") then
os.mkdir("fuzz")
end
os.vrunv("perl", configs, {envs = buildenvs})
import("package.tools.make").build(package)
import("package.tools.make").make(package, {"install_sw"})
end)

on_install("linux", "macosx", "bsd", "cross", "android", "iphoneos", function (package)
on_install("linux", "macosx", "bsd", "cross", "android", "iphoneos", "mingw", function (package)
-- https://wiki.openssl.org/index.php/Compilation_and_Installation#PREFIX_and_OPENSSLDIR
local configs = {}
if package:is_cross() then
local configs = {"no-tests"}
if package:is_cross() or package:is_plat("mingw") then
local target_plat, target_arch
if package:is_plat("macosx") then
target_plat = "darwin64"
Expand All @@ -145,6 +141,21 @@ package("openssl")
end
target_arch = "cross"
end
elseif package:is_plat("mingw") then
target_plat = package:is_arch("i386", "x86") and "mingw" or "mingw64"
elseif package:is_plat("bsd") then
target_plat = "BSD"
if package:is_arch("i386") then
target_arch = "x86"
elseif package:is_arch("x86_64") then
target_arch = "x86_64"
elseif package:is_arch("arm64") then
target_arch = "aarch64"
elseif package:is_arch("riscv64") then
target_arch = "riscv64"
elseif package:is_arch(".*64") then
target_arch = "generic64"
end
else
target_plat = "linux"
if package:is_arch("x86_64") then
Expand All @@ -161,36 +172,83 @@ package("openssl")
target_arch = "generic32"
end
end
table.insert(configs, target_plat .. "-" .. target_arch)
if package:is_plat("cross", "android") then
table.insert(configs, "-DOPENSSL_NO_HEARTBEATS")
table.insert(configs, "no-threads")
end
table.insert(configs, target_arch and (target_plat .. "-" .. target_arch) or target_plat)
end
table.insert(configs, "--openssldir=" .. package:installdir():gsub("\\", "/"))
table.insert(configs, "--prefix=" .. package:installdir():gsub("\\", "/"))
if package:is_plat("cross", "android") then
table.insert(configs, "-DOPENSSL_NO_HEARTBEATS")
table.insert(configs, "no-threads")
end
local installdir = package:installdir()
-- Use MSYS2 paths instead of Windows paths
if is_subhost("msys") then
installdir = installdir:gsub("(%a):[/\\](.+)", "/%1/%2")
end
installdir = installdir:gsub("\\", "/")
table.insert(configs, "--openssldir=" .. installdir)
table.insert(configs, "--prefix=" .. installdir)
table.insert(configs, package:config("shared") and "shared" or "no-shared")
if package:debug() then
table.insert(configs, "--debug")
end

local buildenvs = import("package.tools.autoconf").buildenvs(package)
if package:is_cross() then
if is_host("windows") and package:is_plat("android") then
buildenvs.CFLAGS = buildenvs.CFLAGS:gsub("\\", "/")
buildenvs.CXXFLAGS = buildenvs.CXXFLAGS:gsub("\\", "/")
buildenvs.CPPFLAGS = buildenvs.CPPFLAGS:gsub("\\", "/")
buildenvs.ASFLAGS = buildenvs.ASFLAGS:gsub("\\", "/")
if is_host("windows") and package:is_plat("android") then
buildenvs.CFLAGS = buildenvs.CFLAGS:gsub("\\", "/")
buildenvs.CXXFLAGS = buildenvs.CXXFLAGS:gsub("\\", "/")
buildenvs.CPPFLAGS = buildenvs.CPPFLAGS:gsub("\\", "/")
buildenvs.ASFLAGS = buildenvs.ASFLAGS:gsub("\\", "/")
end
if package:is_plat("mingw") then
buildenvs.RC = package:build_getenv("mrc")
if is_subhost("msys") and buildenvs.RC then
buildenvs.RC = buildenvs.RC:gsub("(%a):[/\\](.+)", "/%1/%2"):gsub("\\", "/")
end
os.vrunv("perl", table.join("./Configure", configs), {envs = buildenvs})
-- fix 'cp: directory fuzz does not exist'
if package:config("shared") then
os.mkdir("fuzz")
end
end

import("lib.detect.find_tool")
local perl = assert(find_tool("perl", {paths={"$(env PERL)"}}), "package(openssl): perl not found!")
local working_dir = os.iorunv(perl.program, {"-MFile::Spec::Functions=rel2abs", "-e", "print rel2abs('.')"})
perl.use_unix_path = working_dir:find("/") == 1
import("configure.patch")(package, {perl = perl})
if package:is_cross() or package:is_plat("mingw") then
os.vrunv(perl.program, table.join("./Configure", configs), {envs = buildenvs})
else
os.vrunv("./config", configs, {shell = true, envs = buildenvs})
end

import("makefile.patch")(package, {perl = perl})
import("package.tools.make").build(package)
import("package.tools.make").make(package, {"install_sw"})
if package:config("shared") then
os.tryrm(path.join(package:installdir("lib"), "*.a"))
os.tryrm(path.join(package:installdir("lib"), "*.a|*.dll.a"))
end
end)
on_test(function (package)
assert(package:has_cfuncs("SSL_new", {includes = "openssl/ssl.h"}))
assert(package:check_csnippets({test = [[
#include <openssl/ssl.h>

int test(){
SSL_library_init();
SSL_load_error_strings();
SSL_CTX *ctx = SSL_CTX_new(SSLv23_client_method());
if(ctx == NULL){
return 1;
}

SSL *ssl = SSL_new(ctx);
if(ssl == NULL){
SSL_CTX_free(ctx);
return 1;
}

SSL_free(ssl);
SSL_CTX_free(ctx);

return 0;
}
]]}))
end)
Loading