CMake中添加的导入库目标为何在install时提示不存在?
问题描述
以下是一段CMake代码,定义了用于添加导入库目标的宏,并调用该宏添加了两个导入目标:
cmake_minimum_required(VERSION 3.24) project(dummy) # etc. etc. set(installation_targets "") macro(add_cc_lib lib_name static_or_shared relative_lib_archive_path) set(tgt ${lib_name}) if(${static_or_shared} STREQUAL "STATIC") string(APPEND tgt "_static") endif() add_library(${tgt} ${static_or_shared} IMPORTED) message("added library ${tgt} with mode ${static_or_shared} IMPORTED GLOBAL") set_target_properties(${tgt} PROPERTIES IMPORTED_LOCATION ${PETMR_CLEARCASE_DEVEL_ROOT}/${relative_lib_archive_path}) foreach(arg IN ITEMS ${ARGN}) if(${arg} STREQUAL "NO_SONAME") set_target_properties(${tgt} PROPERTIES IMPORTED_NO_SONAME TRUE) else() target_include_directories(${tgt} SYSTEM INTERFACE ${PETMR_CLEARCASE_DEVEL_ROOT}/${arg}) endif() endforeach() list(APPEND installation_targets ${tgt}) endmacro() add_cc_lib( bar STATIC foo/bar.a foo/include ) add_cc_lib( baz SHARED foo/baz.a foo/include ) include(GNUInstallDirs) message(STATUS "installation_targets are \"${installation_targets}\"") install( TARGETS ${installation_targets} EXPORT ${PROJECT_NAME}_export RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" )
在GNU/Linux系统上使用CMake 3.31.6执行该代码时,能看到目标名称已被添加到installation_targets列表,但执行install指令时,CMake提示目标不存在,报错信息如下:
$ cmake -B build added library bar_static with mode STATIC IMPORTED added library baz with mode SHARED IMPORTED installation_targets are "bar_static;baz" CMake Error at CMakeLists.txt:31 (install): install TARGETS given target "bar_static" which does not exist. -- Configuring incomplete, errors occurred!
问题原因
核心原因是宏内部创建的导入目标默认仅存在于宏的作用域内,宏执行完毕后,这些目标会超出作用域,后续的install指令无法找到它们。
CMake的宏(macro)基于文本替换实现,其作用域与调用上下文隔离——在宏内部通过add_library创建的导入目标,默认不会暴露到宏外部的全局作用域。虽然目标名称被添加到了installation_targets列表,但实际的目标实体在宏执行结束后就失效了,导致install指令无法识别对应的目标。
解决方法:在创建导入目标时添加GLOBAL关键字,将目标注册为全局可见:
add_library(${tgt} ${static_or_shared} IMPORTED GLOBAL)
添加后,目标会保留在全局作用域中,宏执行完毕后依然有效,install指令就能正常处理这些目标了。
内容的提问来源于stack exchange,提问作者einpoklum
相关产品推荐
相关产品推荐

