I am building some nim code that links statically with libffi, and when i build said code as an standalone app, everything works fine. libffi is linked in statically with:
switch("passL", "/path/to/libffi.a") in config.nims, and ffi calls are executed correctly.
But when i build a static library version of my code with:
nim c --app:staticlib --noMain -d:release -o:lib/libxyz.a src/xyz_lib.nim
And then use the generated static library to link it to a C++ app, the linker then fails with:
Undefined symbols for architecture arm64:
"_ffi_call", referenced from:
cffi::callCFunction(cffi::CFFIFunction, seq<values::Value>) in libxyz.a[38](@mxyz@[email protected])
cffi::callCFunction(cffi::CFFIFunction, seq<values::Value>) in libxyz.a[38](@mxyz@[email protected])
cffi::callCFunction(cffi::CFFIFunction, seq<values::Value>) in libxyz.a[38](@mxyz@[email protected])
cffi::callCFunction(cffi::CFFIFunction, seq<values::Value>) in libxyz.a[38](@mxyz@[email protected])
cffi::callCFunction(cffi::CFFIFunction, seq<values::Value>) in libxyz.a[38](@mxyz@[email protected])
"_ffi_prep_cif", referenced from:
cffi::callCFunction(cffi::CFFIFunction, seq<values::Value>) in libxyz.a[38](@mxyz@[email protected])
"_ffi_type_double", referenced from:
cffi::xyzTypeToFFIType(types::TypeKind) in libxyz.a[38](@mxyz@[email protected])
"_ffi_type_pointer", referenced from:
cffi::xyzTypeToFFIType(types::TypeKind) in libxyz.a[38](@mxyz@[email protected])
"_ffi_type_sint64", referenced from:
cffi::xyzTypeToFFIType(types::TypeKind) in libxyz.a[38](@mxyz@[email protected])
"_ffi_type_uint8", referenced from:
cffi::xyzTypeToFFIType(types::TypeKind) in libxyz.a[38](@mxyz@[email protected])
"_ffi_type_void", referenced from:
cffi::xyzTypeToFFIType(types::TypeKind) in libxyz.a[38](@mxyz@[email protected])
ld: symbol(s) not found for architecture arm64
I then browsed the libxyz.a symbols and found out that said symbols are set to U(undefined):
$ nm lib/libxyz.a | grep _ffi
U _ffi_call
U _ffi_prep_cif
U _ffi_type_double
U _ffi_type_pointer
U _ffi_type_sint64
U _ffi_type_uint8
U _ffi_type_void
Anyone knows what i should be looking for ?
I don't recall ever hearing about a post-link stage - the executable/and/or library being the final thing except for nim r run mode (and this property is not unique to nim, but common among many compilers). Package managers do tend to have post-install hooks, though. So, that sounds like a good idea to me and I would suggest you work on a PR/issue unless it already exists.
In the meantime, from a nim.cfg or config.nims file (user/project/file/etc.) you can set gcc.linkerexe = .. (or whichever compiler) and then just have your wrapper tool/script do the link and then the libtool thing "afterwards". (Other uses of this are things like musl-gcc, cosmocc, etc.) As with many such hacks, there will be platform-specific assumptions (e.g. Unix vs. Windows), but it sounds like you may already be ok with that. Anyway, this is kind of an obvious idea, but maybe it needed saying.
Easiest is probably to use an after hook in Nimble. Something like this:
after build:
exec "libtool -static -o libxyz_merged.a libxyz.a /path/to/libffi.a"
Of course you could add some more logic to get the paths and such.