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

macOS: System image file fails consistency check on binary startup #738

Open
ghyatzo opened this issue Nov 9, 2022 · 60 comments · May be fixed by #930
Open

macOS: System image file fails consistency check on binary startup #738

ghyatzo opened this issue Nov 9, 2022 · 60 comments · May be fixed by #930

Comments

@ghyatzo
Copy link

ghyatzo commented Nov 9, 2022

Upon creating an app, the process goes on smoothly, untill it is time to actually call the binary.
I get the error: ERROR: System image file failed consistency check: maybe opened the wrong version?

Julia Version 1.8.2
Commit 36034abf260 (2022-09-29 15:21 UTC)
Platform Info:
  OS: macOS (arm64-apple-darwin21.3.0)
  CPU: 10 × Apple M1 Pro
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-13.0.1 (ORCJIT, apple-m1)
  Threads: 8 on 8 virtual cores
Environment:
  JULIA_NUM_THREADS = 8
  JULIA_DEPOT_PATH = /Users/cshen/.local/julia

I installed julia through juliaup. the juliaup folder is in ~/.local/juliaup and the julia versions in ~/.local/julia/juliaup.
the binaries in ~/.local/juliaup/bin are symlinked to ~/.local/bin which is in the PATH.
I also have julia aliased to julia --project=@.

Could it be that the symlinking throws some pathing off somewhere?

@FerreolS
Copy link

Similar issue here on

Julia Version 1.8.4
Commit 00177ebc4fc (2022-12-23 21:32 UTC)
Platform Info:
  OS: macOS (x86_64-apple-darwin21.4.0)
  CPU: 16 × Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-13.0.1 (ORCJIT, skylake)
  Threads: 16 on 16 virtual cores
Environment:
  JULIA_NUM_THREADS = auto

the app execute smoothly when it is in the folder where it has been compiled but fail with ERROR: System image file failed consistency check: maybe opened the wrong version? when relocated anywhere else.
Using the example of the package

> Code/Julia/PackageCompiler.jl/examples/MyAppCompiled/bin/MyApp 
  Downloaded artifact: MKL
ARGS = String[]
Base.PROGRAM_FILE = "Code/Julia/PackageCompiler.jl/examples/MyAppCompiled/bin/MyApp"
...

> cp -r Code/Julia/PackageCompiler.jl/examples/MyAppCompiled .
> MyAppCompiled/bin/MyApp                                     
ERROR: System image file failed consistency check: maybe opened the wrong version?

@PhilReinhold
Copy link

PhilReinhold commented Sep 25, 2023

I'm running into this issue as well, just trying to build any sysimage, e.g.

PackageCompiler.create_sysimage(String[], sysimage_path="test_image.so")

then

julia --sysimage=test_image.so gives the same error as above.

Julia Version 1.9.3
Commit bed2cd540a1 (2023-08-24 14:43 UTC)
Build Info:
  Official https://julialang.org/ release
Platform Info:
  OS: macOS (arm64-apple-darwin22.4.0)
  CPU: 12 × Apple M2 Pro
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-14.0.6 (ORCJIT, apple-m1)
  Threads: 1 on 8 virtual cores
Environment:
  JULIA_PKG_USE_CLI_GIT = true

@kevmoor
Copy link

kevmoor commented Sep 27, 2023

Same issue, tried on Julia 1.9.3, 1.9.2, 1.10.0-beta2, all with PackageCompiler version 2.1.9, also tried on Julia 1.9.2 with PackageCompiler version 2.1.7 (the mix I had when I last had it running a few weeks ago), this versioninfo() below is from this latest combination.

Julia Version 1.9.2
Commit e4ee485e909 (2023-07-05 09:39 UTC)
Platform Info:
  OS: macOS (arm64-apple-darwin22.4.0)
  CPU: 10 × Apple M1 Pro
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-14.0.6 (ORCJIT, apple-m1)
  Threads: 1 on 8 virtual cores
Environment:
  JULIA_PKG_USE_CLI_GIT = true

@KwatMDPhD
Copy link

KwatMDPhD commented Oct 26, 2023

I'm seeing the same error when building KwatMDPhD/GSEA.jl@79364ca

comonicon/Comonicon.jl#264

