通过字符串处理$<TARGET_FILE>定义CMake新目标及libtool文件生成问题
解决现代CMake中生成libtool文件的痛点
我完全理解你改造旧CMake脚本时遇到的这些麻烦——现代CMake对目标属性的限制、生成器表达式的使用边界,还有add_custom_command的单行命令限制确实很挠头。下面是针对你问题的具体解决方案,一步步帮你搞定:
1. 替代废弃的LOCATION属性
首先,现代CMake已经不推荐使用LOCATION属性(从3.0开始标记为废弃,3.14后彻底移除),取而代之的是生成器表达式来安全获取目标文件路径:
- 用
$<TARGET_FILE:your_target>获取目标的完整文件路径 - 用
$<TARGET_FILE_DIR:your_target>获取目标文件所在目录 - 用
$<TARGET_FILE_BASE_NAME:your_target>获取不带后缀的文件名
这些生成器表达式会在构建阶段自动求值,完全符合现代CMake的最佳实践。
2. 用cmake -P脚本处理复杂逻辑
你想到用cmake -P拆分复杂逻辑是非常正确的思路——因为add_custom_command的COMMAND字段里的生成器表达式只能直接用于命令参数,没法在里面做变量赋值、get_filename_component或者file(WRITE)这类操作。把这些逻辑放到单独的CMake脚本里,通过参数传递生成器表达式的值,就能完美解决问题。
具体实现步骤
第一步:编写单独的libtool生成脚本
创建一个比如GenerateLibtoolFile.cmake的文件,里面处理路径解析和文件生成逻辑:
cmake_minimum_required(VERSION 3.10) # 解析传入的参数 cmake_parse_arguments(PARSE_ARGV 0 ARGS "" "TARGET_FILE;OUTPUT_FILE;TARGET_VERSION;TARGET_SOVERSION" "") # 用get_filename_component处理路径 get_filename_component(TARGET_DIR "${ARGS_TARGET_FILE}" DIRECTORY) get_filename_component(TARGET_NAME "${ARGS_TARGET_FILE}" NAME_WE) get_filename_component(TARGET_EXT "${ARGS_TARGET_FILE}" EXT) # 生成libtool文件内容(根据你的需求调整字段) file(WRITE "${ARGS_OUTPUT_FILE}" "dlname='${TARGET_NAME}${TARGET_EXT}'\n") file(APPEND "${ARGS_OUTPUT_FILE}" "library_names='${TARGET_NAME}.so.${ARGS_TARGET_VERSION} ${TARGET_NAME}.so.${ARGS_TARGET_SOVERSION} ${TARGET_NAME}.so'\n") file(APPEND "${ARGS_OUTPUT_FILE}" "installed='${TARGET_DIR}/${TARGET_NAME}${TARGET_EXT}'\n") file(APPEND "${ARGS_OUTPUT_FILE}" "shouldnotlink=no\n") file(APPEND "${ARGS_OUTPUT_FILE}" "dlopen=''\n") file(APPEND "${ARGS_OUTPUT_FILE}" "dlpreopen=''\n") file(APPEND "${ARGS_OUTPUT_FILE}" "libdir='${TARGET_DIR}'\n")
第二步:在主CMakeLists.txt中调用这个脚本
在你的目标定义之后,用add_custom_command(如果是POST_BUILD)触发脚本执行,把生成器表达式作为参数传递:
add_library(your_target SHARED ...) set_target_properties(your_target PROPERTIES VERSION 1.0.0 SOVERSION 1 ) add_custom_command( TARGET your_target POST_BUILD COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_SOURCE_DIR}/GenerateLibtoolFile.cmake" --target-file="$<TARGET_FILE:your_target>" --output-file="${CMAKE_CURRENT_BINARY_DIR}/your_target.la" --target-version="$<TARGET_PROPERTY:your_target,VERSION>" --target-soversion="$<TARGET_PROPERTY:your_target,SOVERSION>" COMMENT "Generating libtool file for your_target" )
3. 关键细节说明
- 生成器表达式在
add_custom_command的COMMAND参数里会被正确求值,然后作为字符串传递给cmake -P脚本,脚本里直接用这些参数即可,不需要再处理生成器表达式。 - 如果需要更多目标属性,只需要在主CMake里用
$<TARGET_PROPERTY:your_target,PROPERTY_NAME>作为参数传递,脚本里通过cmake_parse_arguments接收就行。 - 这种方式完全符合现代CMake的非侵入式构建理念,避免了直接操作目标路径的风险,同时兼容各种生成器(Makefile、Ninja等)。
如果还有具体的libtool字段格式或者脚本逻辑的困惑,可以把你的需求细节补充出来,我再帮你调整。
内容的提问来源于stack exchange,提问作者user1832047
相关产品推荐
相关产品推荐

