Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Makefile的良好实践_Makefile - Fatal编程技术网

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创建单独的目录,那么这可能太过分了。

这看起来确实像我想要的一切。我现在无法测试它,但据我所知,这将起作用。非常感谢你。