makefile 杂谈

CC = gcc  
LD = gcc  
CFLAGS = -Wall -c -Dgliethttp -I../include -L lib_path  
LDFLAGS = -lpthread  
  
RCS = $(wildcard *.c source/*.c)  
OBJS = $(patsubst %c, %o, $(SRCS))  
TARGET = gliethttp  
   
.PHONY: all clean  
   
all: $(TARGET)  
  
$(TARGET): $(OBJS)  
    @$(LD) $(LDFLAGS) -o $@ $^  
   
%o: %c  
    @$(CC) $(CFLAGS) -o $@ $<

clean:  
    @rm -f *.o $(TARGET) 

1,特殊符号:四个特殊符号的意义@、$@、$^、$

@:这个符串通常用在“规则”行中,表示不显示命令本身,而只显示它的结果;否则会显示打印该命令信息

$@     --代表目标文件(target) ,如例子的:$(TARGET)

$^            --代表所有的依赖文件(components) ,@$(LD) $(LDFLAGS) -o $@ $^ ;$^代表$(OBJS)所有.o

$<           --代表第一个依赖文件(components中最左边的那个),@$(CC) $(CFLAGS) -o $@ $< ;$< 代表依赖的%c.

2,编译文件和依赖文件的获取

RCS=$(wildcard *.c source/*.c)是为了找出目录和指定目录下所有的后缀为c和cpp的文件,这个功能也可以使用RCS=$(shell echo *.c)实现。

OBJ=$(patsubst %c, %o, $(SRCS))中是为了将所有的cpp文件的后缀替换为o文件,这个功能也可以通过CPP_OBJ=$(CPP_SRC:%.c=%.o)实现 ,替换引用规则,即用您指定的变量替换另一个变量。
它的标准格式是$(var:a=b) 或 ${var:a=b};

3,编译c后缀和cpp后缀文件的规则,后缀规则是一种老风格定义隐含规则的方式。新版本的make中使用模式规则取代了这种实现方式,模式规则和它相比更加清晰明了。现在版本保留它的原因只是为了能够兼容旧的makefile文件。
后缀规则有两种类型:“双后缀”和“单后缀”。
双后缀规则定义一对后缀:目标文件的后缀和依赖目标的后缀。它匹配所有后缀为指定目标后
缀的文件名。对于一个匹配的目标文件,它的依赖文件是这样形成:将目标文件中的后缀替换为依
赖文件的后缀之后得到。如:一个描述目标和依赖后缀的“.o”和“.c”的规则就等价于模式规则
“%o : %c”。
单后缀规则只定义一个后缀:此后缀是源文件的后缀。它可以匹配任何文件,其依赖文件名是
这样形成:将源文件后缀追加到目标文件名之后得到。例如:单后缀“.c”就等价于模式规则“% :
%.c”。
后缀规则的识别过程:比较make本身所定义的后缀和规则中出现的后缀,如果规则的目标中
只有一个可识别的后缀,则这个规则是一个“单后缀”规则;当规则的目标中有两个可识别的后缀
时,这个规则就是“双后缀”规则

.c.s:
	@$(CC) $(CCFLAGS)  -S $<

.s.o:
	@$(AS) $(ASFLAGS) -o $*.o $<

.c.o:
	@$(CC) $(CCFLAGS) -o $*.o -c $<
	@echo [ $*.c Compiled ... ... ]

.cpp.o:
	@$(C++) $(CCFLAGS) -o $*.o -c $<
	@echo [ $*.cpp Compiled ... ... ]

.c.o和.cpp.o,是为了通配编译c后缀和cpp后缀文件的规则,

“.c”和“.o”都是make可识别的后缀。因此当定义了一个目标是“.c.o”的规则时。
make会将它作为一个双后缀规则来处理,它的含义是目标为“.o”文件、依赖为“.c”文件。下
边是使用后追规则定义的、编译.c源文件的规则:
.c.o:
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<

一个后缀规则依赖关系描述中不能包含依赖文件。否则,此规则将被作为一个普通规则对待。因此
规则:
.c.o: foo.h
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
它不是一个后缀规则。它是目标文件为“.c.o”、依赖文件是“foo.h”的普通规则。它不等价于规
则:
%.o: %.c foo.h
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
需要注意的是:没有命令行的后缀规则是没有任何意义的。它和没有命令行的模式规则不同,它并不
能取消之前使用后追规则定义的规则。它所实现的仅仅是将这个后缀规则作为目标加入到make的数据库中。
可识别的后缀指的是特殊目标“.SUFFIXES”的所有依赖的名字。通过给特殊目标“SUFFIXES”添加依赖来增加
一个可被识别的后缀:
.SUFFIXES: .hack .win
它所实现的功能是把后缀“.hack”和“.win”加入到可识别后缀列表的末尾。
如果需要重设默认所有的可识别后缀,可以这样来实现:
.SUFFIXES: #删除所有已定义的可识别后缀
.SUFFIXES: .c .o .h #重新定义
其过程是首先使用没有依赖的特殊目标“.SUFFIXES”来删除所有已定义的可识别后缀;之后再重新定义。
注意: make的“-r”或“-no-builtin-rules”可以清空所有已定义的可识别后缀。

5,去除路径:

file:$(notdir $(src))

6,增加依赖编译的方法:

CC := g++
LD := g++
 
CFLAGS  += -Iinc
LDFLAGS += 
 
BINARY_PATH ?= out/bin
OBJECT_PATH ?= out/objs
TARGET ?= $(BINARY_PATH)/my-app.exe
 
SOURCES := $(wildcard src/*.cpp src/*/*.cpp src/*/*/*.cpp)
OBJECTS := $(addsuffix .o,$(addprefix $(OBJECT_PATH)/,$(basename $(notdir $(SOURCES)))))
DEPENDS := $(addsuffix .d,$(OBJECTS))
 
