CMake:如何更改子目录项目目标的属性?
CMake: How do I change properties on subdirectory project targets?
我正在尝试组织我的子项目中的目标(在本例中为 poco),但我发现无法为 ALIAS 目标修改属性。我希望我的外部项目中的目标位于它们自己的文件夹中,而不是散布在项目树中的任何地方(比如 visual studio 生成器)。有没有更简单的方法来添加具有我自己属性的项目?
所以代替:
- CMakePredefinedTargets
- ALL_BUILD
- INSTALL
- ...
- MyTargets
- SomeLibrary
- SomeExe
- CppUnit
- Crypto
- Data
- ...
我要:
- CMakePredefinedTargets
- ALL_BUILD
- INSTALL
- ...
- MyTargets
- SomeLibrary
- SomeExe
- Poco
- CppUnit
- Crypto
- Data
- ...
我的尝试:
function(add_subdirectory_with_folder folder_name)
function(add_library name type)
_add_library(${ARGV})
set_target_properties(${name}
PROPERTIES
FOLDER "${folder_name}"
)
endfunction()
add_subdirectory(${ARGN})
endfunction()
# External Libs
add_subdirectory_with_folder("Poco" libs/poco)
poco 库中的示例目标:
add_library( "${LIBNAME}" ${LIB_MODE} ${SRCS} )
add_library( "${POCO_LIBNAME}" ALIAS "${LIBNAME}")
set_target_properties( "${LIBNAME}"
PROPERTIES
VERSION ${SHARED_LIBRARY_VERSION} SOVERSION ${SHARED_LIBRARY_VERSION}
OUTPUT_NAME ${POCO_LIBNAME}
DEFINE_SYMBOL JSON_EXPORTS
)
我的目标是做到这一点,这样我就不必分叉和维护我自己的库版本,我只想使用这些库来调整生活质量。我可以使用其他方法来组织 IDE 的项目树吗?我知道 externalproject_add 存在,但我认为这里没有我正在寻找的设施。我将在未来以 git-submodules 的形式添加其他项目,但取决于是否有更简单的方法,我将探索其他途径。
编辑:
澄清一下,我已经为我自己项目的每个模块使用了一个单独的 CMakeLists.txt,加上一个将它们联系在一起的顶级 CMakeLists.txt,以及收集外部库我的目标依赖。我想修改外部库的目标而不必自己分叉和维护它们,这样我就可以在 visual studio、xcode 或其他目录中拥有漂亮的文件夹结构。 Linux 显然无关紧要,因为大多数编辑工具已经基于文件夹。
我试过你的例子,这里是我的两个变体:
使用 BUILDSYSTEM_TARGETS
and SUBDIRECTORIES
目录属性评估 "does not include any Imported Targets or Alias Targets":
目录中的目标名称列表
cmake_minimum_required(VERSION 3.7)
project(AliasFolderSub)
set_property(GLOBAL PROPERTY USE_FOLDERS TRUE)
function(get_all_targets _result _dir)
get_property(_subdirs DIRECTORY "${_dir}" PROPERTY SUBDIRECTORIES)
foreach(_subdir IN LISTS _subdirs)
get_all_targets(${_result} "${_subdir}")
endforeach()
get_property(_sub_targets DIRECTORY "${_dir}" PROPERTY BUILDSYSTEM_TARGETS)
set(${_result} ${${_result}} ${_sub_targets} PARENT_SCOPE)
endfunction()
function(add_subdirectory_with_folder _folder_name _folder)
add_subdirectory(${_folder} ${ARGN})
get_all_targets(_targets "${_folder}")
foreach(_target IN LISTS _targets)
set_target_properties(
${_target}
PROPERTIES FOLDER "${_folder_name}"
)
endforeach()
endfunction()
# External Libs
add_subdirectory_with_folder("Poco" libs/poco)
通过变换 FOLDER
target property into something that is inherited from a directory property of the same name. This can be done using define_property()
重新定义 FOLDER
属性 为 INHERITED
:
With the INHERITED
option the get_property() command will chain up to the next higher scope when the requested property is not set in the scope given to the command. DIRECTORY
scope chains to GLOBAL
. TARGET
, SOURCE
, and TEST
chain to DIRECTORY
.
cmake_minimum_required(VERSION 2.6)
project(AliasFolderSub)
set_property(GLOBAL PROPERTY USE_FOLDERS TRUE)
define_property(
TARGET
PROPERTY FOLDER
INHERITED
BRIEF_DOCS "Set the folder name."
FULL_DOCS "Use to organize targets in an IDE."
)
function(add_subdirectory_with_folder _folder_name _folder)
add_subdirectory(${_folder} ${ARGN})
set_property(DIRECTORY "${_folder}" PROPERTY FOLDER "${_folder_name}")
endfunction()
# External Libs
add_subdirectory_with_folder("Poco" libs/poco)
:使用 define_property()
重新定义现有 属性 的范围是 CMake 的未记录行为。
参考资料
- "make dist" equivalent in CMake
https://github.com/andry81/tacklelib
https://github.com/andry81/tacklelib/blob/trunk/cmake/tacklelib/Project.cmake
cmake_minimum_required(VERSION 3.14)
# enable project folders
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
## cmake builtin search paths and includes
LIST(APPEND CMAKE_MODULE_PATH "${TACKLELIB_CMAKE_ROOT}")
include(tacklelib/Project)
include(tacklelib/EnableTargetsExtension)
project(MyApp)
set(MYLIB_ROOT ...)
# somewhere at the end ...
## project folders
tkl_set_target_folder(CMAKE_CURRENT_LIST_DIR . * . UTILITY . util)
tkl_set_target_folder(CMAKE_CURRENT_LIST_DIR . * "tests" EXECUTABLE . exe)
tkl_set_target_folder(CMAKE_CURRENT_LIST_DIR . * . "SHARED_LIBRARY;STATIC_LIBRARY" . lib)
tkl_set_target_folder(MYLIB_ROOT * * . UTILITY . _3dparty/utility/mylib/util)
tkl_set_target_folder(MYLIB_ROOT * * "tests" EXECUTABLE . _3dparty/utility/mylib/exe)
tkl_set_target_folder(MYLIB_ROOT * * . "SHARED_LIBRARY;STATIC_LIBRARY" . _3dparty/utility/mylib/lib)
tkl_set_target_folder(MYLIB_ROOT * "tests" . * . _3dparty/utility/mylib/tests)
CMake 命令行:
cmake.exe -G "..." "-DTACKLELIB_CMAKE_ROOT=.../_externals/tacklelib/cmake" ...
项目目录结构:
...
_externals/
_out/
include/
src/
CMakeLists.txt
_out
- 带有 cmake 缓存和输出的目录
解决方案布局:
_3dparty
utility
mylib
lib
mylib
CMakePredefinedTargets
ALL_BUILD
INSTALL
ZERO_CHECK
exe
myapp
util
bundle
我正在尝试组织我的子项目中的目标(在本例中为 poco),但我发现无法为 ALIAS 目标修改属性。我希望我的外部项目中的目标位于它们自己的文件夹中,而不是散布在项目树中的任何地方(比如 visual studio 生成器)。有没有更简单的方法来添加具有我自己属性的项目?
所以代替:
- CMakePredefinedTargets
- ALL_BUILD
- INSTALL
- ...
- MyTargets
- SomeLibrary
- SomeExe
- CppUnit
- Crypto
- Data
- ...
我要:
- CMakePredefinedTargets
- ALL_BUILD
- INSTALL
- ...
- MyTargets
- SomeLibrary
- SomeExe
- Poco
- CppUnit
- Crypto
- Data
- ...
我的尝试:
function(add_subdirectory_with_folder folder_name)
function(add_library name type)
_add_library(${ARGV})
set_target_properties(${name}
PROPERTIES
FOLDER "${folder_name}"
)
endfunction()
add_subdirectory(${ARGN})
endfunction()
# External Libs
add_subdirectory_with_folder("Poco" libs/poco)
poco 库中的示例目标:
add_library( "${LIBNAME}" ${LIB_MODE} ${SRCS} )
add_library( "${POCO_LIBNAME}" ALIAS "${LIBNAME}")
set_target_properties( "${LIBNAME}"
PROPERTIES
VERSION ${SHARED_LIBRARY_VERSION} SOVERSION ${SHARED_LIBRARY_VERSION}
OUTPUT_NAME ${POCO_LIBNAME}
DEFINE_SYMBOL JSON_EXPORTS
)
我的目标是做到这一点,这样我就不必分叉和维护我自己的库版本,我只想使用这些库来调整生活质量。我可以使用其他方法来组织 IDE 的项目树吗?我知道 externalproject_add 存在,但我认为这里没有我正在寻找的设施。我将在未来以 git-submodules 的形式添加其他项目,但取决于是否有更简单的方法,我将探索其他途径。
编辑:
澄清一下,我已经为我自己项目的每个模块使用了一个单独的 CMakeLists.txt,加上一个将它们联系在一起的顶级 CMakeLists.txt,以及收集外部库我的目标依赖。我想修改外部库的目标而不必自己分叉和维护它们,这样我就可以在 visual studio、xcode 或其他目录中拥有漂亮的文件夹结构。 Linux 显然无关紧要,因为大多数编辑工具已经基于文件夹。
我试过你的例子,这里是我的两个变体:
使用
目录中的目标名称列表BUILDSYSTEM_TARGETS
andSUBDIRECTORIES
目录属性评估 "does not include any Imported Targets or Alias Targets":cmake_minimum_required(VERSION 3.7) project(AliasFolderSub) set_property(GLOBAL PROPERTY USE_FOLDERS TRUE) function(get_all_targets _result _dir) get_property(_subdirs DIRECTORY "${_dir}" PROPERTY SUBDIRECTORIES) foreach(_subdir IN LISTS _subdirs) get_all_targets(${_result} "${_subdir}") endforeach() get_property(_sub_targets DIRECTORY "${_dir}" PROPERTY BUILDSYSTEM_TARGETS) set(${_result} ${${_result}} ${_sub_targets} PARENT_SCOPE) endfunction() function(add_subdirectory_with_folder _folder_name _folder) add_subdirectory(${_folder} ${ARGN}) get_all_targets(_targets "${_folder}") foreach(_target IN LISTS _targets) set_target_properties( ${_target} PROPERTIES FOLDER "${_folder_name}" ) endforeach() endfunction() # External Libs add_subdirectory_with_folder("Poco" libs/poco)
通过变换
FOLDER
target property into something that is inherited from a directory property of the same name. This can be done usingdefine_property()
重新定义FOLDER
属性 为INHERITED
:With the
INHERITED
option the get_property() command will chain up to the next higher scope when the requested property is not set in the scope given to the command.DIRECTORY
scope chains toGLOBAL
.TARGET
,SOURCE
, andTEST
chain toDIRECTORY
.cmake_minimum_required(VERSION 2.6) project(AliasFolderSub) set_property(GLOBAL PROPERTY USE_FOLDERS TRUE) define_property( TARGET PROPERTY FOLDER INHERITED BRIEF_DOCS "Set the folder name." FULL_DOCS "Use to organize targets in an IDE." ) function(add_subdirectory_with_folder _folder_name _folder) add_subdirectory(${_folder} ${ARGN}) set_property(DIRECTORY "${_folder}" PROPERTY FOLDER "${_folder_name}") endfunction() # External Libs add_subdirectory_with_folder("Poco" libs/poco)
:使用
define_property()
重新定义现有 属性 的范围是 CMake 的未记录行为。
参考资料
- "make dist" equivalent in CMake
https://github.com/andry81/tacklelib
https://github.com/andry81/tacklelib/blob/trunk/cmake/tacklelib/Project.cmake
cmake_minimum_required(VERSION 3.14)
# enable project folders
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
## cmake builtin search paths and includes
LIST(APPEND CMAKE_MODULE_PATH "${TACKLELIB_CMAKE_ROOT}")
include(tacklelib/Project)
include(tacklelib/EnableTargetsExtension)
project(MyApp)
set(MYLIB_ROOT ...)
# somewhere at the end ...
## project folders
tkl_set_target_folder(CMAKE_CURRENT_LIST_DIR . * . UTILITY . util)
tkl_set_target_folder(CMAKE_CURRENT_LIST_DIR . * "tests" EXECUTABLE . exe)
tkl_set_target_folder(CMAKE_CURRENT_LIST_DIR . * . "SHARED_LIBRARY;STATIC_LIBRARY" . lib)
tkl_set_target_folder(MYLIB_ROOT * * . UTILITY . _3dparty/utility/mylib/util)
tkl_set_target_folder(MYLIB_ROOT * * "tests" EXECUTABLE . _3dparty/utility/mylib/exe)
tkl_set_target_folder(MYLIB_ROOT * * . "SHARED_LIBRARY;STATIC_LIBRARY" . _3dparty/utility/mylib/lib)
tkl_set_target_folder(MYLIB_ROOT * "tests" . * . _3dparty/utility/mylib/tests)
CMake 命令行:
cmake.exe -G "..." "-DTACKLELIB_CMAKE_ROOT=.../_externals/tacklelib/cmake" ...
项目目录结构:
...
_externals/
_out/
include/
src/
CMakeLists.txt
_out
- 带有 cmake 缓存和输出的目录
解决方案布局:
_3dparty
utility
mylib
lib
mylib
CMakePredefinedTargets
ALL_BUILD
INSTALL
ZERO_CHECK
exe
myapp
util
bundle