链接从静态库链接符号的动态库:macOS与Linux [英] Linking a dynamic library that links in symbols from a static library: macOS vs Linux

查看:273
本文介绍了链接从静态库链接符号的动态库:macOS与Linux的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将Linux应用程序移植到macOS,并且链接行为有所不同,这花费了我一些时间来展示自己.该项目使用基于CMake的两阶段构建过程:一棵CMake树创建一个动态库,该库链接到在第二个树中创建的静态库,该静态树随后创建.创建动态库时,静态库尚不存在.这在Linux上有效:动态库是使用静态库中的符号创建的,并且它们已被预先声明.构建第二棵树时,动态库将链接到可执行文件,该可执行文件也链接静态库,因此一切正常.这在macOS上不起作用,因为在第一棵CMake树中,编译器在动态库的链接步骤失败,因为第二棵树中的静态库尚不存在.

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).

设置如下:

  • 带有main()函数的最小C程序
  • 具有一个功能的动态库
  • 具有一个功能的静态库
  • 程序从动态库中调用一个函数.动态库当然是动态链接到程序的.
  • 动态库从静态库调用一个函数.静态库静态链接到动态库.

如果我们停止将静态库链接到动态库:

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)

我们当然在构建程序时会出错.但是错误在macOS和Linux上有所不同:

we, of course, get errors when building a program. But the errors are different on macOS and Linux:

macOS/clang较早发生故障,当动态库与 Linux/gcc稍后会失败,在该程序被链接的步骤中

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

我确实认识到差异可能在于我在macOS上使用clang和在Linux上使用gcc,但这并不能向我解释这个问题.

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.

我想知道:

  1. 为什么存在这种差异?
  2. 能否通过调整编译器/链接器标志来获得macOS上的Linux行为?


该示例已发布到Github:链接动态库,该动态库链接静态库中的符号(macOS与Linux).

这些是我在Github上的示例中的关键文件:

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输出

[ 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时遇到的相关问题的解决方案:.

I have managed to find a solution to the related issue that I also encountered while porting the same project from Linux to macOS: How to share a global variable between a main process and a dynamic library via a static library (macOS)?.

事实证明,在macOS上可以使用这种库符号的转发声明":

It turns out that this kind of "forward declaration" of the library symbols is possible on macOS:

添加-undefined dynamic_lookup标志可使macOS传递原始错误.

Adding the -undefined dynamic_lookup flag makes macOS to pass the original error.

将此添加到示例的CMakeLists.txt文件中即可解决此问题:

Adding this to my example's CMakeLists.txt file solves the issue:

target_link_options(dynamic_lib PRIVATE -undefined dynamic_lookup)

这篇关于链接从静态库链接符号的动态库:macOS与Linux的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