Install nested static library, and target_link_library not working
File structure:
HelloLib
WorldLib
CMakeLists.txt
WorldLib.cpp
WorldLib.h
CMakeLists.txt
HelloLib.cpp
HelloLib.h
CMakeLists.txt
main.cpp
main.cpp
#include <iostream>
#include "HelloLib/HelloLib.h"
int main() {
std::cout << hello() << std::endl;
return 0;
}
CMakeLists.txt (root)
cmake_minimum_required(VERSION 3.16.3)
project(HelloWorld)
add_executable(${PROJECT_NAME} main.cpp)
add_subdirectory(HelloLib)
target_link_libraries(
${PROJECT_NAME}
HelloLib
)
HelloLib.cpp
#include <string>
#include "WorldLib/WorldLib.h"
std::string hello() { return "Hello " + world(); }
HelloLib.h
#pragma once
#include <string>
std::string hello();
CMakeLists.txt (HelloLib)
add_library(HelloLib HelloLib.cpp)
add_subdirectory(WorldLib)
target_link_libraries(
HelloLib
WorldLib
)
WorldLib.cpp
#include <string>
std::string world() { return "World!"; }
WorldLib.h
#pragma once
#include <string>
std::string world();
CMakeLists.txt (WorldLib)
add_library(WorldLib WorldLib.cpp)
Build and run, successfully print out Hello World!
Now I would like to make HelloLib as static library
Change CMakeLists.txt (HelloLib), install to /usr/lib and /usr/include
add_library(HelloLib HelloLib.cpp)
add_subdirectory(WorldLib)
target_link_libraries(
HelloLib
WorldLib
)
install(
TARGETS HelloLib
ARCHIVE DESTINATION lib
)
install(
DIRECTORY "${CMAKE_SOURCE_DIR}/" # source directory
DESTINATION "include" # target directory
FILES_MATCHING # install only matched files
PATTERN "*.h" # select header files
)
Run (make install) (CMAKE_INSTALL_PREFIX=/usr)
mkdir -p out/build
cmake -S src -B out/build -DCMAKE_INSTALL_PREFIX=/usr
cd out/build
make
make install
[ 33%] Built target WorldLib
[ 66%] Built target HelloLib
[100%] Built target HelloWorld
Install the project...
-- Install configuration: ""
-- Installing: /usr/lib/libHelloLib.a
-- Up-to-date: /usr/include
-- Installing: /usr/include/HelloLib
-- Installing: /usr/include/HelloLib/HelloLib.h
-- Installing: /usr/include/HelloLib/WorldLib
-- Installing: /usr/include/HelloLib/WorldLib/WorldLib.h
Static library (.a) should generate to /usr/lib/libHelloLib.a
Let’s test it, change CMakeLists.txt (root)
cmake_minimum_required(VERSION 3.16.3)
project(HelloWorld)
add_executable(${PROJECT_NAME} main.cpp)
add_subdirectory(HelloLib)
target_link_libraries(
${PROJECT_NAME}
/usr/lib/libHelloLib.a
)
Then build, it give undefined reference error
/bin/ld: /usr/lib/libHelloLib.a(HelloLib.cpp.o): in function `hello[abi:cxx11]()':
HelloLib.cpp:(.text+0x20): undefined reference to `world[abi:cxx11]()'
What’s wrong with me? This can be successful with no nested library
What is the correct way to install nested static library?
>Solution :
The issue here is not the install process but the fact that you link only to libHelloLib.a.
Your libHelloLib.a need the symbol in libWorldLib.a because libHelloLib.a is a static lib and so only contains its own symbol. It does not contains the symbol world that is defined in libWorldLib.a.
To make your project works, you need to install WorldLib and HelloLib and links against this two lib.
target_link_libraries(
${PROJECT_NAME}
HelloLib
WorldLib
)
Or you can change HelloLib into a shared library. This way the libHelloLib.so will also contains the symbol of WorldLib.
You can also look at this Exported Target.
It’s an install command that will create some FindXX.cmake file that you will be able to use with the find_package command. You also will be able to defined the dependency of your lib. But if you want that HelloLib stay a static library you will have to install WorldLib