Linux系统编程入门(一)

1.环境搭建

Linux系统、Xshell、Xftp、VSCode
用Xshell远程连接,通过命令去操作系统;用Xftp与系统进行文件传输

2.GCC

GCC(GNU Compiler Collection,GNU编译器套件)是由GNU开发的编程语言译器,包括C、C++、Objective-C、Java、Ada和Go语言前端,也包括这些语言的库。
安装命令sudo apt install gcc g++
查看版本gcc/g++ -v/--version

用GCC编译

查看有哪个文件ls
进入文件夹cd 文件名
创建新的文件夹mkdir 文件名
创建c代码touch 文件名.c
在这里插入图片描述
然后就可以去vs中编写代码
在这里插入图片描述
编写完成后就可以回到Xshell6进行编译,
输入gcc test.c -o app,-o是指定生成文件的名称,app为生成文件的名称,然后输入./app运行生成的文件
在这里插入图片描述
也可以输入gcc test
在这里插入图片描述

GCC工作流程

在这里插入图片描述
源代码通过预处理器进行预处理,会把源代码中导入头文件进行展开(把头文件的内容复制到源代码中),并且将源代码中的注释删除,定义的宏也会进行一些替换

预处理后源代码经过编译器编译成汇编代码,再经过汇编器转换成目标代码(计算机能够识别的1010等),再结合启动代码、库代码、其他目标代码通过链接器链接成可执行程序

在VS中编写代码:

#include <stdio.h>

#define PI 3.14
int main(){
    //测试代码
    int sum = PI + 10;
    printf("hello world\n");
    return 0;
}

在Xshell6中输入gcc test.c -E -o test.i,-E表示对test.c继续进行预处理,生成的test.i文件部分如下,注释被删除,头文件被导入,宏被替换成3.14
在这里插入图片描述
在Xshell6中输入gcc test.c -S -o test.s,-S表示对test.i进行编译
在这里插入图片描述
在Xshell6中输入gcc test.s -C -o test.o,-C表示对test.i进行编译
在这里插入图片描述
这个代码不需要链接,输入./test.o直接执行,输出hello world
这里其实就是解释前面用GCC编译的过程,rm 文件名删掉刚才生成的文件,直接输入gcc test.c -S,也会生成test.s文件
在这里插入图片描述

GCC常用参数选项

gcc编译选项说明
-E预处理指定的源文件,不进行编译
-S编译指定的源文件,但不进行汇编
-c编译、汇编指定的源文件,但不进行链接
-o [file1] [file2] / [file2] -o [file1]将文件file2编译成可执行文件file1
-I directory指定include包含文件的搜索目录
-g在编译的时候,生成调试信息,该程序可以被调试器调试
-D在程序编译的时候,指定一个宏
-w不生成任何警告信息
-Wall生成所有警告信息
-Onn的取值范围:0~3。编译器的优化选项的4个级别,-O0表示没有优化,-O1缺省值,-O3优化级别最高
-l在程序编译的时候,指定使用的库
-L指定编译的时候,搜索的库的路径
-fPIC/fpic生成与位置无关的代码
-shared生成共享目标文件,通常用在简历共享库时
-std指定C方言,如-std=c99,gcc默认的方言时GNU C

-o的两种用法:
在这里插入图片描述

3.静态库

库文件时计算机上的一类文件,可以简单的把库文件看成一种代码仓库,它提供给使用者一些可以直接拿来使用的变量、函数或类。

库是特殊的一种程序,编写库的程序和编写一般的程序叙别不大,只是库不能单独运行。

库文件有两种,静态库和动态库(共享库),区别是:
静态库在程序的链接阶段被复制到了程序中;
动态库在链接阶段没有被复制到程序中,而是程序在运行时由系统动态加载到内存中供程序调用。

库的好处:1.代码保密;2.方便部署和开发。

静态库的制作

命名规则:
Linux:libxxx.a,lib是前缀(固定)、xxx是库的名字、.a是后缀(固定)
windows:libxxx.lib,与Linux同理

静态库的制作:
(1)gcc获取.o文件;
(2)使用ar工具(archive)将.o文件打包,ar rcs libxxx.a xxx.o xxx.o,将xxx.o、xxx.o打包成libxxx.a

通过Xftp6将文件传入Ubuntu中
在这里插入图片描述
在Xshell6中将calc中的add.c、div.c、mult.c、sub.c打包成静态库

head.h头文件不需要转成.o形式,在预编译的时候会被复制到.c文件中
main.c是测试文件也不需要要转换

