makeFile基本介绍, 语法, 示例,通用makefile

makefile(结尾有万用makefile)

实际上就是很复杂的编程语言

IDE使用变多使得makefile使用变少;

对于Linux来说了解makefile依然很必要

make 命令: 负责C/C++程序编译与链接

make根据指定命令进行构建

建构规则文件:GNUmakefile, makefile, Makefile; (GNUmakefile是GNU专用, 不建议使用)

makefile文件格式

是固定的:

target...:prerequisites...

[Tab健] commands

makefile文件规则

由一系列规则构成

规则的目的: 建构目标的先决条件是什么以及如何建构目标

如果未指定目标, 缺省执行第一个目标

若prerequisites中有一个以上的文件比target文件要新, 执行commands所定义的命令

target: 目标

通常为编译期的文件名, 以指定要建构的对象, 也可以是执行文件, 还可以是标签(操作名称, 伪目标)

可以为单一目标, 也可以为空格分隔的多个目标

每个目标都定义了一组处理规则, 和其相关规则构成规则链

preprequisites: 先决条件

为生成该目标所需的先决文件或目标(前置条件)

一般为空格分隔的文件名, 指定目标是否重建的判断标准, 即只要有一个先决文件不存在或有过更新, 就重建目标

若目标先决条件本身需要重建, 则匹配该先决条件的目标, 执行其对应的命令

commands: 命令

由一行或多行shell命令组成, 命令前有tab建(顶头必须是tab不能是空格)

指示如何构建目标, 一般为生成目标文件