ifneq (v$(V),v1)
hide?=@
else
hide?=
endif
 
.PHONY : all clean hello prepare build post-build
 
all: hello prepare build post-build
clean: ;rm -rf out
hello: ;$(hide) echo ==== start, $(shell date) ====
prepare: $(BINARY_PATH) $(OBJECT_PATH)
post-build: ;$(hide) echo ==== done, $(shell date) ====
build: $(TARGET)
$(BINARY_PATH) $(OBJECT_PATH): ; mkdir -p $@
 
$(TARGET) : $(OBJECTS)
    $(info LD $@)
    $(hide) $(LD) -o $@ $(OBJECTS) $(LDFLAGS)
 
define make-cmd-cc
$2 : $1
    $$(info CC $$<)
    $$(hide) $$(CC) $$(CFLAGS) -MMD -MT $$@ -MF $$@.d -c -o $$@ $$<   
endef
 
$(foreach afile,$(SOURCES),\
    $(eval $(call make-cmd-cc,$(afile),\
        $(addsuffix .o,$(addprefix $(OBJECT_PATH)/,$(basename $(notdir $(afile))))))))
 
-include $(DEPENDS)

完整的参考示例:

# This file use for compile file of upgtools
#
.PHONY: all clean

all:build_linux

CC=gcc

INC = ./

SRCS = \
        a.c \
        b.c \
        c.c \
        d.c \
        e.c

OBJS := $(SRCS:%.c=%.o)

CFLAGS += --std=c99 -MMD -MP -MF $@.d -MT $@.d
CFLAGS += -Wall -g -I${INC}

%o:%c
        @$(CC) -o $@ $(CFLAGS) -c $<

build_linux:${OBJS}
#@echo ${SRCS}
#@echo ${OBJS}
        @$(CC) -o $@ $(CFLAGS) $^

clean:
        @-rm *.o *.d build_linux -f

头文件关联编译:

-MP:生成头文件目标,避免更改后找不到目标出错;

-MMD:不带系统头文件,-MD 带系统头文件;这个D表示关联错误,编译错误后退出不生成;如果是擦看关联,去掉D和-c;

-MF :生成目标文件,后面跟生成的文件;

-MT:生成.d为目标的关联文件,需要处理%o.d:%c,并转化为%o:%c的关联处理;

