C/C++ 预处理器指令的 Makefile 触发器重建
Makefile trigger rebuild for C/C++ preprocessor directives
假设我有一个如下所示的 C++ 源文件:
int main() {
...
#ifdef flag
// do something
#endif
...
#ifndef flag
// do something different
#endif
...
}
我知道对于 gcc 我可以使用 -D'flag'
作为预处理器的指令来定义 flag
从而确定上面代码的哪一部分实际被编译,并且这可以在 Makefile 中使用。
但是我该如何编写一个 Makefile,以便根据我是否要定义 flag
来重新构建源文件(不对任何文件进行其他更改,包括 Makefile 本身)?
我知道我可以,例如(如果有更好的方法,解决方案不需要遵循这个!),当我 运行 使例如使用 make flag=1 all
,但如果包含 main
的文件(与上面的源代码示例一致)自此之后未更改,则不会触发重建。
即从一个干净的目录开始, 运行ning make all
将 运行 构建,但是如果我立即 运行 make flag=1 all
我想要包含 main
(比如 main.cpp
)无需先 touch main.cpp
即可正确重建。
您可以为您的代码创建对 Makefile 的依赖。这将在 Makefile 更改时触发编译。
或者使用 cmake,然后你的 IDE will/should 为你做这个...
首先make
必须知道flag变了。这意味着您必须将标志存储在“某处”,这通常是某个文件。接下来你必须告诉 make
哪个文件取决于你的标志。除了依赖文件之外,没有必要编译所有的东西。这意味着,您必须指定哪个来源取决于哪个标志,或者在这种情况下,取决于存储标志的文件。
好的,你的 Makefile 可以是这样的:
# define a first rule, that we want, if no target is given, we want to
# compile our program named "go"
all: go
# read the file, where our last given flag was stored.
# the minus in front tells make, that if the file can't be read, simple ignore it!
-include stored_flag.mk
# after that, we compare the old flag and the new one which was given on command
# line or from environment. If it differs or was not present before,
# write the new flag to the file to make it reusable for the next call
ifneq ($(OLDFLAG),$(FLAG))
$(file > stored_flag.mk, OLDFLAG:=$(FLAG))
endif
# now we forward the environment variable to the compiler
# if it is present
ifneq ($(FLAG),)
CXXFLAGS=-DFLAG=$(FLAG)
endif
# as said: we need to make the source files dependent on the flag file,
# if the flag is used in that source. If ot, no need to comoile even if flag has
# changed
main.o: stored_flag.mk
# standard rule:
main.o: main.cpp
# build our program "go"
go: main.o
g++ $< -o go
示例来源 (main.cpp):
#include <iostream>
int main()
{
#ifdef FLAG
std::cout << "Flag is " << FLAG << std::endl;
#else
std::cout << "No flag" << std::endl;
#endif
}
执行方式:
make FLAG=1
make FLAG=1
make FLAG=2
...
测试愉快!
如果你有多个flag,并且你想为每个flag定义独立的依赖,你可以使用多个文件来存储flag。
添加:
问:“只有 Make 知道通过比较依赖项与目标的时间戳来触发重建吗?”
A:这就是make的核心思想!比较文件上的时间戳以确定是否需要做某事。但是:正如您所看到的,make 可以处理“ifdef”,因此您可以在这样一个块内定义规则,这使得编译取决于某些条件,而不比较时间模板或定义依赖关系。
假设我有一个如下所示的 C++ 源文件:
int main() {
...
#ifdef flag
// do something
#endif
...
#ifndef flag
// do something different
#endif
...
}
我知道对于 gcc 我可以使用 -D'flag'
作为预处理器的指令来定义 flag
从而确定上面代码的哪一部分实际被编译,并且这可以在 Makefile 中使用。
但是我该如何编写一个 Makefile,以便根据我是否要定义 flag
来重新构建源文件(不对任何文件进行其他更改,包括 Makefile 本身)?
我知道我可以,例如(如果有更好的方法,解决方案不需要遵循这个!),当我 运行 使例如使用 make flag=1 all
,但如果包含 main
的文件(与上面的源代码示例一致)自此之后未更改,则不会触发重建。
即从一个干净的目录开始, 运行ning make all
将 运行 构建,但是如果我立即 运行 make flag=1 all
我想要包含 main
(比如 main.cpp
)无需先 touch main.cpp
即可正确重建。
您可以为您的代码创建对 Makefile 的依赖。这将在 Makefile 更改时触发编译。
或者使用 cmake,然后你的 IDE will/should 为你做这个...
首先make
必须知道flag变了。这意味着您必须将标志存储在“某处”,这通常是某个文件。接下来你必须告诉 make
哪个文件取决于你的标志。除了依赖文件之外,没有必要编译所有的东西。这意味着,您必须指定哪个来源取决于哪个标志,或者在这种情况下,取决于存储标志的文件。
好的,你的 Makefile 可以是这样的:
# define a first rule, that we want, if no target is given, we want to
# compile our program named "go"
all: go
# read the file, where our last given flag was stored.
# the minus in front tells make, that if the file can't be read, simple ignore it!
-include stored_flag.mk
# after that, we compare the old flag and the new one which was given on command
# line or from environment. If it differs or was not present before,
# write the new flag to the file to make it reusable for the next call
ifneq ($(OLDFLAG),$(FLAG))
$(file > stored_flag.mk, OLDFLAG:=$(FLAG))
endif
# now we forward the environment variable to the compiler
# if it is present
ifneq ($(FLAG),)
CXXFLAGS=-DFLAG=$(FLAG)
endif
# as said: we need to make the source files dependent on the flag file,
# if the flag is used in that source. If ot, no need to comoile even if flag has
# changed
main.o: stored_flag.mk
# standard rule:
main.o: main.cpp
# build our program "go"
go: main.o
g++ $< -o go
示例来源 (main.cpp):
#include <iostream>
int main()
{
#ifdef FLAG
std::cout << "Flag is " << FLAG << std::endl;
#else
std::cout << "No flag" << std::endl;
#endif
}
执行方式:
make FLAG=1
make FLAG=1
make FLAG=2
...
测试愉快!
如果你有多个flag,并且你想为每个flag定义独立的依赖,你可以使用多个文件来存储flag。
添加:
问:“只有 Make 知道通过比较依赖项与目标的时间戳来触发重建吗?”
A:这就是make的核心思想!比较文件上的时间戳以确定是否需要做某事。但是:正如您所看到的,make 可以处理“ifdef”,因此您可以在这样一个块内定义规则,这使得编译取决于某些条件,而不比较时间模板或定义依赖关系。