I am working on a package for a high level language (Matlab) that wraps the functions provided by a third party c/c++ lib.
Goal
Pre-compile the package such that it can be run on any computer without installing the external lib's non-standard dependencies.
Set up
The external lib is a git submodule that is built with cmake. I have an internal library that provides functions for converting between the external lib's data types and Matlab's data types. Then there are individual c functions (refered to as mex functions) dependent on the internal and external library that can be called directly in Matlab after being compiled. Ideally the internal library is compiled as a shared library so the mex files don't all have their own copy of common functions.
Attempts
The easiest thing to do is build the external library as a shared library then have both the internal library and the mex functions link against the external library but then there are runtime dependencies on non-standard libraries.
Build the external library as a static library and have the internal library linked against it then have the mex functions linked against only the internal library. By default, the internal library will only contain the symbols from the external libraries it depends on, so any other symbols needed by the mex functions will be missing. GCC has a linker option
--whole-archivewhich forces the linker to add all objects from the static external library into the internal library. I've been setting it with
target_link_libraries(internallib
PRIVATE -Wl,--whole-archive externallib -Wl,--no-whole-archive
)
From my understanding, having the external lib between --whole-archive and --no-whole-archive ensures that the linker will only link all the objects for that library and not all the libraries. This compiles fine but when testing, there are undefined symbol errors at runtime for symbols defined in the external library and I'm not sure why.
- Instead of linking against the external library, add the external libraries object files as sources for the internal library:
add_library(internallib
SHARED
${src_files}
$<TARGET_OBJECTS:externallib>
)
I'm still getting the same symbol not found errors and I don't think this will prevent the runtime dependencies on the external libraries dependencies anyway.
- Link both the internal library and mex functions against the static external library. This seems to work (on both Linux and macOS) but fails on Windows (using gcc/g++ from mingw) with multiple definition errors. I believe this is due to the internal shared library picking up symbols from the external lib that the mex functions also need, so they're defined in both the internal and external library and the linker doesn't know which to use for the mex functions.
I think option 2 is the most promising, I just can't get it to add all the symbols from the external library. Am I misusing/misunderstanding --whole-archive?