'How to reuse an interface library in another project?
I want to reuse an interface library in another project. I tried it with:
find_package(mylib CONFIG REQUIRED)
target_link_libraries(project mylib)
Which gives the error:
/usr/bin/ld: cannot find -lmylib
Which I do not understand because I want to use an interface library why there is a linker error?
I made a minimal example of the interface library and the consumer project. Based on this stackoverlow answer
Console output install library:
walde@localhost build]$ cmake .. ; cmake --build . ; sudo cmake --install .
-- Configuring done
-- Generating done
-- Build files have been written to: /home/walde/projects/sandbox/cmake_get_target/myLib/build
-- Install configuration: ""
-- Up-to-date: /usr/local/lib/cmake/mylib/mylibTargets.cmake
-- Up-to-date: /usr/local/lib/cmake/mylib/mylibConfigVersion.cmake
-- Up-to-date: /usr/local/lib/cmake/mylib/mylibConfig.cmake
-- Up-to-date: /usr/local/include
-- Up-to-date: /usr/local/include/calc.hxx
-- Up-to-date: /usr/local/include/calc.cxx
-- Up-to-date: /usr/local/include/CMakeLists.txt
Console output consumer:
[walde@localhost build]$ cmake .. ; cmake --build .
-- Configuring done
-- Generating done
-- Build files have been written to: /home/walde/projects/sandbox/cmake_get_target/use_my_lib_in_another_project/build
Consolidate compiler generated dependencies of target project
[ 50%] Linking CXX executable project
/usr/bin/ld: cannot find -lmylib
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/project.dir/build.make:97: project] Error 1
make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/project.dir/all] Error 2
make: *** [Makefile:91: all] Error 2
[walde@localhost build]$
Solution 1:[1]
I want to reuse an interface library in another project. I tried it with:
find_package(mylib CONFIG REQUIRED) target_link_libraries(project mylib)
Three things:
- Absolutely never use
target_link_librarieswithout a visibility specifier. - When exporting targets, always include a namespace (via the
NAMESPACEargument toinstall(EXPORT)) so that theIMPORTEDtarget name contains a::sigil in it. - For consistency in the build and install trees, create an
ALIAStarget in the build with the same namespace prefix as your install will have.
The reason for (1) is that no-visibility is not the same as any of simply PRIVATE, INTERFACE, or PUBLIC, and it drops into a weird legacy compatibility mode when the styles are mixed. Absolutely always include the appropriate one of the three.
The reason for (2) is that names that contain :: are always interpreted as CMake targets. That would make the error you observed absolutely impossible. CMake would instead tell you that namespace::mylib doesn't exist and you could correct the typo.
When target_link_libraries gets a name without a :: sigil, it tries to find a target with the same name, but if that fails, then it forwards it on to the compiler driver with the -l flag (or equivalent).
For (3), consistency is nice and this will also help users of add_subdirectory or FetchContent switch between that and find_package more easily.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Alex Reinking |
