Makefile编译——基础

目录

一、Makefile的作用和基础功能

 (1)Make简介

 (2)主要完成三点编译工作:

(3)Makefile基本结构

二、Makefile编译规则和语法

(1)Makefile规则详解

(2)Makefile核心语法

(3)创建和使用变量

三、Makefile应用实例 

总结



一、Makefile的作用和基础功能

 (1)Make简介

        Make工程管理器也就是个“自动编译管理器”,这里的“自动”是指它能够根据文件时间戳,自动发现更新过的文件而减少编译的工作量,同时,它通过读入Makefile文件的内容来执行大量的编译工作;Make将只编译改动的代码文件,而不用完全编译。

 (2)主要完成三点编译工作:

  • 编译多个源文件;
  • 生成需要的库文件;
  • 生成需求格式的可执行文件

(3)Makefile基本结构

     Makefile是Make读入的唯一配置文件 
     1)由make工具创建的目标体(target),通常是目标文件或可执行文件;
     2)要创建的目标体所依赖的文件(dependency_file);
     3)创建每个目标体时需要运行的命令(command);
     4)注意:命令行前面必须是一个”TAB键”,否则编译错误为:*** missing separator.  Stop.

     Makefile格式
        target  :   dependency_files
        <TAB>  command
        例子
        hello.o :  hello.c hello.h
            gcc  –c  hello.c  –o  hello.o

二、Makefile编译规则和语法

(1)Makefile规则详解

Makefile编写规则:

        target  :   dependency_files
        <TAB>  command

  1. target: 可以是一个object file(目标文件),也可以是一个执行文件,还可以是一个标签(label)。可使用通配符,当有多个目标时,目标之间用空格分隔。
  2. dependency_files: 生成该target所需要的依赖文件,当有多个依赖项时,依赖项之间用空格分隔。
  3. command: 该target要执行的命令(任意的shell命令)。

注意:

(1)– 在执行command之前,默认会先打印出该命令,然后再输出命令的结果;如果不想打印出命令,可在各个command前加上@。
(2)– command可以为多条,可以分行写,但每行都要以tab键开始。另外,如果后一条命令依赖前一条命令,则这两条命令需要写在同一行,并用分号进行分隔。
(3)– 如果要忽略命令的出错,需要在各个command之前加上减号" - "。

实例:
1.在文件当前目录下编译hello.c文件:
hello: hello.o
	gcc -o hello hello.o	    
hello.o: hello.c
	gcc -c hello.c	    
clean:
	rm hello.o
执行make命令:
$ make
gcc -c hello.c
gcc -o hello hello.o
$ ls
hello  hello.c  hello.o  Makefile

%%可以在相关的Shell命令前加上@,可以停止打印命令输出语句,直接执行语句
%%注释:-Wall:表示允许发出gcc所有有用的报警信息.
       -c:只是编译不链接,生成目标文件”.o”
       -o file:表示把输出文件输出到file里

2.清理编译中间文件:Makefile一般都会有一个clean伪目标,
用来清理编译中间产物,或者对源码目录做一些定制化的清理
Hello: main.c main.h 
    $(CC) –o hello main.c
clean:
    $(RM) hello

(2)Makefile核心语法

        Makefile的核心语法包括:命令、变量、条件语句和函数。

        1)命令

Makefile脚本文件中支持运行Linux的shell命令,基本与命令行下的输入方法相同,而且在默认模式下,脚本运行会输出打印运行的命令,可以通过在脚本命令前加符号“@”禁止打印。

  • shell基本命令格式:
  • $ Command  [-Options]  Argument1  Argument2...
              指令         选项           参数1         参数2 ...

      Shell提示符,如果当前用户为超级用户,提示符为“#”,其他用户的提示符均为“$”;
     Command:命令名称,Shell命令或程序,严格区分大小写
     Options:命令选项,用于改变命令执行动作的类型,由“-”引导,可以同时带有多个选项;
     Argument:命令参数,指出命令作用的对象或目标,有的命令允许带多个参数

        2)变量

创建变量的目的: 用来代替一个文本字符串:
          1.系列文件的名字  
          2. 传递给编译器的参数 
          3. 需要运行的程序 
          4. 需要查找源代码的目录 
          5. 你需要输出信息的目录  
          6. 你想做的其它事情。

        (后面的小节中会详细介绍到)

        3)条件语句

Makefile支持条件语句:

基本表达式为:

if ... 
<conditional-directive>
<text-if-true>
endif
if ... else ...
<conditional-directive>
<text-if-true>
else
<text-if-false>
endif

if表示条件语句的开始,并指定一个条件表达式,表达式包含两个参数,以逗号分隔,表达式以圆括号括起。else表示条件表达式为假的情况。endif表示一个条件语句的结束,任何一个条件表达式都应该以endif结束。

