Linux 源文件在不同目录下的 Makefile

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1139271/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 17:31:48  来源:igfitidea点击:

Makefiles with source files in different directories

linuxmakefile

提问by devin

I have a project where the directory structure is like this:

我有一个项目,目录结构是这样的:

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

How should I write a makefile that would be in part/src (or wherever really) that could comple/link on the c/c++ source files in part?/src ?

我应该如何编写一个可以在部分/src(或任何地方)中完成/链接到部分 c/c++ 源文件的 makefile?/src ?

Can I do something like -I$projectroot/part1/src -I$projectroot/part1/inc -I$projectroot/part2/src ...

我可以做类似 -I$projectroot/part1/src -I$projectroot/part1/inc -I$projectroot/part2/src ...

If that would work, is there an easier way to do it. I've seen projects where there is a makefile in each of the corresponding part? folders. [in this post I used the question mark like in bash syntax]

如果那行得通,有没有更简单的方法来做到这一点。我见过在每个相应部分都有一个 makefile 的项目吗?文件夹。[在这篇文章中,我使用了 bash 语法中的问号]

采纳答案by devin

The traditional way is to have a Makefilein each of the subdirectories (part1, part2, etc.) allowing you to build them independently. Further, have a Makefilein the root directory of the project which builds everything. The "root" Makefilewould look something like the following:

传统的方法是有一个Makefile在每个子目录(中part1part2等),使您能够独立构建它们。此外,Makefile在构建所有内容的项目的根目录中有一个。“根”Makefile将类似于以下内容:

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

Since each line in a make target is run in its own shell, there is no need to worry about traversing back up the directory tree or to other directories.

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

I suggest taking a look at the GNU make manual section 5.7; it is very helpful.

我建议查看GNU make 手册第 5.7 节;这是非常有帮助的。

回答by dave4420

If you have code in one subdirectory dependent on code in another subdirectory, you are probably better off with a single makefile at top-level.

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

See Recursive Make Considered Harmfulfor the full rationale, but basically you want make to have the full information it needs to decide whether or not a file needs to be rebuilt, and it won't have that if you only tell it about a third of your project.

有关完整原理,请参阅递归生成被认为有害,但基本上您希望 make 拥有决定是否需要重建文件所需的完整信息,如果您只告诉它大约三分之一你的项目。

The link above seems to be not reachable. The same document is reachable here:

上面的链接似乎无法访问。可以在此处访问相同的文档:

回答by IlDan

I think it's better to point out that using Make (recursive or not) is something that usually you may want to avoid, because compared to today tools, it's difficult to learn, maintain and scale.

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

It's a wonderful tool but it's direct use should be considered obsolete in 2010+.

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

Unless, of course, you're working in a special environment i.e. with a legacy project etc.

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

Use an IDE, CMakeor, if you're hard cored, the Autotools.

使用 IDE、CMakeAutotools(如果您是硬核)。

(edited due to downvotes, ty Honza for pointing out)

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

回答by CodeGoat

The VPATH option might come in handy, which tells make what directories to look in for source code. You'd still need a -I option for each include path, though. An example:

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

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

OutputExecutable: part1api.o part2api.o part3api.o

This will automatically find the matching partXapi.cpp files in any of the VPATH specified directories and compile them. However, this is more useful when your src directory is broken into subdirectories. For what you describe, as others have said, you are probably better off with a makefile for each part, especially if each part can stand alone.

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

回答by RC.

You can add rules to your root Makefile in order to compile the necessary cpp files in other directories. The Makefile example below should be a good start in getting you to where you want to be.

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

回答by jvriesem

RC's post was SUPER useful. I never thought about using the $(dir $@) function, but it did exactly what I needed it to do.

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

In parentDir, have a bunch of directories with source files in them: dirA, dirB, dirC. Various files depend on the object files in other directories, so I wanted to be able to make one file from within one directory, and have it make that dependency by calling the makefile associated with that dependency.

在 parentDir 中,有一堆包含源文件的目录:dirA、dirB、dirC。各种文件依赖于其他目录中的目标文件,因此我希望能够从一个目录中创建一个文件,并通过调用与该依赖项相关联的 makefile 来创建该依赖项。

Essentially, I made one Makefile in parentDir that had (among many other things) a generic rule similar to RC's:

本质上,我在 parentDir 中创建了一个 Makefile,它具有(除其他外)一个类似于 RC 的通用规则:

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

Each subdirectory included this upper-level makefile in order to inherit this generic rule. In each subdirectory's Makefile, I wrote a custom rule for each file so that I could keep track of everything that each individual file depended on.

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

Whenever I needed to make a file, I used (essentially) this rule to recursively make any/all dependencies. Perfect!

每当我需要创建文件时,我(基本上)使用此规则递归创建任何/所有依赖项。完美的!

NOTE: there's a utility called "makepp" that seems to do this very task even more intuitively, but for the sake of portability and not depending on another tool, I chose to do it this way.

注意:有一个名为“makepp”的实用程序似乎可以更直观地完成这项任务,但为了便携性而不是依赖其他工具,我选择了这种方式。

Hope this helps!

希望这可以帮助!

回答by EhevuTov

Recursive Use of Make

Make 的递归使用

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

This allows for maketo split into jobs and use multiple cores

这允许make拆分为作业并使用多个内核

回答by dashesy

If the sources are spread in many folders, and it makes sense to have individual Makefiles then as suggested before, recursive make is a good approach, but for smaller projects I find it easier to list all the source files in the Makefilewith their relative path to the Makefilelike this:

如果源文件分布在许多文件夹中,并且像之前建议的那样拥有单独的 Makefile 是有意义的,那么递归 make 是一种很好的方法,但对于较小的项目,我发现将Makefile中的所有源文件及其相对路径列出会更容易到Makefile像这样:

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

I can then set VPATHthis way:

然后我可以这样设置VPATH

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

Then I build the objects:

然后我构建对象:

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

Now the rule is simple:

现在规则很简单:

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

And building the output is even easier:

构建输出更容易:

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

One can even make the VPATHgeneration automated by:

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

VPATH := $(dir $(COMMON_SRC))

Or using the fact that sortremoves duplicates (although it should not matter):

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

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

回答by user2763812

I suggest to use autotools:

我建议使用autotools

//##Place generated object files (.o) into the same directory as their source files, in order to avoid collisions when non-recursive make is used.

//##将生成的目标文件 (.o) 放在与其源文件相同的目录中,以避免在使用非递归 make 时发生冲突。

AUTOMAKE_OPTIONS = subdir-objects

just including it in Makefile.amwith the other quite simple stuff.

只是将它Makefile.am与其他非常简单的东西一起包含在内。

Here is the tutorial.

这是教程

回答by Matheus Vinícius de Andrade

I was looking for something like this and after some tries and falls i create my own makefile, I know that's not the "idiomatic way" but it's a begining to understand make and this works for me, maybe you could try in your project.

我一直在寻找这样的东西,经过一些尝试和失败,我创建了自己的 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!

I know that's simple and for some people my flags are wrong, but as i said this is my first Makefile to compile my project in multiple dirs and link all of then together to create my bin.

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

I'm accepting sugestions :D

我正在接受建议:D