CMake通过工具链升级进行增量编译
Posted
技术标签:
【中文标题】CMake通过工具链升级进行增量编译【英文标题】:CMake incremental compilation through toolchain upgrade 【发布时间】:2021-03-25 22:11:24 【问题描述】:我正在尝试通过工具链升级找到一种使用 CMake 进行增量编译的方法。这是有问题的场景:
分支main使用g++-9(使用CMAKE_CXX_COMPILER=g++-9
)
一个新分支使用g++-10(使用CMAKE_CXX_COMPILER=g++-10
)
两个分支上都发生了提交
一个分支上的增量构建工作正常
切换到另一个分支并显式调用 CMake 失败
我的问题如下:我正在寻找正确的方法,以使 CMake 的调用成功并在发生工具链更改时从头开始重建所有项目。
这是一个脚本,可以快速轻松地重现问题。此脚本需要 Docker。它将在执行它的位置创建文件夹Sources
和Build
,以避免乱扔文件系统。然后它创建 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:/Build
或 gcc9
。 because CMake generates an error.
什么错误?
非常相关:discourse.cmake.org/t/…
使用根据工具链命名的不同构建目录会起作用。不幸的是,如果不重命名构建文件夹,我无法保护我的构建代理免受开发人员错误的影响,即升级工具链。它还假设开发人员知道可能需要新构建文件夹的所有可能更改。因此,虽然这肯定是一种改进,但我们还能做得更好吗?
我使用了一个根 Makefile,它就像别名一样保留所有 cmake 配置。喜欢here。有些人编写 shell 或 .bat 脚本。所以,是的,它假设或者假设开发人员知道在更改工具链时必须删除二进制目录,这是正常的事情。
【参考方案1】:
我正在寻找正确的方法来使 CMake 的调用成功并在发生工具链更改时从头开始重建所有项目。
正确的方法是使用新的二进制目录。更改时删除二进制目录并让它重新创建,或者为每个工具链使用单独的不同目录。
对 gcc10 构建使用 Build/gcc10
二进制目录,对 gcc9 构建使用 Build/gcc9
。
现在cmake不需要cd Build
和mkdir
- 使用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:arm-xm-linux交叉编译工具链文件及交叉支持HTTPS的curl静态库