想象一下这个结构:
root/
|
+-- include/
+-- src/
+-- build/
+-- lib/
+-- tests/
|
+-- common
+-- test1
+-- test2
+-- test3
在tests/
中,该文件夹common/
包含几个源文件,它们生成数据或从记录的文件中读取数据等,这些文件在所有测试之间共享。因此,每个测试只有一个文件;main.c
(目前)。每个Makefile
测试的看起来像这样:
.SUFFIXES:
.SUFFIXES: .c .o
TARGET := test
# OS dependent stuff omitted for brevity
CFLAGS += -I../../include -I../common
LDFLAGS += -L../../lib -lname
VPATH = ../common
.phony: all clean
all: $(TARGET)
clean:
-$(RM) *.o $(TARGET)
# Other targets removed for brevity
OBJECTS := main.o io.o read_str.o
$(TARGET): $(OBJECTS) ../../lib/libname.a
$(LD) -o $@ $(OBJECTS) $(LDFLAGS)
%.o: %.c
$(CC) -c $(CFLAGS) -o $@ $<
main.o: main.c io.h $(wildcard ../../include/*.h)
起初我common/
在每个测试中都复制了文件,一切都很好,但现在我把它们放进去common/
使用了VPATH
,我遇到了一个问题。
让我解释几行:
main.o: main.c io.h $(wildcard ../../include/*.h)
^^^^
VPATH correctly finds this file in common/
$(TARGET): $(OBJECTS) ../../lib/libname.a
^^^^^^^^^^^^^^^^^^^
If the library is rebuilt, the tests need to re-link
$(LD) -o $@ $(OBJECTS) $(LDFLAGS)
^^^^^^^^^^
I can't use $^ because that also includes ../../lib/libname.a
正如您可能已经猜到的那样,由于common/*.o
文件不在此文件夹中,因此$(LD)
无法找到它们。另一方面,make
, givenVPATH = ../common
找到它们没有问题。如果我可以删除../../lib/libname.a
,然后使用$^
,我可以提供目标文件的正确路径。
然而,删除对 lib 文件的依赖意味着当我make
处于顶层时,如果仅更新 lib 本身,测试将不会得到更新。
所以,我的问题是,如果make
其他依赖项是使用VPATH
?
我考虑过删除依赖项,并在Makefile
that buildslibname.a
中,在创建库后添加一个命令,告诉Makefile
测试的 s 删除它们TARGET
的 s:
lib/Makefile:
.SUFFIXES:
TARGET = libname.a
VPATH = ../build
.PHONY: all clean
all: $(TARGET)
clean:
-$(RM) $(TARGET)
$(TARGET): list.o of.o my.o library.o files.o
$(AR) $(TARGET) $^
@$(MAKE) --no-print-directory -C ../tests remove_targets
这将迫使$(LD)
他们再次制造。然而,这种解决方案往往会使Makefile
关系变得一团糟。Makefile
构建 lib 与是否有测试无关,我更喜欢将它们解耦。
我进行了很多构建和测试,这就是为什么我尝试完成依赖项,以便make
采取尽可能少的操作来正确构建所有内容。说,每次都清理和重建的解决方案不是一种选择。
我也知道这种语法,如果我想将 lib 文件目录提供给gcc
,而不是使用-Lpath/to/lib -lname
. 但是我不确定这是否是一个好主意(我的意思是,我总是看到与 链接-L
,我不确定直接提供库文件是否有缺点)
顺便说一句,如果我做错了什么,或者我让自己太难了,请告诉我应该如何正确地做到这一点。