链接从静态库链接符号的动态库:macOS vs Linux
Linking a dynamic library that links in symbols from a static library: macOS vs Linux
我正在将一个 Linux 应用程序移植到 macOS,我花了一些时间才发现链接行为有所不同。该项目使用基于 CMake 的两阶段构建过程:一个 CMake 树创建一个动态库,该动态库链接到在稍后创建的第二个树中创建的静态库。创建动态库时静态库还不存在。这适用于 Linux:动态库是使用静态库中的符号创建的,并且它们是前向声明的。构建第二棵树时,动态库链接到一个可执行文件,该可执行文件也链接静态库,这样一切都可以正常工作。这在 macOS 上不起作用,因为在第一个 CMake 树中,编译器在动态库的链接步骤失败,因为第二个树中的静态库尚不存在。
我已经将我的应用程序简化为一个最小的示例(代码可以在我的问题的末尾找到)。
设置如下:
- 带有 main() 函数的最小 C 程序
- 一函数动态库
- 一函数静态库
- 程序从动态库中调用函数。动态库当然是动态链接到程序的。
- 动态库调用静态库函数。静态库静态链接动态库
如果我们停止将静态库链接到动态库:
# This target_link_libraries is intentionally commented out.
#target_link_libraries(dynamic_lib static_lib)
当然,我们在构建程序时会遇到错误。但是错误在 macOS 和 Linux:
上是不同的
macOS/clang 较早 在动态库链接 vs 的步骤失败
Linux/gcc稍后在程序链接
的步骤失败
我确实认识到不同之处在于我在 macOS 上使用 clang 而在 Linux 上使用 gcc 但这并没有向我解释问题。
我想知道:
- 为什么会存在这种差异?
- 我可以通过调整 compiler/linker 标志在 macOS 上获得 Linux 行为吗?
示例已发布到 Github:Linking a dynamic library that links in symbols from a static library (macOS vs Linux)。
这些是我在 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 输出
[ 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输出
[ 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
我设法找到了相关问题的解决方案,我在将同一项目从 Linux 移植到 macOS 时也遇到了这个问题:.
事实证明,这种"forward declaration"的库符号在macOS上是可行的:
添加-undefined dynamic_lookup
标志使macOS可以通过原来的错误。
将此添加到我的示例的 CMakeLists.txt 文件中可解决问题:
target_link_options(dynamic_lib PRIVATE -undefined dynamic_lookup)
我正在将一个 Linux 应用程序移植到 macOS,我花了一些时间才发现链接行为有所不同。该项目使用基于 CMake 的两阶段构建过程:一个 CMake 树创建一个动态库,该动态库链接到在稍后创建的第二个树中创建的静态库。创建动态库时静态库还不存在。这适用于 Linux:动态库是使用静态库中的符号创建的,并且它们是前向声明的。构建第二棵树时,动态库链接到一个可执行文件,该可执行文件也链接静态库,这样一切都可以正常工作。这在 macOS 上不起作用,因为在第一个 CMake 树中,编译器在动态库的链接步骤失败,因为第二个树中的静态库尚不存在。
我已经将我的应用程序简化为一个最小的示例(代码可以在我的问题的末尾找到)。
设置如下:
- 带有 main() 函数的最小 C 程序
- 一函数动态库
- 一函数静态库
- 程序从动态库中调用函数。动态库当然是动态链接到程序的。
- 动态库调用静态库函数。静态库静态链接动态库
如果我们停止将静态库链接到动态库:
# This target_link_libraries is intentionally commented out.
#target_link_libraries(dynamic_lib static_lib)
当然,我们在构建程序时会遇到错误。但是错误在 macOS 和 Linux:
上是不同的macOS/clang 较早 在动态库链接 vs 的步骤失败 Linux/gcc稍后在程序链接
的步骤失败我确实认识到不同之处在于我在 macOS 上使用 clang 而在 Linux 上使用 gcc 但这并没有向我解释问题。
我想知道:
- 为什么会存在这种差异?
- 我可以通过调整 compiler/linker 标志在 macOS 上获得 Linux 行为吗?
示例已发布到 Github:Linking a dynamic library that links in symbols from a static library (macOS vs Linux)。
这些是我在 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 输出
[ 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输出
[ 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
我设法找到了相关问题的解决方案,我在将同一项目从 Linux 移植到 macOS 时也遇到了这个问题:
事实证明,这种"forward declaration"的库符号在macOS上是可行的:
添加-undefined dynamic_lookup
标志使macOS可以通过原来的错误。
将此添加到我的示例的 CMakeLists.txt 文件中可解决问题:
target_link_options(dynamic_lib PRIVATE -undefined dynamic_lookup)