如何将应用程序链接到依赖于另一个库的库?

时间:2018-01-09 20:49:41

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

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

构建mylib1成功,但构建app1失败,可能是因为在链接libtinyxml2时未告知链接器与app1链接。

我错过了什么?

[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

3 个答案:

答案 0 :(得分:1)

在最终应用程序链接时解析外部引用,因此在target_link_libraries的{​​{1}}中包含libtinyxml2。

答案 1 :(得分:1)

CMake在模块中实现此功能。见CMake Modules 如果必要,模块创建变量FOOMODULE_LIBRARIES。该变量是

的列表
  

库需要使用......

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

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

    find_package (mylib1)
    include_directories(${mylib1_INCLUDE_DIRS})
    
    add_executable(app1 main.cpp)
    target_link_libraries(app1 ${mylib1_LIBRARIES})
    

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

答案 2 :(得分:0)

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),它构建得很好!这表明我安装的库很好。