来自Makefile中子目录的源代码

gga*_*ett 49 makefile

我有一个使用Makefile构建的C++库.直到最近,所有的源都在一个目录中,Makefile做了这样的事情

SOURCES = $(wildcard *.cpp)

工作得很好.

现在我添加了一些子目录中的源代码subdir.我知道我能做到这一点

SOURCES = $(wildcard *.cpp) $(wildcard subdir/*.cpp)

但我正在寻找一种避免subdir手动指定的方法,即wildcard查看子目录,或以某种方式生成子目录列表并使用多个wildcard函数扩展它.此时,具有非递归解决方案(即,仅扩展第一级)将没有问题.

我没有找到任何东西 - 我最好的猜测是find -type d用来列出子目录,但感觉就像一个黑客.有没有内置的方法来做到这一点?

Bet*_*eta 74

这应该这样做:

SOURCES = $(wildcard *.cpp) $(wildcard */*.cpp)
Run Code Online (Sandbox Code Playgroud)

如果你改变主意并想要一个递归解决方案(即任何深度),它可以完成,但它涉及一些更强大的Make函数.你知道,那些允许你做你真的不应该做的事情.

编辑:
杰克·凯利指出,$(wildcard **/*.cpp)工程的任何深度,至少在某些平台上,使用gnumake的3.81.(他怎么想出来的,我不知道.)

  • 要搜索任何深度,我认为`$(wildcard**/*.cpp)`会起作用. (27认同)
  • `**/*`对我不起作用.OS X 10.8.2,GNU Make 3.81.它实际上表现得很奇怪...... (10认同)
  • `SOURCES:= $(shell find.-name"*.cpp")`也可以. (8认同)
  • `**/*.cpp` *确实* 对我有用,但它不包含当前目录中的任何内容(即获得类似于 `*.cpp */*.cpp */*/*.cpp .. .`,你必须做`*.cpp **/*.cpp`),这是相当不幸的IMO。 (4认同)
  • @Jack Kelly:我刚尝试过,但它没有用(GNU Make 3.81).它适用于您的版本吗? (2认同)
  • `$(wildcard **/*.cpp)` 对我不起作用。它只搜索下一级。如果我想要 2 个级别,我必须执行 `$(wildcard **/**/*.cpp)`。GNU Make 4.3 (2认同)
  • 正如 Yukulélé 指出的,`**/*` 只能向下一级工作,因为它相当于 `*/*`。这难道不是那些相信自己成功的人身上实际发生的事情吗? (2认同)

Lig*_*ruk 20

递归通配符可以完全在Make中完成,无需调用shell或find命令.仅使用Make进行搜索意味着此解决方案也适用于Windows,而不仅仅是*nix.

# Make does not offer a recursive wildcard function, so here's one:
rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))

# How to recursively find all files with the same name in a given folder
ALL_INDEX_HTMLS := $(call rwildcard,foo/,index.html)

# How to recursively find all files that match a pattern
ALL_HTMLS := $(call rwildcard,foo/,*.html)
Run Code Online (Sandbox Code Playgroud)

文件夹名称中的尾部斜杠是必需的.这个rwildcard函数不像Make的内置通配符函数那样支持多个通配符,但是通过foreach的更多用法添加该支持将是直截了当的.


Chr*_*oph 16

如果您不想使用递归makefile,这可能会给您一些想法:

subdirs := $(wildcard */)
sources := $(wildcard $(addsuffix *.cpp,$(subdirs)))
objects := $(patsubst %.cpp,%.o,$(sources))

$(objects) : %.o : %.cpp
Run Code Online (Sandbox Code Playgroud)


Fre*_*Foo 9

通常的做法Makefile在每个子目录中放入一个源代码

all: recursive
    $(MAKE) -C componentX
    # stuff for current dir
Run Code Online (Sandbox Code Playgroud)

要么

all: recursive
    cd componentX && $(MAKE)
    # stuff for current dir

recursive: true
Run Code Online (Sandbox Code Playgroud)

这可能是明智的,把设置每Makefile一个Makefile.inc根源目录.该recursive目标部队make进入子目录.确保它不会重新编译需要的目标中的任何内容recursive.

  • 不要直接调用`make -C`.你需要调用`$(MAKE)-C`.正在运行的`make`版本可能与系统`make`不同.另外,你不是要通过运行`$(MAKE)$ @来引发无限循环吗?最后,递归制作被一些人认为是有害的.见http://miller.emu.id.au/pmiller/books/rmch/ (4认同)
  • 请这样做.只需编译和链接每个子目录中的每个源/目标文件,一旦你想构建一个库,用特殊的编译器设置构建一个文件,编写测试程序等,就会破坏.我总是在Makefile中列出每个目标文件,有时候每个源文件.列出几个要循环的目录并不是很痛苦. (2认同)
  • 注意:使用递归makefile方法,很难正确地建立依赖关系。好的阅读:[Resurvie被认为是有害的](http://aegis.sourceforge.net/auug97.pdf) (2认同)

ist*_*dy0 8

这是一个附注,并没有回答你的问题,但有一篇论文"Recursive Make Considered Harmful".值得一读.

链接在这里.http://aegis.sourceforge.net/auug97.pdf

  • +1.我鄙视递归制作,不要以为任何人都应该再做广告.赋予子目录make.includes并不比给他们自己的makefile更难.事实上,它更容易一些,因为它们不需要包含所有项目定义的"上帝"文件.嘿,你没有得到一堆糟糕的,不完整的依赖图!那篇论文也提供了一些其他好的建议. (5认同)
  • 虽然递归make可能是有害的,但是在原始问题中寻求的技术实际上是通过使顶层makefile知道所有子目录中的源来避免*递归make的方法. (3认同)

Yuk*_*élé 8

您可以在 中使用多个规则wildcard

SOURCES := $(wildcard *.cpp */*.cpp)
Run Code Online (Sandbox Code Playgroud)

如果您需要更多深度:

SOURCES := $(wildcard *.cpp */*.cpp */*/*.cpp */*/*/*.cpp)
Run Code Online (Sandbox Code Playgroud)

不幸的是,与我们有时读到的不同**,makefile 不支持glob ( ) 并且将被解释为普通的通配符 ( *)。

例如**/*.cpp匹配dir/file.cpp但既不是file.cpp也不是dir/sub/file.cpp

如果您需要无限深度,请使用shell

SOURCES := $(shell find . -name "*.cpp")
Run Code Online (Sandbox Code Playgroud)