tree的作用是查看当前文件夹的目录
首先通过gcc -c add.c div.c mult.c sub.c将add.c、div.c、mult.c、sub.c转换成.o形式,
然后通过ar rcs libcalc.a add.o div.o mult.o sub.o将add.o div.o mult.o sub.o打包成静态库。
在这里插入图片描述

静态库的使用

在Linux文件夹下创建lesson05文件夹,
输入cp -r calc/ library/ ../lesson05,将lesson04文件夹下的calc、library复制到上级目录下的lesson05文件夹
在这里插入图片描述
进入到lesson05的library文件夹中可以看到其分包,其中include中包含的是需要用到的头文件、main.c是测试文件、src包含的是源代码文件

将leeson04中的library.a拷贝到lesson05,输入cp ../calc/library.a ./lib/,即将上一级目录(lesson05)下的calc文件夹中的library.a拷贝到当前目录下的lib文件夹下
在这里插入图片描述
使用库文件时也需要库文件依赖的头文件

然后对main.c进行编译,
如果输入gcc -o main.c app就会报错,因为在预处理时需要将head.h中的内容拷贝到main.c中,但现在使用的是相对路径(main.c的目录),找不到head.h;

如果输入gcc -o main.c app -I ./include/,通过-I diretory指定include包含文件的搜索目录。此时提供了头文件,但是函数的定义在library.a中。

因此要输入gcc mai.c -o app -I ./include/ -l calc -L ./lib
通过- l在程序编译的时候,指定使用的库,注意后面跟的是库的名称,而不是库文件的名字
通过- L指定编译的时候,搜索的库的路径
在这里插入图片描述
然后就可以执行app文件
在这里插入图片描述

4.动态库

动态库的制作及使用

命名规则:
Linux:libxxx.so,lib是前缀(固定)、xxx是库的名字、.so是后缀(固定)
windows:libxxx.dll,与Linux同理

静态库的制作:
(1)gcc获取.o文件;得到和位置无关的代码,即gcc -c -fpic/-fPIC a.c b.c
(2)gcc得到动态库,即gcc -shared a.o bo. -o libcalc.so

将lesson05文件夹中的calc、library拷贝到lesson06,cp calc library ../lesson06 -r,因为是目录,因此要加上-r使其递归的拷贝
在这里插入图片描述
删除calc中的.o、.a文件,lib中的libcara.a文件
*.o中的*表示通配符
在这里插入图片描述
进入calc制作动态库
在linux中绿色显示的文件一般都是可执行文件
在这里插入图片描述
将制作好的动态库文件放入library/lib中
然后对main.c进行编译
在这里插入图片描述

动态库加载失败的原因及解决方法

在运行编译好的main文件时会报错,提示加载动态库时找不到动态库文件

静态库:GCC 进行链接时,会把静态库中代码打包到可执行程序中
动态库:GCC 进行链接时,动态库的代码不会被打包到可执行程序中

程序启动之后,动态库会被动态加载到内存中,通过 ldd (list dynamic
dependencies)命令检查动态库依赖关系
在这里插入图片描述
当系统加载可执行代码时候,能够知道其所依赖的库的名字,但是还需要知道绝对路径。此时就需要系统的动态载入器来获取该绝对路径。

对于elf格式的可执行程序,是由ld-linux.so来完成的,它先后搜索elf文件的 DT_RPATH段 ——> 环境变量D_LIBRARY_PATH ——> /etc/ld.so.cache文件列表 ——> /lib/,/usr/lib目录找到库文件后将其载入内存。

动态库加载失败就是因为没有指定动态库的绝对路径
DT_RPATH段修改不了,
因此先配置环境变量D_LIBRARY_PATH
在终端输入export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:动态库的绝对路径
动态库的绝对路径通过pwd获取
配置完成后可以通过echo 环境变量的名称来查看绝对路径
配置完环境变量后再通过ldd main检查动态库依赖关系
main程序也就可以运行了
在这里插入图片描述
但是在终端中配置环境变量,在关闭终端后环境变量就失效了。
为了避免这种情况,有两种方法永久配置环境变量:用户级别配置和系统级别配置

用户级别配置:
可以通过home目录下的隐藏文件.bachrc配置环境变量,vim .bashrc编辑
在这里插入图片描述
在.bashrc中已经存在一些环境变量,按shift+g跳转到最后一行,按o插入新的一行,输入export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:动态库的绝对路径,然后输入:wq保存并退出,最后输入source/. .bashrc使其生效
在这里插入图片描述
系统级别配置:
系统级别配置和用户级别差不多,只不过换了个文件,source vim /etc/profile,然后输入export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:动态库的绝对路径,最后输入source/. /etc/profile使其生效
在这里插入图片描述
还可以修改 /etc/ld.so.cache文件
如果直接输入vim /etc/ld.so.cache会显示二进制文件
在这里插入图片描述
所以通过sudo vim /etc/ld.so.conf来进行修改,修改方式同上
在这里插入图片描述
不推荐修改 /lib/,/usr/lib,因为里面存在很多系统库文件,防止误操作

