Linux命令【三】gcc编译+静态库+动态库+makefile+gdb调试

用C编译器编译源文件:gcc 源文件 -o 可执行文件名
详细步骤:

  • gcc -E a.c -o a.i预处理器将头文件展开,宏替换,去掉注释
  • gcc -S a.i -o a.s编译器将C文件变成汇编文件
  • gcc -c a.s -o a.o汇编器将会变文件变成二进制文件
  • gcc a.o -o a链接器进行链接

ESc+链接
如果不使用参数-o 则自动生成a.out

制定头文件的路径gcc a.c -I 头文件的目录 -o 生成可执行文件的名字在比较旧的版本上-I和头文件目录之间不能有空格,现版本无所谓
指定宏-D 宏名
优化-O1/O2/O3O3优化速度最高
输出警告信息-Wall
生成调试信息-g

静态库

  1. 命名规则
    lib+库的名字+.a
  2. 制作步骤
    生成对应的.o文件,直接使用参数-c得到.o文件,记得不要使用-o参数,否则将会直接生成可执行文件
    将生成的.o文件进行打包,需要使用软件ar.o打包为.a
ar rcs 静态库名称 所有的.o
  1. 发布和使用静态库
    打包静态库和头文件,将所有的静态库放到lib文件夹中,将所有的头文件放到include文件夹中,制作好静态库以后可以发送这两个文件夹。
    用户通过头文件知道有哪些函数接口。通过直接和源文件编译静态库使用。
gcc 源文件 静态库 -o 可执行文件 -Iinclude
gcc 源文件 -Iinclude -L lib -l 静态库文件名(去掉头部lib和尾部.a) -o 可执行文件
  1. 静态库的优缺点
nm 静态库文件 //查看静态库

打包的最小单元为.o
优点:

  1. 库已经打包在程序中,不需要再提供
  2. 库的加载速度比较快
    缺点:
  3. 可执行文件会比较大
  4. 如果库发生了改变需要重新编译

动态库/共享库

  1. 命名规则
    lib+名字+.so
  2. 制作步骤
    (1) 生成与位置无关的代码(.o)
gcc -fPIC -c *.c -Iinlcude

(2) 将.o打包成共享库
Linux每一个运行的程序操作系统都会为其分配一个0-4G的地址空间。Linux下可执行文件格式:ELF

gcc -shared -o libname.so *.o -Iinclude 

再讲lib中的.so文件和include中的头文件发送给用户

  1. 用户使用
gcc main.c lib/libname.so -o main -Iinclude
gcc main.c -Iinclude -L lib -l name -o main//需要注意的是这里的name是不包含lib和后缀.so的

使用ldd查看可执行文件所依赖的所有的共享库的名字

动态库的使用需要动态链接器帮助。我们需要让动态链接器找到我们自己的动态链接库

正常情况下使用会出现动态库无法找到的问题。然后就需要我们去解决。
可是我自己尝试的时候没有遇到这个情况。。。我也不清楚为什么,可能是现在版本的gcc已经智能地解决这个问题了。

(1)将动态库放到系统的lib文件夹中
(2) 配置环境变量LD_LIBRARY_PATH(如果你的动态库没有在默认的环境变量中,会先在这个环境变量中查找)
用于临时测试

echo $LD_LIBRARY_PATH //$从环境变量中取值  查看环境变量
export LD_LIBRARY_PATH=./lib //将当前目录下的lib文件夹导入到环境变量中

关掉终端后失效
(3)

ls -a
vi .bashrc
在里面加上export LD_LIBRARY_PATH=动态库目录
重启终端

永久
(4)工作中更加常用的方法

  • 找到动态链接器的配置文件
    /etc/ld.so.conf
    需要使用管理员权限

  • 将动态库的路径写到配置文件中

  • 更新sudo ldconfig -v -v是提示信息

