在不同目录中包含源文件的生成文件

我有一个项目,其目录结构如下:

                         $projectroot
|
+---------------+----------------+
|               |                |
part1/          part2/           part3/
|               |                |
+------+-----+     +---+----+       +---+-----+
|      |     |     |        |       |         |
data/   src/  inc/  src/     inc/   src/       inc/

我应该如何编写一个 makefile,它应该位于/src 部分(或其他地方) ,可以部分地完成 c/c + + 源文件的/link?SRC?

我能做一些像 - I $projectroot/part1/src-I $projectroot/part1/inc-I $projectroot/part2/src...

如果这能行,有没有更简单的方法。我见过这样的项目,每个对应的部分都有一个 makefile?文件夹。[在这篇文章中,我使用了类似 bash 语法的问号]

274229 次浏览

传统的方法是在每个子目录(part1part2等)中有一个 Makefile,允许您独立地构建它们。此外,在项目的根目录中有一个构建所有内容的 Makefile。“根”Makefile看起来如下:

all:
+$(MAKE) -C part1
+$(MAKE) -C part2
+$(MAKE) -C part3

由于 make 目标中的每一行都在其自己的 shell 中运行,因此无需担心向上遍历目录树或其他目录。

我建议你看看 GNU 手册第5.7节,它很有帮助。

如果一个子目录中的代码依赖于另一个子目录中的代码,那么最好在顶层使用单个 makefile。

请参阅 被认为有害的递归了解完整的基本原理,但是基本上您希望 make 拥有决定是否需要重新构建文件所需的完整信息,如果您只告诉它项目的三分之一,它就不会拥有这些信息。

以上连结似乎无法找到,请按此处下载:

我认为最好指出,使用 Make (递归或非递归)通常是您可能想要避免的,因为与今天的工具相比,它很难学习、维护和扩展。

这是一个很棒的工具,但它的直接使用应该被视为过时在2010 + 。

当然,除非你正在一个特殊的环境中工作,比如一个遗留项目等等。

使用 IDE,CMake或者,如果你是硬核,自动工具

(由于反对票,编辑 Ty Honza 指出)

VPATH 选项可能会派上用场,它告诉 make 在哪些目录中查找源代码。不过,对于每个包含路径,您仍然需要一个-I 选项。举个例子:

CXXFLAGS=-Ipart1/inc -Ipart2/inc -Ipart3/inc
VPATH=part1/src:part2/src:part3/src


OutputExecutable: part1api.o part2api.o part3api.o

这将自动在任何指定的 VPATH 目录中找到匹配的 partXapi.cpp 文件并编译它们。但是,当 src 目录分成子目录时,这更有用。对于您所描述的内容,正如其他人所说的,您可能最好为每个部分使用 makefile,特别是如果每个部分都可以单独存在的话。

您可以向您的根 Makefile 添加规则,以便在其他目录中编译必要的 cpp 文件。下面的 Makefile 示例应该是一个很好的开始,可以帮助您实现目标。

CC=g++
TARGET=cppTest
OTHERDIR=../../someotherpath/in/project/src


SOURCE = cppTest.cpp
SOURCE = $(OTHERDIR)/file.cpp


## End sources definition
INCLUDE = -I./ $(AN_INCLUDE_DIR)
INCLUDE = -I.$(OTHERDIR)/../inc
## end more includes


VPATH=$(OTHERDIR)
OBJ=$(join $(addsuffix ../obj/, $(dir $(SOURCE))), $(notdir $(SOURCE:.cpp=.o)))


## Fix dependency destination to be ../.dep relative to the src dir
DEPENDS=$(join $(addsuffix ../.dep/, $(dir $(SOURCE))), $(notdir $(SOURCE:.cpp=.d)))


## Default rule executed
all: $(TARGET)
@true


## Clean Rule
clean:
@-rm -f $(TARGET) $(OBJ) $(DEPENDS)




## Rule for making the actual target
$(TARGET): $(OBJ)
@echo "============="
@echo "Linking the target $@"
@echo "============="
@$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
@echo -- Link finished --


## Generic compilation rule
%.o : %.cpp
@mkdir -p $(dir $@)
@echo "============="
@echo "Compiling $<"
@$(CC) $(CFLAGS) -c $< -o $@




## Rules for object files from cpp files
## Object file for each file is put in obj directory
## one level up from the actual source directory.
../obj/%.o : %.cpp
@mkdir -p $(dir $@)
@echo "============="
@echo "Compiling $<"
@$(CC) $(CFLAGS) -c $< -o $@


# Rule for "other directory"  You will need one per "other" dir
$(OTHERDIR)/../obj/%.o : %.cpp
@mkdir -p $(dir $@)
@echo "============="
@echo "Compiling $<"
@$(CC) $(CFLAGS) -c $< -o $@


