Search code examples
cmakestatic-librariesstatic-linking

Linker errors on library built using CMake


I am pretty new to CMake and tried to write a simple static library that does some image manipulation using Qt4.

cmake_minimum_required(VERSION 2.8)
project(timage)

find_package(Qt4 REQUIRED)
include(${QT_USE_FILE})
add_definitions(${QT_DEFINITIONS})

include_directories(
    "${PROJECT_SOURCE_DIR}/include"
)
add_library(
    timage
    ${PROJECT_SOURCE_DIR}/source/timage.cpp
)
target_link_libraries(
    timage
    ${QT_LIBRARIES}
)

I can configure, and generate it, and it even successfully builds libtimage.a. Now I want to include it into my main project, and here is where the trouble begins.

I started off with some unit tests, but already I get linker errors (undefined reference for every single function call of the TImage class). I built my unit tests with g++ -Wall -Wextra -std=c++11 -I../include -L../bin -ltimage -o test spec.cpp

I personally do not see the difference between what I am doing to the beginner's tutorial besides the Qt4 work. I would appreciate if someone could give me a hint in the right direction here.

Update I just found out that if I build my test with this CMake file:

link_directories(
    ${PROJECT_BINARY_DIR}
)
add_definitions("-std=c++11")
add_executable(
    test
    spec.cpp
)
target_link_libraries(
    test
    timage
)

Everything works just as expected. I am currently trying to find out what CMake is doing that I am not.


Solution

  • Your problem is that libtimage.a is probably not in ../bin, but will by default be in ${PROJECT_BINARY_DIR} - your build directory.

    In your g++ command, you're adding ../bin to your libraries search paths, but you need to be adding wherever ${PROJECT_BINARY_DIR} is.

    This is achieved in your second CMakeLists file in the link_directories command. However, it's generally better to avoid using this command (the documentation explains why).

    If timage is available in your test's CMakeLists.txt as a CMake target, then there's no need to use link_directories - CMake already knows where to find the built library and will pass the appropriate -L flags automatically. By "CMake target" I mean it's defined in that file or a parent CMakeLists.txt using the add_library command.

    If timage isn't an actual CMake target in the test CMakeLists.txt (i.e. it's a totally separate project which isn't invoked from a common parent CMakeLists.txt), then you have a couple of options.

    You can export your timage project so that the test project can import it using include, or you can build the library separately, and then have the test find it using find_library. This will yield the full path to libtimage.a if it's found.

    All of these options would avoid you having to use link_directories.

    Another point is that you can see exactly what build command CMake is invoking by doing

    make VERBOSE=1
    

    so when you build your test, you can compare the CMake-generated command to your own.