第五课目录

  • GCC用法参考
    • GCC的常用用法
  • make与Makefile
    • Makefile的规则
    • Makefile的语法
    • Makefile实例
  • 调试
    • GDB
    • 设置断点

虽然已经有很多优秀的IDE可以化简开发任务,但在面对从底层到外壳的系统构建任务时,基于Linux的传统开发模式可以让过程更透明,让开发者能够彻底把控开发的每一步,所以了解GCC,make,GDB三个工具是必要的

GCC用法参考

GCC是GNU开发的编程语言套件(GNU Compiler Collection),在默认情况下ubuntu不会提供C/C++的编译环境,ubuntu提供了build-essential包可以一次性把相关软件安装好:

sudo apt install build-essential
apt depends build-essential #查看哪些包被build-essential依赖

一个C语言程序的运行准备工作:
源程序通过GCC编译为汇编程序,汇编程序进一步编译到输出文件(Linux下为*.o,Windows下为*.obj),输出文件通过链接器连接得到可执行文件,加载到内存运行;


当文件过多时,一个一个进行gcc编译很麻烦,所以会借助makefile构建工程,帮助开发者组织程序


现在已经新建了一个C程序hello.c:
下一步借助工具gcc进行编译链接得到可执行文件a.out:

gcc hello.c
./a.out #执行a.out文件

GCC的常用用法

通过对常用用法的举例,实际体会文件运行的过程;
1.源程序预处理
依然是对hello.c文件进行编译,通过-E参数进行预处理,-o参数指定输出文件名:

gcc -E -o hello.cpp hello.c

借助vi打开hello.cpp发现:
hello.c中的内容在预处理文件的最后,前面都是新载入的预处理语句;
2.编译到汇编文件
将预处理后的hello.cpp编译到汇编文件hello.s:

gcc -x cpp-output -S -o hello.s hello.cpp

如果要直接将C源程序编译到汇编文件dihello.s则可以:

gcc -S -o dihello.s hello.c

3.将汇编程序编译到机器码
现在将汇编程序编译到机器码:

gcc -x assembler -c hello.s -o hello.o
#直接利用源程序编译到机器码
gcc -c hello.c -o hello.o

用vi打开机器码观察到:
虽然已经是机器码,但依然不能执行,因为还没有经过链接,所以机器依然不知道这个机器码文件想要发出什么指令;
4.链接生成可执行文件
通过gcc可以直接自动链接到库,生成可执行文件:

gcc -o hello hello.o
#也可以直接从源程序到可执行文件
gcc -o hello hello.c#执行
./hello

make与Makefile

make是一个命令工具,是一个解释Makefile中指令的工具,一般来说,大多数IDE都有这个命令,比如:Linux下GNU的make,Visual C++的nmake;
make命令执行时,需要一个Makefile文件,用以告诉make命令需要如何编译和链接程序;
Makefile被称为工程文件,每个工程都有工程文件,工程文件的作用:

  • 如果这个工程没有编译过,所有的C文件都将被编译并链接;
  • 如果这个工程只是某几个C文件被修改,则只需编译被修改的C文件;
  • 如果头文件被修改了,则只需编译引用到该头文件的C文件;

可以看出,基于make,大幅度节约了构建工程的时间;

Makefile的规则

makefile的格式为:

<target>:<prerequisites>
[tab]<commands> #任意的shell命令

makefile是shell脚本的进一步封装,专用于工程构建;
makefile如何工作
1.make会在当前目录下找名字叫"Makefile"或"makefile"的文件;
2.如果make命令运行时没有指定目标,默认会执行Makefile文件的第一个目标,第一个目标习惯写为all;
3.make会一层一层找目标的依赖关系;
4.目标的前置依赖都执行完毕后,执行该目标下的<commands>;
假设当前目录下有几个头文件.h,几个C源文件.c,一个文件makefile,一个README.md,一个LICENSE,在当前目录执行make能够自动对文件编译并链接再输出可执行文件;
目标target
一个目标构成一条规则,目标通常是文件名,指明make命令要构建的对象,目标可以是一个文件名,也可以是多个文件名,之间用空格分隔;
目标还可以是某个操作的名字,这称为"伪目标"(phony target),比如clean,如果当前目录中,正好有一个文件叫clean,那么这个目标不会执行。因为make发现clean文件已经存在,就认为没有必要重新构建,从而不会执行clean"伪目标",为了避免这种情况,可以明确声明clean是"伪目标":".PHONY:clean"
前置条件prerequisites
前置条件通常是一组文件名,之间用空格分隔,前置条件决定了目标是否需要重新构建:只要有一个前置文件不存在,或者有过更新(根据时间戳判断),"目标"就需要重新构建
命令commands
命令表示如何更新目标文件,由一行或多行shell命令组成,它是构建目标的具体指令,它的运行结果通常就是生成目标文件;
每行命令之前必须有一个tab键,如果想用其他键,可以用内置变量.RECIPEPREFIX声明。用.RECIPEPREFIX指定大于号>替代tab键:

