源文件位于不同目录中的 Makefile
- 2024-10-12 10:28:00
- admin 原创
- 80
问题描述:
我有一个项目,其目录结构如下:
$projectroot
|
+---------------+----------------+
| | |
part1/ part2/ part3/
| | |
+------+-----+ +---+----+ +---+-----+
| | | | | | |
data/ src/ inc/ src/ inc/ src/ inc/
我应该如何编写一个位于 part/src(或实际上任何地方)的 makefile,以便可以完成/链接 part?/src 中的 c/c++ 源文件?
我可以执行类似 -I$projectroot/part1/src -I$projectroot/part1/inc -I$projectroot/part2/src 的操作吗...
如果这样可行,有没有更简单的方法。我见过一些项目,每个相应的部分都有一个 makefile?文件夹。[在这篇文章中,我使用了问号,就像 bash 语法一样]
解决方案 1:
Makefile
传统方法是在每个子目录(part1
、等)中创建一个,part2
以便您独立构建它们。此外,Makefile
在项目的根目录中创建一个,用于构建所有内容。“根”Makefile
看起来类似于以下内容:
all:
+$(MAKE) -C part1
+$(MAKE) -C part2
+$(MAKE) -C part3
由于 make 目标中的每一行都在其自己的 shell 中运行,因此无需担心遍历目录树或其他目录。
我建议看一下GNU make 手册第 5.7 节;它非常有帮助。
解决方案 2:
如果一个子目录中的代码依赖于另一个子目录中的代码,那么最好在顶层使用一个 makefile。
请参阅“递归 Make 被视为有害”以了解完整原理,但基本上您希望 make 拥有所需的全部信息来决定是否需要重建文件,而如果您只告诉它项目的三分之一,它就不会拥有这些信息。
上面的链接似乎无法访问。 同一文档可在此处访问:
aegis.sourceforge.net (已存档)
lcgapp.cern.ch
解决方案 3:
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,特别是如果每个部分都可以独立存在的话。
解决方案 4:
您可以向根 Makefile 添加规则,以便编译其他目录中所需的 cpp 文件。下面的 Makefile 示例应该是一个很好的开始,可以帮助您实现目标。
抄送=g++
目标=cpp测试
OTHERDIR=../../someotherpath/in/project/src
源文件 = cppTest.cpp
源 = $(OTHERDIR)/file.cpp
## 结束源定义
包括 = -I./ $(AN_INCLUDE_DIR)
包括 = -I.$(OTHERDIR)/../inc
## 结束更多包含
VPATH=$(其他目录)
OBJ=$(加入$(addsuffix../obj/,$(dir $(SOURCE))),$(notdir $(SOURCE:.cpp=.o)))
## 修复依赖目标为相对于 src 目录的 ../.dep
DEPENDS=$(加入$(addsuffix../.dep/,$(dir $(SOURCE))),$(notdir $(SOURCE:.cpp=.d)))
## 执行默认规则
全部:$(TARGET)
@真的
## 清洁规则
干净的:
@-rm -f $(目标) $(对象) $(取决于)
## 制定实际目标的规则
$(目标): $(对象)
@echo "=============="
@echo "链接目标 $@"
@echo "=============="
@$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
@echo -- 链接完成 --
## 通用编译规则
%.o : %.cpp
@mkdir -p $(目录 $@)
@echo "=============="
@echo "编译 $<"
@$(CC) $(CFLAGS) -c $< -o $@
## 来自 cpp 文件的目标文件的规则
## 每个文件的目标文件都放在 obj 目录中
## 比实际源目录高一级。
../obj/%.o:%.cpp
@mkdir -p $(目录 $@)
@echo "=============="
@echo "编译 $<"
@$(CC) $(CFLAGS) -c $< -o $@
# “其他目录”规则每个“其他”目录都需要一个
$(OTHERDIR)/../obj/%.o:%.cpp
@mkdir -p $(目录 $@)
@echo "=============="
@echo "编译 $<"
@$(CC) $(CFLAGS) -c $< -o $@
## 制定依赖规则
../.dep/%.d: %.cpp
@mkdir -p $(目录 $@)
@echo "=============="
@echo 为 $*.o 构建依赖文件
@$(SHELL) -ec'$(CC) -M $(CFLAGS) $< | sed"s^$*.o^../obj/$*.o^" > $@'
## “其他”目录的依赖规则
$(OTHERDIR)/../.dep/%.d: %.cpp
@mkdir -p $(目录 $@)
@echo "=============="
@echo 为 $*.o 构建依赖文件
@$(SHELL) -ec'$(CC) -M $(CFLAGS) $< | sed"s^$*.o^$(OTHERDIR)/../obj/$*.o^" > $@'
## 包含依赖文件
-包括 $(取决于)
解决方案 5:
如果源代码分布在许多文件夹中,并且有单独的 Makefile 是有意义的,那么如前所述,递归 make 是一种很好的方法,但对于较小的项目,我发现在 Makefile 中列出所有源文件及其相对于Makefile的相对路径更容易,如下所示:
# common sources
COMMON_SRC := ./main.cpp \ n ../src1/somefile.cpp \ n ../src1/somefile2.cpp \ n ../src2/somefile3.cpp \ n
然后我可以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)))
解决方案 6:
我认为最好指出的是,通常你可能想要避免使用 Make(递归或非递归),因为与今天的工具相比,它很难学习、维护和扩展。
这是一个非常棒的工具,但是在 2010 年以后直接使用应该被认为是过时的。
当然,除非你在特殊环境中工作,例如,有一个遗留项目等等。
使用 IDE、CMake,或者如果您很执着,也可以使用Autotools。
(由于投票反对而进行了编辑,感谢 Honza 指出)
解决方案 7:
我一直在寻找这样的东西,经过几次尝试和失败后,我创建了自己的 makefile,我知道这不是“惯用的方式”,但这是一个理解 make 的开始,而且这对我有用,也许你可以在你的项目中尝试。
PROJ_NAME=mono
CPP_FILES=$(shell find . -name "*.cpp")
S_OBJ=$(patsubst %.cpp, %.o, $(CPP_FILES))
CXXFLAGS=-c \ n -g \ n -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
解决方案 8:
RC 的帖子超级有用。我从来没有想过使用 $(dir $@) 函数,但它确实满足了我的需求。
在 parentDir 中,有一堆包含源文件的目录:dirA、dirB、dirC。各种文件都依赖于其他目录中的目标文件,因此我希望能够在一个目录中创建一个文件,并通过调用与该依赖项关联的 makefile 来创建该依赖项。
本质上,我在 parentDir 中创建了一个 Makefile,它具有(以及许多其他内容)类似于 RC 的通用规则:
%.o : %.cpp @mkdir -p $(dir $@) @echo "=============" @echo "Compiling $<" @$(CC) $(CFLAGS) -c $< -o $@
每个子目录都包含此上级 makefile,以便继承此通用规则。在每个子目录的 Makefile 中,我为每个文件编写了一个自定义规则,以便可以跟踪每个单个文件所依赖的所有内容。
每当我需要创建文件时,我都会使用(本质上)此规则以递归方式创建任何/所有依赖项。完美!
注意:有一个名为“makepp”的实用程序似乎可以更直观地完成这项任务,但为了可移植性并且不依赖于其他工具,我选择以这种方式进行。
希望这有帮助!
解决方案 9:
递归使用 Make
all:
+$(MAKE) -C part1
+$(MAKE) -C part2
+$(MAKE) -C part3
这允许make
拆分作业并使用多个核心
解决方案 10:
我建议使用autotools
:
//##
将生成的目标文件(.o)放入与其源文件相同的目录中,以避免在使用非递归 make 时发生冲突。
AUTOMAKE_OPTIONS = subdir-objects
Makefile.am
只是将其与其他相当简单的东西包括在内。
这是教程。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件