使用完整路径生成gcc依赖项

时间:2017-12-12 23:17:34

标签: c++ makefile g++

我有一个看起来像这样的简单项目

.
├── 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.ofile1.o不匹配,因此,更改src/file1.cpp或其所依赖的任何标头都不会导致目标文件被重建。起初我认为可能是在生成.depend文件之前运行sinclude .depend的问题,但即使我运行make depend后跟make build,问题仍然存在。从我读过的所有内容中,没有g++个参数或选项可以保留名称的路径。

是否有可能以这种方式生成依赖文件,或者这是构建项目的根本不正确的方法?

我看了一下这个问题被标记为可能重复的问题的答案,但似乎问题是如何为项目创建一个完整的makefile,而我的问题不是创建一个Makefile,而是gcc -MM依赖关系生成的问题。这个问题的答案并没有解决我的问题。

3 个答案:

答案 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.cppfile1.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现在能够处理可以在源树“外部”的路径,只需使用'__'而不是'..',并根据找到的模式设置构建目录,所以srcbuild不再有问题。我需要“外部”文件来使用源池,其中本地构建目录位于源池和项目目录的根目录下。

希望有所帮助...

编辑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

这使得可以不将所有使用的目录复制或链接到本地​​项目和构建文件树。