.RECIPEPREFIX = >

需要注意的是,每行命令在一个单独的shell中执行,这些shell之间没有继承关系,即孤立的命令;


这是文件的依赖关系,target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在command中


Makefile的语法

1.makefile中用#表示注释;
2.正常情况下,make会打印每条命令,然后再执行,这叫回声(echoing),在命令前加上@,可以关闭回声;
3.通配符(wildcard)用来指定一组符合条件的文件名,makefile的通配符与Bash一致,主要有*?等,比如*.o表示所有后缀名为o的文件;
模式匹配
make命令允许对文件名进行正则运算匹配,主要用到的匹配符号是%,假设当前目录下有f1.c和f2.c两个文件,需要将其编译为输出文件,则可简写为%.c:%.o
基于通配符%,可以将大量同类型文件使用一条规则完成构建;
变量和赋值
1.使用等号自定义变量,调用时需写在$()中:

txt = Hello
echo $(txt)

2.调用shell变量,需要在美元符号前,再加一个美元符号(因为make命令会对美元符号转义):

echo $$HOME

3.变量的值可能指向另一个变量,例如v1 = $(v2)
赋值运算符

VARIABLE = value #执行时扩展
VARIABLE := value #定义时扩展
VARIABLE ?= value #变量为空时才设置值
VARIABLE += value #将值追加到变量的尾部

内置变量Implicit Variables
make命令提供了一系列的内置变量,主要是为了跨平台的兼容;
$(CC)指向当前使用的编译器,$(MAKE)指向当前使用的make工具;
自动变量Automatic Variables

$@ 指代当前目标,即make命令当前构建的目标
$< 指代第一个前置条件
$? 指代比目标更新的所有前置条件,之间用空格分隔
$^ 指代所有前置条件,之间用空格分隔
$(@D)和$(@F) 分别指向$@的目录名和文件名
$(<D)和$(<F) 分别指向$<的目录名和文件名

判断和循环
Makefile使用Bash语法完成循环和判断:

#判断
ifeq ($(CC),gcc)libs=$(libs_for_gcc)
elselibs=$(normal_libs)
endif#循环
LIST = one two three
all:for i in $(LIST); doecho $$i;done

函数
makefile也可以使用函数,格式为:

$(function arguments)
#或者
${function arguments}

Makefile实例

假设现在有一个Makefile文件:

#cleanall cleanobj cleandiff均不是文件
#如果目录下有例如cleanobj的文件,将不会构建目标cleanobj
#为了避免这一现象,可以用.PHONY声明是伪目标
.PHONY:cleanall cleanobj cleandiffcleanall : cleanobj cleandiffrm programcleanobj : rm *.ocleandiff :rm *.diff

前面已经提到,make指令依据Makefile的描述去执行工程构建的操作,现在目录下有文件:
如果执行:

make cleanobj

会选择出输出文件*.o,并删除;
如果执行:

make cleanall

根据回声echoing看出:
执行顺序是深度优先搜索,先执行前置条件,再执行目标;
如果只输入指令make,会默认执行第一个目标

调试

原始的调试是在源码中插入printf逐步打印变量状态,后来出现了专用的调试工具GDB,将程序装载到GDB下更方便进行调试

GDB

GDB:GNU project Debugger;在开始调试前,必须用程序中的调试信息编译要调试的程序,GDB才能调试所使用的变量,函数;首先,使用gcc -g编译得到程序,参数-g会附加符号信息用于调试:

gcc -g -o hello hello.c

在shell中,可以使用gdb命令并指定程序名参数运行gdb:

gdb hello
程序装入gdb后可以运行
run

或者在gdb中,使用file命令调试:

file hello

如果一切正常,程序将执行到结束,如果出错,gdb会中断程序,让开发者检查变量状态;
退出gdb:

quit

设置断点

可以在源码的某一行设置断点,gdb会在遇到断点时中断执行:

gdb hello #将hello.c编译后的程序hello载入gdb
break main #在main函数行设置断点
break 6 #在源码hello.c第6行设置断点
next #单步执行,子函数作为一步
step #单步执行,具体到子函数的每一语句
info break #列出当前设置的所有断点

back trace可以查看函数调用的层级:

bt

