Linux makefile语法

入门学习Makefile中,本文是集中若干篇博客及网友问答的知识,文中也会附上相关博客链接。

Begin:Makefile的前世今生

1.gcc是GNU Compiler Collection(就是GNU编译器套件),也可以简单认为是编译器,它可以编译很多种编程语言(括C、C++、Objective-C、Fortran、Java等等)。

2.当你的程序只有一个源文件时,直接就可以用gcc命令编译它。

3.但是当你的程序包含很多个源文件时,用gcc命令逐个去编译时,你就很容易混乱而且工作量大

4.所以出现了make工具 make工具可以看成是一个智能的批处理工具,它本身并没有编译和链接的功能,而是用类似于批处理的方式—通过调用makefile文件中用户指定的命令来进行编译和链接的。

5.makefile是什么?简单的说就像一首歌的乐谱,make工具就像指挥家,指挥家根据乐谱指挥整个乐团怎么样演奏,make工具就根据makefile中的命令进行编译和链接的。

6.makefile命令中就包含了调用gcc(也可以是别的编译器)去编译某个源文件的命令。

7.makefile在一些简单的工程完全可以人工手下,但是当工程非常大的时候,手写makefile也是非常麻烦的,如果换了个平台makefile又要重新修改。

8.这时候就出现了Cmake这个工具,cmake就可以更加简单的生成makefile文件给上面那个make用。当然cmake还有其他功能,就是可以跨平台生成对应平台能用的makefile,你不用再自己去修改了。

9.可是cmake根据什么生成makefile呢?它又要根据一个叫CMakeLists.txt文件(学名:组态档)去生成makefile。

10.到最后CMakeLists.txt文件谁写啊?亲,是你自己手写的。

11.当然如果你用IDE,类似VS这些一般它都能帮你弄好了,你只需要按一下那个三角形
作者:辉常哥 链接:http://www.zhihu.com/question/36609459/answer/89743845

1. Make初始语法

一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为
makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。

linux 下 编译c 文件 并运行 利用vim 创建一个c文件

   #include <stdio.h>
   #include <stdlib.h>
   void main(){
           int count =  5 + 5 ;
           printf("结果: %d",count);
   }

使用gcc 编译c 文件生成.o后缀的文件(gcc类似javac工具 生成class文件) gcc -c test.c

linux 使用gcc 提示bash:gcc:command not found 出现这个问题时,首先用命令:

   whereis gcc

查找看看gcc,gcc是否安装好。如果此时显示:

   gcc:/usr/bin/gcc

则说明已装好了,只需要配置到PATH路径下面就行了。 如果只是显示:

   gcc:

则说明gcc没有下载。

Centos(Rehat系列)系统下载gcc命令:yum install gcc Ubuntu系统下载gcc命令:apt-get
inatall gcc

.o文件是中间文件,但是不能够执行, 再执行一个命令:

   gcc -o main test.o

main 是自己定义的让linux 执行的文件名字,然后再执行 ./main 就可以了

实际上makefile 包含gcc 里面所做的操作实际上就是类似上面的操作, Cmakelist 又包含了makefile
简化了makefile 的操作.

linux下编译多个c文件并运行,现在有多个文件

   #ifndef COMMON_H_
   #define COMMON_H_
   int plus(int a, int b);
   int minus(int a, int b);
   int multi(int a, int b);
   int divi(int a, int b);
   #endif

分别定义了加减乘除的函数 然后在外面分别实现了加减乘除的c文件 plus.c 还有减,乘,除的c,剩下的就不写了,以及main.c文件
这个时候 如果我想在linux 下 运行main.c 文件 应该把所有的.c文件都编译一次. 和上面编译单个c文件类似

   [root@host makefile]# ls
   divi.c  include  main.c  minus.c  multi.c  plus.c
   [root@host makefile]# gcc -c divi.c 
   [root@host makefile]# gcc -c main.c 
   [root@host makefile]# gcc -c minus.c 
   [root@host makefile]# gcc -c multi.c 
   [root@host makefile]# gcc -c plus.c 
   [root@host makefile]# ls
   divi.c  divi.o  include  main.c  main.o  minus.c  minus.o  multi.c  multi.o  plus.c  plus.o

