Makefile的语法这里不再赘述,这里主要列出常用的Makefile
# Makefile
all:
gcc -g -Wall -O2 main.c -o test
clean:
rm -f test *.o
应用场景
当测试程序只有一个文件,如main.c,最终需要编译成test可执行文件。
# Makefile
all:
gcc -g -Wall -O2 main.c -o test -lpthread
clean:
rm -f test *.o
后面添加-lpthread
Target := linux_tool
CC := gcc
CFLAG += -Wall -g
COBJS = main.o
OBJS = ${COBJS}
LIBS ?=
INCLUDE ?= -I../include
$(Target):$(OBJS)
$(CC) $(CFLAGS) $^ $(LIBS) -o $(Target)
$(COBJS):%.o:%.c
$(CC) $(CFLAG) -c $(INCLUDE) $< -o $@
clean:
rm -rf $(OBJS) *.o $(Target) *log
.PHONY:clean
其中,Target, CC, CFLAG等都是变量,后面使用$(XX)来引用。
特殊变量:
$@ : 目标文件
$< : 第一个依赖
$^ : 所有的依赖
如上面的
$(CC) $(CFLAG) -c $(INCLUDE) $< -o $@ 其中$@是目标$(COBJS),即上面的main.o
$<是第一个依赖,也就是main.c
$(Target):$(OBJS)
$(CC) $(CFLAGS) $^ $(LIBS) -o $(Target)
这个是生成最终目标, $^指的是 所有依赖,即$(OBJS), 在多个源文件里面更明确。
-I 后面跟头文件的目录,里面的头文件都被可以被发现
-L 后面跟库文件的目录,-l后面跟库文件名称
-D 后面跟宏名称,如-DDEBUG, 相当于源代码里面定义了DEBUG宏(#define DEBUG)
TOPDIR = $(shell pwd) # 变量TOPDIR被赋值给pwd命令的结果,一般用作顶层目录
export TOPDIR # 导出TOPDIR变量,可以给别的Makefile使用,例如给子目录使用
DIRS = $(shell find $(SRC_PATH) -maxdepth 3 -type d) #获取当前目录所有的目录,最大深度3层
patsubst函数:替换
LIBDIRS = lib
LIB := $(patsubst %, -L%, $(LIBDIRS))
以上会把原来LIBDIRS目标值lib替换成-Llib,其实就是添加-L
wildcard函数:通配
$(wildcard $(dir)/*.c)
列出dir目录下所有的.c文件
foreach函数:循环
SRCDIRS = . \
HAL \
CLI
COBJS := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))
扫描SRCDIRS变量,并列出.c文件
TARGET = usbcan_tool
CC ?= gcc
CFLAGS ?= -Wall -g
CXX ?= g++
CXXFLAGS ?= -Wall -g
COBJS = \T
./main.o \
./usbcan.o
CPPOBJS =
OBJS = $(COBJS) $(CPPOBJS)
LIBS = -lpthread -L./lib -lcontrolcan
INCLUDES = -L./include
$(TARGET): $(OBJS)
$(CXX) $(CXXFLAGS) $(LDFLAGS) $^ $(LIBS) -o $(TARGET)
$(COBJS): %.o: %.c
$(CC) $(CFLAGS) -c $(INCLUDES) $< -o $@
$(CPPOBJS): %.o: %.cpp
$(CXX) $(CXXFLAGS) -c $(INCLUDES) $< -o $@
clean:
rm -rf $(OBJS) *.o $(TARGET) *log
.PHONY: clean
假设当前目录结构:
顶层目录有: CLI HAL include (目录下只有源码,没有Makefile)
顶层文件有:main.c start.S Makefile
TARGET := imx6ull
BIN := $(TARGET).bin
CROSS_COMPILE ?= /home/flinn/tools/6.2.1/bin/arm-linux-gnueabihf-
CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
AR := $(CROSS_COMPILE)ar
OBJCOPY := $(CROSS_COMPILE)objcopy
OBJDUMP := $(CROSS_COMPILE)objdump
RM := rm -rf
CFLAGS := -g -c -Wall -O2 -nostdlib -fno-builtin
DIRS = $(shell find $(SRC_PATH) -maxdepth 3 -type d)
SRCDIRS = . \
HAL \
CLI
INCDIRS = include \
HAL \
CLI
LIBDIRS = lib
CPATH := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))
SPATH := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))
INCLUDE := $(patsubst %, -I%, $(INCDIRS))
LIB := $(patsubst %, -L%, $(LIBDIRS))
CFILES := $(CPATH)
SFILES := $(SPATH)
COBJS = $(patsubst %, %, $(CFILES:.c=.o))
SOBJS = $(patsubst %, %, $(SFILES:.S=.o))
OBJS = $(SOBJS) $(COBJS)
$(BIN): $(OBJS)
echo "DIRS : "$(DIRS)
@echo "C : "$(CFILES)
@echo "OBJS : "$(OBJS)
$(LD) -Timx6ull.lds -o $(TARGET).elf $^
$(OBJCOPY) -O binary -S -g $(TARGET).elf $@
$(OBJDUMP) -D $(TARGET).elf > $(TARGET).dis
$(SOBJS) : %.o : %.S
@echo "SOBJS : "$(SOBJS)
$(CC) $(CFLAGS) $(INCLUDE) $(LIB) -o $@ $<
$(COBJS) : %.o : %.c
@echo "COBJS : "$(COBJS)
$(CC) $(CFLAGS) $(INCLUDE) $(LIB) -o $@ $<
install:
./tools/mkimage -n ./tools/imximage.cfg.cfgtmp -T imximage -e 0x80100000 -d $(TARGET).bin $(TARGET).imx
clean:
$(RM) $(TARGET).bin $(TARGET).elf $(TARGET).dis $(OBJS) *.o *.bin *.imx
假设当前目录结构:
顶层目录有: CLI HAL include (目录下有源码,且都有Makefile)
顶层文件有:main.c start.S Makefile
顶层Makefile
TARGET = Tools
BIN = $(TARGET).bin
CROSS_COMPILE := /home/flinn/tools/6.2.1/bin/arm-linux-gnueabihf-
CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
AS := $(CROSS_COMPILE)as
OBJCOPY := $(CROSS_COMPILE)objcopy -O binary
OBJDUMP := $(CROSS_COMPILE)objdump -D
NM := $(CROSS_COMPILE)nm
export AS LD CC NM #将定义的变量导出,方便其他makefile使用
export OBJCOPY OBJDUMP
CFLAGS := -Wall -O2 -nostdlib -fno-builtin \ #编译器参数
-I./include \
-I./HAL \
-I./common \
-I./src
export CFLAGS LDFLAGS
TOPDIR := $(shell pwd) #获得当前程序的顶层目录
export TOPDIR #输出顶层目录
#顶层要生成的.o文件以及顶层文件夹
obj-y += main.o
obj-y += start.o
obj-y += CLI/
obj-y += HAL/
obj-y += common/
all :
make -C ./ -f $(TOPDIR)/Makefile.build #进入当前目录,使用顶层的makefile.build进行编译
$(CC) $(LDFLAGS) -o $(TARGET) built-in.o #将编译好的built-in.o文件链接生成目标文件
clean:
rm -f $(shell find -name "*.o")
rm -f $(shell find -name "*.d")
rm -f $(TARGET)
.PHONY:all clean
依赖Makefile.build
PHONY := build #定义一个PHONY变量
build : #开头说明__build伪目标,使其成为Makefile.build的第一个目标
obj-y :=
subdir-y :=
include Makefile #将当前目录的Makefile包含进来,初始化obj-y
#筛选出当前目录的目标变量中的子目录,并且去掉/
__subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y)))
subdir-y += $(__subdir-y)
#对于subdir-y里面的每一个值(目录),增加一个相应的目录/built-in.o的变量值
subdir_objs := $(foreach f,$(subdir-y),$(f)/built-in.o)
cur_objs := $(filter-out %/, $(obj-y)) #得到obj-y中的.o文件
#对于所有的.o文件,定义它的依赖文件名
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 #第一个规则
#依次进入该子目录变量里面存储的值,使用的Makefile.build进行编译
$(subdir-y): #第一个规则的第一个依赖规则
make -C $@ -f $(TOPDIR)/Makefile.build
built-in.o : $(cur_objs) $(subdir_objs) #第一个规则的第二个依赖规则
$(LD) -r -o $@ $^ #该规则的命令:将该目录下的.o和$(subdir_obj)打包成built-in.o文件
dep_file = [email protected]
%.o : %.c
$(CC) $(CFLAGS) -Wp,-MD,$(dep_file) -c -o $@ $<
.PHONY : $(PHONY)
子目录的Makefile
objs-y := a.o
objs-y += b.o
objs-y += c/
objs-y += d/
参考https://www.cnblogs.com/tureno/articles/6208353.html