c++cmakestaticlib

What does 'target_link_libraries' do when the target is a static library and the target link is a static library too?


From the following example:

CMakeList.txt file:

include_directories(inc)  

# Grab all the cpp and h files to be compile. 
file(GLOB SOURCES
    inc/*.h
    inc/*.hpp
    src/*.cpp
)

add_library(MyStaticLib STATIC ${SOURCES} )


target_link_libraries(MyStaticLib PUBLIC  "${OPENCV_LIBS}/opencv_world410.lib" )
target_link_libraries(MyStaticLib PUBLIC  "${OPENCV_LIBS}/opencv_world410d.lib" )

Does this create a single static library? I thought you could not link a static library to a static library in c++? Why does this work? Also, what would be the best way to do this? For example, if I create an API that is a static Lib i.e., MyStaticLib and it’s dependent on opencv’s Static lib, what would be the best way to set this up in CMake?


Solution

  • In short

    When target_link_libraries is applied to the static library, it won't affect on the resulted library file. But it affects on the target in the similar way, as it would affect on the target of the shared library.

    So, you can use target_link_libraries both for static and shared libraries in the same manner.

    In details

    When applied to the static library, target_link_libraries doesn't have immediate effect on the creation of this library. That is, when static library will be created (as file), it won't store that linkage:

    add_library(MyStaticLib STATIC ${SOURCES} )
    target_link_libraries(MyStaticLib PUBLIC  "${OPENCV_LIBS}/opencv_world410.lib")
    # When file 'MyStaticLib.lib' will be created,
    # it will NOT be linked with 'opencv_world410.lib'.
    

    (As you probably know, a static library doesn't store any information about the linkage, a static library is just a collection of object files.)

    But while the file with the static library doesn't store linkage information, the CMake target, which represents that static library, will be "aware of linkage". This can be useful in many cases:

    1. If in the same project you create an executable or a shared library, and link it with the static library (using target_link_libraries), that executable will actually linked with the dependent library:

      add_executable(myExe ...)
      target_link_libraries(myExe PRIVATE MyStaticLib)
      # When file 'myExe.exe' will be created, it WILL be linked with 'opencv_world410.lib'
      
    2. If in the same project you create another static library, and link it with the static one, the another static library will be "aware of linkage" both with the initial static library and its dependency.

      add_library(MyStaticLibAnother STATIC ..)
      target_link_libraries(MyStaticLibAnother PUBLIC MyStaticLib)
      # "As if" following line is executed
      # target_link_libraries(MyStaticLibAnother PUBLIC  "${OPENCV_LIBS}/opencv_world410.lib")
      
    3. If you install your library target and export it using command install(TARGETS ... EXPORT ...), then the library can be found with find_package. And that find_package will create a static library target, which will be aware of linkage with all its dependencies:

      # [In main project]
      install(TARGETS MyStaticLib EXPORT MyProject)
      install(EXPORT MyProject NAMESPACE MyProject::)
      
      # [In another project]
      find_package(MyProject REQUIRED)
      # It creates the target MyProject::MyStaticLib which is
      # "aware of linkage" with 'opencv_world410.lib'.
      

    Additionally, if you link a static library with a target (not with a plain file), and that target contains compile definitions or other information, applicable to the compile stage, the static library will be compiled using that compile information.