可以看到已经把.o的中间文件生成了. 下面生成可执行的文件,可执行文件是依赖于.o文件的,需要把这些.o文件都打包到可执行文件里面去.
所以命令是

   gcc divi.o main.o minus.o multi.o plus.o -o myapp

最后执行 ./myapp

很麻烦多个c文件, 所以使用makefile.

手动编译的过程 原始的c文件 > 创建.o文件 > 生成可执行文件myapp 在makefile里面 是倒过来的
使用tab键后面跟上规则的命令行. 必须是tab键跟上命令才会执行.要不然不认识.

rm *.o 吧刚才生成的.o文件全部删除 还有myapp也删除

冒号: 代表依赖 main.o:main.c, main.o依赖于main.c

Makefile 文件

   myapp:main.o plus.o minus.o multi.o divi.o
           gcc main.o plus.o minus.o multi.o divi.o -o myapp
   main.o:main.c
           gcc -c main.c
   plus.o:plus.c
           gcc -c plus.c
   minus.o:minus.c
           gcc -c minus.c
   multi.o:multi.c
           gcc -c multi.c
   divi.o:divi.c
           gcc -c divi.c

保存以后返回 执行make 命令,结果和刚才单个执行的结果是一样的.

2.使用Makefile单独执行某个命令

目标“clean”不是一个文件,它仅仅代表执行一个动作的标识。正常情况下,不需要执行这个规则所定义的动作,因此目标clean 没有出现在其它任何规则的依赖列表中。因此在执行make时,它所指定的动作不会被执行。除非在执行make时明确地指定它。 而且目标“clean”没有任何依赖文件,它只有一个目的,就是通过这个目标名来执行它所定义的命令。Makefile中把那些没有任何依赖只有执行动作的目标称为“伪目标”(phony targets)。
在现有的Makefile文件下输入“make clean”, 由于这个规则没有任何依赖文件,所以目标被认为是最新的,因此命令“rm”将不会被执行。这并不是我们的初衷。为了解决这个问题,我们需要将目标“clean”声明为伪目标。将一个目标声明为伪目标的方
法是将它作为特殊目标.PHONY”的依赖。如下:

.PHONY : clean

按照上面的例子在makefile里添加clear, 作用是把之前生成的.o文件删除

myapp:main.o plus.o minus.o multi.o divi.o
        gcc main.o plus.o minus.o multi.o divi.o -o myapp
main.o:main.c
        gcc -c main.c
plus.o:plus.c
        gcc -c plus.c
minus.o:minus.c
        gcc -c minus.c
multi.o:multi.c
        gcc -c multi.c
divi.o:divi.c
        gcc -c divi.c
.PHONY: clean
clean:
        rm -f *.o

保存之后 执行 make clean,则可以在任意时刻进行清空操作。

3.通配符优化

Makefile有三个非常有用的变量。分别是$@,$ ^,$<代表的意义分别是:$@指的是目标文件,$^指所有的依赖文件,$<指的是第一个依赖文件。如果我们使用上面三个变量,那么我们可以简化我们的Makefile文件为:

OBJECTS = main.o plus.o minus.o multi.o divi.o
myapp:$(OBJECTS)
        gcc $(OBJECTS) -o myapp
#通配符.o依赖于.c
%.o:%.c
        gcc -c $^ -o $@

结果在Terminal界面显示的结果为:

[root@host makefile]# vim Makefile 
[root@host makefile]# make
gcc -c main.c -o main.o
gcc -c plus.c -o plus.o
gcc -c minus.c -o minus.o
gcc -c multi.c -o multi.o
gcc -c divi.c -o divi.o
gcc main.o plus.o minus.o multi.o divi.o -o myapp
[root@host makefile]# ls
divi.c  divi.o  include  main.c  main.o  Makefile  minus.c  minus.o  multi.c  multi.o  myapp  plus.c  plus.o