## Make dependancy rules
../.dep/%.d: %.cpp
@mkdir -p $(dir $@)
@echo "============="
@echo Building dependencies file for $*.o
@$(SHELL) -ec '$(CC) -M $(CFLAGS) $< | sed "s^$*.o^../obj/$*.o^" > $@'


## Dependency rule for "other" directory
$(OTHERDIR)/../.dep/%.d: %.cpp
@mkdir -p $(dir $@)
@echo "============="
@echo Building dependencies file for $*.o
@$(SHELL) -ec '$(CC) -M $(CFLAGS) $< | sed "s^$*.o^$(OTHERDIR)/../obj/$*.o^" > $@'


## Include the dependency files
-include $(DEPENDS)


RC 的帖子非常有用。我从来没有想过使用 $(dir $@)函数,但它确实做了我需要它做的事情。

在 ParentDir 中,有一些包含源文件的目录: dirA、 dirB、 dirC。不同的文件依赖于其他目录中的对象文件,因此我希望能够在一个目录中创建一个文件,并通过调用与该依赖项相关联的 makefile 来创建该依赖项。

从本质上讲,我创建了一个 Makefile,它有一个类似于 RC 的通用规则(还有其他很多东西) :

%.o : %.cpp
@mkdir -p $(dir $@)
@echo "============="
@echo "Compiling $<"
@$(CC) $(CFLAGS) -c $< -o $@

为了继承这个通用规则,每个子目录都包含这个上层生成文件。在每个子目录的 Makefile 中,我为每个文件编写了一个自定义规则,以便能够跟踪每个文件所依赖的所有内容。

每当我需要创建一个文件时,我使用(本质上)这个规则来递归地创建任何/所有的依赖项!

注意: 有一个名为“ makepp”的实用程序似乎可以更直观地完成这个任务,但是为了便于移植,而且不依赖于其他工具,我选择这样做。

希望这个能帮上忙!

制造的递归使用

all:
+$(MAKE) -C part1
+$(MAKE) -C part2
+$(MAKE) -C part3

这使得 make可以拆分为多个作业并使用多个核

如果源文件分布在许多文件夹中,并且像之前建议的那样使用单独的 Makefile 是有意义的,递归 make 是一种很好的方法,但是对于较小的项目,我发现更容易列出 马克菲尔中所有的源文件以及它们到 马克菲尔的相对路径,如下所示:

# common sources
COMMON_SRC := ./main.cpp \
../src1/somefile.cpp \
../src1/somefile2.cpp \
../src2/somefile3.cpp \

然后我可以这样设置 VPATH:

VPATH := ../src1:../src2

然后我构建物体:

COMMON_OBJS := $(patsubst %.cpp, $(ObjDir)/%$(ARCH)$(DEBUG).o, $(notdir $(COMMON_SRC)))

现在规则很简单:

# the "common" object files
$(ObjDir)/%$(ARCH)$(DEBUG).o : %.cpp Makefile
@echo creating $@ ...
$(CXX) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<

建立产出甚至更容易:

# This will make the cbsdk shared library
$(BinDir)/$(OUTPUTBIN): $(COMMON_OBJS)
@echo building output ...
$(CXX) -o $(BinDir)/$(OUTPUTBIN) $(COMMON_OBJS) $(LFLAGS)

人们甚至可以通过以下方式实现 VPATH发电的自动化:

VPATH := $(dir $(COMMON_SRC))

或者使用 sort删除重复项这一事实(尽管这应该无关紧要) :

VPATH := $(sort  $(dir $(COMMON_SRC)))

我建议使用 autotools:

将生成的目标文件(。O)放到源文件的同一目录中,以避免在使用非递归 make 时发生冲突。

AUTOMAKE_OPTIONS = subdir-objects

只是把它和其他很简单的东西放在 Makefile.am里。

这是 教程

我一直在寻找这样的东西,经过一些尝试和跌倒我创建自己的 makefile,我知道这不是“惯用的方式”,但它是一个开始了解 make 和这对我来说工作,也许你可以尝试在你的项目。

PROJ_NAME=mono


CPP_FILES=$(shell find . -name "*.cpp")


S_OBJ=$(patsubst %.cpp, %.o, $(CPP_FILES))


CXXFLAGS=-c \
-g \
-Wall


all: $(PROJ_NAME)
@echo Running application
@echo
@./$(PROJ_NAME)


$(PROJ_NAME): $(S_OBJ)
@echo Linking objects...
@g++ -o $@ $^


%.o: %.cpp %.h
@echo Compiling and generating object $@ ...
@g++ $< $(CXXFLAGS) -o $@


main.o: main.cpp
@echo Compiling and generating object $@ ...
@g++ $< $(CXXFLAGS)


clean:
@echo Removing secondary things
@rm -r -f objects $(S_OBJ) $(PROJ_NAME)
@echo Done!

我知道这很简单,对某些人来说,我的标志是错误的,但正如我所说的,这是我第一次在 Makefile 以多目录编译我的项目,然后将它们链接在一起,创建我的 bin。

我接受建议: D