@sloede
Copy link
Collaborator

sloede commented Oct 26, 2023

I'm seeing the same error when building KwatMDPhD/GSEA.jl@79364ca

comonicon/Comonicon.jl#264

This happens on macOS only?

@KwatMDPhD
Copy link

I have only tried on macOS Sonoma 14.0.
If you have a non-mac machine, you can clone the above commit and try julia --project deps/build.lj app.

@jayscook
Copy link

I'm still getting the error on PackageCompiler 2.1.11 (which specifically addresses this issue) on macOS Ventura (13.6). Running Julia 1.8.5, not sure if 1.9 is required for the fix.

@sloede
Copy link
Collaborator

sloede commented Oct 30, 2023

Thanks for reporting. Just to clarify: There is no fix available as of yet (also not in PC v2.1.11)

@jayscook
Copy link

Thanks for reporting. Just to clarify: There is no fix available as of yet (also not in PC v2.1.11)

Thanks for clarifying! I assumed that the closed issue indicated that it was fixed.

Please let me know if I can contribute to a fix in some way.

@sloede
Copy link
Collaborator

sloede commented Oct 30, 2023

Please let me know if I can contribute to a fix in some way.

At the moment we are lacking an understanding of why the consistency check fails. If you manage to find out about this, we could start looking for a remedy 🙂

@KwatMDPhD
Copy link

I'm using 1.9.3

Screenshot 2023-10-30 at 15 48 40

Would be great if this error can be fixed...

@ctarn
Copy link

ctarn commented Oct 31, 2023

I was able to build apps using Julia 1.9.0, PackageCompiler 2.1.7, and macOS 13. Recently I upgraded Julia to 1.9.3, PackageCompiler to 2.1.2, and macOS to 14, and the error occurred.

I tried to restore Julia to 1.9.0 and PackageCompiler to 2.1.7, and the error still occurs. So I guess macOS should cause it since Xcode Command Line Tools was also upgraded to 15, which is required by PackageCompiler to compile executables.

