From 3c34de6893d7cd7022e4e6bc5c66118f4a8c37ac Mon Sep 17 00:00:00 2001 From: Jay Cook Date: Tue, 2 Apr 2024 12:36:03 -0400 Subject: [PATCH 1/9] Fix bug in create_sysimg_from_object_file for Xcode 15 CLT Co-authored-by: Jay Cook Co-authored-by: Phil Reinhold --- src/PackageCompiler.jl | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/PackageCompiler.jl b/src/PackageCompiler.jl index 07d7395f..91a90f6c 100644 --- a/src/PackageCompiler.jl +++ b/src/PackageCompiler.jl @@ -711,7 +711,17 @@ function create_sysimg_from_object_file(object_files::Vector{String}, end mkpath(dirname(sysimage_path)) # Prevent compiler from stripping all symbols from the shared lib. - o_file_flags = Sys.isapple() ? `-Wl,-all_load $object_files` : `-Wl,--whole-archive $object_files -Wl,--no-whole-archive` + if Sys.isapple() + cltools_version_cmd = `pkgutil --pkg-info=com.apple.pkg.CLTools_Executables` + cltools_version = match(r"version: (.*)\n", readchomp(cltools_version_cmd))[1] + if startswith(cltools_version, "15") + o_file_flags = `-Wl,-all_load $object_files -Wl,-ld_classic` + else + o_file_flags = `-Wl,-all_load $object_files` + end + else + o_file_flags = `-Wl,--whole-archive $object_files -Wl,--no-whole-archive` + end extra = get_extra_linker_flags(version, compat_level, soname) cmd = `$(bitflag()) $(march()) -shared -L$(julia_libdir()) -L$(julia_private_libdir()) -o $sysimage_path $o_file_flags $(Base.shell_split(ldlibs())) $extra` run_compiler(cmd; cplusplus=true) From 5edc2def4f0d2b690f2a11f587a72052611348bc Mon Sep 17 00:00:00 2001 From: Jay Cook Date: Thu, 4 Apr 2024 12:46:30 -0400 Subject: [PATCH 2/9] =?UTF-8?q?Check=20for=20versions=20=E2=89=A5=2015,=20?= =?UTF-8?q?handle=20pkgutil=20error?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jay Cook Co-authored-by: Phil Reinhold --- src/PackageCompiler.jl | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/PackageCompiler.jl b/src/PackageCompiler.jl index 91a90f6c..906f997f 100644 --- a/src/PackageCompiler.jl +++ b/src/PackageCompiler.jl @@ -712,9 +712,15 @@ function create_sysimg_from_object_file(object_files::Vector{String}, mkpath(dirname(sysimage_path)) # Prevent compiler from stripping all symbols from the shared lib. if Sys.isapple() - cltools_version_cmd = `pkgutil --pkg-info=com.apple.pkg.CLTools_Executables` - cltools_version = match(r"version: (.*)\n", readchomp(cltools_version_cmd))[1] - if startswith(cltools_version, "15") + try + cltools_version_cmd = `pkgutil --pkg-info=com.apple.pkg.CLTools_Executables` + cltools_version = match(r"version: (.*)\n", readchomp(cltools_version_cmd))[1] + global major_version = split(cltools_version, ".")[1] + catch e + @warn "Could not determine the version of the Command Line Tools, assuming greater than 14" + global major_version = "15" + end + if parse(Int64, major_version) > 14 o_file_flags = `-Wl,-all_load $object_files -Wl,-ld_classic` else o_file_flags = `-Wl,-all_load $object_files` From eeea160c2c2adfeee35e0be387957edee5d4f939 Mon Sep 17 00:00:00 2001 From: Dilum Aluthge Date: Tue, 15 Oct 2024 23:17:09 -0400 Subject: [PATCH 3/9] Use `ignorestatus()` and `isnothing()` (instead of using try-catch) Co-authored-by: Jay Cook Co-authored-by: Phil Reinhold --- src/PackageCompiler.jl | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/PackageCompiler.jl b/src/PackageCompiler.jl index 906f997f..a2472d64 100644 --- a/src/PackageCompiler.jl +++ b/src/PackageCompiler.jl @@ -712,15 +712,7 @@ function create_sysimg_from_object_file(object_files::Vector{String}, mkpath(dirname(sysimage_path)) # Prevent compiler from stripping all symbols from the shared lib. if Sys.isapple() - try - cltools_version_cmd = `pkgutil --pkg-info=com.apple.pkg.CLTools_Executables` - cltools_version = match(r"version: (.*)\n", readchomp(cltools_version_cmd))[1] - global major_version = split(cltools_version, ".")[1] - catch e - @warn "Could not determine the version of the Command Line Tools, assuming greater than 14" - global major_version = "15" - end - if parse(Int64, major_version) > 14 + if _xcode_clt_major_version() > 14 o_file_flags = `-Wl,-all_load $object_files -Wl,-ld_classic` else o_file_flags = `-Wl,-all_load $object_files` @@ -734,6 +726,24 @@ function create_sysimg_from_object_file(object_files::Vector{String}, return nothing end +function _xcode_clt_major_version() + cmd = `pkgutil --pkg-info=com.apple.pkg.CLTools_Executables` + @debug "_xcode_clt_major_version(): Attempting to run command" cmd + # The `ignorestatus` allows us to proceed (with a warning) if + # the command does not run successfully. + output = strip(read(ignorestatus(cmd), String)) * "\n" + r = r"version: (.*)\n" + m = match(r, output) + if isnothing(m) + @warn "Could not determine the version of the Command Line Tools, assuming greater than 14" + major_version_str = "15" + else + major_version_str = split(m[1], '.')[1] + end + major_version_int = parse(Int, major_version_str) + return major_version_int +end + function get_extra_linker_flags(version, compat_level, soname) current_ver_arg = `` compat_ver_arg = `` From 92bf5ea201002cab9e560745663d804d08c24578 Mon Sep 17 00:00:00 2001 From: Dilum Aluthge Date: Tue, 15 Oct 2024 23:56:26 -0400 Subject: [PATCH 4/9] Only apply the extra flags if we have confirmed that the compiler is Xcode's clang --- src/PackageCompiler.jl | 26 ++++-------------- src/xcode.jl | 62 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 20 deletions(-) create mode 100644 src/xcode.jl diff --git a/src/PackageCompiler.jl b/src/PackageCompiler.jl index a2472d64..19ce85d8 100644 --- a/src/PackageCompiler.jl +++ b/src/PackageCompiler.jl @@ -14,9 +14,13 @@ using p7zip_jll: p7zip_path export create_sysimage, create_app, create_library -include("juliaconfig.jl") +# Vendored: include("../ext/TerminalSpinners.jl") + +# Source code for this package: +include("juliaconfig.jl") include("library_selection.jl") +include("xcode.jl") ############## @@ -712,7 +716,7 @@ function create_sysimg_from_object_file(object_files::Vector{String}, mkpath(dirname(sysimage_path)) # Prevent compiler from stripping all symbols from the shared lib. if Sys.isapple() - if _xcode_clt_major_version() > 14 + if _is_xcode_clt_and_is_gte_xcode_15() o_file_flags = `-Wl,-all_load $object_files -Wl,-ld_classic` else o_file_flags = `-Wl,-all_load $object_files` @@ -726,24 +730,6 @@ function create_sysimg_from_object_file(object_files::Vector{String}, return nothing end -function _xcode_clt_major_version() - cmd = `pkgutil --pkg-info=com.apple.pkg.CLTools_Executables` - @debug "_xcode_clt_major_version(): Attempting to run command" cmd - # The `ignorestatus` allows us to proceed (with a warning) if - # the command does not run successfully. - output = strip(read(ignorestatus(cmd), String)) * "\n" - r = r"version: (.*)\n" - m = match(r, output) - if isnothing(m) - @warn "Could not determine the version of the Command Line Tools, assuming greater than 14" - major_version_str = "15" - else - major_version_str = split(m[1], '.')[1] - end - major_version_int = parse(Int, major_version_str) - return major_version_int -end - function get_extra_linker_flags(version, compat_level, soname) current_ver_arg = `` compat_ver_arg = `` diff --git a/src/xcode.jl b/src/xcode.jl new file mode 100644 index 00000000..71d507e2 --- /dev/null +++ b/src/xcode.jl @@ -0,0 +1,62 @@ +# Get the compiler command from `get_compiler_cmd()`, and run `cc --version`, and parse the +# output to determine whether or not the compiler is an Xcode Clang. +function _is_xcode_clt() + cmd = `$(get_compiler_cmd()) --version` + @debug "_active_compiler_is_xcode_clt(): Attempting to run command" cmd + output = "\n" * strip(read(ignorestatus(cmd), String)) * "\n" + is_apple_clang = occursin(r"Apple clang version", output) + installed_dir_m = match(r"\nInstalledDir: ([\w\/]*?)\n", output) + if isnothing(installed_dir_m) + return false + end + installed_dir_str = strip(installed_dir[1]) + is_xcode_app = startswith(installed_dir_str, "/Applications/Xcode.app/") + is_xcode_clt = startswith(installed_dir_str, "/Library/Developer/CommandLineTools/") + res = is_apple_clang && (is_xcode_app || is_xcode_clt) +end + +# Run `pkgutil` to get the version number of the Xcode CLT (Command Line Tools), and return +# the major version number as an integer. +function _xcode_clt_major_version() + cmd = `pkgutil --pkg-info=com.apple.pkg.CLTools_Executables` + @debug "_xcode_clt_major_version(): Attempting to run command" cmd + # The `ignorestatus` allows us to proceed if the command does + # not run successfully. + output = "\n" * strip(read(ignorestatus(cmd), String)) * "\n" + r = r"version: (.*)\n" + m = match(r, output) + if isnothing(m) + major_version_str = nothing + else + major_version_str = split(m[1], '.')[1] + end + major_version_int = parse(Int, major_version_str) + return major_version_int +end + +# Return true iff the Xcode CLT version is >= 15. +# "gte" = greater than or equal to. +function _is_gte_xcode_15() + major_version_int = _xcode_clt_major_version() + isnothing(major_version_int) && return nothing + return major_version_int >= 15 +end + +# Return true iff the compiler is Xcode Clang AND the Xcode CLT version is >= 15. +# +# If the user sets the JULIA_PACKAGECOMPILER_XCODE_CLT_MAJOR_VERSION environment variable, +# we skip our attempt at auto-detection, and instead use whatever value the user gave us. +function _is_xcode_clt_and_is_gte_xcode_15() + str = strip(get(ENV, "JULIA_PACKAGECOMPILER_XCODE_CLT_MAJOR_VERSION", "")) + ver_int = tryparse(Int, str) + (ver_int isa Int) && return ver_int + if _is_xcode_clt() + b = _is_gte_xcode_15() + if isnothing(b) + @warn "Could not determine the version of the Command Line Tools, assuming less than or equal to 14" + end + return b + else + false + end +end \ No newline at end of file From 400b87c8a9285834e12d2f3f53090a12fbb7cc68 Mon Sep 17 00:00:00 2001 From: Dilum Aluthge Date: Wed, 16 Oct 2024 00:09:19 -0400 Subject: [PATCH 5/9] Use the output of `$cc --version` to determine the Xcode CLT version --- src/xcode.jl | 68 +++++++++++++++++++++++----------------------------- 1 file changed, 30 insertions(+), 38 deletions(-) diff --git a/src/xcode.jl b/src/xcode.jl index 71d507e2..afe1d089 100644 --- a/src/xcode.jl +++ b/src/xcode.jl @@ -1,45 +1,39 @@ # Get the compiler command from `get_compiler_cmd()`, and run `cc --version`, and parse the # output to determine whether or not the compiler is an Xcode Clang. +# +# The return value is a NamedTuple of the form (; b, ver) +# b = a Bool that is true iff he compiler is an Xcode Clang. +# ver = the version number of the Xcode Clang. If it's not Xcode Clang, ver is nothing. function _is_xcode_clt() cmd = `$(get_compiler_cmd()) --version` @debug "_active_compiler_is_xcode_clt(): Attempting to run command" cmd + # The `ignorestatus` allows us to proceed if the command does not run successfully. output = "\n" * strip(read(ignorestatus(cmd), String)) * "\n" - is_apple_clang = occursin(r"Apple clang version", output) installed_dir_m = match(r"\nInstalledDir: ([\w\/]*?)\n", output) if isnothing(installed_dir_m) - return false + return (; b=false, ver=nothing) end - installed_dir_str = strip(installed_dir[1]) - is_xcode_app = startswith(installed_dir_str, "/Applications/Xcode.app/") - is_xcode_clt = startswith(installed_dir_str, "/Library/Developer/CommandLineTools/") - res = is_apple_clang && (is_xcode_app || is_xcode_clt) -end - -# Run `pkgutil` to get the version number of the Xcode CLT (Command Line Tools), and return -# the major version number as an integer. -function _xcode_clt_major_version() - cmd = `pkgutil --pkg-info=com.apple.pkg.CLTools_Executables` - @debug "_xcode_clt_major_version(): Attempting to run command" cmd - # The `ignorestatus` allows us to proceed if the command does - # not run successfully. - output = "\n" * strip(read(ignorestatus(cmd), String)) * "\n" - r = r"version: (.*)\n" - m = match(r, output) - if isnothing(m) - major_version_str = nothing + installed_dir_str = strip(installed_dir_m[1]) + is_xcode_app = startswith(installed_dir_str, "/Applications/Xcode.app") + is_xcode_clt = startswith(installed_dir_str, "/Library/Developer/CommandLineTools") + if is_xcode_app || is_xcode_clt + m = match(r"\nApple clang version ([0-9\.]*?) ", output) + if isnothing(m) + @warn "Could not determine the version of the Xcode Command Line Tools" + (; b=false, ver=nothing) + end + ver_str = strip(m[1]) + ver = tryparse(VersionNumber, ver_str) + if isnothing(ver) + @warn "Could not determine the version of the Xcode Command Line Tools" + (; b=false, ver=nothing) + end + b = true else - major_version_str = split(m[1], '.')[1] + b = false + ver = nothing end - major_version_int = parse(Int, major_version_str) - return major_version_int -end - -# Return true iff the Xcode CLT version is >= 15. -# "gte" = greater than or equal to. -function _is_gte_xcode_15() - major_version_int = _xcode_clt_major_version() - isnothing(major_version_int) && return nothing - return major_version_int >= 15 + return (; b, ver) end # Return true iff the compiler is Xcode Clang AND the Xcode CLT version is >= 15. @@ -50,13 +44,11 @@ function _is_xcode_clt_and_is_gte_xcode_15() str = strip(get(ENV, "JULIA_PACKAGECOMPILER_XCODE_CLT_MAJOR_VERSION", "")) ver_int = tryparse(Int, str) (ver_int isa Int) && return ver_int - if _is_xcode_clt() - b = _is_gte_xcode_15() - if isnothing(b) - @warn "Could not determine the version of the Command Line Tools, assuming less than or equal to 14" - end - return b + + (; b, ver) = _is_xcode_clt() + if b + return ver >= v"15" else - false + return false end end \ No newline at end of file From 4446a4c5a774dfe78299453ca6485055231d9f6d Mon Sep 17 00:00:00 2001 From: Dilum Aluthge Date: Wed, 16 Oct 2024 00:11:47 -0400 Subject: [PATCH 6/9] Fix syntax to work on Julia 1.6 --- src/xcode.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/xcode.jl b/src/xcode.jl index afe1d089..ba5ed0ee 100644 --- a/src/xcode.jl +++ b/src/xcode.jl @@ -45,9 +45,9 @@ function _is_xcode_clt_and_is_gte_xcode_15() ver_int = tryparse(Int, str) (ver_int isa Int) && return ver_int - (; b, ver) = _is_xcode_clt() - if b - return ver >= v"15" + result = _is_xcode_clt() + if result.b + return result.ver >= v"15" else return false end From a91901d68af7e4227345eac023bd222813f3a2a5 Mon Sep 17 00:00:00 2001 From: Dilum Aluthge Date: Wed, 16 Oct 2024 00:18:43 -0400 Subject: [PATCH 7/9] Trailing newline --- src/xcode.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xcode.jl b/src/xcode.jl index ba5ed0ee..6330ac7b 100644 --- a/src/xcode.jl +++ b/src/xcode.jl @@ -51,4 +51,4 @@ function _is_xcode_clt_and_is_gte_xcode_15() else return false end -end \ No newline at end of file +end From 53e65d513844ee124867d696234fc0bde09e0af5 Mon Sep 17 00:00:00 2001 From: Dilum Aluthge Date: Wed, 16 Oct 2024 01:47:06 -0400 Subject: [PATCH 8/9] Fix a bug, fix spelling, and improve a log message --- src/xcode.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/xcode.jl b/src/xcode.jl index 6330ac7b..207d4a6c 100644 --- a/src/xcode.jl +++ b/src/xcode.jl @@ -2,7 +2,7 @@ # output to determine whether or not the compiler is an Xcode Clang. # # The return value is a NamedTuple of the form (; b, ver) -# b = a Bool that is true iff he compiler is an Xcode Clang. +# b = a Bool that is true iff the compiler is an Xcode Clang. # ver = the version number of the Xcode Clang. If it's not Xcode Clang, ver is nothing. function _is_xcode_clt() cmd = `$(get_compiler_cmd()) --version` @@ -25,7 +25,7 @@ function _is_xcode_clt() ver_str = strip(m[1]) ver = tryparse(VersionNumber, ver_str) if isnothing(ver) - @warn "Could not determine the version of the Xcode Command Line Tools" + @warn "Could not determine the version of the Xcode Command Line Tools" ver_str (; b=false, ver=nothing) end b = true @@ -43,7 +43,7 @@ end function _is_xcode_clt_and_is_gte_xcode_15() str = strip(get(ENV, "JULIA_PACKAGECOMPILER_XCODE_CLT_MAJOR_VERSION", "")) ver_int = tryparse(Int, str) - (ver_int isa Int) && return ver_int + (ver_int isa Int) && return (ver_int >= 15) result = _is_xcode_clt() if result.b From f387dbb73390ed33114a2a520f55bd8891a5173f Mon Sep 17 00:00:00 2001 From: Dilum Aluthge Date: Thu, 17 Oct 2024 21:52:03 -0400 Subject: [PATCH 9/9] Add a comment with example output of `clang --version` --- src/xcode.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/xcode.jl b/src/xcode.jl index 207d4a6c..bed4aa48 100644 --- a/src/xcode.jl +++ b/src/xcode.jl @@ -9,6 +9,13 @@ function _is_xcode_clt() @debug "_active_compiler_is_xcode_clt(): Attempting to run command" cmd # The `ignorestatus` allows us to proceed if the command does not run successfully. output = "\n" * strip(read(ignorestatus(cmd), String)) * "\n" + + # If this is an Xcode Clang compiler, example output would be: + # > Apple clang version 16.0.0 (clang-1600.0.26.3) + # > Target: arm64-apple-darwin23.6.0 + # > Thread model: posix + # > InstalledDir: /Library/Developer/CommandLineTools/usr/bin + installed_dir_m = match(r"\nInstalledDir: ([\w\/]*?)\n", output) if isnothing(installed_dir_m) return (; b=false, ver=nothing)