Linux学习-用 make 进行宏编译
为什么要用 make
先来想象一个案例,假设我的执行档里面包含了四个原始码文件,分别是 main.c haha.c sin_value.c cos_value.c 这四个文件,这四个文件的目的是:
- main.c :主要的目的是让用户输入角度数据与呼叫其他三支子程序
- haha.c :输出一堆有的没有的讯息而已;
- sin_value.c :计算使用者输入的角度(360) sin 数值;
- cos_value.c :计算使用者输入的角度(360) cos 数值。
# 1. 先进行目标文件的编译,最终会有四个 *.o 的档名出现:
[root@study ~]# gcc -c main.c
[root@study ~]# gcc -c haha.c
[root@study ~]# gcc -c sin_value.c
[root@study ~]# gcc -c cos_value.c
# 2. 再进行连结成为执行档,并加入 libm 的数学函式,以产生 main 执行档:
[root@study ~]# gcc -o main main.o haha.o sin_value.o cos_value.o -lm
# 3. 本程序的执行结果,必须输入姓名、360 度角的角度值来计算
[root@study ~]# ./main
Please input your name: VBird <==这里先输入名字
Please enter the degree angle (ex> 90): 30 <==输入以 360 度角为主的角度
Hi, Dear VBird, nice to meet you. <==这三行为输出的结果喔!
The Sin is: 0.50
The Cos is: 0.87
编译的过程需要进行好多动作啊!而且如果要重新编译,则上述的流程得要重新来一遍,光是找出这 些指令就够烦人的了! 如果可以的话,能不能一个步骤就给他完成上面所有的动作呢?那就利用 make 这个工具吧! 先试看看在这个目录下建立一个名为 makefile 的文件,内容如下:
# 1. 先编辑 makefile 这个规则文件,内容只要作出 main 这个执行档
[root@study ~]# vim makefile
main: main.o haha.o sin_value.o cos_value.o
gcc -o main main.o haha.o sin_value.o cos_value.o -lm
# 注意:第二行的 gcc 之前是 <tab> 按键产生的空格喔!
# 2. 尝试使用 makefile 制订的规则进行编译的行为:
[root@study ~]# rm -f main *.o <==先将之前的目标文件去除
[root@study ~]# make
cc -c -o main.o main.c
cc -c -o haha.o haha.c
cc -c -o sin_value.o sin_value.c
cc -c -o cos_value.o cos_value.c
gcc -o main main.o haha.o sin_value.o cos_value.o -lm
# 此时 make 会去读取 makefile 的内容,并根据内容直接去给他编译相关的文件啰!
# 3. 在不删除任何文件的情况下,重新执行一次编译的动作:
[root@study ~]# make
make: `main' is up to date.
# 看到了吧!是否很方便呢!只会进行更新 (update) 的动作而已。
或许你会说:『如果我建立一个 shell script 来将上面的所有动作都集结在一起,不是具有同样的效 果吗?』效果当然不一样,以上面的测试为例,我们仅写出 main 需要的目标文件,结果 make会主动的去判断每个目标文件相关的原始码文件,并直接予以编译,最后再直接进行连结的动作!真 的是很方便啊!此外,如果我们更动过某些原始码文件,则 make 也可以主动的判断哪一个原始码 与相关的目标文件文件有更新过, 并仅更新该文件,如此一来,将可大大的节省很多编译的时间呢!所以说, make 有这些好处:
- 简化编译时所需要下达的指令;
- 若在编译完成之后,修改了某个原始码文件,则 make 仅会针对被修改了的文件进行编译,其他的 object file不会被更动;
- 最后可以依照相依性来更新 (update) 执行档。
既然 make 有这么多的优点,那么我们当然就得好好的了解一下 make 这个令人关心的家伙啦!而 make 里面最需要注意的大概就是那个规则文件,也就是 makefile 这个文件的语法啦!所以底下我 们就针对 makefile 的语法来加以介绍啰。
makefile 的基本语法与变量
make 的语法可是相当的多而复杂的,这里 仅列出一些基本的规则,基本的 makefile 规则是这样的:
目标(target): 目标文件 1 目标文件 2
<tab> gcc -o 欲建立的执行文件 目标文件 1 目标文件 2
那个目标 (target) 就是我们想要建立的信息,而目标文件就是具有相关性的 object files ,那建立执 行文件的语法就是以 按键开头的那一行!特别给他留意喔,『命令行必须要以 tab 按键作为
开头』才行!他的规则基本上是这样的:
- 在 makefile 当中的 # 代表批注;
- 需要在命令行 (例如 gcc 这个编译程序指令) 的第一个字符;
- 目标 (target) 与相依文件(就是目标文件)之间需以『:』隔开。
同样的,我们以刚刚上一个小节的范例进一步说明,如果我想要有两个以上的执行动作时, 例如下 达一个指令就直接清除掉所有的目标文件与执行文件,该如何制作呢?
# 1. 先编辑 makefile 来建立新的规则,此规则的目标名称为 clean :
[root@study ~]# vi makefile
[root@study ~]# vi makefile
main: main.o haha.o sin_value.o cos_value.o
gcc -o main main.o haha.o sin_value.o cos_value.o -lm
clean:
rm -f main main.o haha.o sin_value.o cos_value.o
# 2. 以新的目标 (clean) 测试看看执行 make 的结果:
[root@study ~]# make clean <==就是这里!透过 make 以 clean 为目标
rm -rf main main.o haha.o sin_value.o cos_value.o
如此一来,我们的 makefile 里面就具有至少两个目标,分别是 main 与 clean ,如果我们想要建立 main 的话,输入『make main』,如果想要清除有的没的,输入『make clean』即可啊!而如果想要 先清除目标文件再编译 main 这个程序的话,就可以这样输入:『make clean main』,如下所示:
[root@study ~]# make clean main
rm -rf main main.o haha.o sin_value.o cos_value.o
cc -c -o main.o main.c
cc -c -o haha.o haha.c
cc -c -o sin_value.o sin_value.c
cc -c -o cos_value.o cos_value.c
gcc -o main main.o haha.o sin_value.o cos_value.o -lm
这样就很清楚了吧!但是,你是否会觉得,咦! makefile 里面怎么重复的数据这么多啊!没错!所 以我们可以再藉由 shell script 那时学到的『变数』来更简化 makefile 喔:
[root@study ~]# vi makefile
LIBS = -lm
OBJS = main.o haha.o sin_value.o cos_value.o
main: ${OBJS}
gcc -o main ${OBJS} ${LIBS}
clean:
rm -f main ${OBJS}
与 bash shell script 的语法有点不太相同,变量的基本语法为:
- 变量与变量内容以『=』隔开,同时两边可以具有空格;
- 变量左边不可以有 ,例如上面范例的第一行 LIBS 左边不可以是 ;
- 变量与变量内容在『=』两边不能具有『:』;
- 在习惯上,变数最好是以『大写字母』为主;
- 运用变量时,以 ${变量} 或 $(变量) 使用;
- 在该 shell 的环境变量是可以被套用的,例如提到的 CFLAGS 这个变数!
- 在指令列模式也可以给予变量。
由于gcc 在进行编译的行为时,会主动的去读取 CFLAGS 这个环境变量,所以,你可以直接在 shell 定义出这个环境变量,也可以在 makefile 文件里面去定义,更可以在指令列当中给予这个咚咚呢! 例如:
[root@study ~]# CFLAGS="-Wall" make clean main
# 这个动作在上 make 进行编译时,会去取用 CFLAGS 的变量内容!
也可以这样:
[root@study ~]# vi makefile
LIBS = -lm
OBJS = main.o haha.o sin_value.o cos_value.o
CFLAGS = -Wall
main: ${OBJS}
gcc -o main ${OBJS} ${LIBS}
clean:
rm -f main ${OBJS}
我可以利用指令列进行环境变量的输入,也可以在文件内直接指定环境变量,那万一这个 CFLAGS 的内容在指令列与 makefile 里面并不相同时,以那个方式输入的为主?呵呵!问了个好问 题啊! 环境变量取用的规则是这样的:
- make 指令列后面加上的环境变量为优先;
- makefile 里面指定的环境变量第二;
- shell 原本具有的环境变量第三。
此外,还有一些特殊的变量需要了解的喔:
- $@:代表目前的目标(target)
所以也可以将 makefile 改成:
[root@study ~]# vi makefile
LIBS = -lm
OBJS = main.o haha.o sin_value.o cos_value.o
CFLAGS = -Wall
main: ${OBJS}
gcc -o $@ ${OBJS} ${LIBS} <==那个 $@ 就是 main !
clean:
rm -f main ${OBJS}
Linux学习-用 make 进行宏编译的更多相关文章
- Linux学习-以最新核心版本编译 CentOS 7.x 的核心
为了某些缘故需要最新的 4.x.y 的核心版本来实作某些特定的功能时,那该 如何是好?没办法,只好使用最新的核心版本来编译你可以依照上面的程序来一个一个处理, 没有问题~不过,你也可以根据 ELRep ...
- Linux学习-额外(单一)核心模块编译
编译前注意事项 由于我们的核心原本就有提供很多的核心工具给硬件开发商来使用, 而硬件开发商也需要针对核心 所提供的功能来设计他们的驱动程序模块,因此, 我们如果想要自行使用硬件开发商所提供的模块 来进 ...
- 【Linux学习】Ubuntu下内核编译(一)
(1)当要运行内核配置时,输入make menuconfig时出现错误 遇到这个问题,主要是以为没有ncurses库,而make menconfig 须要这个库.因此须要安装ncurses或者ncur ...
- Linux学习系列八:操作网口
一些相对高性能的单片机会带以太网接口,网口在MCU里算是比较复杂的外设了,因为它涉及到网络协议栈,通常情况下网络协议栈会运行在一个RTOS中,所以对普通单片机开发者来说网口使用起来相对难度较大一些.在 ...
- #define中 #与##的神奇用法linux学习 (转)
#define中 #与##的神奇用法linux学习 (转) #define f(a,b) a##b #define d(a) #a #define s(a) d(a) void main( void ...
- linux学习书籍推荐《鸟哥的Linux私房菜》下载
下载地址:点我 <鸟哥的Linux私房菜:基础学习篇>是具有知名度的Linux入门书<鸟哥的Linux私房菜基础学习篇>的最新版,全面而详细地介绍了Linux操作系统.< ...
- Linux 学习笔记
Linux学习笔记 请切换web视图查看,表格比较大,方法:视图>>web板式视图 博客园不能粘贴图片吗 http://wenku.baidu.com/view/bda1c3067fd53 ...
- Linux学习心得之 Linux下命令行Android开发环境的搭建
作者:枫雪庭 出处:http://www.cnblogs.com/FengXueTing-px/ 欢迎转载 Linux学习心得之 Linux下命令行Android开发环境的搭建 1. 前言2. Jav ...
- Linux学习心得之 Linux下ant安装与使用
作者:枫雪庭 出处:http://www.cnblogs.com/FengXueTing-px/ 欢迎转载 Linux学习心得之 Linux下ant安装与使用 1. 前言2. ant安装3. 简单的a ...
随机推荐
- OpenCV图像处理之 Mat 介绍
我记得开始接触OpenCV就是因为一个算法里面需要2维动态数组,那时候看core这部分也算是走马观花吧,随着使用的增多,对Mat这个结构越来越喜爱,也觉得有必要温故而知新,于是这次再看看Mat. Ma ...
- Unity Log重新定向
Unity Log重新定向 使用Unity的Log的时候有时候需要封装一下Debug.Log(message),可以屏蔽Log或者把log内容写到文本中.通过把文本内容传送到服务器中,查找bug出现的 ...
- To the world you may be one person, but to one person you may be the world.
To the world you may be one person, but to one person you may be the world.对于世界而言,你是一个人:但对于某人而言,你是他的 ...
- Appium基础二:Appium的安装(基Windows)
1.JAVA环境配置: 1.1安装jdk: 1.2配置JAVA_Home.Path配置.java验证 Path: 输入C:\Program Files\Java\jdk1.8.0_121\bin:C: ...
- ArcGIS Server 10.1发布GP服务
ArcGIS Server 10.1发布GP服务 ArcGIS Server 10.1发布GP服务确实更简单了,只是刚使用不怎么习惯.ArcGIS Server 10.1发布GP服务需要先在ArcCa ...
- 网站安全webshell扫描
做个记录,使用Detector进行php网站webshell扫描 开源项目托管地址:https://github.com/emposha/PHP-Shell-Detector安装使用都很简单
- 重温Javascript(一)-基本概念
工作中要用到JavaScript,一组复习笔记. 一些看法 1. 想想JavaScript目前最常用的宿主环境,浏览器或者服务端V8,都是单线程,所以不用过多的考虑并发的问题,如果是协程来实现异步的方 ...
- .net代码获取节点以及读取属性
获取配置文件的节点,可以使用System.Configuration.ConfigurationManager.GetSection方法获取指定的节点,以sessionstate节点为例,如果需要获取 ...
- 【UML】协作图Collaboration diagram(交互图)(转)
http://blog.csdn.net/sds15732622190/article/details/49402269 前言 学完UML时序图,就要看一下UML协作图,因为两张图是相 ...
- 设置DataGridView单元格的文本对齐方式
实现效果: 知识运用: DataGridViewCellStyle类的Alignment属性 //获取或设置DataGridView单元格内的单元格内容的位置 public DataGridV ...