DEPS:= $(SRCS:%.c=%.o.d出

%o:%c
    #$(CC) -o $@ $(CFLAGS) -c $< -MMD -MP -MF $@.d -MT $@.d
######生成.o为目标的依赖文件######
    $(CC) -o $@ $(CFLAGS) -c $< -MMD -MP -MF $@.d

###输出关联.d目标:-MT $@.d,需要处理%o.d:%c#####

%o.d:%c
    @if [ -f $@ ];then \
            $(CC) -MM -MP $< $(CFLAGS) -MF $@.$$$$; \
            sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@;\
            rm $@.$$$$; fi;

###必须在目标之下####
-include ${DEPS} 

常见用法:

Makefile 使用总结 - wang_yb - 博客园

makefile 条件判断有两种形式,一种是command内部的sh方式,一种是command外部的宏方式:

command内部的sh方式:遵循sh的判断方法,方法如下:

target:

       if [ "X$(COPY_BACK_TARGET)" = "XY" ]; then \
        cp -f target ../target_back; \
        else \
        cp -f target img/; \
        fi

这种方式,if到fi整个内容为command;

command外部的宏方式:遵循宏的定义和方法,方法如下

ifeq/ifneq/ifdef/ifndef

else

endif

关键字功能
ifeq判断参数是否相等,相等为true,否则为false
ifneq判断参数是否不相等,不相等为true,否则为false
ifdef判断参数是否有值,有值为true,否则为false
ifndef判断参数是否没有值,没有值为true,否则为false

target:

ifeq ($(COPY_BACK_TARGET),y)

      cp -rf target ../target_back(command):

else

     cp -rf target img/(cmmand)

endif

这种方式,条件判断在command外部,条件的执行体才是command

执行体赋值方法:在主执行体前声明变量,且只能每次声明一个,在子执行体都可以应用。

.PHONY:p_test p_test1 p_test2 p_test3

p_test1:
@if [ "X${owner}" = "Xgchen" ];then \
    cp -rf test1.bin ${targ_dir}; \
  else \
     cp -rf test2.bin ${targ_dir}; \; \
  fi;
p_test2:
    @echo " ${owner} ${date} test2!"
p_test3:
    @echo " ${owner} ${date} test3!"
   
p_test:owner=gchen
p_test:date=20200201
p_test:targ_dir=test/gchen/20200201/
p_test:p_test1 p_test2 p_test3
    @echo " ${owner} ${date} test!"

多个执行体执行相同的功能[解决在同一次make 执行相同目标后,第二次不执行的问题],问题如下:

function1:

   echo "this function1"

p_test :

   function1

p_test1 :

   function1

test:p_test   p_test1

只执行一次function1,解决每次都要支持function1的方法:

1,目标并列法:

.PHONY:p_test p_test1 p_test2 p_test3
p_test1 p_test2 p_test3:
    call function1
    call function2
    call function3

p_test :p_test1 p_test2 p_test3

2,公共执行体定义法:

define function1
echo "this function1";

echo "this function2";
endef   

p_test1 :

    $(function1)

p_test2 :

    $(function1)

条件执行注意:

define function1
echo "this function1";\

echo "this function1 second";[由执行体确定是否加“;”或“\”]
endef   

.PHONY:p_test2
p_test2 :
    @if [ "X_${selecte}" = "X_function1" ];then \
   $(function1);\
  else \
   $(function2);\
  fi

3,多模目标法:

%_test:

     echo "this function $@";

test:1_test 2_test 3_test

价值参考:
https://blog.csdn.net/dlf1769/article/details/78997967/

Makefile 在执行体运用变量 ubi_count

ubi_count=$(shell python ubi_test.py -b 128K -e 124K -s 100M)

auto_partition:

    @echo "auto partition"

    @echo "ubi_count:${ubi_count}"

     @mkfs.ubifs -r $(IMAGE_DIR)/datafs -F -m 2048 -e 126976 -c ${ubi_count} -o $(IMAGE_DIR)/dataubifs.img; 

遍历目录结构编译方法:

ARCH ?= x86

ifeq ($(ARCH),x86)
CC=gcc
else
CC=arm-linux-gnueabihf-gcc
endif

TARGET=mp3
BUILD_DIR=build
SRC_DIR=module1 module2
INC_DIR=include
CFLAGS=$(patsubst %,-I%,$(INC_DIR))
INCLUDES=$(foreach dir,$(INC_DIR),$(wildcard $(patsubst)/*.h))

SOURCES=$(foreach dir,$(SRC_DIR),$(wildcard $(dir)/*.c))
OBJS=$(patsubst %.c,$(BUILD_DIR)/%.o,$(notdir $(SOURCES)))
VPATH=$(SRC_DIR)

$(BUILD_DIR)/$(TARGET):$(OBJS)
$(CC) $^ -o $@

$(BUILD_DIR)/%.o:%.c $(INCLUDES) | create_build
$(CC) -c $< -o $@ $(CFLAGS)

.PHONY:clean create_build

clean:
rm -r $(BUILD_DIR)

create_build:
mkdir -p $(BUILD_DIR)

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值