makefile_demo目录下的所有文件归属结构
zgjias@ubuntu:~/linux/mysource/makefile_demo$ tree
.
├── a
│ ├── Makefile
│ ├── sub2.c
│ └── sub3.c
├── include
│ ├── sub2.h
│ ├── sub3.h
│ └── sub.h
├── main.c
├── Makefile
├── Makefile.build
└── sub.c
下面记录下此通用Makefile的使用方法
#1.把顶层Makefile, Makefile.build放入程序的顶层目录在各自子目录创建一个空白的
Makefile - - - -顶层目录
#4. 使用哪个编译器?
# 修改顶层目录Makefile的CROSS_COMPILE, 用来指定工具链的前缀(比如arm-linux-)
CROSS_COMPILE =
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
export AS LD CC CPP AR NM
export STRIP OBJCOPY OBJDUMP
#3. 确定编译选项、链接选项
# 修改顶层目录Makefile的CFLAGS,这是编译所有.c文件时都要用的编译选项;
# 修改顶层目录Makefile的LDFLAGS,这是链接最后的应用程序时的链接选项;
# 修改各自子目录下的Makefile:
# "EXTRA_CFLAGS", 它给当前目录下的所有文件(不含其下的子目录)设置额外的编译选项, 可以不设置
# "CFLAGS_xxx.o", 它给当前目录下的xxx.c设置它自己的编译选项, 可以不设置
CFLAGS := -Wall -O2 -g
CFLAGS += -I $(shell pwd)/include
LDFLAGS :=
export CFLAGS LDFLAGS
TOPDIR := $(shell pwd)
export TOPDIR
#5. 确定应用程序的名字:
# 修改顶层目录Makefile的TARGET, 这是用来指定编译出来的程序的名字
TARGET := test
#2.确定编译哪些源文件
# 修改顶层目录和各自子目录Makefile的obj-y :
# obj-y += xxx.o
# obj-y += yyy/
# 这表示要编译当前目录下的xxx.c, 要编译当前目录下的yyy子目录
obj-y += main.o
obj-y += sub.o
obj-y += a/
all : start_recursive_build $(TARGET)
@echo $(TARGET) has been built!
start_recursive_build:
make -C ./ -f $(TOPDIR)/Makefile.build
$(TARGET) : built-in.o
$(CC) -o $(TARGET) built-in.o $(LDFLAGS)
# 6. 执行"make"来编译,执行"make clean"来清除,执行"make distclean"来彻底清除
clean:
rm -f $(shell find -name "*.o")
rm -f $(TARGET)
distclean:
rm -f $(shell find -name "*.o")
rm -f $(shell find -name "*.d")
rm -f $(TARGET)
Makefile.build - - - -顶层目录
PHONY := __build
__build:
obj-y :=
subdir-y :=
EXTRA_CFLAGS :=
include Makefile
# obj-y := a.o b.o c/ d/
# $(filter %/, $(obj-y)) : c/ d/
# __subdir-y : c d
# subdir-y : c d
__subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y)))
subdir-y += $(__subdir-y)
# c/built-in.o d/built-in.o
subdir_objs := $(foreach f,$(subdir-y),$(f)/built-in.o)
# a.o b.o
cur_objs := $(filter-out %/, $(obj-y))
dep_files := $(foreach f,$(cur_objs),.$(f).d)
dep_files := $(wildcard $(dep_files))
ifneq ($(dep_files),)
include $(dep_files)
endif
PHONY += $(subdir-y)
__build : $(subdir-y) built-in.o
$(subdir-y):
make -C $@ -f $(TOPDIR)/Makefile.build
built-in.o : $(cur_objs) $(subdir_objs)
$(LD) -r -o $@ $^
dep_file = .$@.d
%.o : %.c
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -Wp,-MD,$(dep_file) -c -o $@ $<
.PHONY : $(PHONY)
main.c - - - -顶层目录
#include <stdio.h>
extern void sub_fun(void);
extern void sub2_fun(void);
void sub3_fun(void);
int main(int argc, char* argv[])
{
printf("Main fun!\n");
sub_fun();
sub2_fun();
sub3_fun();
return 0;
}
sub.c - - - -顶层目录
#include <stdio.h>
#include "sub.h"
void sub_fun(void)
{
printf("Sub fun, A = %d!\n", A);
}
sub2.c - - - -子目录 a
#include <stdio.h>
#include <sub2.h>
void sub2_fun(void)
{
printf("Sub2 fun, B = %d!\n", B);
#ifdef DEBUG
printf("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
#endif
}
sub3.c - - - -子目录 a
#include <stdio.h>
#include <sub3.h>
void sub3_fun(void)
{
printf("Sub3 fun, C = %d!\n", C);
#ifdef DEBUG
printf("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
#endif
#ifdef DEBUG_SUB3
printf("It is only debug info for sub3.\n");
#endif
}
Makefile - - - -子目录 a
EXTRA_CFLAGS := -D DEBUG
CFLAGS_sub3.o := -D DEBUG_SUB3
obj-y += sub2.o
obj-y += sub3.o
include 目录下的三个头文件
sub.h
#define A 1
void sub_fun(void);
sub2.h
#define B 2
void sub2_fun(void);
sun3.h
#define C 3
void sub3_fun(void);
理解了这个通用Makefile 之后只需要修改相应的目录即可使用,硬核!