Unfortunately, when I tried to downgrade Xcode Command Line Tools, it warned that older version Xcode C. L. T. can not be installed on macOS 14... And I can not downgrade the OS... :(

I would recommend anyone (@jayscook ?) still using macOS 13 try to install an older version (v14.3?)of Xcode. It can be downloaded from: https://developer.apple.com/download/all/

@bjarthur
Copy link

i can't build sysimages on apple silicon either. please let me know how i can help fix it.

@hycakir
Copy link

hycakir commented Nov 2, 2023

I can confirm it is related to clang version. I have compiled MyLib with gcc from homebrew and it works.

@ctarn
Copy link

ctarn commented Nov 3, 2023

it really works! but remember to set the compiler to gcc-13 instead of just gcc since gcc is just an alias of clang by default.

you can specify the compiler by running an export in your shell:

export JULIA_CC="gcc-13"

@sloede
Copy link
Collaborator

sloede commented Nov 3, 2023

Great catch! Could you please report which version of clang/gcc you are each using by default on your systems that works (using gcc --version), which version did not work, and the output of your Julia versioninfo()?

@ctarn
Copy link

ctarn commented Nov 3, 2023

clang v15 from Xcode CLT doesn't work

$ gcc --version
Apple clang version 15.0.0 (clang-1500.0.40.1)
Target: x86_64-apple-darwin23.1.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

(clang v14 should work, but older version Xcode CLT can not be installed on latest macOS)

gcc v13 from brew works

$ gcc-13 --version
gcc-13 (Homebrew GCC 13.2.0) 13.2.0
Copyright (C) 2023 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

versioninfo

julia> versioninfo()
Julia Version 1.9.3
Commit bed2cd540a1 (2023-08-24 14:43 UTC)
Build Info:
  Official https://julialang.org/ release
Platform Info:
  OS: macOS (x86_64-apple-darwin22.4.0)
  CPU: 16 × Intel(R) Core(TM) i9-9900K CPU @ 3.60GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-14.0.6 (ORCJIT, skylake)
  Threads: 1 on 16 virtual cores
Environment:
  JULIA_CC = gcc-13

@jayscook
Copy link

jayscook commented Nov 3, 2023

Good catch!

I've installed gcc-13 with brew install gcc@13 and set it as an env var but am still getting the error after restarting the shell. Any thoughts on what I'm missing here?

$ gcc-13 --version
gcc-13 (Homebrew GCC 13.2.0) 13.2.0
Copyright (C) 2023 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
julia> versioninfo()
Julia Version 1.8.5
Commit 17cfb8e65ea (2023-01-08 06:45 UTC)
Platform Info:
  OS: macOS (arm64-apple-darwin21.5.0)
  CPU: 10 × Apple M1 Pro
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-13.0.1 (ORCJIT, apple-m1)
  Threads: 1 on 8 virtual cores
Environment:
  JULIA_CC = gcc-13

@ctarn
Copy link

ctarn commented Nov 3, 2023

Since the versions of Julia and LLVM are different, maybe you should try older versions of gcc or upgrade Julia to 1.9.

@sloede
Copy link
Collaborator

sloede commented Nov 4, 2023

I've installed gcc-13 with brew install gcc@13 and set it as an env var but am still getting the error after restarting the shell. Any thoughts on what I'm missing here?

Hm, this is unfortunate. It also means we're back to square one, since I don't understand now (again) what the necessary conditions are to trigger the error.

@hycakir
Copy link

hycakir commented Nov 4, 2023

I've installed gcc-13 with brew install gcc@13 and set it as an env var but am still getting the error after restarting the shell. Any thoughts on what I'm missing here?

julia> versioninfo()
Julia Version 1.8.5
...
  JULIA_CC = gcc-13

This is expected as per JuliaLang/julia#49581. You should pick an earlier version of GCC/Clang or newer version of Julia.

@sloede
Copy link
Collaborator

sloede commented Nov 4, 2023

@hycakir Thanks for letting us know, I didn't know about this!

@jayscook Could you please confirm that it works with gcc-12? If yes, we might want to add a note about this behavior to the docs.

@KwatMDPhD
Copy link

How can we make this work with the latest mac gcc? I would be nice to not have to downgrade.

@sloede
Copy link
Collaborator

sloede commented Nov 5, 2023

How can we make this work with the latest mac gcc? I would be nice to not have to downgrade.

TBH, I do not know, since I neither know the rationale behind this check nor do I understand what it actually checks 😅 It seems this check was introduced in JuliaLang/julia@4e7ec79, specifically here.

@vtjnash can you maybe shed some light on this and help us understand

  • what exactly causes this error to appear when loading sysimages built with clang/gcc versions that are "too new" in some sense,
  • if there is anything we can do about it on PC side, and if not
  • what could be done on the Julia side to remedy this issue for building custom sysimages?

@vtjnash
Copy link
Sponsor Member

vtjnash commented Nov 6, 2023

It simply checks if the symbol jl_RTLD_DEFAULT_handle_pointer exists, which is something added by codegen to the image, and that it linked to jl_RTLD_DEFAULT_handle. You may want to try setting LD_DEBUG to find out why this did not generate a completed dylib for you.

@sloede
Copy link
Collaborator

sloede commented Nov 6, 2023

It simply checks if the symbol jl_RTLD_DEFAULT_handle_pointer exists, which is something added by codegen to the image, and that it linked to jl_RTLD_DEFAULT_handle. You may want to try setting LD_DEBUG to find out why this did not generate a completed dylib for you.

Thanks for the explanation! So you mean we should set LD_DEBUG when calling Julia with the broken sysimage? Can you tell us which value should we set the variable to? Also, this error does only seem to occur on macOS - there's no LD_DEBUG available IIRC, maybe you have an alternative?

Sorry for the many questions, we just don't have any enough experience to tackle this at the moment.

@vtjnash
Copy link
Sponsor Member

vtjnash commented Nov 6, 2023

See man dyld for the available env options

@sloede
Copy link
Collaborator

sloede commented Nov 7, 2023

I've been trying to reproduce the problem on my M1 Macbook, but without success so far - all my sysimages or apps I build seem to work.

@KwatMDPhD @bjarthur @hycakir @ctarn Can someone who had this problem please provide an MWE with a sysimage/app as small as possible and the exact commands you use to build it? In addition, please also post the output of gcc --version and Julia's versioninfo() such that we understand which environment is used exactly.

@hycakir
Copy link

hycakir commented Nov 10, 2023

@sloede I tried the same thing on my macbook with the same setup but it worked out just fine for me. One thing caught my attention: I do not receive the warning that you do with -lgcc. Reading the discussions here and here, this might be the culprit for your setup. Can you try uninstalling and installing (or updating) gcc@12 as it seems to have been resolved by Homebrew/homebrew-core#149350?

julia> versioninfo()
Julia Version 1.9.1
Commit 147bdf428cd (2023-06-07 08:27 UTC)
Platform Info:
  OS: macOS (arm64-apple-darwin22.4.0)
  CPU: 8 × Apple M1 Pro
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-14.0.6 (ORCJIT, apple-m1)
  Threads: 1 on 6 virtual cores
Environment:
  JULIA_CC = gcc-12

@PhilReinhold
Copy link

I'll admit that I don't really understand what's going on here, but I saw this exhortation of success by adding the flags -Wl,-ld_classic, and decided to try it here.

I modified o_file_flags in PackageCompiler.jl:create_sysimg_from_object_file like so

function create_sysimg_from_object_file(object_files::Vector{String},
                                        sysimage_path::String;
                                        version,
                                        compat_level::String,
                                        soname::Union{Nothing, String})

    if soname === nothing && (Sys.isunix() && !Sys.isapple())
        soname = basename(sysimage_path)
    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,-ld_classic` : `-Wl,--whole-archive $object_files -Wl,--no-whole-archive`
    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)
    return nothing
end

and now I am able to produce sysimages following the tutorial which have symbols exported and julia happily loads, despite being on xcode CLT version 15.

Probably not the right course of action to just add this flag universally, but maybe having a mechanism for passing additional linker flags could be part of the create_sysimage interface.

@DilumAluthge
Copy link
Member

DilumAluthge commented Dec 6, 2023

Maybe helpful: you can use the open-source xcodes command-line tool to install and switch between different Xcode versions. So you could use xcodes to install Xcode 14.

Note: xcodes is a command-line tool, and it's the one that I prefer. However, there also is a GUI version, which is called Xcodes.app.

@DilumAluthge DilumAluthge changed the title System Image file fails consistency check on binary startup. macOS: System Image file fails consistency check on binary startup. Dec 6, 2023
@DilumAluthge DilumAluthge changed the title macOS: System Image file fails consistency check on binary startup. macOS: System image file fails consistency check on binary startup Dec 6, 2023
@dokie
Copy link

dokie commented Dec 9, 2023

I'll admit that I don't really understand what's going on here, but I saw this exhortation of success by adding the flags -Wl,-ld_classic, and decided to try it here.

I modified o_file_flags in PackageCompiler.jl:create_sysimg_from_object_file like so

function create_sysimg_from_object_file(object_files::Vector{String},
                                        sysimage_path::String;
                                        version,
                                        compat_level::String,
                                        soname::Union{Nothing, String})

    if soname === nothing && (Sys.isunix() && !Sys.isapple())
        soname = basename(sysimage_path)
    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,-ld_classic` : `-Wl,--whole-archive $object_files -Wl,--no-whole-archive`
    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 $(Basks for me on e.shell_split(ldlibs())) $extra`
    run_compiler(cmd; cplusplus=true)
    return nothing
end

and now I am able to produce sysimages following the tutorial which have symbols exported and julia happily loads, despite being on xcode CLT version 15.

Probably not the right course of action to just add this flag universally, but maybe having a mechanism for passing additional linker flags could be part of the create_sysimage interface.

I can confirm this works for me too on MacBook Air M1 with

Julia Version 1.9.4
Commit 8e5136fa297 (2023-11-14 08:46 UTC)
Build Info:
  Official https://julialang.org/ release
Platform Info:
  OS: macOS (arm64-apple-darwin22.4.0)
  CPU: 8 × Apple M1
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-14.0.6 (ORCJIT, apple-m1)
  Threads: 1 on 4 virtual cores

and

λ gcc --version
Apple clang version 15.0.0 (clang-1500.0.40.1)
Target: arm64-apple-darwin23.1.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

But as @PhilReinhold stated, that is one heck of a hack!

@terasakisatoshi
Copy link
Sponsor Contributor

#738 (comment) works on my Intel macOS :D

using PackageCompiler
using PackageCompiler: get_extra_linker_flags, julia_libdir, julia_private_libdir, ldlibs, bitflag, march, run_compiler
# https://github.com/JuliaLang/PackageCompiler.jl/issues/738#issuecomment-1838901893

# I know this causes type piracy, which is a bad solution, but it will save life for those who want to comple for macOS somehow
function PackageCompiler.create_sysimg_from_object_file(object_files::Vector{String},
                                        sysimage_path::String;
                                        version,
                                        compat_level::String,
                                        soname::Union{Nothing, String})

    if soname === nothing && (Sys.isunix() && !Sys.isapple())
        soname = basename(sysimage_path)
    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,-ld_classic` : `-Wl,--whole-archive $object_files -Wl,--no-whole-archive`
    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)
    return nothing
