我的项目中有以下目录结构:
bin/
dist/
include/
├── module_a/
└── module_b/
Makefile
src/
├── module_a/
└── module_b/
文件夹include/
包含*.hpp
,*.cpp
位于src/
。我想将所有来源汇编到bin/
,然后将它们连接到dist/
。对我来说似乎是一个非常合理的愿望。
我想知道针对此案例的Makefile的最佳做法。我所能找到的只是%.o: %.cpp
目标,但由于源文件夹和二进制文件夹不同而无法正常工作。
我试图使用这样的东西:
D_SRC = src
D_BIN=bin
F_CPP := $(shell find $(D_SRC) -iname '*.cpp' -type f)
F_OBJ := $(shell echo $(F_CPP) | sed s:\ :\\n:g | sed s:$(D_SRC):$(D_BIN): | sed 's:^\(.*\)\.cpp$$:\1\.o:')
$(F_OBJ): $(F_SRC)
$(foreach file, $(F_SRC), \
$(GXX) $(CXXFLAGS) -c $(file)\
)
此目标不起作用,因为$(F_OBJ)
路径以bin/
开头,而foreach
将源编译为当前工作目录。我可以将其编译为bin/
,但只有少数几个sed
表达式才会发生这种情况,而且它很难实现。
这对我来说可能很难,因为我不知道make
那么好,但我不能成为唯一一个有这个项目设置的人。在我看来,它必须是一个非常普遍的。我知道我可以分别为每个模块写一个Makefile
,但这真的是最好的选择吗?
src/module_a
处于根,另一个在bin/
,那么后者如何知道make -f src/module_a/Makefile
?如果你用make -C include/module_a
执行它,它将与从根目录执行它一样,因为它的工作目录是root。我想另一种方法是在执行之前更改目录,如下所示:bin/
,但在这种情况下,它会如何找到D_BIN = ../../bin
?我不希望在Makefile中有类似{{1}}的内容。
答案 0 :(得分:6)
我通常做的是在src目录中有一个Makefile(如果你愿意,可以从顶级Makefile中调用),然后使用这样的规则:
D_BIN = ../bin
$(D_BIN)/%.o: %.cpp
您还可以在顶级目录中尝试使用makefile,并使用如下所示的规则:
D_BIN = bin
D_SRC = src
$(D_BIN)/%.o: $(D_SRC)/%.cpp
但我没有使用过这样的规则,所以我不知道利弊与我通常做的方式。我通常这样做的方式工作正常,我甚至有建立的规则依赖于这样:
$(D_BIN)/%.d: %.cpp
,链接规则如下:
../dist/outexe: $(F_OBJ)
使用foreach通常是不受欢迎的,因为它没有使用普通makefile规则中内置的所有功能(即,没有依赖于每个文件的检查,无论是构建一切还是什么都没有),以及这样的foreach应该只作为最后的手段使用,但在这种情况下,你可以在没有foreach的情况下让它工作。
除此之外,还有更简单的方法来构建文件列表,您不需要使用shell或sed。
F_CPP = $(wildcard *.cpp)
F_OBJ = $(F_CPP:.cpp=.o)
更新:这就是我通常发出递归制作的方式:
SUBDIRS = src
.PHONY: $(SUBDIRS)
all: $(SUBDIRS)
$(SUBDIRS):
@echo "Building $@..."
$(MAKE) -C $@ $(MFLAGS)
然后确实在你的子制作中,你需要使用../bin作为例子。
然而,对于像您这样简单的项目,您可能最好只在根级别使用一个makefile并使用如下规则:
D_BIN = bin
D_SRC = src
$(D_BIN)/%.o: $(D_SRC)/%.cpp
如果你有一个非常复杂的目录结构,那么递归makefile是可以的(好但不是很好),随着时间的推移你将添加/删除/修改新的目录树。但对于一个简单的项目,你只想拥有代码和objs的单独目录,这可能有点过头了。