每行命令都在单独的进程中执行, 彼此间没有继承关系, 不能简单传递数据;
解决方法:用分号将多条命令书写在单行(此时可用"\"折行), 或者为该条规则添加指示
.ONESHELL:

伪目标 操作名称, 而不是文件名

删除编译后的二进制目标文件, 例如:

clean:

    rm -f *.o

执行命令时须指定伪目标: $ make clean

若当前目录下有clean文件, 则此规则不会被执行;此时可用".PHONY:clean"明确指示clean为伪目标; make将跳过文件检查, 执行其对应的命令;

执行清除任务的伪目标一般放置在脚本的最后

伪目标惯例

all: 所有目标的目标, 一般为编译所有的目标, 对同时编译多个程序极为有用

clean: 删除由make创建的文件

install: 安装已编译好的程序, 主要任务是完成目标执行文件的拷贝

print: 列出改变过的源文件

tar: 打包备份源文件

dist: 创建压缩文件, 一般将tar文件压缩成Z文件或gz文件

TAGS: 更新所有的目标, 以备完整地重编译使用

checktest: 一般用来测试makefile的流程

示例: 主程序文件"main.c", 使用library库
prog : main.o library.o
 cc -o prog main.o library.o

main.o:main.c library.h
 cc -c main.c

library.o : library.c library.h
 cc -c library.c

.PHONY : clean

clean:
 rm main.o library.o

makefile语法

很多时候和shell的编程规范相似;

  • 行解析: 命令按行解析

    命令行的行首字符为Tab, 其他行的行首字符不得为Tab, 但可以使用多个空格缩进;

  • 换行: 命令太长时, 行尾用""换行 \

  • "#"是注释 #

  • 关闭回显: 行首字符后和命令前加"@" @

    未关闭回显时, make会首先回显(打印)命令, 然后执行该命令

    通常仅在注释和纯显示的echo命令前使用;

  • include filename: 包含其他文件

    像C/C++;

    行首加"-":忽略文件包含的错误

通配符

正则匹配;

变量

基本变量定义:

var_name = value

$(变量名):引用变量(无多余空格);
shell变量用"$$", 如:

@echo $$HOME

变量在使用时展开, 形式上类似于宏替换(当作字符串处理);

变量的使用场合: 几乎所有场合: 目标, 先决条件, 新变量;

内置变量

$(CC):当前使用的编译器;

$(MAKE):当前使用的make工具

自动变量

符号含义
$@当前目标;
$< 当前目标的首个先决条件;
$?比目标更新的所有先觉条件;
$^所有先决条件;
$(@F), $(@D)$@的目录名和文件名;
$(<D), $(<F)$< 的目录名和文件名

不太好理解和记忆

变量定义格式

var_name = value : 在执行时扩展, 允许递归, 可以使用后续代码中出现的值

var_name :=value : 在定义时扩展, 不允许递归, 使用右侧的现值, 不能使用后续代码中出现的值;

var_name ?= value : 只有在该变量为空时才设置值, 否则维持原值

var_name += value : 将值追加到变量的尾部; 若变量未定义, 则"+=“自动解释为”=";
若变量已定义, 则"+="继承上次的操作符, 并追加新值(如之前是:=赋值, 追加时也用:=)

多行变量

不经常使用

define var_name
    @echo "One"
    @echo "Two"
endef

define和endef行首字符不能为Tab, 对齐时可使用空格(它俩本身不是命令)

引用: $(var_name)

多行变量主要用于定义命令包, 使用多行变量要小心, 展开时可能导致脚本错误;

目标变量: 类似局部变量, 仅对本目标规则链有效

tatget ...:var_name = value:定义目标变量

静态模式:以"%"通配

基本模式:

target ...: target-pattern:prerequisites ...
[tab键]commands

目的: 用于处理模式相同的多目标, 简化脚本代码

示例:每个目标文件都以.o结尾, 先决文件都.c结尾
objs = main.o library.o
$(objs):%.o:%.c
    $(CC) -c $(CFLAGS) $< -o $@

# 翻译出来就是:
main.o:main.c
    $(CC) -c $(CFLAGS) main.c -o main.o

library.o:library.c
    $(CC) -c $(CFLAGS) library.c -o library.o

条件判断基本格式

conditional-directive
    text-if-true
else
    text-if-false
endif
可用的条件判断
  • 是否相等

ifeq(arg1, arg2), ifeq ‘arg1’‘arg2’, ifeq"arg1"“arg2”

  • 是否不等

ifneq …

  • 是否已定义

ifdef var_name

  • 是否未定义

ifndef var_name

循环:可以使用shell循环

rulefor:
    for filename in `echo $(objs)`;\
    do\
        rm -f $$filename;\
    done
注意

循环为shell循环, 为保证多行命令在同一进程下执行, 必须合成单行命令, 所以需要添加分行标识

可以使用反引号执行命令, 所获得的结果集合可以作为循环的处理集合

filename本身是shell变量, 需使用"$$"引用

函数:像变量一样使用"$()"标识

$(function arg1,arg2,...): 函数调用, 函数名为function,
后跟逗号分隔的参数列表, 函数参数前后不能有多余的空格

$(subst from,to,text): make的字符串替代函数,将text中的from字符串替换为to,
返回替换后的字符串

函数例子

comma:=,
# 定义空值
empty:=
# 定义空格
space:=$(empty) $(empty)
foo:=a b c
# 将"a b c" 替换为 "a,b,c"
bar:=$(subst $(space),$(comma),$(foo))

附一份在用的万用模板

####################################################
# Generic makefile - 万能Makefile
# for compiling and linking C++ projects on Linux
# Author: George Foot  Modified:Jackie Lee
####################################################
### Customising
#
# Adjust the following if necessary; EXECUTABLE is the target
# executable's filename, and LIBS is a list of libraries to link in
# (e.g. alleg, stdcx, iostr, etc). You can override these on make's
# command line of course, if you prefer to do it that way.
#
#
EXECUTABLE := main    # 可执行文件名
LIBDIR:=              # 静态库目录
LIBS :=               # 静态库文件名
INCLUDES:=.           # 头文件目录
SRCDIR:=              # 除了当前目录外,其他的源代码文件目录
#
# # Now alter any implicit rules' variables if you like, e.g.:

CC:=g++
CFLAGS := -g -Wall -O3
CPPFLAGS := $(CFLAGS)
CPPFLAGS += $(addprefix -I,$(INCLUDES))
CPPFLAGS += -MMD
#
# # The next bit checks to see whether rm is in your djgpp bin
# # directory; if not it uses del instead, but this can cause (harmless)
# # `File not found' error messages. If you are not using DOS at all,
# # set the variable to something which will unquestioningly remove
# # files.
#

RM-F := rm -f


# # You shouldn't need to change anything below this point.
#
SRCS := $(wildcard *.cpp) $(wildcard $(addsuffix /*.cpp, $(SRCDIR)))
OBJS := $(patsubst %.cpp,%.o,$(SRCS))
DEPS := $(patsubst %.o,%.d,$(OBJS))
MISSING_DEPS := $(filter-out $(wildcard $(DEPS)),$(DEPS))
MISSING_DEPS_SOURCES := $(wildcard $(patsubst %.d,%.cpp,$(MISSING_DEPS)))


.PHONY : all deps objs clean veryclean rebuild info

all: $(EXECUTABLE)

deps : $(DEPS)

objs : $(OBJS)

clean :
	@$(RM-F) *.o
	@$(RM-F) *.d
	veryclean: clean
	@$(RM-F) $(EXECUTABLE)

rebuild: veryclean all
	ifneq ($(MISSING_DEPS),)
$(MISSING_DEPS) :
	@$(RM-F) $(patsubst %.d,%.o,$@)
-include $(DEPS)
$(EXECUTABLE) : $(OBJS)
	$(CC) -o $(EXECUTABLE) $(OBJS) $(addprefix -L,$(LIBDIR)) $(addprefix -l,$(LIBS))

info:
	@echo $(SRCS)
	@echo $(OBJS)
	@echo $(DEPS)
	@echo $(MISSING_DEPS)
	@echo $(MISSING_DEPS_SOURCES)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值