makefile工程编译模板

1、前言

    最近在调试一个解码器工程时,编写了一个简单的makefile,通过makefile实现工程demo的编译,涉及到makefile使用的相关知识,分享出来供大家学习。
    makefile旨在构建目标文件,实现工程的自动化编译。

2、makefile使用相关知识

2.1 规则语法:

target ... : prerequisites ...
    command
    ...

2.2 VPATH的使用

  1. 示例1 - 当前目录中找不到文件时, 按顺序从 src目录, ../parent-dir目录中查找文件
    VPATH src:../parent-dir

  2. 示例2 - .h结尾的文件都从 ./header 目录中查找
    VPATH %.h ./header

2.3 变量的定义

  1. = 延迟赋值 ,将整个makefile中的所有变量的值都计算完之后,确定该变量的值。
    1. := 立即赋值,:=只能使用前面定义好的变量。
    2. += 追加赋值
    3. ?= 条件赋值

2.4 自动变量

  1. $@ 所有目标的集合
  2. $^ 所有依赖目标的集合, 会去除重复的依赖目标
  3. $+ 所有依赖目标的集合, 不会去除重复的依赖目标
  4. $? 比目标新的依赖目标的集合

2.5 伪目标

并不是一个”目标(target)”, 不像真正的目标那样会生成一个目标文件.

典型的伪目标是 Makefile 中用来清理编译过程中中间文件的 clean 伪目标, 一般格式如下:

.PHONY: clean   <-- 这句没有也行, 但是最好加上
clean:
    -rm -f *.o

2.6 变量替换和变量引用

#变量替换
SRCS := programA.c programB.c programC.c
OBJS := $(SRCS:%.c=%.o)
#变量引用
$(SRCS)
echo $(SRCS)

2.7 C相关命令和参数定义

命令 含义 示例
RM rm -f RM=rm -f
AR ar AR=ar
CC gcc CC=gcc
CXX g++ CXX=g++
ARFLAGS AR命令的参数 -crus
CFLAGS C语言编译器的参数 CFLGAS+=-Wall -O3 -fPIC -fsigned-char
CXXFLAGS C++语言编译器的参数 同上
LDFLAGS ld链接器的参数 同上

3、makefile工程编译模板

#指定后缀名和伪目标
.SUFFIXES: .c,.o,.cpp,.S,.s  
.PHONY: all,clean
#设置相关工具
CC = gcc
CXX = g++
AR = ar
LD = ld

#设置相关路径
VPATH %.h ./inc
ROOTSRC = ./src
INCLUDES = ./inc

#设置工具的相关参数
BIN_TARGET = DEMO
CFLAGS += -Wall -O3  -g  -I$(INCLUDES)
CXXFLAGS += -Wall -g
LDFLAGS += -Wall -O3 -g
ARFLAGS += -crus

#以下获取OBJS文件的方式适用于含有少量文件的编译
SRCS = $(ROOTSRC)/file1.c            \
       $(ROOTSRC)/file2.cpp         \
       $(ROOTSRC)/file3.s           \
       $(ROOTSRC)/file4.S                
OBJS = $(patsubst %.s, %.o, $(patsubst %.cpp,%.o, $(patsubst %.c,%.o,$(SRCS))))

