JuliaLang / PackageCompiler.jl

Compile your Julia Package
https://julialang.github.io/PackageCompiler.jl/dev/
MIT License
1.42k stars 188 forks source link

Failed consistency check when trying to relocate compiled app (MacOS) #943

Closed rallen10 closed 4 months ago

rallen10 commented 4 months ago

I am running into an error when trying to relocate a very simple compiled app to a different part of my machine (not even a different machine).

System and Library Info

Minimum working example

I'm just trying to create a very simple app I'm calling AppSandbox

# AppSandbox.jl/src/AppSandbox.jl
module AppSandbox

function julia_main()::Cint
    print("Hello World from my compiled app!\n")
    return 0 # if things finished successfully
end

greet() = print("Greetings from AppSandbox!")

export greet

end # module AppSandbox

Then to build, I run the following using a local fix for issue #738 (see comment with fix here)

# pwd AppSandbox.jl. Started Julia with `julia --project=.`
using PackageCompiler

# re-define the create_sysimg_from_object_file function
using PackageCompiler: get_extra_linker_flags, julia_libdir, julia_private_libdir, ldlibs, bitflag, march, run_compiler
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

# build the compiled app, overwritting compiled direction if it exists (force=true)
create_app(".", "build", force=true)

The app builds and I can successfully run it in the location it was built

# pwd is AppSandbox.jl
./build/bin/AppSandbox
# output:
# Hello World from my compiled app!

But if I try to relocate the app locally, I get the following error

cp -r build/ ~/Desktop/AppSandboxBuild
~/Desktop/AppSandboxBuild/bin/AppSandbox

# output
ERROR: System image file failed consistency check: maybe opened the wrong version?

[65750] signal (11.2): Segmentation fault: 11
in expression starting at none:0

[65750] signal (6): Abort trap: 6
in expression starting at none:0
Abort trap: 6
hbe72 commented 4 months ago

Maybe macOS security mechanism kicks in. macOS caches information about the code’s signature in the kernel. It seems that Apple M processors require all code to be validly signed (if only ad hoc) or the operating system will not execute it, instead killing it on launch.

See https://developer.apple.com/documentation/security/updating_mac_software and some related discussion in https://stackoverflow.com/questions/67378106/mac-m1-cping-binary-over-another-results-in-crash

rallen10 commented 4 months ago

@hbe72 This seems to be the issue! Thank you.

The fix/workaround is identified in Mac's documentation. In short, use ditto to move instead of cp

cp -r build/ ~/Desktop/AppSandboxBuild
~/Desktop/AppSandboxBuild/bin/AppSandbox
# This will fail with the above error

ditto build/ ~/Desktop/AppSandboxBuild2
~/Desktop/AppSandboxBuild2/bin/AppSandbox
# This works