在一个大型CMake/c++项目中,我们的主要库目标Foo
正在被添加。它有许多静态链接的依赖项,作为target_link_libraries()
的绝对路径提供。现在我正在写CMake来导出这个库一旦建成,包括生成的CMake,这样一个库消费者可以简单地使用CMakefind_package()
。然而,生成的FooTargets.cmake
嵌入了链接库的绝对路径,而不仅仅是库的名称。
此外,我已经创建了一个add_library(BarCommon INTERFACE)
,分别打包引用的第三方静态库,这似乎正在工作,客户端应用程序使用它。这占FOO提到的库的90%。所以FOO输出的INTERFACE_LINK_LIBRARIES
应该是3个文件名,而不是40个绝对路径名。
我很困惑,为什么
target_link_libraries(FOO PRIVATE ${libs}
正在定义导出的'INTERFACE_LINK_LIBRARIES'属性?我希望生成的
INTERFACE_LINK_LIBRARIES
属性仅为库文件名,并且最好能够更好地控制哪些文件名最终在其中。我如何控制它?
代码:
在一个大型CMake宏中生成目标,我们有这样的:-
- 我调用它来创建库/目标FOO。 <
_TARGET_ARGS_LIB_DEPENDS
将决心em>文件绝对路径名40静态链接库依赖关系。
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>
)
在这个较长的函数返回的地方,我刚刚添加了这些块:
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
)
在我的CMakeLists.txt的末尾有一些更多的"安装"样板文件在我运行CMAKE,构建项目并运行从Visual Studio生成的'INSTALL'目标CMAKE之后,我可以检查生成的文件:local_installReleaseWindowsFoolibcmakeFooFooTargets.cmake
显示:
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>>"
)
(包含大约40个库的完整路径)。
p。我正在阅读专业CMake:实用指南,所以如果有人能引用回答这个问题的章节/子节,可能会有所帮助。
这是因为你的库是静态的,所以如果不包括它对消费者链接行的依赖,它就不能正确地链接到消费者。对于共享库的共享依赖项也是如此。共享库的静态依赖被完全"吸收";到共享库中,所以它们不会出现
CMake知道所有这些,因此为了尊重PRIVATE
的其他语义,它插入了$<LINK_ONLY:...>
生成器表达式。这确保了库仅用于链接,并且不传播任何相关的INTERFACE_*
属性。
也就是说,CMake在这里的行为是正确的。
你应该通过创建和链接到目标libB
和朋友,你可以导出作为你的主要构建的一部分或导入到你的主要构建和通过find_dependency
在你的分布式包,当然,随着库本身来解决这个问题。
我能给你的最好的建议是总是链接到目标在CMake中,永远不要使用路径或原始库标志。