我有一个非常简单的makefile,如下所示:
.PHONY: clean all
CC = /home/utils/gcc-5.2.0/bin/g++
CFLAGS = -Wall -Werror -fPIC
SRC = $(wildcard *.c)
OBJ = $(subst .c,.o,$(SRC))
.INTERMEDIATE: $(OBJ)
all: test.so
%.o: %.c
$(CC) $(CFLAGS) -o $@ -c $<
test.so: $(OBJ)
$(CC) -shared $^ -o $@
clean:
@rm -f *.o *~ *.so
我在同一目录中只有两个文件:a.c和b.c 当我执行“全部制作”时,我得到了以下完美的结果。
/home/utils/gcc-5.2.0/bin/g++ -Wall -Werror -fPIC -o a.o -c a.c
/home/utils/gcc-5.2.0/bin/g++ -Wall -Werror -fPIC -o b.o -c b.c
/home/utils/gcc-5.2.0/bin/g++ -shared a.o b.o -o test.so
rm a.o b.o
但是,如果我这样做: 触摸交流全部制作
我得到了与上面相同的make执行序列,这不是我期望的。 a.c和b.c之间没有依赖关系。我期望的是:
/home/utils/gcc-5.2.0/bin/g++ -Wall -Werror -fPIC -o a.o -c a.c
/home/utils/gcc-5.2.0/bin/g++ -shared a.o b.o -o test.so
rm a.o
我不明白为什么再次编译b.c。根据gnumake手册:
第一个区别是如果中间文件不存在会发生什么。如果普通文件b不存在,并且make考虑依赖于b的目标,则它总是创建b,然后从b更新目标。但是,如果b是一个中间文件,那么make可以单独放置。除非b的某些先决条件比该目标新,或者有其他原因更新该目标,否则不会麻烦更新b或最终目标。
b.o是一个中间文件,不应更改它,因为b.c尚未更改。 我想念什么?
答案 0 :(得分:0)
如果未重新编译b.o
,则无法创建test.so
,因为它依赖于b.o
。如果a.o
被删除,则无法从b.o
和b.o
创建共享库。
如果您尝试创建静态库,则可以使用make的特殊存档语法替换a.o
,而无需重新编译b.o
,但这是不可能的,除非您使用存档特殊语法,并且对于共享库(例如您要在此处构建的库)无法完成。
有一个原因是默认情况下这些.o
文件不被视为中间文件,通过添加.INTERMEDIATE
目标强制将它们设置为中间文件并不意味着您可以避免重建它们。
答案 1 :(得分:0)
您的困难源于中间文件的含义
不是GNU Make的意思;但是.INTERMEDIATE
特殊目标可让您坚持
a.o
和b.o
(在您的makefile中)不是GNU Make的中间文件
在意义上,应视为它们在GNU Make的意义上是中间 ,并且
然后您会对后果感到惊讶。
F 的意思是中间文件: F是目标T和
F本身具有先决条件。因此a.o
和b.o
相对于
test.so
,因为它们是该目标的先决条件,并且自身具有
相应的先决条件a.c
和b.c`。
从您的理解为中级,使目标test.so
并不需要
(a.o
| b.o
)要重制,除非它早于(a.c|b.c
)。所以你被事实吓了一跳
当将a.o
和b.o
制成.INTERMEDIATE
时,GNU Make 总是删除它们
当它变成test.so
时:
b.o是一个中间文件,不应更改它,因为b.c尚未更改。我想念什么?
您很想念10.4 Chains of Implicit Rules
通常,如果文件在makefile中被提及为目标或先决条件,则该文件不能为中间文件。 但是,您可以通过将文件列出为特殊目标.INTERMEDIATE的先决条件来将其明确标记为中间文件。 即使以其他方式明确提及该文件,此操作也将生效。
因此,在GNU Make的意义上,a.o
和b.o
通常不是是中间的,
因为它们在您的Makefile中被称为test.so
的先决条件。但是你可以
按照您的意愿,通过将它们列为.INTERMEDIATE
的先决条件,使它们被视为GNU Make的中间语言。
GNU Make通过 intermediate 意味着什么比您的意图更具有技术性, 手册的同一部分对此进行了说明:
有时可以通过一系列隐式规则来创建文件。例如,一个文件n.o 可以通过先运行Yacc然后运行cc由n.y生成。这样的序列称为链。
如果文件n.c存在或在makefile中提到,则不需要特殊搜索: make查找可以通过n.c的C编译来创建目标文件;后来,当 考虑如何制作n.c,使用运行Yacc的规则。最终,n.c和n.o都会更新。
但是,即使n.c不存在并且没有被提及,make也知道如何将其设想为 n.o和n.y之间缺少链接! 在这种情况下,n.c被称为中间文件。 一旦make决定使用中间文件,该文件将作为以下内容输入数据库 如果在makefile文件中已提及它,以及说明如何创建它的隐式规则。
(我的重点)。简而言之,如果需要Make来生成目标 output ,并发现文件 input
至关重要的是,由于 stage 不是您的目标之一,也不是任何目标的先决条件,因此 知道这只是从 input 产生 output 的一次性副产品, 因此可以在达到该目的后将其删除。
这是一个简单的示例项目,涉及的文件实际上是GNU Make的中间意思。
在项目目录中,我们有一些yacc
源yacc.y
和lex
源lex.l
,
并且我们要使用以下makefile从它们parse
中构建一个解析器:
制作文件
YFLAGS := -d
OBJS := yacc.o lex.o
.PHONY: all clean
all: parse
parse: $(OBJS)
$(CC) $^ -o $@
clean:
$(RM) parse $(OBJS)
运行方式:
$ make
yacc -d yacc.y
mv -f y.tab.c yacc.c
cc -c -o yacc.o yacc.c
lex -t lex.l > lex.c
cc -c -o lex.o lex.c
cc yacc.o lex.o -o parse
rm lex.c yacc.c
现在,您会看到Make使用其隐式规则目录可以算出
yacc.o
可以通过编译不存在的C源文件来完成
yacc.c
,而该yacc.c
可以从现有的源文件中产生
通过运行yacc.y
yacc -d yacc.y; mv -f y.tab.c yacc.c
。同样,它发现lex.o
可以通过编译不存在的C源lex.c
来完成,而该lex.c
可以通过运行lex.l
从lex -t lex.l > lex.c
中创建。那么parse
是
由yacc.o
和lex.o
通过makefile的常规链接制成
指定。
但是您的makefile对yacc.c
和lex.c
来说什么也没说。据,直到...为止
您已经告诉了Make,这些文件是否存在与您无关紧要。
它们是中间文件,仅处于.y -> .o
和.l -> .o
生产中。所以
当用它们完成制作时:
rm lex.c yacc.c
然后,如果您:
$ touch yacc.y
再次:
$ make
yacc -d yacc.y
mv -f y.tab.c yacc.c
cc -c -o yacc.o yacc.c
cc yacc.o lex.o -o parse
rm yacc.c
只有yacc.o
为parse
和 one 的链接而被重制。
这次生成的中间文件yacc.c
被删除。
底线
您的目标文件不是GNU Make的中间文件,您也不是
希望像对待他们一样对待他们。这对于目标文件是正常的。
因此,删除.INTERMEDIATE: $(OBJ)
。