我正在尝试为当前项目扩展一个继承的Makefile中的有趣行为。
LIBS := lib/precompiled1.a lib/precompiled2.a lib/mylib1.a lib/mylib2.a
mylib1-src := (source directory)
mylib1-obj := $(patsubst $(mylib1-src)/%.c, obj/LIB1/%.o, $(wildcard $(mylib1-src)/*.c))
mylib2-src := (source directory)
mylib2-obj := $(patsubst $(mylib2-src)/%.cpp, obj/LIB2/%.o, $(wildcard $(mylib2-src)/*.cpp))
default: all
lib/mylib1.a: $(mylib1-obj)
ar -r $@ $^
lib/mylib2.a: $(mylib2-obj)
ar -r $@ $^
all: exe/my_out
exe/my_out: $(my_out-obj)
g++ $^ $(COMMON_FLAGS) $(LIBS) $(MY_FLAGS)
当我运行make时,遇到一个错误,它无法与lib / mylib1.a链接,并中断了。太酷了,我只需要确保正在构建.a目标即可。像这样天真地弄混makefile:
lib/mylib1.a: $(mylib1-obj)
ar -r $@ $^
lib/mylib2.a: $(mylib2-obj)
ar -r $@ $^
default: all
现在可以编译mylib1.a了,但是既不编译mylib2.a也不编译“全部”。
这是我卡住的地方。如果我执行以下操作:
default: all
lib/mylib1.a: $(mylib1-obj)
ar -r $@ $^
lib/mylib2.a: $(mylib2-obj)
ar -r $@ $^
all: lib/mylib1.a exe/my_out
然后,编译器会抱怨lib / mylib1.a不是可执行文件。虽然不是很好,但是却让我陷入了怪异的境地。我可以单独编译.a文件。我可以将它们链接到可执行文件。我不能一次做完所有这些事情,只能弄乱makefile,这在一定程度上是错误的。
我的问题是,为什么更改默认顺序会更改构建的内容?如何获得所有.a文件来构建并链接到主要可执行文件,而不必每次都手动弄乱makefile?一般而言,我对makefile还是相当陌生,我不确定为什么会发生这种情况。
谢谢!
答案 0 :(得分:1)
makefile中目标的顺序无关紧要,只有一个例外:第一个目标是默认目标,即在您没有目标的情况下调用make
时的目标。可以使用.DEFAULT_GOAL := ...
串行构建(make -j1
)中重要的是目标定义中的依存顺序,例如
T: A B C
或
T: A B
T: C
rule
在串行构建make
中,将首先满足“ A”,然后满足“ B”,然后满足“ C”。如果在构建“ A”时缺少满足的“ C”依赖关系,则构建将成功。将生成文件更改为
T: C A B
...,串行构建将开始失败。
在并行构建(make -jN
中,依赖性顺序无关紧要,因为make
将尝试并行构建“ A”,“ B”和“ C”(如果允许)
如果未为目标“ T”列出强制性依赖性“ D”,则一旦满足列出的依赖性,make
将允许构建目标“ T”。但是它不会等待“ D”完成。因此,构建成功取决于未定义的行为,
并行构建的最坏情况:如果在读取“ D”的同时“ T”的规则没有失败,并且同时编写了“ D”,则最终构建成功,但是构建无效文物。
不完全依赖项的常用指标是
始终为所有目标指定完全依赖项。在您的情况下,至少是:
# Add internal dependencies included in $(LIBS)
exe/my_out: $(my_out-obj) $(filter lib/%.a, $(LIBS))
g++ $^ $(COMMON_FLAGS) $(LIBS) $(MY_FLAGS)
答案 1 :(得分:0)
默认目标是Makefile中的第一个目标,名为“ default”的目标没有特殊意义。
对于最新版本的Make,可以像这样显式指定默认目标:
DEFAULT_GOAL:=全部
应该将库添加为可执行文件的先决条件,而不是添加到所有目标,例如:
exe/my_out: $(my_out-obj) lib/mylib1.a lib/mylib2.a
g++ $^ $(COMMON_FLAGS) $(LIBS) $(MY_FLAGS)
lib/mylib1.a: $(mylib1-obj)
ar -r $@ $^
lib/mylib2.a: $(mylib2-obj)
ar -r $@ $^
答案 2 :(得分:0)
如安迪(Andy)建议的那样,通过执行此操作(通常在makefile的顶部附近)来将默认规则设置为all:
:
.DEFAULT_GOAL = all
然后将所有定义为:
LIB_DEPS = lib/mylib1.a lib/mylib2.a
all: exe/my_out $(LIB_DEPS)
# Also to ensure that the libs are built first (for example with parallel builds):
exe/my_out: $(my_out-obj) $(LIB_DEPS)
... recipe here...
这样,如果您执行make或make -j,则可以确保您的构建顺序。
注意:我没有看到$(my_out-obj)
的规则-您错过了还是只是没有打印?