Cmake Imported Library Behaviour

CMake imported library behaviour

For a shared library, the IMPORTED_LOCATION must point to the DLL, not the import lib. See the documentation. You might also want to set the IMPORTED_IMPLIB property.

BTW, CMake also has a find package for Curl; perhaps you could use that?

CMake - How to handle dependencies of imported library targets with TARGET_RUNTIME_DLLS

Since there seems to be no proper solution to this issue I came up with a (possibly fragile) workaround involving a meta target:

# same as before
add_library(foo_real SHARED IMPORTED)
set_target_properties(foo_real PROPERTIES
IMPORTED_LOCATION "${foo_dll_path}"
IMPORTED_IMPLIB "${foo_lib_path}"
)

# add SHARED IMPORTED target with the importlib pointing to foo_reals importlib location
add_library(bar SHARED IMPORTED)
set_target_properties(bar PROPERTIES
IMPORTED_LOCATION "${bar_dll_path}"
IMPORTED_IMPLIB "${foo_lib_path}" # same lib path as for imported target foo
)

# add meta target to combine both
add_library(foo INTERFACE IMPORTED)
target_link_libraries(foo INTERFACE foo_real bar)

# finally link the meta target to the final project
target_link_libraries(my_project PUBLIC foo)

This workaround will cause CMake to generate a build script passing foo.lib multiple times to the linker which does not seem to cause problems with the current MSVC Toolset. Also bar.dll will now be part of TARGET_RUNTIME_DLLS as intended.

CMake: add dependency to IMPORTED library

IMPORTED_LINK_INTERFACE_LIBRARIES:

There is an additional target property you can set, IMPORTED_LINK_INTERFACE_LIBRARIES

Transitive link interface of an IMPORTED target.

Set this to the list of libraries whose interface is included when an
IMPORTED library target is linked to another target.

The libraries will be included on the link line for the target.

Unlike the LINK_INTERFACE_LIBRARIES property, this property applies to all imported target types, including STATIC libraries.

set_target_properties(lib_foo 
PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES
pthread
)

-pthread Compiler Flag:

However, in this particular case, pthread linking issues, the problem would likely be solved by adding -pthread to your compiler flags

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread" )

From man gcc:

-pthread Adds support for multithreading with the pthreads library. This option sets flags for both the preprocessor and linker.

It causes files to be compiled with -D_REENTRANT, and linked with -lpthread. On other platforms, this could differ. Use -pthread for most portability.

See this question for more information

cmake: linking against STATIC IMPORTED library fails

I suspect that you ran into a visibility problem with the IMPORTED library target. According to the documentation:

An IMPORTED library target references a library file located outside the
project. ... The target name has scope in the directory in which it is
created and below, but the GLOBAL option extends visibility.

That's why the correct library path is used for the inner trading_demo target, but not for the outer order_example target. To fix the problem, adding the GLOBAL option should be sufficient:

add_library(lime_api STATIC IMPORTED GLOBAL)

How to make static imported library dependent on another static imported library in CMake?

The feature which I was looking for (add dependency of static import library on other import libraries) is called transitive linking. It is implemented by setting target property IMPORTED_LINK_INTERFACE_LIBRARIES. They say this property is depricated and recommend using INTERFACE_LINK_LIBRARIES, but in my case (cmake version 2.8.11.2) only IMPORTED_LINK_INTERFACE_LIBRARIES is working.

So for example above the end of CMakeLists.tst for LibA should look like this:

  add_library(LibC STATIC IMPORTED)
a̶d̶d̶_̶d̶e̶p̶e̶n̶d̶e̶n̶c̶i̶e̶s̶(̶L̶i̶b̶A̶ ̶L̶i̶b̶C̶)̶
set_property(TARGET LibC PROPERTY IMPORTED_LOCATION /path/to/LibC)

set_property(TARGET LibA PROPERTY IMPORTED_LINK_INTERFACE_LIBRARIES LibC)

Hope this information will be useful for someone.

CMake imported library rpath

If anyone cares, it was the IMPORTED_NO_SONAME property (absence of it set to TRUE) of each imported lib that forced the full path to be taken.

Also CMAKE_SKIP_RPATH and CMAKE_SKIP_INSTALL_RPATH are useful in my opinion to make sure you have clean runtime paths (not straightly related to the question but still).

Why use add_library({tgt} IMPORTED) versus target_link_libraries( -l {.so | .a})?

You should use add_library(<tgt> [SHARED|STATIC] IMPORTED) whenever you need to set properties such as dependencies, compile definitions, compile flags etc for <tgt>, and/or by extension, any targets that are linking against <tgt>.

Let's say you have two static libraries; libfoobar.a and libraboof.a, where libfoobar.a requires libraboof.a. Let's also say that these libraries contain some features that are enabled by -DSOME_FEATURE.

add_library(raboof STATIC IMPORTED)
set_target_properties(raboof PROPERTIES
IMPORTED_LOCATION <path-to-libraboof.a>
INTERFACE_COMPILE_DEFINITIONS "SOME_FEATURE"
)

add_library(foobar STATIC IMPORTED)
set_target_properties(foobar PROPERTIES
IMPORTED_LOCATION <path-to-libfoobar.a>
INTERFACE_LINK_LIBRARIES raboof
)

So when you link against libfoobar.a:

add_executable(my_app main.cpp)
target_link_libraries(my_app foobar)

CMake will make sure to link all dependencies in the correct order and will in this case also append -DSOME_FEATURE to the compile flags when you build my_app. Note that since we added libraboof.a as a dependency to libfoobar.a, -DSOME_FEATURE is added to any target that link against libfoobar.a through the transitive property.

If you don't use add_library(<tgt> <SHARED|STATIC> IMPORTED) in a scenario like this, you would have to manage any dependencies and required build options yourself for each target, which is quite error-prone.

This method is also often used in Config-modules for multi-component libraries to manage dependencies between the components.



Related Topics



Leave a reply



Submit