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.