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

Time:03-21

i have a C project , all source file (C and H files)in src directory , have lots of subdirectories

now I want to

1 copy all h files to .\header, without folder struct
2 complier all c files to .\obj, without folder stuct
3 myproject.exe in .\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

the expected output as follows:

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

the follows posts give a good reference , but this post can not support if the source in multiple directory , all obj files is in the same directory as c file Makefile : Automatically compile all c files, keeping .o files in separate folder
How can I create a Makefile for C projects with SRC, OBJ, and BIN subdirectories?

can any give some example makefile?

CodePudding user response:

You want to put a Makefile in each subdirectory where you want to compile some source. And put a Makefile in your project root directory. In your root Makefile, do this:

ALL : make1 make2 ... maken mv_obj

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

Alternatively, you can specify where to save your .o file in each Makefile in your subdirectory. E.g.

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

CodePudding user response:

First we construct a list of the sources in the tree:

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

Then use that to construct a list of the object files we want:

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

If all the source files were in the working directory, we could use a simple static pattern rule:

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

And to get that to work when the sources are in different directories, all we need is the vpath directive:

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

Now for the headers. To steer the compiler toward the directories containing the headers, we could construct a string of -I flags in one line or we could copy all of the headers into header/ as follows.

To keep all of the headers up to date, and not copy them unnecessarily, we must treat them as targets. First we make a list of them, as we did with the objects:

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

Then we write a static pattern rule, just as we did for the objects:

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

vpath %.h $(SRCDIRS)

And finally add the headers as prerequisites of the objects:

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

This is slightly inefficient, as it will rebuild all objects if even one header has changed, but to correct that shortcoming would require a more complex makefile.

  • Related