表示条件关键字,有4个关键字:ifeq、ifneq、ifdef、ifndef。

  • ifeq   (<arg1>, <arg2>)  %()可换为 " "、' '

        比较arg1和arg2的值是否相同,如果相同则为真。

  • ifneq (<arg1>, <arg2>)  %()可换为 " "、' '

        比较arg1和arg2的值是否不同,如果不同则为真。

  • ifdef  <variable-name>

        如果值非空,则表达式为真,否则为假。

  • ifndef  <variable-name>

        如果值为空,则表达式为真,否则为假。也可以是函数的返回值。

        4)函数

函数格式:
$(function arguments) 

  • function是函数名,arguments是该函数的参数。
  • 参数和函数名之间是用空格或 <Tab> 隔开。
  • 如果有多个参数,它们之间用逗号隔开。这些空格和逗号不是参数值的一部分

   内核的 Makefile 中用到大量的函数,现在介绍一些常用的:

1.获取文件名中的路径部分
$(dir names…)
eg:  $(dir src/foo.c hacks)
     结果为src/ ./

2.获取names中的真正文件名
$(notdir names…)  
eg:  $(notdir src/foo.c hacks) 
     结果为foo.c hacks

3.抽取names中每一个文件名的后缀。
$(suffix names…)
eg:  $(suffix src/foo.c src-1.0/bar.c hacks) 
     结果为.c .c

4.抽取names中每一个文件名中除后缀外一切字符
$(basename names…)
eg:  $(basename src/foo.c src-1.0/bar hacks) 
     结果为src/foo src-1.0/bar hacks

5.参数pattern是一个文件名格式,包含有通配符(通配符和 shell 中的用法一样)。
函数 wildcard 的结果是一列和格式匹配的且真实存在的文件的名称,文件名用空格隔开。
比如若当前目录下有文件 1.c、2.c、1.h、2.h,则:
$(wildcard pattern)
eg:  c_src := $(wildcard *.c) 
     结果为1.c 2.c

(3)创建和使用变量

        1)变量定义的两种方式:
          a. 递归展开方式VAR=var
          b. 简单方式 VAR:=var
          * 变量使用$(VAR)
          注:用”$”则用”$$”来表示、类似于编程语言中的宏 。

        2)为变量添加值 你可以通过+=为已定义的变量添加新的值:

Main=hello.o hello-1.o

Main+=hello-2.o

        3)自动变量

  • $*       不包含扩展名的目标文件名称
  • $+       所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件
  • $<       第一个依赖文件的名称
  • $?        所有时间戳比目标文件晚的的依赖文件,并以空格分开
  • $@      目标文件的完整名称
  • $^        所有不重复的目标依赖文件,以空格分开
  • $%       如果目标是归档成员,则该变量表示目标的归档成员名称 

        4)系统中预定义的变量 :

  • AR:     库文件维护程序的名称,默认值为ar。
  • AS:        汇编程序的名称,默认值为as。
  • CC        C编译器的名称,默认值为cc。
  • CPP      C预编译器的名称,默认值为$(CC) –E。
  • CXX      C++编译器的名称,默认值为g++。
  • FC         FORTRAN编译器的名称,默认值为f77
  • RM        文件删除程序的名称,默认值为rm -f

三、Makefile应用实例 

1.变量使用的简单实例 

Hello: main.c main.h 
<tab> $(CC) –o hello main.c
clean:
<tab> $(RM) hello

  2.较为完整的实例

OBJS = kang.o yul.o
CC = gcc
CFLAGS = -Wall -O -g
sunq : $(OBJS)
	$(CC) $(OBJS) -o sunq
kang.o : kang.c kang.h
	$(CC) $(CFLAGS) -c kang.c -o kang.o
yul.o : yul.c yul.h
	$(CC) $(CFLAGS) -c yul.c -o yul.o

3.同时编译多个可执行文件

CC  = gcc

all: server client
server:server.c net.h
	$(CC) -o server server.c
client:client.c net.h
	$(CC) -o client client.c

clean:
	rm server client

4.效率高,精炼,支持检测头文件(手动添加)

test : main.o sub.o
gcc -o test main.o sub.o

%.o : %.c
gcc -c -o $@ $<

sub.o : sub.h

clean:
rm *.o test -f

5.效率高,精炼,支持自动检测头文件

objs := main.o sub.o

test : $(objs)
gcc -o test $^

# 需要判断是否存在依赖文件
# .main.o.d .sub.o.d
dep_files := $(foreach f, $(objs), .$(f).d)
dep_files := $(wildcard $(dep_files))

# 把依赖文件包含进来
ifneq ($(dep_files),)
 include $(dep_files)
endif

%.o : %.c
gcc -Wp,-MD,.$@.d -c -o $@ $<

clean:
rm *.o test -f

distclean:
rm $(dep_files) *.o test -f

 

总结

1. 本文只是基础的Makefile编译规则和方法,复杂的编译经验有待积累,文中有问题的欢迎指出;

2. 最后列出部分学习及参考的博客,并致谢:


【1】编译—Makefile基础知识_JackRsir的博客-CSDN博客_makefile编译【2】Makefile 的使用(在 Linux 中使用 make 命令来编译程序)_韦东山的博客-CSDN博客_编写makefile文件,通过make命令进行编译

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

求上进的小怪兽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值