关于通配符* %之间的区别与联系:“%”的意思是匹配零或若干字符,例如,“%.h”表示所有以“.h”结尾的文件.它是在GUNmake的语法层次上的,例如 vpath %.h …/headers ,该语句表示,要求make在“…/headers”目录下搜索所有以“.h”结尾的文件.
*是Shell所支持的通配符,是在shell的语法层次上,*.c,一般用在shell命令里面,如:

clean:
rm -f *.o

另重复以上的通配符:
$@:目标的名字
$^:构造所需文件列表所有所有文件的名字
$<:构造所需文件列表的第一个文件的名字
$?:构造所需文件列表中更新过的文件

@’ 符号的使用
通常makefile会将其执行的命令行在执行前输出到屏幕上。如果将‘@’添加到命令行前,这个命令将不被make回显出来。
@echo --compiling module----; // 屏幕输出 --compiling module----
echo --compiling module----; // 没有@ 屏幕输出echo --compiling module----

- ’ 符号的使用
通常删除,创建文件如果碰到文件不存在或者已经创建,那么希望忽略掉这个错误,继续执行,就可以在命令前面添加 -,

 -rm dir;
 -mkdir aaadir;

'$'符号的使用
美元符号$,主要扩展打开makefile中定义的变量

'$$'符号的使用
$$ 符号主要扩展打开makefile中定义的shell变量

4.makefile 函数的使用

wildcard 函数查找:
找到所有的.c文件 放到SOURCE变量里面

SOURCE=$(wildcard *.c)

找到所有.o文件, 可以用上面的复制把c换成o,也可以直接把上面的代码替换.
patsubst 函数替换

   SOURCES=$(wildcard *.c)
   OBJECTS=$(patsubst %.c %.o,$(SOURCES)

后面和上面 的类似. 最后用@echo 打印下

SOURCES=$(wildcard *.c)
OBJECTS=$(patsubst %.c,%.o,$(SOURCES))
myapp:$(OBJECTS)
        gcc $^ -o $@
%o:%c
        gcc -c $^ -o $@
        @echo $(OBJECTS)

常见的Makefile函数见此链接
https://www.cnblogs.com/edver/p/7229792.html

5. = 之间的区别

= :最基本的赋值
:= :覆盖之前的值
?= :如果没有被赋值过就赋予等号后面的值
+= :在末尾添加等号后面的值

关于“=”

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 了。

6. Makefile的编译语法

config/configure/Configure

这个是用来检测你的安装平台的目标特征的。比如它会检测你是不是有CC或GCC,并不是需要CC或GCC,它是个shell脚本
这一步一般用来生成 Makefile,为下一步的编译做准备,你可以通过在 configure 后加上参数来对安装进行控制,比如:
./configure --prefix=/usr
上面的意思是将该软件安装在 /usr 下面
执行文件就会安装在 /usr/bin (而不是默认的 /usr/local/bin)
资源文件就会安装在 /usr/share(而不是默认的/usr/local/share)
同时一些软件的配置文件你可以通过指定 --sys-config= 参数进行设定
还有诸如:–with、–enable、–without、–disable 等等参数对编译加以控制,你可以通过 ./configure --help 察看详细的说明帮助

make

这一步是用来编译的,它从Makefile中读取指令,然后编译
这一步就是编译,大多数的源代码包都经过这一步进行编译
当然有些perl或python编写的软件需要调用perl或python来进行编译
如果 在 make 过程中出现 error ,你就要记下错误代码(注意不仅仅是最后一行),然后你可以向开发者提交 bugreport(一般在 INSTALL 里有提交地址),或者你的系统少了一些依赖库等,这些需要自己仔细研究错误代码

make test / make check

顾名思义,这一步就是对上一步 make 的检查了,要确保 make 是没有错误的,也就是这一步的 test、check要全部是 OK 的,error 为0

sudo make install

这一步是用来安装的,它也从Makefile中读取指令,安装到指定的位置
这条命令来进行安装,一般需要你有 root 权限(因为要向系统写入文件),所以前面用了 sudo

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值