end

using MyExe

create_app(pkgdir(MyExe), "build", force=true)

See also my gist

@justinesjw
Copy link

justinesjw commented Jan 12, 2024

Hello @PhilReinhold @dokie @terasakisatoshi,

Could you please explain a little more on where should I implement these code #738

I am totally new to julia and am using it as a dependency of a dependency of a snakemake pipeline. Some clue will be very helpful!

Thanks!!

@mfbolus
Copy link

mfbolus commented Jan 14, 2024

I'll admit that I don't really understand what's going on here, but I saw this exhortation of success by adding the flags -Wl,-ld_classic, and decided to try it here.

I modified o_file_flags in PackageCompiler.jl:create_sysimg_from_object_file like so

function create_sysimg_from_object_file(object_files::Vector{String},
                                        sysimage_path::String;
                                        version,
                                        compat_level::String,
                                        soname::Union{Nothing, String})

    if soname === nothing && (Sys.isunix() && !Sys.isapple())
        soname = basename(sysimage_path)
    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,-ld_classic` : `-Wl,--whole-archive $object_files -Wl,--no-whole-archive`
    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)
    return nothing
end

and now I am able to produce sysimages following the tutorial which have symbols exported and julia happily loads, despite being on xcode CLT version 15.

Probably not the right course of action to just add this flag universally, but maybe having a mechanism for passing additional linker flags could be part of the create_sysimage interface.

@PhilReinhold , I can also confirm your hack worked for my use case. Definitely would prefer a cleaner solution but thank all of you for your efforts and for sharing.

@SWSAmor
Copy link
Sponsor

SWSAmor commented Jan 17, 2024

Here are my tests on macOS Sonoma 14.2.1 M1 (for aarch64) with PackageCompiler v2.1.17:

clang 15.0.0 + Julia 1.9.4 = GOOD
clang 15.0.0 + Julia 1.10.0 = FAILED
gcc 13.2.0 + Julia 1.9.4 = GOOD
gcc 13.2.0 + Julia 1.10.0 = FAILED

Based on this, I would be more inclined to think that this is an issue with Julia 1.10 rather than a difference between gcc and clang, but I am noob in this.
If it helps, I can also run the same tests on M1 for x64...

@hbe72
Copy link

hbe72 commented Jan 23, 2024

Brand new machine M3 (today) on Sonoma 14.3 and install from scratch.

None of options work:
clang 15.0.0 + Julia 1.9.4 = FAILED
clang 15.0.0 + Julia 1.10.0 = FAILED
gcc 13.2.0 + Julia 1.9.4 = FAILED
gcc 13.2.0 + Julia 1.10.0 = FAILED

Just observing the generated Sysimage.dylib one easily can see that it is empty. That's the reason at least for me it not passing the consistency check. Size is 17KB for a project I usually get 400MB *.dylib.

Do note that macos uses macos linker: Homebrew/homebrew-core#17794

Check the notes for XCode 15 linker section: https://developer.apple.com/documentation/xcode-release-notes/xcode-15-release-notes#Linking

"A new linker has been written to significantly speed up static linking. It’s the default for all macOS, iOS, tvOS and visionOS binaries and anyone using the “Mergeable Libraries” feature. The classic linker can still be explicitly requested using -ld64, and will be removed in a future release."

Some discussion also here: https://www.scivision.dev/xcode-ld_classic/, but setting LDFLAGS in environment variable seem not get passed to PlatformCompiler.

Only thing which helped for me was manual modification of o_file_flags in PackageCompiler.jl:create_sysimg_from_object_file as suggested above

Hope these observations point to correct direction. Perhaps as an intermediate solution adding -Wl,-ld_classic to PackageCompiler linker flags. But if this option will be removed in future generations of XCode more permanent solution is needed.

@ghyatzo
Copy link
Author

ghyatzo commented Jan 23, 2024

Only thing which helped for me was manual modification of o_file_flags in PackageCompiler.jl:create_sysimg_from_object_file as suggested above

With "helped" do you mean that it works properly when using the workaround? Or that it generated "non-empty" .dylib files but still failed the consistency check?

@hbe72
Copy link

hbe72 commented Jan 23, 2024

Let me try to be clearer:

Just using different combinations of clang, gcc and julia "out-of-the-box" did not produce complete sysimage. Some combination did produce slightly larger (2MB vs 17kB), but not complete sysimage (~400MB). At the time I did not document exactly. But I can try to reproduce if needed. In all of the combinations, the compilation works fine, it takes time and compiles all the dependencies, but fails to link the complete *.dylib. And none of the produced libraries pass the consistency check.

Setting just the LDFLAGS environment variable as suggested in one of the links did not help. It does not have any impact to Julia compiler as it has to CMake based C or C++ compilation.

If I manually modify the PackageCompiler.jl as suggested at least Apple Clang 15.0.0 + Julia 1.10.0 combination works. It produces complete Sysimage and passes consistency check. I stopped there as I was happy to do some work. I can try other combinations as well, but I imagine they work as well if the culprit is the new XCode 15 linker or how it is used.

In an another machine two months back after an upgrade from MacOS 13 to 14, a Mac Mini M2, just setting JULIA_CC=gcc-13 solved the same error with Julia 1.9.3. Initially there as well the sysimage *.dylib was empty (17kB). Due to this OS upgrade, XCode was also upgraded to version 15. I can dig deeper details on this as well if needed. I do not have explanation why that works if macos ld is the root cause.

Still have access to both of the machines for further testing.

@hbe72
Copy link

hbe72 commented Jan 23, 2024

FYI:

Have to add that in all of these cases below the precompilation, excution of the program and then the compilation take approximately the same time. Only thing which I see is different is the failed or working linking of dylib.

Apple Clang (15.0.0) and Julia 1.10:

This does not work out-of-the-box:

% ls -la MySysimagePrecompile.dylib
-rwxr-xr-x   1 justme  staff  16768 Jan 23 21:33 MySysimagePrecompile.dylib
% nm -g MySysimagePrecompile.dylib 
MySysimagePrecompile.dylib: no symbols

gcc-13 (13.2.0) and Julia 1.10:

This does not work out-of-the-box:

% ls -la MySysimagePrecompile.dylib
-rwxr-xr-x   1 justme  staff  2662912 Jan 23 21:36 MySysimagePrecompile.dylib
% nm -g MySysimagePrecompile.dylib 
00000000000143f0 T ___bid128_abs
00000000000201f0 T ___bid128_add
0000000000014410 T ___bid128_class
00000000000143d4 T ___bid128_copy
0000000000014400 T ___bid128_copySign
0000000000029de0 T ___bid128_div
000000000001bd54 T ___bid128_fma
000000000001f010 T ___bid128_from_int32
000000000001f040 T ___bid128_from_int64
000000000001f030 T ___bid128_from_uint32

... list continues ...

U _realloc
U _sys_icache_invalidate

Manual edit of PackageCompiler.jl w Apple Clang (15.0.0) and Julia 1.10

... that is addition of -Wl,-ld_classic to o_file_flags

This works:

% ls -la MySysimagePrecompile.dylib 
-rwxr-xr-x  1 justme  staff  450527424 Jan 23 22:12 MySysimagePrecompile.dylib
nm -g MySysimagePrecompile.dylib 
                 U ___divti3
                 U ___modti3
                 U ___udivti3
                 U ___umodti3
                 U _bzero
                 U _ijl_adopt_thread
                 U _ijl_apply_generic
                 U _ijl_boundp
                 U _ijl_bounds_error_int
                 U _ijl_bounds_error_ints
                 U _ijl_bounds_error_tuple_int
                 U _ijl_bounds_error_unboxed_int
                 U _ijl_box_char
                 U _ijl_box_float32
                 U _ijl_box_int16
                 U _ijl_box_int32
                 U _ijl_box_int64
                 U _ijl_box_ssavalue
                 U _ijl_box_uint16
                 U _ijl_box_uint32
                 U _ijl_box_uint64
                 U _ijl_checked_assignment
                 U _ijl_copy_ast
                 U _ijl_current_exception
                 U _ijl_enter_handler
                 U _ijl_error
                 U _ijl_excstack_state
                 U _ijl_field_index
                 U _ijl_gc_pool_alloc
                 U _ijl_gc_queue_root
                 U _ijl_get_binding_or_error
                 U _ijl_get_nth_field_checked
                 U _ijl_has_no_field_error
                 U _ijl_invoke
                 U _ijl_isa
                 U _ijl_lazy_load_and_lookup
                 U _ijl_load_and_lookup
                 U _ijl_new_structt
                 U _ijl_new_structv
                 U _ijl_object_id_
                 U _ijl_pop_handler
                 U _ijl_restore_excstack
                 U _ijl_subtype
                 U _ijl_throw
                 U _ijl_type_error
                 U _ijl_typeassert
                 U _ijl_undefined_var_error
                 U _jl_RTLD_DEFAULT_handle
00000000013bc3a8 S _jl_RTLD_DEFAULT_handle_pointer
                 U _jl_add_int
                 U _jl_boxed_int8_cache
                 U _jl_boxed_uint8_cache
                 U _jl_diverror_exception
                 U _jl_egal__unboxed
                 U _jl_emptytuple
                 U _jl_f__apply_iterate
                 U _jl_f__apply_pure
                 U _jl_f__call_in_world
                 U _jl_f__call_latest
                 U _jl_f__expr
                 U _jl_f__svec_ref
                 U _jl_f__typevar
                 U _jl_f_applicable
                 U _jl_f_apply_typ
                 U _jl_f_arraysize
                 U _jl_f_fieldtype
                 U _jl_f_finalizer
                 U _jl_f_getfield
                 U _jl_f_isa
                 U _jl_f_isdefined
                 U _jl_f_issubtype
                 U _jl_f_setfield
                 U _jl_f_sizeof
                 U _jl_f_svec
                 U _jl_f_tuple
                 U _jl_f_typeassert
                 U _jl_false
                 U _jl_field_isdefined_checked
00000000013c1580 D _jl_image_pointers
                 U _jl_libjulia_internal_handle
                 U _jl_neg_int
                 U _jl_not_int
                 U _jl_nothing
00000000013c15c0 D _jl_system_image_data
0000000001157118 S _jl_system_image_size
                 U _jl_true
                 U _jl_undefref_exception
                 U _jl_world_counter
                 U _jl_xor_int
                 U _julia__gnu_f2h_ieee
                 U _julia__gnu_h2f_ieee
                 U _julia__truncdfhf2
                 U _memcpy
                 U _memmove
                 U _memset
                 U _sigsetjmp

@bjarthur
Copy link

others have this problem too and used the same -ld_classic workaround: https://www.scivision.dev/xcode-ld_classic/. possibly needed because of weak references as described in the "known issues" section here: https://developer.apple.com/documentation/xcode-release-notes/xcode-15-release-notes#Linking

@bjarthur
Copy link

can someone with xcode version 14 or less try the -ld_classic workaround described above? if it continues to work, i'd suggest we just add it universally.

@PhilReinhold
Copy link

@bjarthur

Unfortunately I've seen this flag break compilation with xcode 14 since I think it's unrecognized. I've used the following locally to detect xcode version and conditionally apply the flag:

function PackageCompiler.create_sysimg_from_object_file(object_files::Vector{String},
                                        sysimage_path::String;
                                        version,
                                        compat_level::String,
                                        soname::Union{Nothing, String})

    if soname === nothing && (Sys.isunix() && !Sys.isapple())
        soname = basename(sysimage_path)
    end
    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")
            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)
    return nothing
end

@bjarthur
Copy link

@PhilReinhold submit a PR! is there any reason not to? you've found a nice solution and everyone here has verified it works for them.

@thomasjankovic
Copy link

I'll admit that I don't really understand what's going on here, but I saw this exhortation of success by adding the flags -Wl,-ld_classic, and decided to try it here.

I modified o_file_flags in PackageCompiler.jl:create_sysimg_from_object_file like so

function create_sysimg_from_object_file(object_files::Vector{String},
                                        sysimage_path::String;
                                        version,
                                        compat_level::String,
                                        soname::Union{Nothing, String})

    if soname === nothing && (Sys.isunix() && !Sys.isapple())
        soname = basename(sysimage_path)
    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,-ld_classic` : `-Wl,--whole-archive $object_files -Wl,--no-whole-archive`
    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)
    return nothing
