CMake通过工具链升级进行增量编译

Posted

技术标签:

【中文标题】CMake通过工具链升级进行增量编译【英文标题】:CMake incremental compilation through toolchain upgrade 【发布时间】:2021-03-25 22:11:24 【问题描述】:

我正在尝试通过工具链升级找到一种使用 CMake 进行增量编译的方法。这是有问题的场景:

分支ma​​in使用g++-9(使用CMAKE_CXX_COMPILER=g++-9) 一个新分支使用g++-10(使用CMAKE_CXX_COMPILER=g++-10) 两个分支上都发生了提交 一个分支上的增量构建工作正常 切换到另一个分支并显式调用 CMake 失败

我的问题如下:我正在寻找正确的方法,以使 CMake 的调用成功并在发生工具链更改时从头开始重建所有项目。

这是一个脚本,可以快速轻松地重现问题。此脚本需要 Docker。它将在执行它的位置创建文件夹SourcesBuild,以避免乱扔文件系统。然后它创建 Dockerfiles 以使用 g++ 和 cmake 构建 docker 容器。然后它会创建一个虚拟的 Hello World C++ CMake 项目。最后,它为构建工件创建一个文件夹,然后使用 g++-9 和 g++-10 执行构建。第二次构建失败,因为 CMake 生成错误。

#!/bin/bash
set -e

mkdir -p Sources
mkdir -p Build

# Creates a script that will be executed inside the docker container to perform builds
cat << EOF > Sources/Compile.sh
cd /Build \
    && cmake /Sources \
    && make \
    && ./IncrementalBuild
EOF

# Creates a Dockerfile that will be used to have both gcc-9 and cmake
cat << EOF > Sources/Dockerfile-gcc9
FROM gcc:9
RUN apt-get update && apt-get install -y cmake
RUN ln -s /usr/local/bin/g++ /usr/local/bin/g++-9
ADD Compile.sh /Compile.sh
RUN chmod +x /Compile.sh
ENTRYPOINT /Compile.sh
EOF

# Creates a Dockerfile that will be used to have both gcc-10 and cmake
cat << EOF > Sources/Dockerfile-gcc10
FROM gcc:10
RUN apt-get update && apt-get install -y cmake
RUN ln -s /usr/local/bin/g++ /usr/local/bin/g++-10
ADD Compile.sh /Compile.sh
RUN chmod +x /Compile.sh
ENTRYPOINT /Compile.sh
EOF

# Creates a dummy C++ program that will be compiled
cat << EOF > Sources/main.cpp
#include <iostream>
  
int main()

  std::cout << "Hello World!\n";

EOF

# Creates CMakeLists.txt that will be used to compile the dummy C++ program
cat << EOF > Sources/CMakeLists.txt
cmake_minimum_required(VERSION 3.9)
  
project(IncrementalBuild CXX)
add_executable(IncrementalBuild main.cpp)
set_target_properties(IncrementalBuild PROPERTIES CXX_STANDARD 17)
EOF

# Build the docker images with both Dockerfiles created earlier
docker build -t cmake-gcc:9 -f Sources/Dockerfile-gcc9 Sources
docker build -t cmake-gcc:10 -f Sources/Dockerfile-gcc10 Sources

# Run a build with g++-9
echo ""
echo "### Compiling with g++-9 and then running the result..."
docker run --rm --user $(id -u):$(id -g) -v $(pwd)/Sources:/Sources -v $(pwd)/Build:/Build -e CXX=g++-9 cmake-gcc:9
echo ""

# Run a build with g++-10
echo "### Compiling with g++-10 and then running the result..."
docker run --rm --user $(id -u):$(id -g) -v $(pwd)/Sources:/Sources -v $(pwd)/Build:/Build -e CXX=g++-10 cmake-gcc:10
echo ""

# Print success if we reach this point
echo "SUCCESS!"

【问题讨论】:

Sooo 只需为每个配置使用单独的二进制目录。 $(pwd)/Build:/Build -> $(pwd)/Build/gcc10:/Buildgcc9because CMake generates an error.什么错误? 非常相关:discourse.cmake.org/t/… 使用根据工具链命名的不同构建目录会起作用。不幸的是,如果不重命名构建文件夹,我无法保护我的构建代理免受开发人员错误的影响,即升级工具链。它还假设开发人员知道可能需要新构建文件夹的所有可能更改。因此,虽然这肯定是一种改进,但我们还能做得更好吗? 我使用了一个根 Makefile,它就像别名一样保留所有 cmake 配置。喜欢here。有些人编写 shell 或 .bat 脚本。所以,是的,它假设或者假设开发人员知道在更改工具链时必须删除二进制目录,这是正常的事情。 【参考方案1】:

我正在寻找正确的方法来使 CMake 的调用成功并在发生工具链更改时从头开始重建所有项目。

正确的方法是使用新的二进制目录。更改时删除二进制目录并让它重新创建,或者为每个工具链使用单独的不同目录。

对 gcc10 构建使用 Build/gcc10 二进制目录,对 gcc9 构建使用 Build/gcc9

现在cmake不需要cd Buildmkdir - 使用cmake -S. -BBuild。也不要使用make - 更喜欢cmake --build Build 让您稍后切换生成器。

【讨论】:

【参考方案2】:

“如果你改变了工具链,你应该从一个新的构建开始。有太多的东西假设工具链不会改变,虽然你可能能够找到看起来有效的解决方法,但我建议你总是使用用于不同工具链的新构建树。如果您就地更新现有工具链(例如,您在 Linux 上更新到较新版本的 GCC,在 macOS 上更新到较新版本的 Xcode 等),同样的逻辑也适用。CMake 查询“ - 克雷格·斯科特

所以基本上我认为这是不可能的。你只需要吹走你的构建。你能做的最好的事情是在 CMake 没有为你做这件事时提醒用户。

也许也可以回复: https://discourse.cmake.org/t/how-to-change-toolchain-without-breaking-developer-workflows/1166

或者开始另一个话题。

【讨论】:

以上是关于CMake通过工具链升级进行增量编译的主要内容,如果未能解决你的问题,请参考以下文章

cmake:ESP32交叉编译工具链定义

cmake/ASR1603:交叉编译工具链定义

带有 cmake 工具链文件的 Yocto SDK

cmake:arm-xm-linux交叉编译工具链文件及交叉支持HTTPS的curl静态库

cmake:arm-xm-linux交叉编译工具链文件及交叉支持HTTPS的curl静态库

cmake:基于MDK(Keil)的Nationstech.N32G45x平台交叉编译工具链定义