问题
I am porting a Linux application to macOS and there is a difference in the linking behavior that took some of my time to reveal itself. The project uses a two-stage CMake-based build process: one CMake tree creates a dynamic library that links to static library that is created in the second tree that is created later. The static library does not exist yet when the dynamic library is created. This works on Linux: dynamic library gets created with symbols from static library and they are forward-declared. When the second tree is built, the dynamic library gets linked to an executable which also links the static library and this way everything works fine. This does not work on macOS because in the first CMake tree, the compiler fails at the dynamic library's linking step because the static library from the second tree does not exist yet.
I have reduced my application to a minimal example (the code can be found at the end of my question).
The setup is as follows:
- Minimal C program with a main() function
- Dynamic library with one function
- Static library with one function
- The program calls a function from the dynamic library. The dynamic library is of course linked dynamically to the program.
- The dynamic library calls a function from the static library. The static library is linked statically to the dynamic library.
If we stop linking the static library to dynamic library:
# This target_link_libraries is intentionally commented out.
#target_link_libraries(dynamic_lib static_lib)
we, of course, get errors when building a program. But the errors are different on macOS and Linux:
macOS/clang fails earlier at the step when the dynamic library gets linked vs Linux/gcc fails later at the step when the program gets linked
I do recognize that the difference can be in the fact that I am using clang on macOS and gcc on Linux but this does not explain the issue to me.
I would like to know:
- Why does this difference exist?
- Can I get the Linux behavior on macOS by tweaking the compiler/linker flags?
The example has been published to Github: Linking a dynamic library that links in symbols from a static library (macOS vs Linux).
These are the key files from my example on Github:
CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project(untitled1 C)
add_compile_options("-fPIC")
set(CMAKE_C_STANDARD 99)
add_library(static_lib static_lib.c)
add_library(dynamic_lib SHARED dynamic_lib.c)
# THE ISSUE IS HERE:
# This target_link_libraries is intentionally commented out.
# on macOS the build process fails when linking dynamic_lib
# on Linux the build process fails when linking the
# 'untitled1' program.
#target_link_libraries(dynamic_lib static_lib)
add_executable(untitled1 main.c)
target_link_libraries(untitled1 dynamic_lib)
dynamic_lib.c
#include "dynamic_lib.h"
#include "static_lib.h"
void dynamic_lib_func() {
static_lib_func();
}
static_lib.c
#include "static_lib.h"
void static_lib_func() {}
macOS output
[ 25%] Building C object CMakeFiles/dynamic_lib.dir/dynamic_lib.c.o
/Library/Developer/CommandLineTools/usr/bin/cc -Ddynamic_lib_EXPORTS -g -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk -fPIC -fPIC -std=gnu99 -o CMakeFiles/dynamic_lib.dir/dynamic_lib.c.o -c /Users/stanislaw/workspace/code/Examples/untitled1/dynamic_lib.c
[ 50%] Linking C shared library libdynamic_lib.dylib
/Applications/CLion.app/Contents/bin/cmake/mac/bin/cmake -E cmake_link_script CMakeFiles/dynamic_lib.dir/link.txt --verbose=1
/Library/Developer/CommandLineTools/usr/bin/cc -g -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk -dynamiclib -Wl,-headerpad_max_install_names -o libdynamic_lib.dylib -install_name @rpath/libdynamic_lib.dylib CMakeFiles/dynamic_lib.dir/dynamic_lib.c.o
Undefined symbols for architecture x86_64:
"_static_lib_func", referenced from:
_dynamic_lib_func in dynamic_lib.c.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Linux output
[ 16%] Linking C shared library libdynamic_lib.so
[ 33%] Built target dynamic_lib
Scanning dependencies of target untitled1
[ 50%] Linking C executable untitled1
libdynamic_lib.so: undefined reference to `static_lib_func'
collect2: error: ld returned 1 exit status
来源:https://stackoverflow.com/questions/59687933/linking-a-dynamic-library-that-links-in-symbols-from-a-static-library-macos-vs