1 linux系统编程入门-linux gcc 静态库 动态库 Makefile GDB
标题: linux gcc 静态库 动态库 Makefile GDB
1.1linux开发环境搭建
1 linux系统
虚拟机 云服务器
sudo apt-install openssh-server |
2 xshell xftp
ifconfig ip地址 端口22 用户名 密码 |
3 vscode
安装插件 Chinese、Remote Develoment、c++
远程资源管理器 SSH Targets 点击configure(齿轮) 默认地址(点第一个)
Host 随便填 HostName ip地址 User 用户名
ssh-keygen -t rsa |
生成ssh公钥 每次连接不用输密码
1.2 gcc
支持c、c++、object-c、java、go等
安装
sudo apt-install gcc g++ |
查看版本
gcc/g++ -v/--version |
编译
gcc xxx.c -o xxx |
运行
./xxx |
gcc工作流程:
源代码.h .cpp-(预处理)-预处理后的源代码.i-(编译器编译)-汇编代码.s-(汇编器)-目标代码.o-(链接器+启动代码、代码库、其他代码)-最终可执行文件
1.3静态库
好处:1代码保密 2方便部署和分发
命名规则:
linux |
libxxx.a |
windows |
libxxx.lib |
制作:
1 gcc获得.o文件
2 将.o文件打包,使用ar工具(archive)
ar rcs libxxx.a xxx.o xxx.o |
r 将文件插入备存文件中 c 建立备存文件 s 索引
使用:使用-l参数 和 -L参数
gcc main.c -o app -L ./lib -l calc |
注意头文件也要导入
1.4动态库
- 命名规则:
linux |
libxx.so |
windows |
libxxx.dll |
-
制作:
1 gcc得到.o文件,得到和位置无关的代码
gcc -c -fpic/-fPIC a.c b.c |
2gcc得到动态库
gcc -shared a.o b.o -o libcalc.sp |
- 使用:
gcc main.c -o app -L ./lib -l calc |
编译没错,但是运行 ./app 时会报错,原因见下面动态库工作原理
ldd app可以查看app程序 动态库依赖、加载情况;需要系统的动态载入器来获取绝对路劲加载动态库,查找路径见下
要解决,将动态库加入到这些路径中其一就行
evn 显示环境变量,将动态库的路径加入到LD_LIBRARY,加入方法:
-
方法一(1当次终端有效):export LD_LIBRARY=$LD_LIBRARY_PATH:xxx(动态库的绝对路径)
(2一直有效,用户层面):cd ./ vim ./.bashrc 最后一行插入export LD_LIBRARY=$LD_LIBRARY_PATH:xxx(动态库的绝对路径) source ~/.bashrc
(3一直有效,系统级别):sudo vim /etc/profile 然后和方法二一样插入 source /etc/profile
- 方法二:修改 /etc/ld/so.cache 具体不写了
-
方法三(不建议):将文件放到 /lib 或 /usr/lib
2022年5月7日20:30:54 根据经验 使用第二种方法比较好,具体过程可以看ns3-vscode配置调试 笔记里有写动态库加入系统
静态库和动态库的工作原理:
1.5静态库和动态库对比
每个程序使用静态库都需要加载到内存里,所以更加消耗系统资源;而动态库加载一次,可以供多个程序使用。
1.6Makefile
一个工程中源文件很多,按类型、功能、模块分目录保存,Makefile文件定义了一系列规则来指定哪些文件要先编译,哪些后编译。
自动化编译,指导我们的源文件怎么进行编译
make nmake …
-
文件命名:
makefile 或者 Makefile
-
Makefile 规则:
一个makefile文件可以有一个或者多个规则
目标 … : 依赖 …
命令 (shell命令)
…
- 目标:最终要生成的文件(伪目标除外)
- 依赖:生成目标所需要的文件或是目标
-
命令:通过执行命令对依赖操作生成目标(命令前必须Tab缩进)
- 例子:
touch makefile app:sub.c add.c mult.c div.c main.c gcc sub.c add.c mult.c div.c main.c -o app make ./app |
-
工作原理
-
命令执行前,需要先检查规则中的依赖是否存在
- 如果存在,执行命令
-
如果不存在,向下检查其他的规则,检查有没有一个规则是用来生成这个依赖的,
如果找到了,则执行该规则中的命令
-
检测更新,在执行规则中的命令时,会比较目标和依赖文件的时间
- 如果依赖的时间比目标的时间晚,需要重新生成目标
-
如果依赖的时间比目标的时间早,目标不需要更新,对于规则中的命令不需要被执行
-
-
变量
-
自定义变量
- 变量名= 变量值 var = hello
-
预编译变量
- AR:归档维护程序的名称,默认值为ar
- CC:C编译器的名称,默认值为cc
- CXX:C++编译器的名称,默认值为g++
- $@:目标的完整名称
- $<:第一个依赖文件的名称
- $^:所有依赖文件
-
获取变量的值
-
$(变量名)
-
-
-
模式匹配
%.o:%.c
- %:通配符,匹配一个字符串
- 两个%匹配的是同一个字符串
-
函数
-
$(wildcard OATTERN…)
- 功能:获取指定目录下指定类型的文件列表
- 参数:PATTERN指的是某个或多个目录下的对应的某种类型的文件,如果有多个目录,一般使用空格间隔
- 返回:得到的若干个的文件列表,文件名之间使用空格间隔
-
示例:
- $(wildcard *.c ./sub/*.c)
- 返回值格式:a.c b.c c.c d.c e.c f.c
-
$(patsubst <pattern>,<replacement>,<text>)
-
功能:查找<text>中的单词(单词以"空格"、"Tab"或者"回车"、"换行"分隔)是否符合模式<pattern>,
如果匹配的话,则以<replacement>替换
-
<pattern>可以包括通配符 `%`,表示任意长度的字串。如果<replacement>中也包含 `%`,那么 ,<replacement>中的这个% 将是<pattern>中的那个
%所代表的字串。(可以用\%来转义,以\%来表示真实含义的%字符)
- 返回:函数返回被替换过后的字符串
-
示例:
%(patsubst %.c, %.o, x.c bar.c)
返回值格式:x.o bar.o
-
-
-
-
clean
-
clean:
rm -f xxx
- make clean
-
如果同目录有clean文件,则不能进行正常运行clean,要在makefile文件中设置clean为伪目标文件
- .PHONY:clean
-
1.7GDB
-
什么是GDB:
- GDB 是由GNU 软件系统社区提供的调试工具,同GCC 配套组成了一套完整的开发环境,GDB 是Linux 和许多类Unix 系统中的标准开发环境。
-
一般来说,GDB 主要帮助你完成下面四个方面的功能:
- 启动程序,可以按照自定义的要求随心所欲的运行程序
- 可让被调试的程序在所指定的调置的断点处停住(断点可以是条件表达式)
- 当程序被停住时,可以检查此时程序中所发生的事
- 可以改变程序,将一个BUG 产生的影响修正从而测试其他BUG
-
准备工作:
- 通常,在为调试而编译时,我们会()关掉编译器的优化选项( -O ), 并打开调试选项( -g )。
- 另外, -Wall 在尽量不影响程序行为的情况下选项打开所有warning,也可以发现许多问题,避免一些不必要的BUG。
gcc -g -Wall program.c -o program |
-
-g 选项的作用是在可执行文件中加入源代码的信息,比如可执行文件中第几条机器指令对应源代码的第几行,
但并不是把整个源文件嵌入到可执行文件中,所以在调试时必须保证gdb 能找到源文件。
-
启动、退出、查看代码
-
断点操作
-
调试命令
-fpic 用于编译阶段,产生的代码没有绝对地址,全部用相对地址,这正好满足了共享库的要求,共享库被加载时地址不是固定的。如果不加-fpic ,那么生成的代码就会与位置有关,当进程使用该.so文件时都需要重定位,且会产生成该文件的副本,每个副本都不同,不同点取决于该文件代码段与数据段所映射内存的位置。
来自 <https://www.nowcoder.com/study/live/504/1/6?autoplay=1>