CMake 如何将生成目录设置为不同于源目录

我对 CMake 相当陌生,阅读了一些关于如何使用它的教程,并且写了一些复杂的50行 CMake 脚本,以便为3个不同的编译器编写一个程序。这可能就是我在 CMake 中的全部知识。

现在我的问题是,我有一些源代码,我不想触摸/混乱的文件夹时,我做的程序。我希望所有的 CMake 和 make输出文件和文件夹都进入到 ../Compile/中,所以我在 CMake 脚本中为此修改了一些变量,当我在笔记本电脑上做类似的事情时,它曾经起过作用:

Compile$ cmake ../src
Compile$ make

我现在所在的文件夹中有一个干净的输出,这正是我要找的。

现在我转移到另一台计算机,重新编译了 CMake 2.8.11.2,我几乎又回到了起点!它总是编译的东西到 src文件夹中,我的 CMakeLists.txt是位于。

我在 CMake 脚本中选择目录的部分如下:

set(dir ${CMAKE_CURRENT_SOURCE_DIR}/../Compile/)
set(EXECUTABLE_OUTPUT_PATH ${dir} CACHE PATH "Build directory" FORCE)
set(LIBRARY_OUTPUT_PATH ${dir} CACHE PATH "Build directory" FORCE)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${dir})
set(CMAKE_BUILD_FILES_DIRECTORY ${dir})
set(CMAKE_BUILD_DIRECTORY ${dir})
set(CMAKE_BINARY_DIR  ${dir})
SET(EXECUTABLE_OUTPUT_PATH ${dir})
SET(LIBRARY_OUTPUT_PATH ${dir}lib)
SET(CMAKE_CACHEFILE_DIR ${dir})

而现在,它总是以:

-- Build files have been written to: /.../src

我错过了什么吗?

344140 次浏览

您不应该依赖脚本中的硬编码构建目录名称,因此必须更改 ../Compile代码行。

这是因为它应该由用户决定在哪里编译。

取而代之的是使用一个预定义的变量: Http://www.cmake.org/wiki/cmake_useful_variables (查找 CMAKE_BINARY_DIRCMAKE_CURRENT_BINARY_DIR)

不需要设置您正在设置的所有变量。CMake 将它们设置为合理的默认值。你一定要 没有修改 CMAKE_BINARY_DIRCMAKE_CACHEFILE_DIR。将它们视为只读。

首先从 src 目录中删除现有的有问题的缓存文件:

cd src
rm CMakeCache.txt
cd ..

然后删除所有 set()命令并执行:

cd Compile && rm -rf *
cmake ../src

只要在运行 CMake 时不在源目录中,它就不会修改源目录,除非 CMakeList 明确告诉它这样做。

一旦完成了这项工作,您就可以查看 CMake 在默认情况下放置东西的位置,并且只有在您对默认位置(例如 EXECUTABLE_OUTPUT_PATH的默认值)不满意的情况下,才可以修改那些您需要的位置。并尝试表达相对于 CMAKE_BINARY_DIRCMAKE_CURRENT_BINARY_DIRPROJECT_BINARY_DIR等。

如果查看 CMake 文档,您将看到变量被划分为语义部分。除了 非常特殊情况外,您应该将“提供信息的变量”下列出的所有变量视为 CMakeList 中的只读变量。

听起来你想要 源代码之外的构建。有几种方法可以创建源代码外构建。

  1. 做你该做的,快跑

     cd /path/to/my/build/folder
    cmake /path/to/my/source/folder
    

    这将导致 cmake 在 /path/to/my/build/folder中为 /path/to/my/source/folder中的 源树生成 建树

    一旦您创建了它,cmake 就会记住源文件夹的位置-这样您就可以重新运行它 构建树上的 cmake

     cmake /path/to/my/build/folder
    

    甚至

     cmake .
    

    如果你的工作目录已经是 build 文件夹。

  2. 对于 CMake 3.13或更高版本,使用 < a href = “ https://cmak.org/CMake/help/best/Manual/CMake.1.html”rel = “ nofollow noReferrer”> 这些选项来设置源代码和构建文件夹

     cmake -B/path/to/my/build/folder -S/path/to/my/source/folder
    
  3. 对于较老的 CMake,使用一些 设置源文件夹和生成文件夹的未记录选项:

     cmake -B/path/to/my/build/folder -H/path/to/my/source/folder
    

    这将做完全相同的事情(1) ,但没有依赖于目前的工作目录。