end

and now I am able to produce sysimages following the tutorial which have symbols exported and julia happily loads, despite being on xcode CLT version 15.

Probably not the right course of action to just add this flag universally, but maybe having a mechanism for passing additional linker flags could be part of the create_sysimage interface.

Can confirm that this worked for me too. Julia 1.9.4 and gcc-13.

@jayscook
Copy link

jayscook commented Apr 3, 2024

Hey folks, I went ahead and opened a PR for @PhilReinhold's fix. I'd love it if someone can review! I haven't contributed here before so please let me know if I'm missing any conventions, considerations, etc.

@rallen10
Copy link

@bjarthur

Unfortunately I've seen this flag break compilation with xcode 14 since I think it's unrecognized. I've used the following locally to detect xcode version and conditionally apply the flag:

function PackageCompiler.create_sysimg_from_object_file(object_files::Vector{String},
                                        sysimage_path::String;
                                        version,
                                        compat_level::String,
                                        soname::Union{Nothing, String})

    if soname === nothing && (Sys.isunix() && !Sys.isapple())
        soname = basename(sysimage_path)
    end
    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")
            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)
    return nothing
end

I was experiencing the same problem and I can confirm the above fix works on

  • Apple M1, Sonoma 14.4.1
  • julia v1.8.0
  • PackageCompiler v2.0.9
  • gcc --version Apple clang version 15.0.0 (clang-1500.3.9.4)