动态库没有加载到源文件中,而是在需要使用的位置加上了一个标记,在使用的时候才进行访问。
优点:

  1. 执行程序很小
  2. 动态库更新方便
    缺点:
  3. 需要将动态库发布给用户
  4. 加载库的时候速度较慢

gdb 调试

  • l 默认展示包含main()的文件
  • l 文件名:行号 展示以行号为中心上下文件的内容
  • l 文件名:函数名 展示文件中的函数,输入l继续展示后面的内容,然后后面再直接按回车,会继续向下展示文件,一次展示10行
  • break 行号在某一行打断点b 行号
  • b 行号 if 条件条件断点,条件断点只能设置在循环内部,如果设置在边界不会停止
  • b filename:行号在某个文件的某一行设置断点
  • info break i b查看断点信息
  • start gdb开始运行程序,每次运行一行,n单步调试,c继续执行到断点
  • s下一步,会进入函数体内部(step)
  • n下一步,不会进入函数内部
  • run直接运行到断点,如果没有断点直接运行结束
  • p 变量 展示某个变量的值
  • ptype 变量 展示变量的类型
  • display 变量追踪某个变量的值
  • undisplay 变量编号取消追踪某个变量
  • info display 打印所有追踪变量的信息
  • u将循环运行结束,结束循环
  • finish 跳出当前函数,需要将函数中的断点消除
  • d 断点编号删除断点(del)
  • set var 变量=x直接运行到变量为x的时候
  • quit退出gdb

makefile

makefile项目管理工具,用于管理源代码

简单makefile文件

  1. 命名规则
    (1) makefile
    (2) Makefile

  2. 编写规则
    makefile 一般情况下要和.c文件在一个文件夹中,如果不在需要绝对路径
    三要素:

目标:依赖 		//目标就是想要生成文件的名字  依赖:`.c`文件命令(必须要有Tab缩进):gcc a.c b.c c.c -o 目标
  1. 使用
    make

进阶makefile文件

当一些文件修改以后需要重新编译,为了解决这个问题:
例如:

app:main.o add.o sub.o mul.o		//终极目标,默认第一条语句是终极目标gcc main.o add.o sub.o mul.o -o app
//如果依赖中的文件没有发现,就去下面的子目标中查找有没有相关的规则用于生成文件
main.o:main.c gcc main.c -c
add.o:add.cgcc add.c -c
sub.o:sub.cgcc sub.c -c
mul.o:mul.cgcc mul.c -c

上面的写法会自动查找文件是否修改,如果没有修改就不会编译,从而提高效率
工作原理:通过比较修改时间,目标应该比依赖的修改时间迟,如果发现目标比依赖的修改时间早则重新生成目标。

进进阶makefile文件

上面的写法有些冗余,通过变量来将写法变得简洁

obj=main.o add.o sub.o mul.o
target=app
$(target):$(obj)	//$取obj变量中的值gcc $^ -o $@
//模式规则
%.o:%.cgcc -c $< -o &@	

makefile中的自动变量:

  • $<规则中的第一个依赖
  • $@规则中的目标
  • $^规则中的所有依赖
  • 只能够在规则中的命令来使用
    makefile自己维护的变量:
  • 都是大写,例如CC,CPPFLAGS,CFLAGS,LDFLAGS

进进进阶makefile文件

在makefile中的函数都是有返回值的

  • 获取指定目录下所有的.c文件
