Home > Software engineering >  Cmake install nested static library target_link_library undefined reference
Cmake install nested static library target_link_library undefined reference

Time:08-10

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?

CodePudding user response:

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

  • Related