静态库和动态库的对比

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.Makefile

Makefile 文件定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 Makefile 文件就像一个 Shell 脚本一样,也可以执行操作系统的命令。

Makefile 带来的好处就是“自动化编译” ,一旦写好,只需要一个 make 命令,整个工程完全自动编译,极大的提高了软件开发的效率。make 是一个命令工具,是一个解释 Makefile 文件中指令的命令工具,一般来说,大多数的 IDE 都有这个命令,比如 Delphi 的 make,Visual C++ 的 nmake,Linux 下 GNU 的 make。

Makefile文件制作

文件命名:makefile 或者 Makefile
Makefile规则
在这里插入图片描述
在lesson07下中如果要手动编译,就要输入gcc add.c div.c main.c mult.c sub.c -o app
也可以写一个Makefile进行自动编译:
首先创建一个Makefile文件vim Makefile
然后输入

app:add.c div.c main.c mult.c sub.c              //目标:依赖
	gcc add.c div.c main.c mult.c sub.c -o app   //命令

然后输入make执行make指令,需要sudo apt install make安装
make执行后就会编译成一个可执行程序
在这里插入图片描述

Makefile工作原理

1.命令在执行之前,需要先检查规则中的依赖是否存在

  • 如果存在,执行命令
  • 如果不存在,向下检查其它的规则,检查有没有一个规则是用来生成这个依赖的,如果找到了,则执行该规则中的命令

例如在lesson07中,修改Makefile文件:
add.o等在文件中并不存在,那么就会向下检查其他命令,如
add.o:add.c gcc -c add.c -o add.o是生成add.o的规则,那么就会执行该规则命令
在这里插入图片描述
通过执行make命令可以看出执行顺序
在这里插入图片描述
2.检测更新,在执行规则中的命令时,会比较目标和依赖文件的时间

  • 如果依赖的时间比目标的时间晚,需要重新生成目标
  • 如果依赖的时间比目标的时间早,目标不需要更新,对应规则中的命令不需要被执行

如果再次执行make命令,会提示app已是最新
如果修改任意.c文件,如add.c,
再次执行make命令,会进行检查更新,即时间的对比
在这里插入图片描述

Makefile写法的优化

变量

自定义变量:变量名=变量值 var=hello

预定义变量
AR : 归档维护程序的名称,默认值为 ar
CC : C 编译器的名称,默认值为 cc
CXX : C++ 编译器的名称,默认值为 g++
$@ : 获取目标的完整名称,$@
$< : 获取第一个依赖文件的名称,$<
$^ : 获取所有的依赖文件,$^

注: @ 、 @、 @< 、$^为自动变量,只能在规则的命令中使用

如:

app:main.c a.c b.c
	gcc -c main.c a.c b.c -o app
//可以替换成
app:main.c a.c b.c
	$(CC) -c $^ -o $@

获取变量的值$(变量名),如$(var)

因此可以用变量对前面的Makefile文件进行简化
在这里插入图片描述

模式匹配

%.o:%.c
%: 通配符,匹配一个字符串;两个%匹配的是同一个字符串

如:

add.o:add.c
        gcc -c add.c -o add.o
//通过模式匹配
%.o:%.c
	$(CC) -c $< -o $@

在这里插入图片描述

函数

$(wildcard PATTERN...)
功能:获取指定目录下指定类型的文件列表
参数:PATTERN 指的是某个或多个目录下的对应的某种类型的文件,如果有多个目录,一般使用空格间隔
返回:得到的若干个文件的文件列表,文件名之间使用空格间隔
示例$(wildcard *.c ./sub/*.c),返回值格式: a.c b.c c.c d.c e.c f.c

$(patsubst <pattern>,<replacement>,<text>)
功能:查找 中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合
模式 <pattern>,如果匹配的话,则以 <replacement>替换 <pattern>可以包括通配符 %,表示任意长度的字串。如果 <replacement>中也包含 %,那么, <replacement>中的这个 %将是 <pattern>中的那个 %所代表的字串。(可以用 \来转义,以 \%来表示真实含义的 %字符)
返回:函数返回被替换过后的字符串
示例$(patsubst %.c, %.o, x.c bar.c),返回值格式: x.o bar.o
在这里插入图片描述
执行完make命令后会生成非常多的.o文件,但是并不需要这些文件,因此可以继续修改makefile文件,保存后通过 make clean去运行clean规则删除.o文件
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值