Makefile 仅当源被上一个命令修改时重新生成 我有一个Python脚本,它从C++源文件中提取信息并将其写入头文件。每当这个生成的头更改时(这种情况很少发生),我都想重新编译它(通过GCC预编译头特性)

Makefile 仅当源被上一个命令修改时重新生成 我有一个Python脚本,它从C++源文件中提取信息并将其写入头文件。每当这个生成的头更改时(这种情况很少发生),我都想重新编译它(通过GCC预编译头特性),makefile,cmake,precompiled-headers,Makefile,Cmake,Precompiled Headers,显然,调用脚本的命令取决于源文件,而重新编译命令取决于脚本生成的头文件 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") add_custom_命令(输出“file.pch.h”命令依赖于“file.cpp

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

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")
add_custom_命令(输出“file.pch.h”命令依赖于“file.cpp”)
添加自定义命令(输出“file.pch.h.gch”命令依赖于“file.pch.h”)

但是现在
file.pch.h.gch
依赖于
file.cpp
,并且每当它更改时都会重新编译。如何避免这种情况?

让脚本将标题写入临时文件,并且仅在现有的
文件.pch.h
上复制它(如果已更改)。然后每次
file.cpp
更改时(fast)脚本都会运行,但只有在更改了预编译头的情况下才会重新编译它

如果不想修改脚本,可以使用单独的脚本,沿以下行运行命令:

myscript < file.cpp > file.pch.h.tmp && move-if-change file.pch.h.tmp file.pch.h
生成预编译头的程序,
生成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
让我们构建它:

$ 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
$cmake。
--C编译器标识为GNU4.2.1
--CXX编译器标识为Clang 4.1.0
--检查C编译器是否具有-isysroot
--检查C编译器是否具有-isysroot-yes
--检查C编译器是否支持OSX部署目标标志
--检查C编译器是否支持OSX部署目标标志-是
--检查C编译器是否工作:/usr/bin/gcc
--检查C编译器是否正常工作:/usr/bin/gcc--works
--检测C编译器ABI信息
--检测C编译器ABI信息-完成
--检查CXX编译器是否工作:/usr/bin/c++
--检查CXX编译器是否正常工作:/usr/bin/c++--正常工作
--检测CXX编译器ABI信息
--检测CXX编译器ABI信息-完成
--配置完成
--生成完成
--构建文件已写入:/Users/andrew/sx/14662471
$make
[33%]生成foo.pch.h
标题已更改,正在更新
[66%]生成foo.pch.h.gch
呼叫gcc
扫描目标foo的依赖项
[100%]构建C对象CMakeFiles/foo.dir/foo.C.o
链接C可执行文件foo
[100%]构建目标foo
美元/英尺
你好,世界
$#它是最新的,因此再次调用make不会产生任何效果
$make
[100%]构建目标foo
$让我们更改C文件
$sed-i-e's/Hello,world/Hello there,world/'foo.c
$make
[33%]生成foo.pch.h
标题未更改
扫描目标foo的依赖项
[33%]生成foo.pch.h
标题未更改
[66%]构建C对象CMakeFiles/foo.dir/foo.C.o
链接C可执行文件foo
[100%]构建目标foo
$#请注意,预编译的标头*未*重新编译
美元/英尺
你好,世界
$#现在让我们添加一个头文件
$sed-i-e$'s/stdio.h>/stdio.h>\\\n\35; include/'foo.c
$make
[33%]生成foo.pch.h
标题已更改,正在更新
[66%]生成foo.pch.h.gch
呼叫gcc
扫描目标foo的依赖项
[100%]构建C对象CMakeFiles/foo.dir/foo.C.o
链接C可执行文件foo
[100%]构建目标foo
$#预编译头文件*已*重新编译

您的问题是file.pch.h.gch最终取决于file.cpp的内容,因此如果file.cpp发生更改,则应重新生成。你不想避免这个,是吗?我不理解这个问题。我提取了file.cpp的前几行(包括外部库标题的那几行),只有当这些行发生变化时,我才需要重新编译标题。否则file.cpp可以重用预编译头。除非必须,否则脚本不会覆盖生成的文件。问题不在于头被不必要地更改,而是它被编译了,因为它的一个依赖项被重建了(或者至少重建它的命令被执行了)。请查看更新的答案——我已经用CMake测试了我的建议,到目前为止,它似乎起到了作用。它仍然一遍又一遍地调用
make pch
,但它是有效的,谢谢!
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