Reputation: 5039
I wrote a shared library mylib1
that uses a 3rd-party shared library, in my case libtinyxml2
(for this problem the 3rd-party library is irrelevant: it can be any library). And I wrote an application app1
which depends on mylib1
.
Building mylib1
succeeds, but building app1
fails, presumably because the linker was not told to link against libtinyxml2
when linking app1
.
What am I missing?
[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
# Top level CMakeLists.txt
cmake_minimum_required(VERSION 3.8.2)
add_subdirectory(app1)
add_subdirectory(mylib1)
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)
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})
The readelf
output shows the library has a dependency to libtinyxml2.so.6
, and this file exists as /usr/lib/libtinyxml2.so.6
on my system.
[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]
Running the generated Makefile
in verbose mode shows that indeed when app1
is linked, it does not link against 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
Upvotes: 1
Views: 1357
Reputation: 5039
There must be something wrong with the tinyxml2 library or my installation of it (but it's from the official ArchLinux repository), because I've replaced it with 2 other libraries, and there were no issues building app1
.
I even tried to link app1
manually and it would still give the same undefined reference
errors:
/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
I also tried using find_package()
instead of find_library()
, because libtinyxml2 comes with a CMake module, but the problem remained.
What's funny is that I don't even make use of tinyxml2::StrPair::Reset()
. This is all that the library implements:
#include <tinyxml2.h>
bool is_xml_empty() {
tinyxml2::StrPair pair;
char* a;
char* b;
pair.Set(a, b, 0);
return pair.Empty();
}
And yet! I can build a software (encfs) that depends on tinyxml2
, and it builds just fine! This indicates my installation of the library is fine.
Upvotes: 0
Reputation: 2824
CMake implements this feature in the modules. See CMake Modules
If necessary modules create a variable FOOMODULE_LIBRARIES
. This variable is a list of
The libraries needed to use ...
Thus you can add this dependency by:
Example:
find_package (mylib1)
include_directories(${mylib1_INCLUDE_DIRS})
add_executable(app1 main.cpp)
target_link_libraries(app1 ${mylib1_LIBRARIES})
Note: This makes mylib1
independent from app1
. You have to do extra work to trigger a build of app1
for any change of mylib1
. See CMake Tutorials at http://www.th-thielemann.de/development
Upvotes: 1
Reputation: 1181
External references are resolved when the final application is linked so include libtinyxml2 in target_link_libraries
in app1/CMakeLists.txt
.
Upvotes: 1