第五课.Linux开发基础相关推荐

  1. 假设linux分配给u盘设备名是,嵌入式linux开发基础试卷-应用物理A答案

    试 卷 考试科目: 嵌入式 linux 开发基础 姓名: 试卷适用专业(班) : 09 应用物理 套别:A 套(√)B 套( ) 五 20 六 七 总计 100 考核方式:开卷( )闭卷(√) 了多达 ...

  2. 视频教程-嵌入式Linux开发基础-嵌入式

    嵌入式Linux开发基础 嵌入式工程师.嵌入式讲师.10多年嵌入式开发实战经验,6年专业嵌入式课程培训经验.主要研究方向是嵌入式Linux系统应用和物联网技术应用.先后参与过武警边防音视频矩阵切换系统 ...

  3. 北京linux嵌入式培训,北京嵌入式培训上嵌Linux开发基础和嵌入式C语言初级编程总结...

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 说到学习Linux开发基础,有一样是不得不说,而且Llinux系统中最常用也最有用的东西,那就是各种命令.虽然Linux桌面应用发展很快,但是命 令在Li ...

  4. 第五模块·WEB开发基础-第2章JavaScript基础

    第1章 JavaScript基础 01-JavaScript历史介绍 02-JavaScript的组成 03-JavaScript的引入方式 04-变量的使用 05-基本数据类型(一) 06-基本数据 ...

  5. TurboLinux入门教程:第六课Linux与其他操作系统的区别(转)

    TurboLinux入门教程:第六课Linux与其他操作系统的区别(转) 第六课 Linux 与其他操作系统的区别 目前运行在 PC 机上的操作系统主要有 Microsoft 的 MS-DOS . W ...

  6. 网易云课堂Web安全工程师课程分享——第二章 Web开发基础知识

    第一节 前端开发基础--HTML 课程回顾 Web页面通常使用哪几种语言开发? HTML结构包含哪两部分? HTML元素由哪几部分组成? 常见的HTML标签有哪些? HTML DOM是什么结构? 总结 ...

  7. 嵌入式设备开发专题《tiny4412开发,嵌入式linux开发环境搭建》

    嵌入式linux开发基础: 1.系统组成: 嵌入式linux系统的组成包括三部分:bootloader程序.linux内核.根文件系统 bootloader程序:系统上电后首先要执行的程序,主要功能是 ...

  8. 列表怎么有限的初始化为零_《零基础学习Android开发》第五课 类与面向对象编程1-1...

    视频:<零基础学习Android开发>第五课 类与面向对象编程1-1 类的定义.成员变量.构造方法.成员方法 一.从数据与逻辑相互关系审视代码 通过前面的课程,我们不断接触Java语言的知 ...

  9. 【Linux探索之旅】第二部分第五课:用户和权限,有权就任性

    内容简单介绍 1.第二部分第五课:用户和权限,有权就任性 2.第二部分第六课预告:Nano,刚開始学习的人的文本编辑器 用户和权限.有权就任性 今天的标题也挺任性的啊,虽说小编是一个非常本分的人(真的 ...

最新文章

  1. shell中三种引号的区别
  2. RecyclerView(滚动控件)的用法
  3. 使用Apriori进行关联分析(二)
  4. C++primer第九章 顺序容器 9.1 顺序容器概述 9.2容器库概览
  5. Flutter实战一Flutter聊天应用(十)
  6. NGFF、M.2、PCIe、NVMe概念区分以及PCIEx1 x4 x8 x16区别
  7. 视频剪辑怎么学?五大经验分享,入门可参考
  8. noip2018提高组广东省成绩
  9. Unity 接入天气系统
  10. 棋牌游戏开发之地主算法判断牌型
  11. 简易酒店管理系统(c++)
  12. response.sendError() 和 response.setStatus()的区别
  13. C++ 强制类型转换操作符(static_cast、dynamic_cast、const_cast和reinterpret_cast)
  14. tkinter显示图片
  15. 手把手交你安装配置sumo(解决netedit.exe打不开.xml文件)
  16. 分享3个CPU跑分数据库查询,AMD Inter cpu各项分数查询
  17. 笔记:视音频基础6——视频基础
  18. 考研经验帖 西南交通大学
  19. 威纶触摸屏在easybuilder pro中如何添加棒图元件?
  20. shell wc -l

热门文章

  1. 缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级
  2. 极客新闻——04、WiFi万能钥匙万玉权:管理应该是“自下而上”
  3. 我们用了两年的敏捷开发工具
  4. 某大厂程序员吐槽:在北京当码农,不敢结婚不敢生娃,真是注孤生!
  5. 高并发服务优化篇:从RPC预热转发看服务端性能调优
  6. 负载均衡续:万亿流量场景下的负载均衡实践
  7. 【Redis】缓存的三大问题及其解决方案
  8. Redis系列(七):缓存只是读写回种这么简单吗?如果是,那么请你一定看看这篇文章!...
  9. 详细!看看顶级互联网公司都在研究的无服务器架构!
  10. Leangoo背景更新-看板背景任你选!!!