makefile - 仅当源被先前的命令修改时才重建

标签 makefile cmake precompiled-headers

我有一个 python 脚本,它从 C++ 源文件中提取信息并将其写入头文件。每当这个生成的 header 发生变化(这种情况很少发生)时,我想重新编译它(通过 GCC 预编译 header 功能)。

显然,调用脚本的命令依赖于源文件,而重新编译命令依赖于脚本生成的头文件。

add_custom_command(OUTPUT "file.pch.h" COMMAND <script> DEPENDS "file.cpp")
add_custom_command(OUTPUT "file.pch.h.gch" COMMAND <compile> DEPENDS "file.pch.h")

但现在 file.pch.h.gch 依赖于 file.cpp 并且只要它发生变化就会重新编译。我怎样才能避免这种情况?

最佳答案

让您的脚本将 header 写入临时文件,并且仅将其复制到现有的 file.pch.h(如果发生更改)。然后,(快速)脚本每次 file.cpp 更改时都会运行,但预编译头仅在发生更改时才会重新预编译。

如果不想修改脚本,可以使用单独的move-if-change脚本,按照以下方式运行命令:

myscript < file.cpp > file.pch.h.tmp && move-if-change file.pch.h.tmp file.pch.h

使用 Cmake 可能有更好的方法来做到这一点,但这是使用 Make 解决此问题的老式方法。


这是一个使用 CMake 的工作示例。

主程序,foo.c:

#include "foo.pch.h"

#ifndef FOO_PCH
#include <stdio.h>
#endif

int main() {
    printf("Hello, world\n");
    return 0;
}

生成预编译头的程序,make-pch:

#!/bin/bash

(echo '#define FOO_PCH 1'
 awk '/^#endif/ { p = 0 }
      p { print $0 }
      /^#ifndef FOO_PCH/ { p = 1 }') < foo.c > foo.pch.h.tmp

if ! cmp -s foo.pch.h{.tmp,}; then
    echo 'Header changed, updating'
    mv foo.pch.h{.tmp,}
else
    echo 'Header not changed'
    rm -f foo.pch.h.tmp
fi

CMakeLists.txt:

cmake_minimum_required(VERSION 2.8)
add_executable(foo foo.c foo.pch.h.gch)
add_custom_command(OUTPUT "foo.pch.h" COMMAND ./make-pch DEPENDS "foo.c")
add_custom_command(OUTPUT "foo.pch.h.gch"
                   COMMAND echo calling gcc
                   COMMAND gcc foo.pch.h
                   DEPENDS "foo.pch.h")

让我们构建它:

$ cmake .
-- The C compiler identification is GNU 4.2.1
-- The CXX compiler identification is Clang 4.1.0
-- Checking whether C compiler has -isysroot
-- Checking whether C compiler has -isysroot - yes
-- Checking whether C compiler supports OSX deployment target flag
-- Checking whether C compiler supports OSX deployment target flag - yes
-- Check for working C compiler: /usr/bin/gcc
-- Check for working C compiler: /usr/bin/gcc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/andrew/sx/14662471
$ make
[ 33%] Generating foo.pch.h
Header changed, updating
[ 66%] Generating foo.pch.h.gch
calling gcc
Scanning dependencies of target foo
[100%] Building C object CMakeFiles/foo.dir/foo.c.o
Linking C executable foo
[100%] Built target foo
$ ./foo
Hello, world
$ # it’s up-to-date, so calling make again does nothing
$ make
[100%] Built target foo
$ Let’s change the C file
$ sed -i -e 's/Hello, world/Hello there, world/' foo.c
$ make
[ 33%] Generating foo.pch.h
Header not changed
Scanning dependencies of target foo
[ 33%] Generating foo.pch.h
Header not changed
[ 66%] Building C object CMakeFiles/foo.dir/foo.c.o
Linking C executable foo
[100%] Built target foo
$ # note that the precompiled header was *not* recompiled
$ ./foo
Hello there, world
$ # now let’s add a header file
$ sed -i -e $'s/stdio.h>/stdio.h>\\\n#include <stdlib.h>/' foo.c
$ make
[ 33%] Generating foo.pch.h
Header changed, updating
[ 66%] Generating foo.pch.h.gch
calling gcc
Scanning dependencies of target foo
[100%] Building C object CMakeFiles/foo.dir/foo.c.o
Linking C executable foo
[100%] Built target foo
$ # the precompiled header file *was* recompiled

关于makefile - 仅当源被先前的命令修改时才重建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14662471/

相关文章:

C 库公共(public)头接口(interface)

c++ - 预编译头文件,重新包含文件和智能感知

g++ - 为什么g++找不到-I include-path中的预编译头?

c++ - 制作 ATIDAQ C 库

ubuntu - 弓工具包 ubuntu/usr/bin/ld : cannot find -lgcc_s collect2: ld returned 1 exit status make: *** [rainbow] Error 1

c++ - 库 header 在 header 中不可见,但在 cmake 构建下的 .cpp 文件中完全可见。为什么?

c++ - 如何使用 CMake 将 C++ 程序与 Boost 链接

cmake - "make dist"在 CMake 中等效

c - 带有两个 .c 文件且没有头文件的 Makefile

c++ - 为什么 Hello world 在 vi​​m 中无法打印,但在 tty 中却可以打印?