我有一个看起来像这样的简单项目
.
├── build
│ ├── file1.o
│ └── one
│ ├── file1.o
│ └── file2.o
├── .depend
├── Makefile
└── src
├── file1.cpp
└── one
├── file1.cpp
└── file2.cpp
Makefile是这样的:
# Get all of the source files
SRC = $(shell find src/ -name "*.cpp")
# Get all of the object files
OBJ = $(subst src,build,$(SRC:.cpp=.o))
$(OBJ):
@mkdir -p $(shell dirname $@)
g++ -g -c $(subst build,src,$(subst .o,.cpp,$@)) -o $@
all: depend build
build: $(OBJ)
gcc -o project $^
depend:
g++ -MM $(SRC) > .depend
sed -i 's/.\/src/.\/build\//g' .depend
sinclude .depend
我试图通过运行g++ -MM src/file1.cpp src/one/file1.cpp src/one/file2.cpp > .depend
来生成makefile依赖项,并生成以下指令:
file1.o: src/file1.cpp <other headers>
file1.o: src/one/file1.cpp <other headers>
file2.o: src/one/file2.cpp <other headers>
问题在于,build/file1.o
与file1.o
不匹配,因此,更改src/file1.cpp
或其所依赖的任何标头都不会导致目标文件被重建。起初我认为可能是在生成.depend文件之前运行sinclude .depend
的问题,但即使我运行make depend
后跟make build
,问题仍然存在。从我读过的所有内容中,没有g++
个参数或选项可以保留名称的路径。
是否有可能以这种方式生成依赖文件,或者这是构建项目的根本不正确的方法?
我看了一下这个问题被标记为可能重复的问题的答案,但似乎问题是如何为项目创建一个完整的makefile,而我的问题不是创建一个Makefile,而是gcc -MM
依赖关系生成的问题。这个问题的答案并没有解决我的问题。
答案 0 :(得分:2)
怎么样:
# Get all of the source files
SRC = $(shell find src/ -name "*.cpp")
# Get all of the object files
OBJ = $(patsubst src/%.cpp,build/%.o,$(SRC))
.PHONY: all
all: project
project: $(OBJ)
gcc -o $@ $^
$(OBJ): build/%.o: src/%.cpp
@mkdir -p $(dir $@)
g++ -g -c $< -o $@
.depend: $(SRC)
g++ -MM $^ > $@ && \
sed -Ei 's#^(.*\.o: *)src/(.*/)?(.*\.cpp)#build/\2\1src/\2\3#' $@
include .depend
sed
命令替换任何:
file.o: src/file.cpp ...
由:
build/file.o: src/file.cpp ...
和任何:
file.o: src/X/Y/Z/file.cpp ...
由:
build/X/Y/Z/file.o: src/X/Y/Z/file.cpp ...
目标直接是.depend
,并且它将所有源文件都作为依赖项,以便在丢失或比任何源文件旧时自动重建。无需使用depend
虚假目标或将其添加为all
的先决条件(如果需要,自动尝试重建include
附带的文件)。
我添加了一些GNU make功能(patsubst
,静态模式规则,系统使用自动变量......)如果你使用另一个make,则重做不受支持的功能。
答案 1 :(得分:1)
以下是三种方法。
一,用sed修改输出(类似于Renaud Pacalet的答案):
depend:
g++ -MM $(SRC) | sed 's/.*: src\([^ ]*\)cpp/build\1o: src\1cpp/' > .depend
二,使用shell循环:
STEMS := file1 one/file1 one/file2
depend:
rm -f .depend
for x in $(STEMS); do g++ -MM -MT build/$$x.o src/$$x.cpp >> .depend; done
三,制作方法:
DEPENDENCIES := $(addsuffix -depend,$(STEMS))
clear-depend:
rm -f .depend
depend: $(DEPENDENCIES)
%-depend: clear-depend
g++ -MM -MT build/$*.o src/$*.cpp >> .depend
(我最喜欢的方法是为每个目标文件设置一个单独的依赖文件,而不是一个大的.depend
文件。它有几个优点,但它需要一些时间来解释,它也是如果源树中存在名称冲突,例如file1.cpp
和file1.cpp
,则会很棘手。)
答案 2 :(得分:0)
我使用以下序列进行构建:
define req
$(subst ..,__,$(dir build-$(TARGET)$(build_dir_ext)/$(1)))%.o: $(dir $1)%.cpp
mkdir -p $$(dir $$(subst ..,__,$$@))
$$(CXX) -MM $$(CXXFLAGS) $$< -MT $$(subst ..,__,$$@) > $$(patsubst %.o,%.d,$$(subst ..,__,$$@))
$$(CXX) $$(CXXFLAGS) $$< -c -o $$(subst ..,__,$$@)
endef
$(eval $(foreach x,$(OBJ),$(call req,$(x))))
因此make现在能够处理可以在源树“外部”的路径,只需使用'__'而不是'..',并根据找到的模式设置构建目录,所以src
和build
不再有问题。我需要“外部”文件来使用源池,其中本地构建目录位于源池和项目目录的根目录下。
希望有所帮助...
编辑1:为什么要替换'..'
考虑以下源代码树:
./sourcepool/lib1/src/one.cpp
./sourcepool/project/build
如果您的Makefile位于./sourcepool/project路径中,并且其中一个OBJ是“../lib1/src/one.o”,则Makefile应该在构建目录中创建一个等效路径。也就是说,如果使用'..',则不可能,因为路径在构建中不再长,而是一个深度更高。如果用__替换..结果如下:
./sourcepool/project/build/__/lib1/src/one.o
这使得可以不将所有使用的目录复制或链接到本地项目和构建文件树。