实用的Makefile

Makefile的语法这里不再赘述,这里主要列出常用的Makefile

1.最简单的Makefile

# Makefile

all:
    gcc -g -Wall -O2 main.c -o test

clean:
    rm -f test *.o

应用场景

当测试程序只有一个文件,如main.c,最终需要编译成test可执行文件。

 

2.使用特殊的库,例如pthead

# Makefile

all:
    gcc -g -Wall -O2 main.c -o test -lpthread

clean:
    rm -f test *.o

后面添加-lpthread

3. 使用变量

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), 在多个源文件里面更明确。

 

4.常用的参数

-I 后面跟头文件的目录,里面的头文件都被可以被发现
-L 后面跟库文件的目录,-l后面跟库文件名称
-D 后面跟宏名称,如-DDEBUG, 相当于源代码里面定义了DEBUG宏(#define DEBUG)

5.使用函数

5.1使用shell命令

TOPDIR = $(shell pwd)          # 变量TOPDIR被赋值给pwd命令的结果,一般用作顶层目录
export TOPDIR                  # 导出TOPDIR变量,可以给别的Makefile使用,例如给子目录使用

DIRS = $(shell find $(SRC_PATH) -maxdepth 3 -type d)  #获取当前目录所有的目录,最大深度3层

5.2Makefile嵌入的函数

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文件

6.常用的工具Makefile

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

7.多目录的第一种写法

假设当前目录结构:

顶层目录有: 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

8.多目录的第二种写法

假设当前目录结构:

顶层目录有: 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

你可能感兴趣的:(ARM,-Linux,工具类)