【问题标题】:How to link app against a library that depends on another library?如何将应用程序链接到依赖于另一个库的库?
【发布时间】:2018-01-09 20:49:41
【问题描述】:

我写了一个共享库mylib1,它使用了一个第三方共享库,在我的例子中是libtinyxml2(对于这个问题,第三方库是无关紧要的:它可以是任何库)。我写了一个应用程序app1,它依赖于mylib1

构建mylib1 成功,但构建app1 失败,大概是因为在链接app1 时链接器没有被告知链接libtinyxml2

我错过了什么?

[I][~/Programs/cmake-jenkins/big_proj/src/build]$ make
[ 25%] Building CXX object mylib1/CMakeFiles/mylib1.dir/src/my_functions.cpp.o
[ 50%] Linking CXX shared library libmylib1.so
[ 50%] Built target mylib1
[ 75%] Building CXX object app1/CMakeFiles/app1.dir/src/main.cpp.o
[100%] Linking CXX executable app1
../mylib1/libmylib1.so: undefined reference to `tinyxml2::StrPair::Reset()'
../mylib1/libmylib1.so: undefined reference to `tinyxml2::StrPair::~StrPair()'
collect2: error: ld returned 1 exit status
make[2]: *** [app1/CMakeFiles/app1.dir/build.make:97: app1/app1] Error 1
make[1]: *** [CMakeFiles/Makefile2:402: app1/CMakeFiles/app1.dir/all] Error 2
make: *** [Makefile:84: all] Error 2

文件夹结构

.
├── app1
│   ├── CMakeLists.txt
│   ├── src
│   │   ├── include
│   │   │   └── functions_p.hpp
│   │   └── main.cpp
├── CMakeLists.txt
└── mylib1
    ├── CMakeLists.txt
    ├── src
    │   ├── include
    │   │   └── my_functions.hpp
    │   └── my_functions.cpp

./CMakeLists.txt

# Top level CMakeLists.txt
cmake_minimum_required(VERSION 3.8.2)

add_subdirectory(app1)
add_subdirectory(mylib1)

app1/CMakeLists.txt

project("app1" CXX)

set(APP1_SOURCE_FILES src/main.cpp )
add_executable(app1 ${APP1_SOURCE_FILES})

target_include_directories(app1
    PRIVATE src/include)
target_link_libraries(app1 mylib1)

mylib1/CMakeLists.txt

project("lib1" CXX)

find_library(TINYXML_LIB tinyxml2 REQUIRED)

set(MYLIB1_SOURCE_FILES src/my_functions.cpp )
set(MYLIB_INCLUDE_FILES src/include/my_functions.hpp)
add_library(mylib1 SHARED ${MYLIB1_SOURCE_FILES} ${MYLIB1_INCLUDE_FILES} )

target_include_directories(mylib1
    PUBLIC src/include)
# I have checked that TINYXML_LIB is set, so the library IS found.
target_link_libraries(mylib1 PUBLIC ${TINYXML_LIB})

readelf 输出显示该库依赖于libtinyxml2.so.6,并且此文件在我的系统上以/usr/lib/libtinyxml2.so.6 的形式存在。

[I][~/Programs/cmake-jenkins/big_proj/src/build]$ readelf -d mylib1/libmylib1.so
Dynamic section at offset 0x16cd0 contains 29 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libtinyxml2.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000000e (SONAME)             Library soname: [libmylib1.so]

在详细模式下运行生成的Makefile 表明,当app1 确实链接时,它不会链接到libtinyxml2

[ 75%] Linking CXX executable app1
cd /home/danb/Programs/cmake-jenkins/big_proj/src/build/app1 && /usr/bin/cmake -E cmake_link_script CMakeFiles/app1.dir/link.txt --verbose=1
/usr/bin/c++     CMakeFiles/app1.dir/src/main.cpp.o  -o app1 -Wl,-rpath,/home/danb/Programs/cmake-jenkins/big_proj/src/build/mylib1 ../mylib1/libmylib1.so

【问题讨论】:

  • 哪个链接命令用于创建您的可执行文件?您可以通过make VERBOSE=1 看到它。此外,/usr/include/libtinyxml2.so.6 似乎是一个错字 - 库通常位于 /usr/lib 左右。
  • @Tsyvarev 你是对的,这是一个错字,谢谢。我在问题的末尾粘贴了详细链接命令。
  • libtinyxml2链接不是CMake的责任,所以命令行中没有这个库。链接器应该检测DT_NEEDED 事物并相应地处理它们。但由于某种原因,它没有这样做。关于“二级链接”的一些描述可以在这篇博文中找到:kaizou.org/2015/01/linux-libraries
  • @Tsyvarev 感谢您的意见。在发布这个问题之前,我已经阅读了那篇文章,但没有找到我的答案。我将尝试在不使用 CMake/make 的情况下手动链接,它可能会提示出现了什么问题。
  • 你能显示message(STATUS "${TINYXML_LIB}")吗?因为它在PUBLIC 它应该填充目标INTERFACE_LINK_LIBRARIES 你也可以使用 find_package() 而不是 find_library 来获取包含目录等的目标“对象”...

标签: c++ linux cmake linker shared-libraries


【解决方案1】:

链接最终应用程序时会解析外部引用,因此请在 target_link_libraries 中包含 app1/CMakeLists.txt 中的 libtinyxml2。

【讨论】:

  • 但是构建系统应该处理依赖树。如果在目标mylib1 中我定义了它的所有依赖项,我当然不必在每个依赖于mylib1 的目标中再次定义mylib1 的所有依赖项。
【解决方案2】:

CMake 在模块中实现了此功能。见CMake Modules 如果需要,模块创建一个变量FOOMODULE_LIBRARIES。这个变量是一个列表

需要使用的库...

因此,您可以通过以下方式添加此依赖项:

  1. 为 mylib1 提供模块脚本
  2. 在项目 app1 中使用 find_package(mylib1)

例子:

find_package (mylib1)
include_directories(${mylib1_INCLUDE_DIRS})

add_executable(app1 main.cpp)
target_link_libraries(app1 ${mylib1_LIBRARIES})

注意:这使得mylib1 独立于app1。对于mylib1 的任何更改,您必须做额外的工作才能触发app1 的构建。见CMake Tutorials at http://www.th-thielemann.de/development

【讨论】:

    【解决方案3】:

    tinyxml2 库或我的安装肯定有问题(但它来自 ArchLinux 官方存储库),因为我已经用其他 2 个库替换了它,并且构建 app1 没有问题。

    我什至尝试手动链接app1,但它仍然会给出相同的undefined reference 错误:

    /usr/bin/c++     CMakeFiles/app1.dir/src/main.cpp.o  -o app1 -Wl,-rpath,/home/danb/Programs/cmake-jenkins/big_proj/src/build/mylib1 ../mylib1/libmylib1.so -ltinyxml2 -L /usr/lib
    

    我也试过用find_package()代替find_library(),因为libtinyxml2自带了一个CMake模块,但是问题依旧。

    有趣的是我什至不使用tinyxml2::StrPair::Reset()。这就是库实现的全部内容:

    #include <tinyxml2.h>
    
    bool is_xml_empty() {
        tinyxml2::StrPair pair;
        char* a;
        char* b;
        pair.Set(a, b, 0);
        return pair.Empty();
    }
    

    然而!我可以构建一个依赖于tinyxml2 的软件(encfs),它构建得很好!这表明我安装的库很好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-25
      • 2014-05-27
      • 1970-01-01
      • 2015-04-18
      • 1970-01-01
      • 2011-12-05
      相关资源
      最近更新 更多