Makefile与源文件在不同的目录中

dev*_*vin 123 linux makefile

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

                         $projectroot
                              |
              +---------------+----------------+
              |               |                |
            part1/          part2/           part3/
              |               |                |
       +------+-----+     +---+----+       +---+-----+
       |      |     |     |        |       |         |
     data/   src/  inc/  src/     inc/   src/       inc/
Run Code Online (Sandbox Code Playgroud)

我应该如何编写部分/ src(或其他任何地方)的makefile,它可以补充/链接部分?/ src中的c/c ++源文件?

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

如果这样可行,是否有更简单的方法.我看过每个相应部分都有makefile的项目?文件夹.[在这篇文章中我使用了像bash语法中的问号]

小智 104

传统的方法是有一个Makefile在每个子目录(中part1,part2等),使您能够独立构建它们.此外,Makefile在项目的根目录中有一个构建一切的东西."root" Makefile看起来如下所示:

all:
    +$(MAKE) -C part1
    +$(MAKE) -C part2
    +$(MAKE) -C part3
Run Code Online (Sandbox Code Playgroud)

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

我建议看看GNU make手册第5.7节 ; 这非常有帮助.

  • 这应该是`+ $(MAKE)-C part1`等.这允许Make的作业控制在子目录中工作. (26认同)
  • 这是一种经典的方法,并且被广泛使用,但随着项目的发展,它在几个方面都是次优的.Dave Hinton有指针跟随. (25认同)
  • + 符号是什么意思? (5认同)

dav*_*420 84

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

请参阅Recursive Make Considered Harmful的完整原理,但基本上你希望make获得它所需的全部信息来决定是否需要重建文件,如果你只告诉它大约三分之一,那就不会有.你的项目.

上面的链接似乎无法访问.这里可以访问相同的文档:

  • 谢谢你,没有意识到这一点.了解做事的"正确方式"而不是"正常工作"或被接受为标准的方式非常有用. (3认同)
  • 递归 make 被认为是有害的,回到它确实不能正常工作的时候。这些天它不被认为是有害的,事实上,它是 autotools / automake 管理更大项目的方式。 (3认同)

Cod*_*oat 33

VPATH选项可能派上用场,它告诉make要查找源代码的目录.但是,对于每个包含路径,您仍然需要-I选项.一个例子:

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

OutputExecutable: part1api.o part2api.o part3api.o
Run Code Online (Sandbox Code Playgroud)

这将自动在任何VPATH指定目录中找到匹配的partXapi.cpp文件并进行编译.但是,当您的src目录分解为子目录时,这会更有用.正如你所描述的那样,正如其他人所说,你可能最好使用每个部分的makefile,特别是如果每​​个部分都可以独立存在.

  • 我不相信这个简单完美的答案没有得到更多的选票.它来自我的+1. (2认同)
  • 我在子目录中的几个不同项目的较高目录中有一些通用源文件,`VPATH = ..`对我有用! (2认同)

RC.*_*RC. 23

您可以向根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)

  • 我知道现在已经很老了但是,不是SOURCE和INCLUDE后来被另一个作业覆盖了吗? (7认同)

das*_*esy 19

如果源代码分布在许多文件夹中,并且按照之前的建议建立单独的Makefile是有意义的,递归make是一种很好的方法,但对于较小的项目,我发现使用它们的相对路径列出Makefile中的所有源文件更容易像这样的Makefile:

# common sources
COMMON_SRC := ./main.cpp \
              ../src1/somefile.cpp \
              ../src1/somefile2.cpp \
              ../src2/somefile3.cpp \
Run Code Online (Sandbox Code Playgroud)

然后我可以这样设置VPATH:

VPATH := ../src1:../src2
Run Code Online (Sandbox Code Playgroud)

然后我构建对象:

COMMON_OBJS := $(patsubst %.cpp, $(ObjDir)/%$(ARCH)$(DEBUG).o, $(notdir $(COMMON_SRC)))
Run Code Online (Sandbox Code Playgroud)

现在规则很简单:

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

构建输出更容易:

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

甚至可以VPATH通过以下方式使生成自动化:

VPATH := $(dir $(COMMON_SRC))
Run Code Online (Sandbox Code Playgroud)

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

VPATH := $(sort  $(dir $(COMMON_SRC)))
Run Code Online (Sandbox Code Playgroud)


IlD*_*Dan 8

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

这是一个很棒的工具,但直接使用应该在2010年以后被认为是过时的.

当然,除非您在特殊环境中工作,例如遗留项目等.

使用IDE,CMake,或者,如果你是硬盘,使用Autotools.

(由于downvotes编辑,ty Honza指出)

  • 如果可以的话,用几句话来解释现代工具如何使编写Makefile的生活变得更容易,这将是一件好事.它们是否提供更高级别的抽象?或者是什么? (7认同)
  • downvotes可能是因为你回答了自己的问题.问题不在于是否应该使用Makefile.这是关于如何写它们. (5认同)
  • 我赞成"不要那样做"的建议--KDevelop有一个非常图形化的界面来配置Make和其他构建系统,虽然我自己写Makefiles,但KDevelop是我给我的同事们的 - 但我不要认为Autotools链接有帮助.要了解Autotools,您需要了解m4,libtool,automake,autoconf,shell,make以及基本上整个堆栈. (2认同)

Mat*_*ade 5

我一直在寻找这样的东西,经过一番尝试和失败后,我创建了自己的 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!
Run Code Online (Sandbox Code Playgroud)

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

我接受建议 :D