我的Makefile:
compiler=g++
cflags=-g -Wall -I.
src=$(shell find . -name *.cc) #find all .cc files, with path name
srcBaseName=$(shell basename -a $(src)) # extract base names by stripping off the path
header=$(shell find . -name *.h) # all header files
obj=$(patsubst %.cc, %.o, $(srcBaseName)) # Problematic line
bin=bin/myProgram
all: $(bin)
$(bin): $(obj)
$(compiler) $^ -o $@
%.o: %.cc
$(compiler) $(cflags) -c $^ -o $@
clean:
rm $(obj) $(bin)
导致以下错误:
make:***没有规则要制作目标' SomeObjectFile.o',需要 '箱/ myProgram&#39 ;.停止。
有问题的一行:
obj=$(patsubst %.cc, %.o, $(srcBaseName))
如果我将$(srcBaseName)更改为$(src),那么一切都很好。但在这种情况下,.o文件将分散在相应的文件夹中,其中包含我不想要的.cc文件。
我希望有一个专用的(obj /)文件夹来存储所有.o文件。
我该怎么做?
首先尝试:
obj=$(patsubst %.cc, %.o, obj/$(srcBaseName))
第二次尝试:
obj=$(patsubst %.cc, %.o, obj\/$(srcBaseName))
他们为什么不工作?
/ ********************** 2015年2月16日编辑******************* *** /
根据答案中的建议,我将Makefile更新为:
compiler=g++
# source compilation flags
cflag=-g -Wall -std=gnu++0x -I./header/
# source link flags
lflag=
# lib used by proj
lib=
tflag=-g -Wall -std=gnu++0x
# test link flags
tlflag=
# test libs
testLib=lib/libgtest.a
# source code
src=$(shell find "./src" -name "*.cc")
srcBaseName=$(shell basename -a $(src))
obj=$(addprefix obj/, $(patsubst %.cc, %.o, $(srcBaseName)))
vpath %.cc $(dir $(src))
# header files
header=$(shell find "./header" -name "*.h")
# test files
testSrc=$(shell find "./test" -name "*.cc")
testSrcBase=$(shell basename -a $(testSrc))
testObj=$(addprefix obj/, $(patsubst %.cc, %.o, $(testSrcBase)))
vpath %.cc $(dir $(testSrc))
# binary files
bin=bin/Driver
testBin=bin/Test
all: prog test
prog: $(bin)
$(bin): $(obj)
$(compiler) $(lflag) $^ $(lib) -o $@
#$(obj): $(src) $(header)
obj/%.o: %.cc $(header)
$(compiler) $(cflag) -c $< -o $@
test: $(testBin)
$(testBin): $(testObj)
$(compiler) $(tlflag) $^ $(testLib) -o $@
obj/%.o: %.cc
$(compiler) $(tflag) -c $< -o $@
clean:
rm $(obj) $(bin) $(testObj) $(testBin)
这是制作背后的意图:
制作编:
make应找到./src目录下的所有源文件(.cc),并在./obj目录中生成一个文件名相同的.o文件,对子目录的级别不敏感,以便我可以自由添加新的cc文件,无需更新Makefile。每个.o文件都取决于相应的(只是具有相同名称的文件,而不是全部).cc文件和所有标题( make不会自动知道cc文件包含哪些头文件而不解析文件;如果你有一个聪明的方法来实现这一点,请告诉我! )。例如,。/ src / sububirectory1 / sample1.cc应生成./obj/sample1.o和./obj/sample1.o取决于./src/subdirectory1/sample1.cc + ./header/sample1.h +。 /header/sample2.h + ...
进行测试:
它应该对./test文件夹中的测试源文件做类似的事情,除了没有涉及头文件。如果这个细节有帮助,我会使用Google测试。
但是,我的Makefile并没有按照预期的方式工作,因为它有以下问题:
1,如果我运行make test
,则不会执行配方$(compiler) $(tflag) -c $< -o $@
(tflag表示&#39;测试编译标记&#39;,它没有-I./ header / part; cflag表示&#39;源代码编译标志&#39;,它有-I./header/部分)。相反,执行假冒进程$(compiler) $(cflag) -c $< -o $@
中的配方。这个观察来自于输出,其中&#39; -I。/ header /&#39;出现。我猜这是因为假冒测试中的cflag模式规则会覆盖虚假测试中的tflag一个?我依稀记得make picks是最匹配的模式规则 - 两者基本上是相同的(我的意图是当执行伪造时,特定假冒下的模式规则应该被执行,这似乎不可行? ),所以make总会选择第一个。通过交换Makefile中两个模式规则的顺序来验证这个结论,这次tflag规则总是被选中。 所以,一个自然要问的问题是,当手机执行时,如何在特定的假冒条件下执行模式规则?
2,假设在第1点做我想做的事情是不可行的,我开始考虑替代方案。我可以执行以下操作:#$(obj): $(src) $(header)
以便我可以摆脱模式规则来解决模式规则。但是,这显然是不正确的,因为它说,$(obj)中的每个.o文件都依赖于所有src文件和所有头文件。 这是一个正确的方向吗?
非常感谢,期待收到您的回复。
以粗体和斜体突出显示了3个关键问题。
答案 0 :(得分:1)
你的问题就在这一行:
%.o: %.cc
该行告诉make要创建一些/ path / file.o,你将使用一些/ path / file.cc。
如果您希望将所有.o文件放在一个目录中,但仍希望将源文件放在不同的目录中,则每个源目录都需要一个这样的规则。或者,您可以将所有目录添加到VPATH变量中,例如:
VPATH=$(dir $(src))
或者更好:
VPATH=$(dir $(SRC))
在Makefile中为变量使用大写字母是避免将它们与函数名混淆的好方法。
答案 1 :(得分:1)
我会尽力回答你的新问题:
1)当您使用gnu编译器时,可以在.c文件中自动查找.h文件的依赖项。您可以将这样的规则添加到Makefile:
# Where .d-files will be created for dependencies
DEP=dep
# Dependency files
DEPS = $(srcBaseName:%.cc=$(DEP)/%.d)
# Before compiling object file, also make sure dependency file is
# created to test the need for future recompilation
obj/%.o: %.cc $(DEP)/%.d
$(compiler) $(cflags) -c $< -o $@
# Use gnu compiler to create dependency files
$(DEPS): $(DEP)/%.d: %.cc $(filter-out $(wildcard $(DEP)), $(DEP))
$(compiler) -MM $(cflags) -MT $@ $< > $@
# Create directories which might be needed
$(DEP) $(OBJ) $(BIN) $(MO):
mkdir -p $@
# Let Makefile use any generated dependency files
ifneq ($(wildcard $(DEPS)),)
include $(wildcard $(DEPS))
endif
请注意,在编译规则中,我将$^
替换为$<
,因为我们不想编译依赖项文件。
2)我会避免两个看起来相同的模式规则。相反,我会根据目标更改cflag,如下所示:
ifeq ($(MAKECMDGOALS),debug)
CFLAGS += -g
else
CFLAGS += -O2
endif
我希望这些答案会引导你朝着正确的方向前进
答案 2 :(得分:0)
主要问题是make
无法使用模式规则
%.o: %.cc
$(compiler) $(cflags) -c $^ -o $@
构建obj
,因为它无法在.o文件和.cc文件之间找到与%
匹配的公共词干。解决此问题的一种简单方法是通过make
指令告诉vpath
这些文件的位置,例如通过添加
vpath %.cc $(dir $(src))
vpath %.o obj/ #not a good idea for .o files though, see below
并将模式规则(使用vpath %.o
所需)更改为
%.o: %.cc
$(compiler) $(cflags) -c $^ -o obj/$@
编辑:MadScientist提出了一个非常好的观点,我完全错过了,基于此,一个不涉及vpath %.o
的更好的解决方案
vpath %.cc $(dir $(src))
obj=$(addprefix obj/,$(patsubst %.cc, %.o, $(srcBaseName)))
obj/%.o: %.cc
$(compiler) $(cflags) -c $^ -o $@