我的Makefile每次运行时都会编译所有文件,尽管这些文件没有更改。我知道这个问题已经问过几次了,但是所提供的解决方案似乎都不适合我。我是Makefile的新手,大多数时候我不了解解决方案中使用的行话。另外,我想将所有生成的.o文件保存在“ obj”文件夹下
这是我的文件夹结构
project (-)
gen (-)
display (-)
.c and .h files
logic (-)
.c and .h files
lib (-)
include (-)
.h files
.lib files
man (-)
.c and .h files
obj (-)
want to save all the .o files here
我正在使用MinGW在Windows操作系统上运行它
这是我的Makefile:
ALL: demo
SRCS:= filename1.o filename2.o filename3.o filename4.o and so on till filename27.o
demo: display.o logic.o man.o
gcc $(SRCS) -lglut32 -loglx -lopengl32 -Llib -o demo
display.o:
gcc -Igen/display -Igen/logic -Iman -Ilib/include gen/display/*.c -lglut32 -loglx -lopengl32 -Llib -c
logic.o:
gcc -Igen/display -Igen/logic -Iman -Ilib/include gen/logic/*.c -lglut32 -loglx -lopengl32 -Llib -c
man.o:
gcc -Igen/display -Igen/logic -Iman -Ilib/include man/*.c -lglut32 -loglx -lopengl32 -Llib -c
clean:
@echo "Cleaning up.."
-rm -rf *.o
-rm *.exe
注意:lib文件夹中包含glut和oglx文件。 Display.o,lib.o和man.o没有相应的.c文件。它们只是其中包含许多c文件的文件夹名称。
我知道这可能是问题所在。由于没有创建display.o,logic.o和man.o文件,因此MAKE遵守与其传送时间相关的规则。因此,我如何告诉它检查时间戳的实际.o filename1.o,filename2.o等,并仅在它们早于相应的c文件和h文件(甚至是它们依赖的lib文件)之前重新编译。 >
我尝试了以下方法来创建依赖关系,并避免每次都编译文件。但这没有帮助。
%.d: %.c
@set -e; rm -f $@; \
$(CC) -M $(CFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
答案 0 :(得分:1)
从根本上讲,make
正在寻找以下行:
target: dependency
command
如果target
不存在,它将调用dependency
的规则,然后运行command
。如果确实存在target
,它将测试dependency
是否较新或不存在。如果是这样,它将调用dependency
的规则,然后运行command
。否则,它将停止。
重要的是,只有在(a)dependency
不存在,或者(b)dependency
比dependency
更新时,才会调用target
的规则。 / p>
在问题中,假设我们运行make demo
。然后make
查找以demo:
开头的行,并注意它声明了依赖项。因此,它依次查看每个依赖项,以查看他们是否需要采取措施。它首先发现display.o
。它注意到display.o:
不存在,因此它运行关联的规则。其他*.o
也是如此。
为避免*.o
规则由于不存在关联文件而始终运行,可以像这样重写:
ALL: demo
SRCS:= filename1.o filename2.o filename3.o filename4.o and so on till filename27.o
demo: display.ts logic.ts man.ts
gcc $(SRCS) -lglut32 -loglx -lopengl32 -Llib -o demo
display.ts: gen/display/*.c
gcc -Igen/display -Igen/logic -Iman -Ilib/include gen/display/*.c -lglut32 -loglx -lopengl32 -Llib -c
echo . > display.ts
logic.ts: gen/logic/*.c
gcc -Igen/display -Igen/logic -Iman -Ilib/include gen/logic/*.c -lglut32 -loglx -lopengl32 -Llib -c
echo . > logic.ts
man.ts: man/*.c
gcc -Igen/display -Igen/logic -Iman -Ilib/include man/*.c -lglut32 -loglx -lopengl32 -Llib -c
echo . > man.ts
clean:
@echo "Cleaning up.."
-rm -rf *.o *.ts
-rm *.exe
答案 1 :(得分:1)
问题是您的二进制对象目标(如display.o
)实际上与它们的规则所产生的文件不匹配。如果您告诉make
它需要作为目标display.o
,则它(通常是假目标除外,但总是重新运行)期望该规则的配方生成相应的文件,并且可以跟踪该文件是否目标需要重新制定。如果没有生成此类文件,则此目标始终被评估为过时且需要重新构建。
下面这棵树是一个愚蠢的例子:
.
├── Makefile
├── main.c
└── test
└── file.c
和Makefile:
main: test.o main.o
$(CC) -o main *.o
test.o:
$(CC) $(CFLAGX) -c test/*.c
没有test.o
文件,需要重新设置目标……规则运行,再次产生file.o
。由于这个目标已经过重制,并且是main
的前提,所以……一切都会被重制。
现在进行一下小的修改:
main: test.o main.o
$(CC) -o main *.o
test.o:
$(CC) $(CFLAGX) -o $@ -c test/*.c
test.o
目标确实会生成test.o
文件,并且如果test.c
不变,并且test.o
不变且main.c
同样,我们得到:
$ make
make: 'main' is up to date.
它仍然不完全正确,因为它应该读为:
main: test.o main.o
$(CC) -o main $+
test.o: test/*.c
$(CC) $(CFLAGX) -o $@ -c $^
我在其中声明test.o
的先决条件,并通过规则配方中的自动变量来引用它们和目标。同样,链接也需要先决条件。当然,在这个简单的示例中,我可以依靠隐式模式规则来做到这一点:
main: test/file.o main.c
test/file.o: test/*.c
这对您的Makefile意味着什么?编译目标文件时,请查看它们实际产生什么并将目标与之匹配,或者(例如,以-o $@
告诉它们,以产生与目标完全匹配的文件。
我已经扩展了这个愚蠢的示例,test/
中现在有两个文件:
.
├── Makefile
├── main.c
└── test
├── file.c
└── other.c
Makefile可能如下所示:
main: obj/file.o obj/other.o main.c
obj/%.o: test/%.c
mkdir -p obj
$(CC) $(CFLAGS) -c -o $@ $^
它现在将目标文件存储在obj/
中,并且仍然了解什么需要什么并可以跟踪更改。当然,您的设置会更复杂,并且需要更多规则,也许还会从目录树中划分出实际来源或中间目标,并定义一些变量来处理该信息,例如:
OBJS := $(patsubst test/%.c,obj/%.o,$(wildcard test/*.c))
main: $(OBJS) main.c
obj/%.o: test/%.c
mkdir -p obj
$(CC) $(CFLAGS) -c -o $@ $^
但是原理保持不变。