In a large CMake/C++ project our major library target Foo
is being added. It has many statically linked dependencies that are provided as absolute-paths to target_link_libraries()
. Now I'm writing the CMake to export this library once built, including the generated CMake so a library consumer can simply use CMake find_package()
. However the generated FooTargets.cmake
is embeding the absolute-paths of the link-libraries instead of just the library names.
Additionally, I've already created an add_library(BarCommon INTERFACE)
, to wrap up the referenced 3rd-party static libs separately and that seems to be working and the client-application consumed it. That accounts for 90% of the libraries also mentioned by FOO. So really FOO's exported INTERFACE_LINK_LIBRARIES
should be about 3 file names instead of 40 absolute-pathnames.
I'm confused, why is the target_link_libraries(FOO PRIVATE ${libs}
is defining the exported 'INTERFACE_LINK_LIBRARIES' property?
I would like that generated INTERFACE_LINK_LIBRARIES
property to be only library filenames, and optimally have finer control over which filenames end up in it. How do I control this?
Code:
Inside a large CMake Macro for generating targets we have this: -
_TARGET_ARGS_LIB_DEPENDS
will resolve to ABSOLUTE FILE PATHNAMES for about 40 statically linked library dependencies.add_library(${TargetName} STATIC ${AllSources} ${_TARGET_ARGS_OBJ_FILES})
<snip>
target_link_libraries(${TargetName}
PRIVATE
$<${GCC}:-Wl,--start-group>
${_TARGET_ARGS_LIB_DEPENDS}
$<${GCC}:-Wl,--end-group>
)
where that longish function returns I have just added these blocks:
target_link_directories(FOO
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
$<INSTALL_INTERFACE:foo/lib>
)
target_include_directories(FOO
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:foo/include>
)
install(TARGETS Foo
EXPORT
FooTargets
DESTINATION
foo/lib
)
There is some more 'install' boilerplate at the end of my CMakeLists.txt
After I run CMAKE, build the project and run the 'INSTALL' target CMake generated from Visual Studio I can examine generated file: local_install\Release\Windows\Foo\lib\cmake\Foo\FooTargets.cmake
shows:
set_target_properties(Nexidia.Workbench.StaticLib.StaticLib PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/Foo/include"
INTERFACE_LINK_DIRECTORIES "${_IMPORT_PREFIX}/Foo/lib"
INTERFACE_LINK_LIBRARIES "\$<LINK_ONLY:\$<0:-Wl,--start-group>>;C:/full/path/to/libA.lib;C:/full/path/to/libB.lib \$<LINK_ONLY:\$<0:-Wl,--end-group>>"
)
(with the full paths to about 40 libraries).
PS. I'm reading Professional CMake: A Practical Guide, so if someone could cite the chapter/sub-section that answers this it might help.
This is because your library is static and so it cannot be correctly linked to consumers without including its dependencies on consumers' link lines. The same thing happens with the shared dependencies of shared libraries. Static dependencies of shared libraries are fully "absorbed" into the shared library and so they don't appear.
CMake is aware of all this, and so to respect the other semantics of PRIVATE
, it inserts the $<LINK_ONLY:...>
generator expression. This ensures that the libraries are used for linking only and that any associated INTERFACE_*
properties are not propagated.
In other words, CMake is behaving correctly here.
You should resolve this by creating and linking to targets for libB
and friends that you can either export as part of your main build or import into both your main build and via find_dependency
in your distributed package, along with the libraries themselves, of course.
The best advice I can give you is to always link to targets in CMake, never to paths or raw library flags.