CMake 默认将其所有输出放在 建树中,因此除非您在 CMake 文件中大量使用 ${CMAKE_SOURCE_DIR}${CMAKE_CURRENT_SOURCE_DIR},否则它不应该触及您的 源树

可能出现的最大问题是,如果您以前在源代码树中生成了一个构建树(即,您有一个 源头构建)。完成这一步之后,上面(1)的第二部分就开始了,cmake 不会对源代码或构建位置做任何更改。因此,不能使用源内生成为源目录创建源外生成。通过从源目录中删除(至少) CMakeCache.txt,可以相当容易地解决这个问题。CMake 生成的其他一些文件(主要在 CMakeFiles目录中)也应该删除,但是这些文件不会导致 CMake 将源树视为构建树。

由于源代码外构建通常比源代码内构建更受欢迎,因此您可能需要修改 cmake 以要求源代码外构建:

# Ensures that we do an out of source build


MACRO(MACRO_ENSURE_OUT_OF_SOURCE_BUILD MSG)
STRING(COMPARE EQUAL "${CMAKE_SOURCE_DIR}"
"${CMAKE_BINARY_DIR}" insource)
GET_FILENAME_COMPONENT(PARENTDIR ${CMAKE_SOURCE_DIR} PATH)
STRING(COMPARE EQUAL "${CMAKE_SOURCE_DIR}"
"${PARENTDIR}" insourcesubdir)
IF(insource OR insourcesubdir)
MESSAGE(FATAL_ERROR "${MSG}")
ENDIF(insource OR insourcesubdir)
ENDMACRO(MACRO_ENSURE_OUT_OF_SOURCE_BUILD)


MACRO_ENSURE_OUT_OF_SOURCE_BUILD(
"${CMAKE_PROJECT_NAME} requires an out of source build."
)

上面的宏来自一个常用的模块 MacroOutOfSourceBuild。在谷歌上有很多关于 MacroOutOfSourceBuild.cmake的资源,但是我似乎找不到原始的,它足够短,包括在这里完整。

不幸的是,cmake 通常在调用宏时编写了一些文件,所以尽管它会阻止您实际执行构建,但您仍然需要删除 CMakeCache.txtCMakeFiles

您可能会发现设置二进制文件、共享库和静态库所写入的路径是有用的——在这种情况下,请参阅 我如何使 cmake 输出成为一个“ bin”dir?(免责声明,关于这个问题,我有最佳投票答案... ... 但这是我了解它的方式)。

CMake Wiki开始:

CMAKE _ BINARY _ DIR 如果您正在构建内部源代码,则这与 CMAKE _ SOURCE _ DIR 相同,否则这是您的 建树

比较这两个变量以确定是否启动了源代码外生成

将我的评论转化为答案:

如果有人像我一样,首先把所有的构建文件放到源目录中:

cd src
cmake .

Cmake 将在 src目录中放入一组构建文件和缓存文件(CMakeCache.txtCMakeFilescmake_install.cmake等)。

要更改为源代码外构建,我必须删除所有这些文件。然后,我就可以按照@安格在他的回答中所建议的那样做:

mkdir -p src/build
cd src/build
cmake ..

从 cmake 3.19开始,你也可以使用 预置文件,在这里你可以指定其他有用的东西,比如输出二进制目录:

{
"version": 2,
"cmakeMinimumRequired": {
"major": 3,
"minor": 19,
"patch": 0
},
"configurePresets": [
{
"name": "default",
"displayName": "Default",
"description": "Default build cfg",
"generator": "Unix Makefiles",
"binaryDir": "${sourceDir}/Compile",
"cacheVariables": {
},
"environment": {
}
}
]
}

然后使用 --preset arg 运行 cmake:

cmake --preset=default

然后将 cd转到构建目录并运行 make,在您的情况下:

cd ./Compile
make