我仍然不完全了解使用源代码的嵌套文件夹的深层次结构配置CMake项目的正确方法。这里,为MSVC 2013配置
以下是此类项目的示例:
+RootFolder(no code)
+NestedFolder1(no code)
+NestedNestedFolder1(has code .h and .cpp)
+NestedNestedFolder2(has code and nested folder with code)
+NestedNestedNestedFolder1(has code .h and .cpp)
我在CMake中配置它的方式:
RootFolder CMakeLists:
project(MyDemoCmakeProject)
add_subdirectory(NestedFolder1)
NestedFolder1 CMakeLists:
add_subdirectory(NestedNestedFolder1)
add_subdirectory(NestedNestedFolder2)
add_definitions(.....)
include_directories(.....)
NestedNestedFolder1 CMakeLists:
set(mysources ${sources})
add_library(MyLib STATIC ${mysources })
NestedNestedFolder2 CMakeLists:
subdirs(NestedNestedNestedFolder1)
set(mysources ${sources})
add_library(MyLib STATIC ${mysources })
NestedNestedNestedFolder1 CMakeLists:
set(mysources ${sources})
add_library(MyLib STATIC ${mysources })
运行CMake时使用此配置我得到:
add_library无法创建目标" MyLib"因为另一个目标 同名已存在。现有目标是静态库 在源目录NestedNestedFolder1
中创建
现在,如果我删除 add_subdirectory(NestedNestedFolder1) add_subdirectory(NestedNestedFolder2)
来自NestedFolder1 CMakeLists.txt它运行正常。我不完全理解这一刻。例如在NestedNestedFolder2中我也为嵌套的子目录做了add_subdirectory但是它没有抱怨。我也没有&# 39;了解CMake如何能够揭示' NestedFolder1的子目录,如果我不是add_subdirectory()那些。从不同的例子中我了解到每个具有源子目录的目录必须用subdirs()或add_subdirectory()公开它。我想念这里?
答案 0 :(得分:2)
subdirs
是添加子目录的旧方法,已弃用。 CMake docs说要使用add_subdirectory
代替。 subdirs
的行为与add_subdirectory
略有不同,因为前者还会搜索子目录中的CMakeLists.txt
个文件并自动添加它们。
有一些方法可用于管理深层次结构,例如您描述的方案。按照我个人的偏好顺序:
方法1:
这需要CMake 3.1或更高版本,因为它使用target_sources
命令。您可以在顶层定义可执行目标,然后在每个子目录中调用target_sources
以向其添加源。您还可以根据需要在每个子目录中使用target_include_directories
和target_compile_definitions
,而不是在顶层调用add_definitions
和include_directories
,以使这些依赖项附加到目标而不是应用于一切(如果你以后在顶级CMakeLists.txt文件中添加了更多内容,那么这里真的很重要)。对于您的场景,它看起来类似于以下内容(为了说明目的,我插入了虚拟源文件名和编译定义):
RootFolder CMakeLists:
project(MyDemoCmakeProject)
# add_library() requires a source file argument to be
# present, but it can be an empty string if there are
# no source files, headers, etc. that should be added
# from this directory.
add_library(MyLib STATIC "")
add_subdirectory(NestedFolder1)
NestedFolder1 CMakeLists:
add_subdirectory(NestedNestedFolder1)
add_subdirectory(NestedNestedFolder2)
NestedNestedFolder1 CMakeLists:
target_sources(MyLib PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/fileNN1a.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/fileNN1b.cpp"
)
target_include_directories(MyLib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
NestedNestedFolder2 CMakeLists:
add_subdirectory(NestedNestedNestedFolder1)
target_sources(MyLib PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/fileNN2a.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/fileNN2b.cpp"
)
target_include_directories(MyLib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
target_compile_definitions(MyLib PUBLIC -DSOME_VAL=42)
NestedNestedNestedFolder1 CMakeLists:
target_sources(MyLib PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/fileNNN1a.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/fileNNN1b.cpp"
)
target_include_directories(MyLib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
这种方法的优点是每个子目录都是自包含的。上层不必知道较低层正在做什么。此外,信息在该信息最相关/已知的级别添加到目标。一个缺点是你必须添加每个源的完整路径,但这是一个小小的不便。
方法2:
使用变量来累积源文件名,并在包含所有子目录后在顶层添加该变量的内容,而不是使用target_sources
。我们也使用include
而不是add_subdirectory
,以便我们的变量始终在同一范围内进行操作。由于在之后拉入子目录时未定义目标,因此您也无法使用target_compile_definitions
或target_include_directories
,因此这些也必须通过变量进行处理。
RootFolder CMakeLists:
project(MyDemoCmakeProject)
set(MyLib_SOURCES)
set(MyLib_INCLUDE_DIRS)
set(MyLib_DEFINITIONS)
include(NestedFolder1/CMakeLists.txt)
add_library(MyLib STATIC ${MyLib_SOURCES})
target_include_directories(MyLib PUBLIC ${MyLib_INCLUDE_DIRS})
target_compile_definitions(MyLib PUBLIC ${MyLib_DEFINITIONS})
NestedFolder1 CMakeLists:
include(NestedNestedFolder1/CMakeLists.txt)
include(NestedNestedFolder2/CMakeLists.txt)
NestedNestedFolder1 CMakeLists:
list(APPEND MyLib_SOURCES
"${CMAKE_CURRENT_SOURCE_DIR}/fileNN1a.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/fileNN1b.cpp"
)
list(APPEND MyLib_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}")
NestedNestedFolder2 CMakeLists:
include(NestedNestedNestedFolder1/CMakeLists.txt)
list(APPEND MyLib_SOURCES
"${CMAKE_CURRENT_SOURCE_DIR}/fileNN2a.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/fileNN2b.cpp"
)
list(APPEND MyLib_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}")
list(APPEND MyLib_DEFINITIONS -DSOME_VAL=42)
NestedNestedNestedFolder1 CMakeLists:
list(APPEND MyLib_SOURCES
"${CMAKE_CURRENT_SOURCE_DIR}/fileNNN1a.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/fileNNN1b.cpp"
)
list(APPEND MyLib_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}")
这不如方法1的主要原因是通过变量携带所有源,头路径和编译定义使其更脆弱。所有子目录都必须运行良好,不要使用相同的变量名称来处理其他任何事情(小问题)和处理嵌入空间的路径需要更多的关注(棘手的问题)。另一个缺点是必须更仔细地处理可变范围。任何add_subdirectory
调用都会改变范围。这种方法优于方法1的一个优点是它适用于许多旧版本的CMake。
方法3:
另一种方法是在每个子目录级别定义一个库,并对其进行顶级库链接。这些子目录级库可以是静态库或共享库,也可以是对象库(这需要更新的CMake版本)。这种方法的优点是它甚至可以用于旧版本的CMake。缺点取决于您的观点。这将导致定义更多的目标,并且可能降低并行构建的有效性。对于少数子目录,我建议这种方法可能实际上是最好的,但是一旦你超越了几个子目录,事情就会很快开始失控。
答案 1 :(得分:0)
问题是您有多个具有相同名称的目标:" MyLib"。只需给每个库一个唯一的名称,它应该可以工作。