如何针对依赖于另一个库的库 link 应用程序?
How to link app against a library that depends on another library?
我写了一个使用第 3 方共享库的共享库 mylib1
,在我的例子中 libtinyxml2
(对于这个问题,第 3 方库是无关紧要的:它可以是任何库) .我写了一个应用程序 app1
依赖于 mylib1
.
构建 mylib1
成功,但构建 app1
失败,大概是因为 linker 没有被告知 link 反对 libtinyxml2
当 [=56] =]ing 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
被 linked 时,它不会 link 反对 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
链接最终应用程序时会解析外部引用,因此在 target_link_libraries
中将 libtinyxml2 包含在 app1/CMakeLists.txt
中。
CMake 在模块中实现了这个特性。参见 CMake Modules
如果需要,模块会创建一个变量 FOOMODULE_LIBRARIES
。此变量是
的列表
The libraries needed to use ...
因此您可以通过以下方式添加此依赖项:
- 为 mylib1 提供模块脚本
- 在项目 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
tinyxml2 库或我的安装一定有问题(但它来自官方 ArchLinux 存储库),因为我用其他 2 个库替换了它,并且构建没有问题 app1
.
我什至尝试手动 link 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),并且构建得很好!这表明我的库安装没问题。
我写了一个使用第 3 方共享库的共享库 mylib1
,在我的例子中 libtinyxml2
(对于这个问题,第 3 方库是无关紧要的:它可以是任何库) .我写了一个应用程序 app1
依赖于 mylib1
.
构建 mylib1
成功,但构建 app1
失败,大概是因为 linker 没有被告知 link 反对 libtinyxml2
当 [=56] =]ing 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
被 linked 时,它不会 link 反对 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
链接最终应用程序时会解析外部引用,因此在 target_link_libraries
中将 libtinyxml2 包含在 app1/CMakeLists.txt
中。
CMake 在模块中实现了这个特性。参见 CMake Modules
如果需要,模块会创建一个变量 FOOMODULE_LIBRARIES
。此变量是
The libraries needed to use ...
因此您可以通过以下方式添加此依赖项:
- 为 mylib1 提供模块脚本
- 在项目 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
tinyxml2 库或我的安装一定有问题(但它来自官方 ArchLinux 存储库),因为我用其他 2 个库替换了它,并且构建没有问题 app1
.
我什至尝试手动 link 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),并且构建得很好!这表明我的库安装没问题。