“=” 是最基本的赋值。make会将整个makefile展开后,再决定变量的值。也就是说,变量的值将会是整个makefile中最后被指定的值。
x = foo
y = $(x) bar
x = xyz
在上例中,y的值将会是 xyz bar ,而不是 foo bar
“:=”表示变量的值决定于它在makefile中的位置,而不是整个makefile展开后的最终值。
x := foo
y := $(x) bar
x := xyz
在上例中,y的值将会是 foo bar ,而不是 xyz bar 了
?= 是如果没有被赋值过就赋予等号后面的值
+= 是添加等号后面的值
-
$@ (full target name of the current target)
-
$? (returns the dependencies that are newer than the current target)
-
$* (returns the text that corresponds to % in the target)
-
$< (name of the first dependency)
-
$^ (name of all the dependencies with space as the delimiter)
DEMO 1
configurate脚本,就是一段bash脚本
# linux系统除了提供位置参数还提供内置参数,内置参数如下:
# $0 ----脚本名称
# $# ----传递给程序的总的参数数目
# $? ----上一个代码或者shell程序在shell中退出的情况,如果正常退出则返回0,反之为非0值。
# $* ----传递给程序的所有参数组成的字符串。(尽量使用$@并将其用双引号括起来)
# $@----以"参数1" "参数2" ... 形式保存所有参数(传递给脚本/函数的所有参数)
# $n ----表示第几个参数,$1 表示第一个参数,$2 表示第二个参数 ... $0 ----表示当前程序的名称
# $$ ----本程序的(进程ID号)PID
# $! ----上一个命令的PID
if [ "$1" = "x86" ];then
echo "copy config.x86 to config";
cp config.x86 config;
elif [ "$1" = "arm" ];then
echo "copy config.arm to config"
cp config.arm config;
else
echo "Invalid param, usage: [./configure arm ...] or [./configure x86 ...]"
exit 1
fi
#这是把多余的后面的那几个参数打印一下
if [ "$#" -gt 1 ];then
i=0
arglist=
for arg in "$@"
do
if [ $i -ne 0 ];then
arglist=$arglist" "$arg
fi
((i++))
done
echo "arglist:"$arglist
sed -i "/^PUBLIC_FLAGS.*$/ s/$/$arglist/" config
fi
config.arm文件
ARCH=arm
CROSS_COMPILE := arm-none-linux-gnueabi-
#这里指定了不使用优化,这样就可以使用gdb调试了!
PUBLIC_FLAGS:=-g -O0 -Wall -L$(ROOT_DIR)/libs/arm_linux -DARM_LINUX
#这是使用优化的gcc public flags,这样声称的binary/.so比较小,但不能gdb调试
#PUBLIC_FLAGS := -O2 -L$(ROOT_DIR)/libs/arm_linux -DARM_LINUX -fno-strict-aliasing -ffunction-sections -fdata-sections
CC := $(CROSS_COMPILE)gcc
G++ := $(CROSS_COMPILE)g++
AR := $(CROSS_COMPILE)ar
LD := $(CROSS_COMPILE)ld
export CC G++ AR LD
顶层目录makefile,下面这个include如果执行出错会终止,除非前面加上一个 -
include config
ROOT_DIR = $(shell pwd)
OUT_DIR = $(shell pwd)/build
export ROOT_DIR
export OUT_DIR
#用@告诉makefile这条 命令本身 不回显
#make执行时从第一个伪目标开始执行,这里即all
all: clean
@if [ ! -d $(OUT_DIR) ]; then mkdir $(OUT_DIR);fi
@$(MAKE) -j4 -C udrv
@$(MAKE) -j4 -C app
@echo "***********************************************"
@echo "** Build Finished **"
@echo "***********************************************"
modules:
@if [ ! -d $(OUT_DIR) ]; then mkdir $(OUT_DIR);fi
@$(MAKE) -C kdrv
@echo "***********************************************"
@echo "** Build Modules Finished **"
@echo "***********************************************"
modules_clean:
@$(MAKE) -C kdrv clean
@echo "***********************************************"
@echo "** Clean Modules Finished **"
@echo "***********************************************"
#命令前面有个 - 表示出错也不停止
.PHONY: clean
clean:
@$(MAKE) -j4 -C udrv clean
@$(MAKE) -j4 -C app clean
-rm -rf $(OUT_DIR)
@echo "***********************************************"
@echo "** Clean Finished **"
@echo "***********************************************"
udrv目录下的makefile
# ?=表示如果外面传进来(此前已经被定义)就用外面的, 否则就用等号后面的
# :=表示等号左边的值类似一个拷贝,当前就使用这个拷贝。后面再改变也和本次使用无关
# =表示等号左边的值类似一个全局变量
ROOT_DIR ?= $(shell pwd)/../
OUT_DIR ?= $(ROOT_DIR)/build
include $(ROOT_DIR)/config
export ROOT_DIR
export OUT_DIR
all: clean
@if [ ! -d $(OUT_DIR) ]; then mkdir $(OUT_DIR);fi
$(MAKE) -j4 -C util
$(MAKE) -j4 -C ufrontend
$(MAKE) -j4 -C udemux
$(MAKE) -j4 -C si
$(MAKE) -j4 -C avm
clean:
-rm -rf $(OUT_DIR)
$(MAKE) clean -C util
$(MAKE) clean -C ufrontend
$(MAKE) clean -C udemux
$(MAKE) clean -C si
$(MAKE) clean -C avm
avm目录下的makefile(avm下面的子目录就不再设makefile了)
# Build configurations
ROOT_DIR ?= $(shell pwd)/../../
OUT_DIR ?= $(ROOT_DIR)/build
include $(ROOT_DIR)/config
export ROOT_DIR
export OUT_DIR
######################################################
# Module library (or Module binary)
MODULE_LIBRARY = libzxdtv.so
MODULE_OBJS += $(patsubst %.c,%.o ,$(wildcard codec/audio_dec/*.c codec/video_dec/*.c input/ts_dmx/*.c input/pvr_src/*.c))
MODULE_OBJS += $(patsubst %.c,%.o ,$(wildcard output/av_sync/*.c output/audio_out/*.c output/video_out/*.c player/av_player/*.c))
######################################################
# Header files
MODULE_INCLUDE += -I./output/av_sync -I./output/audio_out -I./output/video_out -I./player/av_player
MODULE_INCLUDE += -I../udemux/include
MODULE_INCLUDE += -I./ffmpeg
######################################################
# Module flags
#如果要生成binary而不是.so,LDFLAGS空着就好了
LDFLAGS += --shared -fPIC
LIB_FLAGS += -L$(OUT_DIR) -lzxutil -lpthread
LIB_FLAGS += -L./ffmpeg/arm-linux-lib/ -lavcodec -lavformat -lavutil -lswresample
######################################################
# Common dependency process
.PHONY:all clean
%.o: %.c
$(CC) $(LDFLAGS) $(PUBLIC_FLAGS) $(MODULE_INCLUDE) -c $< -o $@
all : clean $(MODULE_OBJS)
$(CC) $(MODULE_OBJS) $(PUBLIC_FLAGS) $(LDFLAGS) $(LIB_FLAGS) -o $(OUT_DIR)/$(MODULE_LIBRARY)
clean:
-rm -f $(LIBS_DIR)/$(MODULE_LIBRARY)
-rm -f $(MODULE_OBJS)
DEMO 2
小型程序makefile典例~~
若要编译得到so,则MODULE_BIN改为libxx.so,编译.c到.o时候加上-fPIC,链接时加上--shared 即可(此时不要有main()函数),得到的so加上.h文件就可以使用了
MODULE_BIN = maxHeapTest
#MODULE_SRCS = $(shell find . -name "*.c")
MODULE_OBJS += $(patsubst %.c,%.o ,$(wildcard ./*.c))
CC = gcc
OUT_DIR = .
PUBLIC_FLAGS:=-g -O0 -Wall
LDFLAGS = -lm -lz -lpthread
MODULE_INCLUDE = -I.
.PHONY:all clean
%.o: %.c
$(CC) $(PUBLIC_FLAGS) $(MODULE_INCLUDE) -c $< -o $@
all : clean $(MODULE_OBJS)
$(CC) $(MODULE_OBJS) $(PUBLIC_FLAGS) $(LDFLAGS) -o $(OUT_DIR)/$(MODULE_BIN)
clean:
-rm -f $(OUT_DIR)/$(MODULE_BIN)
-rm -f $(MODULE_OBJS)
DEMO 3
嵌入式makefile demo,以下为顶级makefile
CROSS = arm-none-linux-gnueabi-
CFLAGS := -nostdinc -nostdlib -fno-builtin -Wall -O2
INCLUDE = -I$(shell pwd)/include -I$(shell pwd)/start
ROOTDIR = $(shell pwd)/
SUBDIRS = start ucos ff9a device lib app avrnet
SUBOBJS := $(foreach n, $(SUBDIRS), obj/lib$(n).a)
export CROSS INCLUDE CFLAGS ROOTDIR
#objs := start.o init.o boot.o
#模式匹配当前目录下所有.c 文件,wildcard为一个预定义的宏
C_sources_files = $(wildcard *.c)
S_sources_files = $(wildcard *.S)
#模式匹配,由当前目录下所有.c文件得到对应的.o文件
C_objs = $(patsubst %.c,%.o,$(C_sources_files))
S_objs = $(patsubst %.S,%.o,$(S_sources_files))
bootloader.bin: $(S_objs) $(C_objs) $(SUBOBJS)
#原来的那句,ld命令默认不会给你连接gcc库的
#${CROSS}ld -Tboot.lds -o bootloader.elf $^
#连接阶段加入libgcc.a库,否则除法没法用啊
${CROSS}ld -Bstatic -Tboot.lds -L /usr/local/arm-linux-gcc4.4.3/lib/gcc/arm-none-linux-gnueabi/4.4.3 \
-L /usr/local/arm-linux-gcc4.4.3/arm-none-linux-gnueabi/sys-root/usr/lib \
-o bootloader.elf $^ --start-group -lgcc -lgcc_eh -lgcov -lc --end-group
${CROSS}objcopy -O binary -S bootloader.elf $@
${CROSS}objdump -D -m arm bootloader.elf > bootloader.dis
mv *.o *.bin *.elf *.dis ./obj
%.o:%.c
${CROSS}gcc $(CFLAGS) $(INCLUDE) -c -o $@ $<
%.o:%.S
${CROSS}gcc $(CFLAGS) $(INCLUDE) -c -o $@ $<
$(SUBOBJS) : $(SUBDIRS)
.PHONY: $(SUBDIRS)
$(SUBDIRS):
make -C $@
.PHONY:clean
clean:
for dir in $(SUBDIRS); do \
make -C $$dir clean; \
done
rm -f *.elf *.o *.bin *.dis
rm -f ./obj/*.elf ./obj/*.bin ./obj/*.dis ./obj/*.o ./obj/*.a
一下为子级makefile, 生成.a静态库
CURDIR = $(shell pwd)
#就为了得到lib<目录名>.a,累死我了..这样TARGET便具有自适应能力了
#<目录名>是当前父目录的名字和shell pwd不一样
TARGET = $(addsuffix .a,$(subst $(ROOTDIR),lib,$(CURDIR)))
#objs := start.o init.o main.o led.o key.o adc.o Nand.o timer.o uart.o
#模式匹配当前目录下所有.c 文件,wildcard为一个预定义的宏
C_sources_files = $(wildcard *.c)
S_sources_files = $(wildcard *.S)
#模式匹配,由当前目录下所有.c文件得到对应的.o文件
C_objs = $(patsubst %.c,%.o,$(C_sources_files))
S_objs = $(patsubst %.S,%.o,$(S_sources_files))
$(TARGET):$(S_objs) $(C_objs)
${CROSS}ar -r -o $@ $^
mv *.o *.a ../obj
%.o:%.c
${CROSS}gcc $(CFLAGS) $(INCLUDE) -c -o $@ $<
%.o:%.S
${CROSS}gcc $(CFLAGS) $(INCLUDE) -c -o $@ $<
.PHONY:clean
clean:
rm -f *.elf *.o *.bin *.dis *.a
boot.lds链接脚本
SECTIONS
{
. = 0x33f80000;
.text :
{
./obj/start.o (.text)
./obj/init.o (.text)
*(.text)
}
. = ALIGN(4);
.rodata :
{
*(.rodata*)
}
. = ALIGN(4);
.data :
{
*(.data)
}
. = ALIGN(4);
__bss_start = .;
.bss :
{
*(.bss)
*(COMMON)
}
__bss_end = .;
}
在 .c 中可以这么使用链接脚本中的变量
void __clear_bss(void)
{
extern int __bss_start, __bss_end;
int *p = &__bss_start;
for (; p < &__bss_end; p++)
*p = 0;
}
在 .S 中可以这么使用链接脚本中的变量
ldr r2, =__bss_start