src=$(wildcard 所需要查找的目录/*.c)
  • 获取指定目录下所有的.o文件
obj=$(patsubst ./%.c , ./%.o , $(src))		#模式匹配
  • 自动删除以前生成的目标文件
clean:rm $(target) -f	#如果不存在也会强制删除,不会弹出提示信息

生成文件 时候:

make clean   #会删除目标文件,只会执行生成clean的语句

如果目录中真的存在clean目标,则会提示目标是最新的而不会运行。

.PHONY:clean  #声明clean为伪目标,不会与目录中的目标进行比较

在命令前面加上-,则命令执行失败以后也不会停下来,继续向后执行

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/383725.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用c++模拟实现一个学生成绩管理系统

https://blog.csdn.net/yanxiaolx/article/details/53393437题目&#xff1a;用c模拟实现一个学生成绩的信息管理系统&#xff0c;要求能添加、删除、修改、查看和保存学生的信息等功能 源代码如下:[cpp] view plaincopy#define _CRT_SECURE_NO_WARNINGS #include<iostr…

Linux命令【四】文件+虚拟内存+常用系统函数

File*其实是一个结构体 文件描述符FD&#xff1a;索引到对应的磁盘文件文件读写位置指针FP_POS&#xff0c;如果同时读写需要注意文件指针的位置I/O缓冲区BUFFER&#xff1a;保存内存指针&#xff0c;默认大小是8kb&#xff0c;用于减小我们对硬盘操作的次数。因为我们对硬盘的…

Python3列表

操作&#xff1a;索引、切片、加、乘、检查成员、确定序列长度、确定最大最小元素 定义&#xff1a; 列表名 [元素]下标列表名[x] 截取:列表名[x:y] 更新&#xff1a; list[x]y 或者使用append()方法添加列表项删除&#xff1a; del list[x]常用操作&#xff1a; 截取与…

Linux惊群效应详解(最详细的了吧)

https://blog.csdn.net/lyztyycode/article/details/78648798?locationNum6&fps1 linux惊群效应详细的介绍什么是惊群&#xff0c;惊群在线程和进程中的具体表现&#xff0c;惊群的系统消耗和惊群的处理方法。1、惊群效应是什么&#xff1f;惊群效应也有人叫做雷鸣群体效应…

epoll原理详解(最清晰)

https://blog.csdn.net/lyztyycode/article/details/79491419我只是把内容搬运过来做个记录&#xff0c;方便自己以后回头看。第一部分&#xff1a;select和epoll的任务关键词&#xff1a;应用程序 文件句柄 用户态 内核态 监控者要比较epoll相比较select高效在什么地方&#x…

Linux命令【五】系统函数

系统文件函数 stat函数 指针如果没有const一般表示传出参数&#xff0c;如果加const表示传入参数 struct stat dev_t st_dev文件设备编号ino_t st_ino节点 inode号是唯一的&#xff0c;每个inode节点的大小一般是128字节活着256字节&#xff0c;一般文件每2KB就设置一个ino…

生产者-消费者模型的两种实现方式

https://www.cnblogs.com/caolicangzhu/p/7086176.html本文主要来总结生产者-消费者模型的代码实现,至于其原理,请大家自行百度. 一、基于链表的生产-消费模型(条件变量)我们以链表为例,生产者进行头部插入,消费者进行头部删除,因此,先将链表相关操作封装为LinkList.h,具体代码…

Linux系统【一】CPU+MMU+fork函数创建进程

切板中的内容输出到文件### 进程相关概念 程序&#xff1a;编译好的二进制文件&#xff0c;在磁盘上&#xff0c;不占用系统资源&#xff08;不包括磁盘&#xff09;。&#xff08;剧本&#xff09; 进程&#xff1a;占用系统资源&#xff0c;是程序的一次运行。&#xff08;戏…

Ubuntu卸载软件

用过使用dpkg软件管理工具得到所有已经安装的软件&#xff0c;如果不清楚软件的全名可以使用grep命令进行查找 然后再使用sudo apt-get remove --purge 软件名卸载软件&#xff08;--purge参数会删除配置文件&#xff0c;删的干净一些&#xff09; 例如&#xff1a;

一个重要且实用的signal---SIGCHLD

https://blog.csdn.net/lyztyycode/article/details/78150805SIGCHLD(修改)因为笔者之前的文章里面有错误&#xff0c;今天发现&#xff0c;立马做个修改。在下面我的一段关于sigchld信号相对于直接调用wait函数的好处时&#xff0c;我说调用wait函数要一直检测子进程是否执行完…

数据结构实验之链表七:单链表中重复元素的删除

https://blog.csdn.net/blessingxry/article/details/794455111.知识点&#xff1a;逆序建立链表&#xff0b;节点删除 2.题意&#xff1a;按照数据输入的相反顺序&#xff08;逆位序&#xff09;建立一个单链表&#xff0c;并将单链表中重复的元素删除&#xff08;值相同的元素…

Python3函数和代码复用

函数的定义 def 函数名([参数列表]):注释函数体注意事项 函数形参不需要声明类型&#xff0c;可以使用return语句在结束函数执行的同时返回任意类型的值&#xff0c;函数返回值类型与return语句返回表达式i的类型一致 即使该函数不需要接受任何参数&#xff0c;也必须保留一堆…

一文说尽C++赋值运算符重载函数(operator=)

http://www.cnblogs.com/zpcdbky/p/5027481.html在前面&#xff1a;关于C的赋值运算符重载函数(operator)&#xff0c;网络以及各种教材上都有很多介绍&#xff0c;但可惜的是&#xff0c;内容大多雷同且不全面。面对这一局面&#xff0c;在下在整合各种资源及融入个人理解的基…

Python a和a[:]的区别

简单来讲a[:]是深复制&#xff0c;a是浅复制&#xff0c;相当于赋值a的话是赋值了指针&#xff0c;赋值a[:]相当于复制了a对应的那段空间 例如&#xff1a; a [1,1,1,1,1,1]for x in a:if x1:a.remove(x)print(a)运行结果&#xff1a; remove操作是移除序列中第一个x元素。…

约瑟夫环(c语言程序完整版)

https://blog.csdn.net/m_hahahaha1994/article/details/51742453约瑟夫环&#xff08;约瑟夫问题&#xff09;是一个数学的应用问题&#xff1a;已知n个人&#xff08;以编号1&#xff0c;2&#xff0c;3…n分别表示&#xff09;围坐在一张圆桌周围。从编号为k的人开始报数&am…

Linux系统【二】exec族函数及应用

文件描述符 文件描述符表是一个指针数组&#xff0c;文件描述符是一个整数。 文件描述符表对应的指针是一个结构体&#xff0c;名字为file_struct&#xff0c;里面保存的是已经打开文件的信息 需要注意的是父子进程之间读时共享&#xff0c;写时复制的原则是针对物理地址而言…

白话C++系列(27) -- RTTI:运行时类型识别

http://www.cnblogs.com/kkdd-2013/p/5601783.htmlRTTI—运行时类型识别 RTTI&#xff1a;Run-Time Type Identification。 那么RTTI如何来体现呢&#xff1f;这就要涉及到typeid和dynamic_cast这两个知识点了。为了更好的去理解&#xff0c;那么我们就通过一个例子来说明。这个…

使用头文件的原因和规范

原因 通过头文件来调用库功能。在很多场合&#xff0c;源代码不便&#xff08;或不准&#xff09;向用户公布&#xff0c;只 要向用户提供头文件和二进制的库即可。用户只需要按照头文件中的接口声明来调用库 功能&#xff0c;而不必关心接口怎么实现的。编译器会从库中提取相应…

转圈踢人问题

https://www.cnblogs.com/lanxuezaipiao/p/3339603.html 有N个人围一圈依次报数&#xff0c;数到3的倍数的人出列&#xff0c;问当只剩一个人时他原来的位子在哪里&#xff1f; 解答&#xff1a;经典的转圈踢人问题&#xff0c;好吧专业一点&#xff0c;约瑟夫环问题&#xff0…

Linux系统【三】回收子进程

孤儿进程 父进程先于子进程结束&#xff0c;则子进程成为孤儿进程&#xff0c;子进程的父进程成为init进程&#xff0c;则称init进程领养孤儿进程。现在好像是用户进程中的system进程。 僵尸进程 进程终止&#xff0c;父进程不进行回收&#xff0c;自己成残留资源(PCB)存放在…