139

我对 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

我错过了什么吗?

4

6 回答 6

133

听起来你想要一个out of source build。有几种方法可以创建源外构建。

  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 .
    

    如果您的当前目录已经是构建文件夹。

  2. 对于 CMake 3.13 或更高版本,使用这些选项来设置源和构建文件夹

    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}它,否则它不应触及您的source tree

最大的问题是如果您之前在源代码树中生成了一个构建树(即您有一个源代码构建)。完成此操作后,上面 (1) 的第二部分就会启动,并且 cmake 不会对源代码或构建位置进行任何更改。因此,您不能为具有 in-source build 的源目录创建 out-of-source 构建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”目录?(免责声明,我在这个问题上获得了最高票数的答案……但这就是我所知道的)。

于 2014-06-26T16:31:52.690 回答
77

几乎不需要设置您要设置的所有变量。CMake 将它们设置为合理的默认值。你绝对应该修改CMAKE_BINARY_DIRor CMAKE_CACHEFILE_DIR。将这些视为只读。

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

cd src
rm CMakeCache.txt
cd ..

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

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

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

一旦你完成了这项工作,你可以查看 CMake 默认放置东西的位置,只有当你对默认位置不满意时(例如 的默认值EXECUTABLE_OUTPUT_PATH),才只修改你需要的位置。并尝试相对于 , 等来CMAKE_BINARY_DIR表达CMAKE_CURRENT_BINARY_DIR它们PROJECT_BINARY_DIR

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

于 2013-09-16T12:01:07.737 回答
11

将我的评论变成答案:

万一有人做了我所做的,首先将所有构建文件放在源目录中:

cd src
cmake .

cmake 会将一堆构建文件和缓存文件(CMakeCache.txt, CMakeFiles,cmake_install.cmake等)放在src目录中。

要更改为源外构建,我必须删除所有这些文件。然后我可以做@Angew 在他的回答中推荐的事情:

mkdir -p src/build
cd src/build
cmake ..
于 2018-01-03T18:09:29.737 回答
8

CMake Wiki开始:

CMAKE_BINARY_DIR 如果您在源代码中构建,这与 CMAKE_SOURCE_DIR 相同,否则这是构建树的顶级目录

比较这两个变量以确定是否启动了源外构建

于 2014-09-11T10:51:48.740 回答
6

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

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

而不是使用预定义变量之一: http ://www.cmake.org/Wiki/CMake_Useful_Variables (查找CMAKE_BINARY_DIRCMAKE_CURRENT_BINARY_DIR

于 2013-09-16T11:32:13.510 回答
1

从 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": {
      }
    }
  ]
}

然后只需使用--presetarg 运行 cmake:

cmake --preset=default

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

cd ./Compile
make
于 2021-11-02T19:05:40.323 回答