源文件位于不同目录中的 Makefile

2024-10-12 10:28:00
admin
原创
79
摘要:问题描述:我有一个项目,其目录结构如下: $projectroot | +---------------+----------------+ | ...

问题描述:

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

                         $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只是将其与其他相当简单的东西包括在内。

这是教程。

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用