@rallen10
Copy link

Similar issue here on

Julia Version 1.8.4
Commit 00177ebc4fc (2022-12-23 21:32 UTC)
Platform Info:
  OS: macOS (x86_64-apple-darwin21.4.0)
  CPU: 16 × Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-13.0.1 (ORCJIT, skylake)
  Threads: 16 on 16 virtual cores
Environment:
  JULIA_NUM_THREADS = auto

the app execute smoothly when it is in the folder where it has been compiled but fail with ERROR: System image file failed consistency check: maybe opened the wrong version? when relocated anywhere else. Using the example of the package

> Code/Julia/PackageCompiler.jl/examples/MyAppCompiled/bin/MyApp 
  Downloaded artifact: MKL
ARGS = String[]
Base.PROGRAM_FILE = "Code/Julia/PackageCompiler.jl/examples/MyAppCompiled/bin/MyApp"
...

> cp -r Code/Julia/PackageCompiler.jl/examples/MyAppCompiled .
> MyAppCompiled/bin/MyApp                                     
ERROR: System image file failed consistency check: maybe opened the wrong version?

@FerreolS did you ever get resolution for your problem? It seems to be closely-related-yet-distinct from the workarounds mentioned in this thread. After using @PhilReinhold fix I am able to build an app and run it in its build location; but now I am facing your problem where relocating the app causes the consistency check error to re-appear.

I've created a new issue: #943

@ctarn
Copy link

ctarn commented May 25, 2024

I run into the same problem again... I previously set JULIA_CC to gcc-13, and it doesn't work after some changes to my iMac (maybe updating OS).
So I switched back clang, and changed the flag to -Wl,-ld_classic, as suggested by @PhilReinhold, and it works now.

o_file_flags = Sys.isapple() ? `-Wl,-ld_classic,-all_load $object_files` : `-Wl,--whole-archive $object_files -Wl,--no-whole-archive`

Hope we can solve the issue soon.😵‍💫

@stevezhaoUS
Copy link

I have face the same issue, hope it can be fix soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.