7

我的项目中有以下目录结构:

bin/
dist/
include/
├── module_a/
└── module_b/
Makefile
src/
├── module_a/
└── module_b/

文件夹include/包含*.hpp's while *.cpp's are in 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为每个模块单独编写一个,但这真的是最好的选择吗?

编辑:我现在想知道使用几个 Makefile 可以实现什么。如果一个在根,另一个在根,src/module_a后者怎么知道bin/?如果你用 执行它make -f src/module_a/Makefile,它与从根目录执行它是一样的,因为它的工作目录是根目录。我猜另一种方法是在执行之前更改目录,例如:make -C include/module_a,但在这种情况下,它会如何找到bin/?我不想D_BIN = ../../bin在 Makefile 中有类似的东西。

4

1 回答 1

7

我通常做的是在 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

如果您有一个非常复杂的目录结构,那么递归生成文件是可以的(可以但不是很好),随着时间的推移,您将在其中添加/删除/修改新的目录树。但是对于一个简单的项目,您只想为代码和 obj 提供单独的目录,这可能是矫枉过正。

于 2012-12-03T19:55:34.087 回答