如何使用项目编写 make 文件:多级子目录中的源代码,将 obj 文件保存在单独的文件夹中?

how to write a make file with a project : source in multi-level sub dir , keep obj file in separate folder?

我有一个C项目,所有源文件(C和H文件)都在src目录下,有很多子目录

现在我想

1 将所有 h 文件复制到 .\header,不带文件夹 struct
2 将所有 c 文件编译到 .\obj,没有文件夹 stuct
3 myproject.exe 在 .\bin

D:\myproject
+---bin
+---header
+---obj
\---src
    |   main.c
    |   main.h
    |
    +---sub1
    |   |   1.c
    |   |   1.h
    |   |
    |   \---sub11
    |       |   11.c
    |       |   11.h
    |       |
    |       \---sub111
    |               111.c
    |               111.h
    |
    \---sub2
        |   2.c
        |   2.h
        |
        \---sub22
            |   22.c
            |   22.h
            |
            \---sub221
                    221.c
                    221.h

预期输出如下:

D:.
+---bin
|       myproject.exe
|
+---header
|       1.h
|       11.h
|       111.h
|       2.h
|       22.h
|       221.h
|       main.h
|
+---obj
|       1.o
|       11.o
|       111.o
|       2.o
|       22.o
|       221.o
|       main.o
|
\---src
    |   main.c
    |
    +---sub1
    |   |   1.c
    |   |   1.h
    |   |
    |   \---sub11
    |       |   11.c
    |       |   11.h
    |       |
    |       \---sub111
    |               111.c
    |               111.h
    |
    \---sub2
        |   2.c
        |   2.h
        |
        \---sub22
            |   22.c
            |   22.h
            |
            \---sub221
                    221.c
                    221.h

下面的posts给了一个很好的参考,但是这个post不支持如果源在多个目录下,所有的obj文件和c文件在同一个目录下
How can I create a Makefile for C projects with SRC, OBJ, and BIN subdirectories?

任何人都可以给出一些示例 makefile 吗?

您想在每个要编译某些源代码的子目录中放置一个 Makefile。并在您的项目根目录中放置一个 Makefile。在您的根 Makefile 中,执行此操作:

ALL : make1 make2 ... maken mv_obj

make1 :; make -C src/sub1
...
mv_obj :; mv `find . -name "*.o"` obj/

或者,您可以在子目录的每个 Makefile 中指定保存 .o 文件的位置。例如

gcc -o ../../obj/foo.o 1.c

首先我们构建树中的源列表:

SRCDIR := src
SOURCES := $(shell find $(SRCDIR) -name "*.c")

然后用它来构建我们想要的 object 文件的列表:

OBJDIR := obj
OBJECTS := $(patsubst %.c,$(OBJDIR)/%.o,$(notdir $(SOURCES)))

如果所有源文件都在工作目录中,我们可以使用简单的静态模式规则:

$(OBJECTS): $(OBJDIR)/%.o: %.c
    blah blah building $@ from $<

当源文件位于不同的目录时,要使其正常工作,我们只需要 the vpath directive:

SRCDIRS := $(dir $(SOURCES))
vpath %.c $(SRCDIRS)

现在是 header 年代。为了将编译器引导至包含 header 的目录,我们可以在 一行 中构造一串 -I 标志,或者我们可以复制所有 headers 变成 header/ 如下。

为了使所有 header 保持最新,并且避免不必要地复制它们,我们必须将它们视为目标。首先我们列出它们,就像我们对 objects:

所做的那样
HEADERS := $(shell find $(SRCDIR) -name "*.h")
HEADERDIR := header
HEADERTARGS := $(addprefix $(HEADERDIR)/,$(notdir $(HEADERS)))

然后我们编写一个静态模式规则,就像我们为 object 所做的那样:

$(HEADERTARGS): $(HEADERDIR)/%.h: %.h
    cp $< $@

vpath %.h $(SRCDIRS)

最后添加 header 作为 object 的先决条件:

$(OBJECTS): $(OBJDIR)/%.o: %.c $(HEADERTARGS)
    ...

这有点低效, 因为它会重建 all objects if even one header 已更改,但要纠正该缺点将需要更复杂的 makefile。