#以下通过通配符和字符串函数获取OBJS的方式适用于较大工程(含有大量文件)的编译
SRCOBJS := $(patsubst %.cpp, %.o, $(wildcard $(SRCDIR)/*.cpp))
TESTOBJS := $(patsubst %.cpp, %.o, $(wildcard $(TESTDIR)/*.cpp))
OBJS := $(SRCOBJS) $(TESTOBJS)

#编译规则
all: clean $(BIN_TARGET)
BIN_TARGET:    $(OBJS)
    $(CXX) -o $@ $(OBJS) $(LDFLAGS)
    rm $(OBJS)

%.o: %.c
    $(CC) -c $< $(CFLAGS) -o $@
%.o: %.cpp
    $(CXX) -c $< $(CXXFLAGS) -o $@

clean:
    rm    $(OBJS)
    rm  $(BIN_TARGET)

关于第二种获取OBJS方式的说明:
   这是通过make的两个内置函数wildcard和patsubst实现的。wildcard返回所有符合给定模式的匹配。在上面的例子中,我们要匹配所有处于$(SRCDIR)和$(TESTDIR)目录下的.cpp文件,并将其路径作为变量传入另一个函数patsubst,它会将每个路径中的.cpp替换成.o,最后存入我们指定的变量中。

关于写一个通用makefile的相关知识更多可以参考:

  1. https://bitmingw.com/2015/03/21/general-makefile/
  2. https://www.cnblogs.com/vamei/archive/2013/04/29/3051062.html

4、更加完善的makefile编译模板

(1)系统或架构相关宏、FLAGS配置在config.mk中:

#检测系统
OS = $(shell uname)

#设置是否调试
ifeq ($(DEBUG), 0)
    DEBUG_FLAGS := -O3
else
    DEBUG_FLAGS := -G
endif

#########################################
############linux系统 ###################
ifeq ($(findstring Linux, $(OS)), Linux)
    CROSS ?=
    CC    := $(CROSS)gcc -fPIC -DPIC
    CPP    := $(CROSS)g++ -fPIC -DPIC
    LD    := $(CROSS)ld
    AR    := $(CROSS)ar
    ASM    :=    yasm -DPIC

###ARM32架构
ifeq ($(platform), arm32)
    ARCH_DEF    :=
    EXTRA_CFLAGS := -march=armv7-a -marm $(ARCH_DEF)
    EXTRA_LFLAGS := -march=armv7-a -marm
    EXTRA_AFLAGS := -march=armv7-a $(ARCH_DEF)
    OUT_DIR        := ./bin/arm32
endif

###ARM64架构
ifeq ($(platform), arm64)
    ARCH_DEF    :=
    EXTRA_CFLAGS := -march=armv8-a $(ARCH_DEF)
    EXTRA_LFLAGS := -march=armv8-a  
    EXTRA_AFLAGS := -march=armv8-a $(ARCH_DEF)
    OUT_DIR        := ./bin/arm64
endif

###X86_32架构
ifeq ($(platform), x86_32)
    ARCH_DEF    :=
    EXTRA_CFLAGS := -m32 $(ARCH_DEF)
    EXTRA_LFLAGS := -m32 -shared
    EXTRA_AFLAGS := -m x86 $(ARCH_DEF)
    OUT_DIR        := ./bin/x86m32
endif


###X86_64架构
ifeq ($(platform), x86_64)
    ARCH_DEF    :=
    EXTRA_CFLAGS := -m64 $(ARCH_DEF)
    EXTRA_LFLAGS := -m64 -shared -Wl, -Bsymbolic
    EXTRA_AFLAGS := -m amd64 $(ARCH_DEF)
    OUT_DIR        := ./bin/x86m64
endif

endif

#########################################
############MAC/IOS系统 ###################
ifeq ($(findstring Darwin, $(OS)), Darwin)

###MAC平台
ifeq ($(target_plat), mac)
    CROSS ?=
    CC    := $(CROSS)gcc -fPIC -DPIC
    CPP    := $(CROSS)g++ -fPIC -DPIC
    AR    := $(CROSS)ar
    ASM    :=    yasm -DPIC

##X86_32架构
ifeq ($(platform), x86_32)
    ARCH_DEF :=
    EXTRA_CFLAGS    := -m32
    EXTRA_LFLAGS    := -m32 -dynamiclib -Wl, -dynamic -Wl, -read_only_relocs, suppress
    EXTRA_AFLAGS    := -f macho32 -m x86
    OUT_DIR            := ./bin/mac32
endif

##X86_64架构
ifeq ($(platform), x86_64)
    ARCH_DEF :=
    EXTRA_CFLAGS    := -m64
    EXTRA_LFLAGS    := -m64 -dynamiclib -Wl, -dynamic
    EXTRA_AFLAGS    := -f macho64 -m amd64
    OUT_DIR            := ./bin/mac64
endif

endif

###IOS平台
ifeq ($(target_plat), ios)
    CROSS := iphone
ifeq ($(platform), ios32)
    CC    := xcrun -sdk $(CROSS)os clang
    CPP    := g++
    AR    := ar
    ASM    := gas-preprocessor.pl -arch arm -as-type apple-clang --$(CC)

    ARCH_DEF    :=
    EXTRA_CFLAGS := -arch armv7 -mios-version-min=6.0
    EXTRA_LFLAGS := -arch armv7 -mios-version-min=6.0
    EXTRA_AFLAGS := -arch armv7 -mios-version-min=6.0
    OUT_DIR        := ./bin/ios32
endif

ifeq ($(platform), ios64)
    CC    := xcrun -sdk $(CROSS)os clang
    CPP := g++
    AR    := ar
    ASM    := gas-preprocessor.pl -arch aarch64 -as-type apple-clang --$(CC)

    ARCH_DEF    :=
    EXTRA_CFLAGS := -arch arm64 -mios-version-min=6.0
    EXTRA_LFLAGS := -arch arm64 -mios-version-min=6.0
    EXTRA_AFLAGS := -arch arm64 -mios-version-min=6.0
    OUT_DIR        := ./bin/ios64
endif

ifeq ($(platform), ios_sim32)
    CC    := xcrun -sdk $(CROSS)simulators clang
    CPP    := g++
    AR    := ar
    ASM    := yasm

    ARCH_DEF    :=
    EXTRA_CFLAGS := -arch i386 -mios-simulator-version-min=6.0
    EXTRA_LFLAGS := -arch i386 -mios-simulator-version-min=6.0 -Wl, -Bsymbolic-functions -read_only_relocs suppress
    EXTRA_AFLAGS := -f macho32 -m x86
    OUT_DIR        := ./bin/ios_sim
endif

ifeq ($(platform), ios_sim64)
    CC    := xcrun -sdk $(CROSS)simulators clang
    CPP    := g++
    AR    := ar
    ASM    := yasm

    ARCH_DEF    :=
    EXTRA_CFLAGS := -arch x86_64 -mios-simulator-version-min=6.0
    EXTRA_LFLAGS := -arch x86_64 -mios-simulator-version-min=6.0
    EXTRA_AFLAGS := -f macho64 -m amd64
    OUT_DIR        := ./bin/ios_sim
endif

endif ##ifeq ($(target_plat), ios)

endif

(2)构建法则在Makefile中

include config.mk

SRC_PATH    := ../src
INCLUDE_PATH:= ../include
LIB_PATH    := $(OUT_DIR)
LIB_NAME    := xxx

ARFLAGS        := cru

CFLAGS        := $(DEBUG_FLAGS)
CFLAGS        +=$(EXTRA_CFLAGS) -I$(INCLUDE_PATH)

ASMFLAGS    :=
ASMFLAGS    += $(EXTRA_AFLAGS) -I$(INCLUDE_PATH)

LDFALGS        := -lm -ldl
LDFALGS        += $(EXTRA_LFLAGS)

LIB         := $(LIB_PATH)/$(LIB_NAME).a $(LIB_PATH)/$(LIB_NAME).so

OBJS        := $(SRC_PATH)/x.o        \
               $(SRC_PATH)/y.o

all: clean $(LIB)

$(filter %.a, $(LIB)):$(OBJS)
    $(AR) $(ARFLAGS) $@ $^

$(filter %.so, $(LIB)):$(OBJS)
    $(CC) $(LDFALGS) -shared -o $@ $^

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

%.o:%.asm
    $(ASM) $< $(ASMFLAGS) -c -o $@

clean:
    rm -rf $(OBJS)
    rm -rf $(LIB)

5、参考

https://www.cnblogs.com/wang_yb/p/3990952.html
https://www.cnblogs.com/yyangblog/p/4159778.html
https://bitmingw.com/2015/03/21/general-makefile/
https://github.com/switchbrew/34c3-demo/blob/master/Makefile
https://blog.csdn.net/listener51/article/details/84930829


THE END!


本博文只能阅读,谢绝转载,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 2963033731@qq.com

文章标题:makefile工程编译模板

字数:1.5k

本文作者:Soaring Lee

发布时间:2018-09-10, 21:45:47

最后更新:2021-06-14, 12:13:44

原始链接:https://soaringleefighting.github.io/2018/09/10/【PE系列】makefile工程编译模板/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

×

喜欢就点赞,疼爱就打赏

相册