Skip to content

ccall() with an absolute library path while outputting an .o file causes linker issues on Windows #34680

@staticfloat

Description

@staticfloat

Kristoffer and I were tracking down precompilation failures for PackageCompilerX, when we noticed a strange error coming from ld while it was trying to link together the system image:

Warning: .drectve `-export:ccalllib_C:\Users\Matthis\.julia\packages\FreeType\2dE5w\deps\usr\bin\libfreetype-6.dll,data ' unrecognized
C:/Users/Matthis/.julia/artifacts/572b61b5075459e3ed62317e674398166ca98dd4/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: Cannot export FreeType: symbol not found
C:/Users/Matthis/.julia/artifacts/572b61b5075459e3ed62317e674398166ca98dd4/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: Cannot export Users: symbol not found
C:/Users/Matthis/.julia/artifacts/572b61b5075459e3ed62317e674398166ca98dd4/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: Cannot export ccalllib_C:: symbol not found
C:/Users/Matthis/.julia/artifacts/572b61b5075459e3ed62317e674398166ca98dd4/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: Cannot export packages: symbol not found

This is being emitted as a global variable from ccall(), but appears to have some quoting issues on Windows, as the linker doesn't like the backslashes in the symbol name. We're not sure if the linker is truly to blame here, as we usually don't pass absolute library paths so we may have never actually tried to link a system image with this usage pattern before.

You can reproduce this with the following mini reproducer:

using Pkg.BinaryPlatforms

open("libfoo.c", "w") do io
    write(io, """
    #include <stdio.h>

    void foo() {
        printf("Hello, Foo!\\n");
    }
    """)
end

@info("Compiling C source...")
libfoo_fname = string("libfoo.", platform_dlext())
run(`gcc -o $libfoo_fname libfoo.c -shared`)

open("Foo.jl", "w") do io
    write(io, """
    module Foo
    const libfoo = joinpath(@__DIR__, "$libfoo_fname")
    ccall((:foo, libfoo), Cvoid, ())
    end
    """)
end

@info("Compiling Julia module...")
run(`$(Base.julia_cmd()) --startup-file=no --output-o foo.o Foo.jl`)

@info("Dumping `ccalllib` julia module symbols...")
run(pipeline(`nm foo.o`, `grep ccalllib`))

Looking at the other ccalllib symbols, they are all "soname" style:

0000000001615770 b _ccalllib_/Users/sabae/libfoo.dylib
000000000162c3d0 b _ccalllib_libcholmod
00000000016160d8 b _ccalllib_libdSFMT
0000000001615b48 b _ccalllib_libgit2
0000000001618f40 b _ccalllib_libgmp
0000000001611b50 b _ccalllib_libmpfr
000000000162ae30 b _ccalllib_libopenblas64_
0000000001623800 b _ccalllib_libopenlibm
0000000001610b60 b _ccalllib_libpcre2-8
000000000162c430 b _ccalllib_libsuitesparse_wrapper
000000000162c510 b _ccalllib_libsuitesparseconfig

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions