我正在从现有的GNU makefile重写cmake构建脚本。这是我试图编写的第一个cmake脚本。
GNU make提供vpaths命令,但我找不到相应的命令。
我已经实现了一个宏来解决它,但我发现它很难涵盖所有异常情况。
你有解决方法吗?
在许多来源和目录下需要一些时间。
macro(vpath resultSource NumOfSource NumOfDir sourceList DirList) math(EXPR startDirIndex“3 + $ {NumOfSource}”) math(EXPR endIndex“2 + $ {NumOfSource} + $ {NumOfDir}”)
message(STATUS "startDirIndex: ${startDirIndex}")
message(STATUS "endIndex: ${endIndex}")
set( __SRC_LIST__ )
set( __SRC_DIR__ )
set( pos 0 )
foreach(item ${ARGV})
if( ${pos} EQUAL ${startDirIndex}
OR ${pos} GREATER ${startDirIndex} )
list( APPEND __SRC_DIR__ ${item} )
#message(STATUS "DIR:${item}")
elseif( ${pos} GREATER 2 )
list( APPEND __SRC_LIST__ ${item} )
#message(STATUS "SRC:${item}")
endif( ${pos} EQUAL ${startDirIndex}
OR ${pos} GREATER ${startDirIndex} )
math(EXPR pos "${pos}+1")
endforeach(item ${ARGV})
#message(STATUS "__SRC_LIST__: ${__SRC_LIST__}")
#message(STATUS "__SRC_DIR__: ${__SRC_DIR__}")
#set( SOURCE_EXTENTION cpp c C CPP)
set( SOURCE_EXTENTION cpp )
#list( APPEND SOURCE_EXTENTION ${CMAKE_CXX_SOURCE_FILE_EXTENSIONS} ${CMAKE_C_SOURCE_FILE_EXTENSIONS} )
#message(STATUS "SOURCE_EXTENTION: ${SOURCE_EXTENTION}")
set( temp_list "" )
foreach( dir ${__SRC_DIR__} )
foreach( src ${__SRC_LIST__} )
set( cand_src )
foreach( postfix ${SOURCE_EXTENTION})
set( cand_src "${dir}/${src}.${postfix}" )
file(GLOB result ${cand_src} )
if( NOT ${result} STREQUAL "" )
list( APPEND temp_list ${result} )
endif( NOT ${result} STREQUAL "" )
endforeach( postfix ${SOURCE_EXTENTION})
endforeach( src ${__SRC_LIST__} )
endforeach( dir ${__SRC_DIR__} )
set( ${resultSource} ${temp_list} )
#message(STATUS "temp_list: ${temp_list}")
endmacro(vpath resultSource NumOfSource NumOfDir sourceList DirList)
答案 0 :(得分:3)
这就是我的想法。完全免责声明:我不是真正的cmake
大师,这个答案完全基于我在阅读问题后的研究。我没有测试此项目的项目,我从未在vpath
中使用过Makefile
。
此外,这个问题没有发布一个例子Makefile
,也没有发布OP使用的宏,这让我对提供一个"使用这个"而犹豫不决。回答,但是这里。
首先:为什么我们在vpath
使用Makefile
?
因为我不知道vpath
是什么,所以我查了一下。来自GNU Make Manual,第4.5节:
make的目录搜索功能通过自动搜索多个目录来查找先决条件来促进这一点... 类似于
VPATH
变量,但更具选择性,是vpath
指令(注意小写),它允许您为特定类别的文件名指定搜索路径:与特定模式匹配的那些。因此,您可以为一类文件名提供某些搜索目录,为其他文件名提供其他目录(或无)。
因此,您正在使用vpath
查找分布在多个目录中的文件。我进一步假设,这些文件要么是源文件,要么是在构建过程中创建的中间文件。
我找到了几个vpath
的示例,这些示例似乎表明了它的用法 - this StackOverflow question,this one以及最后Managing Projects with GNU make, 3rd Edition部分2.3。
这样为什么您正在使用vpath
。所以,继续前进:
其次,如何使用cmake
实现同样的目标。这是OP的进一步投入有用的地方。
如果你有多个目标,你正在从这样的目录结构构建:
|- library1/
|-- {C++ Source}
|- Tool/
|-- {C++ Source}
|- Project/
|-- src/
|---- {C++ Source}
您应该使用多个CMakeLists.txt
,每个子目录中都有一个library1
。在ADD_LIBRARY( libNAME src1.cxx src2.cxx src3.cxx )
中,您构建了库(Tool
),在ADD_EXECUTABLE( theTOOL src1.cxx src2.cxx )
中添加了可执行文件(Project/src/
)。最后,在ADD_EXECUTABLE
中,您使用libNAME
构建项目可执行文件,并将其链接到您在library1
中构建的CMakeLists.txt
。
在这种情况下,您永远不需要搜索,因为您的来源明确放置在|-Project/
|--src/
|----maths/
|------ { SOURCE FILES }
|----sound/
|------ { SOURCE FILES }
|----imagegeneration/
|------ { SOURCE FILES }
中。
如果您不执行上述操作,并且您的源代码遍布许多目录,请执行以下操作:
cmake --help-command file
在这种情况下,您只构建了一件事,而您只是为了易于使用而将源代码传播出去。在这种情况下,有几种选择。
您可以使用已发布的答案here自动将所有类型的文件添加到目标。这是 NOT 应该完成的!从add_subdirectory
(强调我的):
GLOB将生成一个与globbing表达式匹配的所有文件的列表并将其存储到变量中...我们不推荐使用GLOB从源代码树中收集源文件列表。[见下文查看原因]
您可以使用add_subdirectory
指令添加多个子目录,每个子目录对应一个子目录。这也不理想。 (一些支持文档:link讨论以这种方式使用aux_source_directory
)
您可以使用cmake --help-command aux_source_directory
从指定目录中收集源文件并存储在变量中。 (如果您对此感兴趣,请阅读cmake
)。但是,这也是不推荐。
所以为什么你不应该使用(1),(2)或(3)?
make
不是Makefiles
或cmake
的替换。相反,build system
生成一个CMakeLists.txt
,然后您可以使用它来构建项目。这是一个值得注意的区别。虽然您可以轻松地自动向cmake
添加多个来源,但会导致cmake
出现歧义:cmake --help-command aux_source_directory
将无法创建一个知道源文件的构建系统来确定变了!
这是上述所有三种方法的问题。来自cmake
:
虽然这似乎有效, CMake没有办法生成一个知道何时a的构建系统 新的源文件已添加。通常是生成的构建系统 知道何时需要重新运行CMake,因为CMakeLists.txt文件是 修改为添加新源。当源只是添加到 目录无需修改此文件,必须手动完成 重新运行CMake以生成包含新文件的构建系统。
总结:如何将源文件添加到cmake
?
使用CMakeLists.txt
时,您应明确将源文件添加到每个CMakeLists.txt
。如果您使用多个目录来分隔逻辑代码片段,则应在set ( MyApplication_SRC_FILES
maths/a.cpp
maths/b.cpp
sound/c.cpp
sound/d.cpp
imagegeneration/e.cpp
imagegeneration/f.cpp
)
ADD_EXECUTABLE ( MyApplication ${MyApplication_SRC_FILES} )
中明确设置,类似于以下内容:
cmake
这允许Makefile
生成可以构建代码的构建系统。有适当的方法可以将目录中的大量文件添加到构建系统中,如上面(1),(2)和(3)所述;但是他们应该谨慎对待,而不是因为"我是如何用Makefile
"来做的。你不会自己编写构建系统;这是{{1}}的后退,因此应该稍微区别对待。