保持文件层次结构在CMake中的子目录 [英] Keeping file hierarchy across subdirectories in CMake

查看:2480
本文介绍了保持文件层次结构在CMake中的子目录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

到目前为止,我仍然不明白为许多子目录下的CMake项目做这个最好的做法。



说我有一个项目层次结构因此,每个子目录中都有源文件...

   -  CMake项目源dir 
| SubD1
| - SubSubD1
| - SubD2

do是对根目录的CMakeLists.txt中的D2分别执行 add_subdirectory(SubD1),并递归地为SubD1目录的CMakeLists.txt中的子目录执行,而在每个子目录中声明变量,并使它们在根目录中显示 PARENT_SCOPE



code> Source2.cpp 存在于`SubSubD1',我只需要

  set(SUBSUBD1_SOURCES Source2.cpp PARENT_SCOPE)

并且希望能够在我的<$ c中使用SUBSUBD1_SOURCE $ c> SubD1 目录。
随后,在SubD1中存在 Source.cpp ,我会做

  set(SUBD1_SOURCES $ {SUBSUBD1_SOURCES} Source.cpp PARENT_SCOPE)

在根目录中可见。



问题是当然,当变量到达根目录时,文件路径不会保留。我现在正在做的是所有的源文件,我设置,我包括一个 $ {CMAKE_CURRENT_LIST_DIR}

 设置(SUBSUBD1_SOURCES $ {CMAKE_CURRENT_LIST_DIR} /Source2.cpp PARENT_SCOPE)

 设定(SUBD1_SOURCES $ {SUBSUBD1_SOURCES} $ {CMAKE_CURRENT_LIST_DIR} /Source.cpp PARENT_SCOPE)

在这种情况下,我可以说, c $ c> add_executable(myProg SUBSUBD1_SOURCES)在我的CMake项目的根目录。



有没有更好的方法,然后必须始终在所有源文件前面包含一个CMake变量?

解决方案

我有3种方式。我通常喜欢第一种方式,但已经使用所有3,取决于用例:



1。 root CMakeLists.txt 档案

 设定(
SUBD1_SOURCES
SubD1 / SubSubD1 / Source2.cpp
SubD1 / Source.cpp


set(
SUBD2_SOURCES
SubD2 / Source3.cpp


add_executable(myProg $ {SUBD1_SOURCES} $ {SUBD2_SOURCES})

2。您使用 OBJECT intermediate 媒体库收集/分组您​​的来源



SubD1 / SubSubD1 /CMakeLists.txt:

  add_library(SubSubD1Objs OBJECT Source2.cpp)
pre>

SubD1 / CMakeLists.txt:

  add_subdirectory(SubSubD1) 
add_library(SubD1Objs OBJECT Source.cpp)

CMakeLists.txt:

  add_executable(myProg $< TARGET_OBJECTS:SubSubD10bjs> $< TARGET_OBJECTS:SubD1Objs>)

3。 function()收集数据(并进行前缀)



CMakeLists.txt:

  function(my_collect_sources)
foreach(_source IN ITEMS $ {ARGN})
if(IS_ABSOLUTE$ {_ source} )
set(source_abs$ {_ source})
else()
get_filename_component(_source_abs$ {_ source}ABSOLUTE)
endif()
set_property GLOBAL APPEND PROPERTY GlobalSourceList$ {_ source_abs})
endforeach()
endfunction(my_collect_sources)

add_subdirectory(SubD1)
#add_subdirectory(SubD2)

get_property(MY_SOURCES GLOBAL PROPERTY GlobalSourceList)
add_executable(myProg $ {MY_SOURCES})

SubD1 / CMakeLists.txt:

  add_subdirectory(SubSubD1)
my_collect_sources(Source.cpp)$ b $

$

 $ 

 

p> my_collect_sources(Source2.cpp)


Till date I still do not really understand what the 'best practice' is for doing this for a CMake project with many subdirectories.

Say I have a project hierarchy as such and each subdirectory has source files in it...

--CMake Project Source dir
 |-- SubD1
   |-- SubSubD1
 |-- SubD2

What I would usually do is to do add_subdirectory(SubD1) and respectively for D2 in the CMakeLists.txt of the root directory and recursively for the subdirectory in the CMakeLists.txt of the SubD1 directory, while declaring variables in each subdirectory and making them visible in the root directory with PARENT_SCOPE.

That means if a file Source2.cpp exists in `SubSubD1', I'd simply do

set(SUBSUBD1_SOURCES Source2.cpp PARENT_SCOPE)

and expect to be able to use SUBSUBD1_SOURCE in my SubD1 directory. Subsequently, say Source.cpp exists in SubD1, I would do

set(SUBD1_SOURCES ${SUBSUBD1_SOURCES} Source.cpp PARENT_SCOPE)

so that all sources would be visible in root dir.

The problem is of course that the file paths aren't kept when the variables arrive at the root directory. What I'm currently doing is for all source files that I set, I include a ${CMAKE_CURRENT_LIST_DIR}, making it

set(SUBSUBD1_SOURCES ${CMAKE_CURRENT_LIST_DIR}/Source2.cpp PARENT_SCOPE)

and

set(SUBD1_SOURCES ${SUBSUBD1_SOURCES} ${CMAKE_CURRENT_LIST_DIR}/Source.cpp PARENT_SCOPE)

In this case, I could then say, do add_executable(myProg SUBSUBD1_SOURCES) in the root directory of my CMake project.

Are there any better ways of doing this then having to always include a CMake variable in front of all source files?

解决方案

There are 3 ways I have used before. I normally prefer the 1st way, but have already used all 3 depending on the use case:

1. You directly name the sources in your root CMakeLists.txt file

set(
    SUBD1_SOURCES
    "SubD1/SubSubD1/Source2.cpp"
    "SubD1/Source.cpp"
)

set(
    SUBD2_SOURCES
    "SubD2/Source3.cpp"
)

add_executable(myProg ${SUBD1_SOURCES} ${SUBD2_SOURCES})

2. You use OBJECT intermediate libraries to collect/group your sources

SubD1/SubSubD1/CMakeLists.txt:

add_library(SubSubD1Objs OBJECT Source2.cpp)

SubD1/CMakeLists.txt:

add_subdirectory(SubSubD1)
add_library(SubD1Objs OBJECT Source.cpp)

CMakeLists.txt:

add_executable(myProg $<TARGET_OBJECTS:SubSubD1Objs> $<TARGET_OBJECTS:SubD1Objs>)

3. You write your own function() to collect the data (and do the prefixing)

CMakeLists.txt:

function(my_collect_sources)
    foreach(_source IN ITEMS ${ARGN})
        if (IS_ABSOLUTE "${_source}")
            set(source_abs "${_source}")
        else()
            get_filename_component(_source_abs "${_source}" ABSOLUTE)
        endif()
        set_property(GLOBAL APPEND PROPERTY GlobalSourceList "${_source_abs}")
    endforeach()
endfunction(my_collect_sources)

add_subdirectory(SubD1)
#add_subdirectory(SubD2)

get_property(MY_SOURCES GLOBAL PROPERTY GlobalSourceList)
add_executable(myProg ${MY_SOURCES})

SubD1/CMakeLists.txt:

add_subdirectory(SubSubD1)
my_collect_sources(Source.cpp)

SubD1/SubSubD1/CMakeLists.txt:

my_collect_sources(Source2.cpp)

这篇关于保持文件层次结构在CMake中的子目录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