Makefile的良好实践
我的项目中有以下目录结构:Makefile的良好实践,makefile,Makefile,我的项目中有以下目录结构: bin/ dist/ include/ ├── module_a/ └── module_b/ Makefile src/ ├── module_a/ └── module_b/ 文件夹include/包含*。hpp,而*。cpp位于src/中。我想将所有源代码编译到bin/,然后将它们链接到dist/。对我来说似乎是一个合理的愿望 我想知道这个案例中Makefile的最佳实践。我只能找到%.o:%.cpptarget,但这并不能真正起作用,因为源代码和二进制文件夹
bin/
dist/
include/
├── module_a/
└── module_b/
Makefile
src/
├── module_a/
└── module_b/
文件夹include/
包含*。hpp
,而*。cpp
位于src/
中。我想将所有源代码编译到bin/
,然后将它们链接到dist/
。对我来说似乎是一个合理的愿望
我想知道这个案例中Makefile的最佳实践。我只能找到%.o:%.cpp
target,但这并不能真正起作用,因为源代码和二进制文件夹不同
我试着用这样的东西:
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)\
)
D_BIN = ../bin
$(D_BIN)/%.o: %.cpp
D_BIN = bin
D_SRC = src
$(D_BIN)/%.o: $(D_SRC)/%.cpp
D_BIN = bin
D_SRC = src
$(D_BIN)/%.o: $(D_SRC)/%.cpp
此目标不起作用,因为$(F_OBJ)
路径以bin/
开头,而foreach
将源编译为当前工作目录。我可以把它编译成bin/
,但那只会发生在更多的sed
表达式中,而且它已经够难看的了
这对我来说可能太难了,因为我不知道make
,但我不可能是唯一一个有这个项目设置的人。在我看来,这一定是一个相当普遍的现象。我知道我可以分别为每个模块编写Makefile
,但这真的是最好的选择吗
编辑:我现在想知道使用几个makefile可以实现什么。如果一个在根目录下,另一个在
src/module_a
中,后者如何知道bin/
?如果使用make-fsrc/module\u a/Makefile
执行它,它将与从根目录执行它相同,因为它的工作目录将是根目录。我猜,另一种方法是在执行它之前更改目录,比如:make-C include/module_a
,但在这种情况下,它如何找到bin/
?我不希望在Makefile中有类似于D_BIN=../../BIN
的东西。我通常做的是在src目录中有一个Makefile(如果愿意,可以从顶级Makefile调用),然后使用如下规则:
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)\
)
D_BIN = ../bin
$(D_BIN)/%.o: %.cpp
D_BIN = bin
D_SRC = src
$(D_BIN)/%.o: $(D_SRC)/%.cpp
D_BIN = bin
D_SRC = src
$(D_BIN)/%.o: $(D_SRC)/%.cpp
您还可以在顶级目录中使用一个makefile,并使用如下规则:
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)\
)
D_BIN = ../bin
$(D_BIN)/%.o: %.cpp
D_BIN = bin
D_SRC = src
$(D_BIN)/%.o: $(D_SRC)/%.cpp
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)
更新:这是我通常发布递归make的方式:
SUBDIRS = src
.PHONY: $(SUBDIRS)
all: $(SUBDIRS)
$(SUBDIRS):
@echo "Building $@..."
$(MAKE) -C $@ $(MFLAGS)
实际上,在您的submake中,您需要使用../bin作为示例
但是,对于像您这样简单的项目,您最好在根级别使用一个makefile,并使用如下规则:
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)\
)
D_BIN = ../bin
$(D_BIN)/%.o: %.cpp
D_BIN = bin
D_SRC = src
$(D_BIN)/%.o: $(D_SRC)/%.cpp
D_BIN = bin
D_SRC = src
$(D_BIN)/%.o: $(D_SRC)/%.cpp
如果您有一个非常复杂的目录结构,随着时间的推移,您将添加/删除/修改新的目录树,那么递归生成文件是可以的(可以,但不是很好)。但是对于一个简单的项目来说,如果您只想为代码和objs创建单独的目录,那么这可能太过分了。这看起来确实像我想要的一切。我现在无法测试它,但据我所知,这将起作用。非常感谢你。