###变量及通配符
A := $(C) # 即时变量,此时C未定义,A为空
B = $(C) # 延时变量,用到B时再确定具体的值
C = abc
C ?= 123 # C不是第一次定义,被忽略
C += 789
D ?= xyz # D是第一次定义
all:
@echo A = $(A)
@echo B = $(B)
@echo C = $(C)
@echo D = $(D)
输出:
A =
B = abc 789
C = abc 789
D = xyz
###函数
A = a b c
B = $(foreach v, $(A), $(v).c) # 取出$(A)中的每一项存到v中,执行$(v).c,最后以空格分隔返回
C = $(B)
C += d.o
D = $(filter %.c, $(C)) # 返回$(C)中所有符合%.c的项
E = $(filter-out %.c, $(C)) # 返回$(C)中所有不符合%.c的项
files := $(wildcard *.c) # 获取当前目录下所有的.c文件
files_obj := $(patsubst %.c, %.o, $(files)) # 将$(files)中所有符合%.c的项替换为%.o
files_obj2 := $(files:%.c=%.o) # 效果和patsubat相同
func:
@echo A = $(A)
@echo B = $(B)
@echo C = $(C)
@echo D = $(D)
@echo E = $(E)
@echo files = $(files)
@echo files_obj = $(files_obj)
@echo files_obj2 = $(files_obj2)
输出:
A = a b c
B = a.c b.c c.c
C = a.c b.c c.c d.o
D = a.c b.c c.c
E = d.o
files = a.c test.c
files_obj = a.o test.o
files_obj2 = a.o test.o
###实例:
default:
arm-linux-gcc -c start.s -o OBJ/start.o
arm-linux-gcc -c LED/led.c -o OBJ/led.o
arm-linux-gcc -c KEY/key.c -o OBJ/key.o
arm-linux-gcc -c main.c -o OBJ/main.o
arm-linux-ld -Ttext=0x42C00000 OBJ/start.o OBJ/led.o OBJ/key.o OBJ/main.o -o OBJ/main.elf
arm-linux-objcopy -I elf32-littlearm -Obinary OBJ/main.elf main.bin
clean:
rm *.bin OBJ/*.o OBJ/*.elf
上面是一般的写法;
下面是优雅点的写法:
CC = arm-linux-gcc
LD = arm-linux-ld
OBJCOPY = arm-linux-objcopy
CFLAGS = -Wall -g
TARGET := main
TOP_DIR := $(shell pwd)
# SRC_DIRS := $(shell ls -F | grep /$)
SRC_DIRS := $(shell find $(TOP_DIR) -maxdepth 1 -type d)
C_SRCS = $(foreach dir, $(SRC_DIRS), $(wildcard $(dir)/*.c))
C_HEADS = $(patsubst %.c, %.h, $(C_SRCS))
C_OBJS = $(patsubst %.c, %.o, $(C_SRCS))
C_OBJS += $(TOP_DIR)/start.o
$(TARGET):$(C_OBJS)
$(shell if [ ! -d $(TOP_DIR)/OBJ ]; then mkdir $(TOP_DIR)/OBJ; fi)
$(LD) -Ttext=0x42C00000 $^ -o OBJ/$@.elf
$(OBJCOPY) -I elf32-littlearm -Obinary OBJ/$@.elf OBJ/$@.bin
%.o:%.c %.h
$(CC) -c -o $@ $<
%.o:%.s
$(CC) -c -o $@ $<
.PHONY:clean
clean:
rm -rf $(C_OBJS) OBJ/*.*
测试这段优雅的Makefile后,发现生成的.bin文件下载到板子上运行不了。
原来,ld链接器对文件顺序是有要求的,从左到右,如果a依赖b,则a应该放在b的左边,ld a b,上面的例子,start.o是启动文件,所以start.o应该放在最前头;
将
C_OBJS = $(patsubst %.c, %.o, $(C_SRCS))
C_OBJS += $(TOP_DIR)/start.o
替换成
C_OBJS = $(TOP_DIR)/start.o $(patsubst %.c, %.o, $(C_SRCS))