Linux系统编程入门(上)

网络编程系列文章

第1章 Linux系统编程入门(上)
第1章 Linux系统编程入门(下)

第2章 Linux多进程开发(上)
第2章 Linux多进程开发(下)

第3章 Linux多线程开发

第4章 Linux网络编程


第5章 Web服务器

第一章 Linux系统编程入门(上)

1.1 GCC

  • GCC 原名为 GNU C 语言编译器( GNU C Compiler)
  • GCC ( GNU Compiler CollectionGNU 编译器套件)是由 GNU 开发的编程语言译器。 GNU 编译器套件包括 CC++Objective-CJavaAdaGo 语言前端,也包括了这些语言的库(如 libstdc++libgcj 等)
  • GCC 不仅支持 C 的许多“方言”,也可以区别不同的 C 语言标准;可以使用命令行选项来控制编译器在翻译源代码时应该遵循哪个 C 标准。例如,当使用命令行参数 std=c99 启动 GCC 时,编译器支持 C99 标准
  • 安装命令 sudo apt install gcc g++ (版本 > 4.8.5)
  • 查看版本 gcc/g++ -v/--version

编程语言的发展

在这里插入图片描述

GCC 工作流程

在这里插入图片描述

gcc 和 g++ 的区别

  • gccg++ 都是 GNU( 组织 ) 的一个编译器。
  • 误区一gcc 只能编译 c 代码, g++ 只能编译 c++ 代码。两者都可以,请注意:
    • 后缀为 .c 的, gcc 把它当作是 C 程序,而 g++ 当作是 c++ 程序
    • 后缀为 .cpp 的,两者都会认为是 C++ 程序C++ 的语法规则更加严谨一些
    • 编译阶段g++ 会调用 gcc ,对于 C++ 代码,两者是等价的,但是因为 gcc 命令不能自动和 C++ 程序使用的库联接,所以通常用 g++ 来完成链接,为了统 一起见,干脆编译/链接统统用 g++ 了,这就给人一种错觉,好像 cpp 程序只能用 g++ 似的
  • 误区二gcc 不会定义 __cplusplus 宏,而 g++
    • 实际上,这个只是标志着编译器将会把代码按 C 还是 C++ 语法来解释
    • 如上所述,如果后缀为 .c ,并且采用 gcc 编译器,则该宏就是未定义的,否则,就是已定义
  • 误区三编译只能用 gcc链接只能用 g++
    • 严格来说,这句话不算错误,但是它混淆了概念,应该这样说:编译可以用 gcc/g++ ,而链接可以用 g++ 或者 gcc lstdc++
    • gcc 命令不能自动C++ 程序使用的库联接,所以通常使用 g++ 来完成联接。 但在编译阶段, g++ 会自动调用 gcc ,二者等价

GCC 常用参数选项

在这里插入图片描述

# 1. 将test.c文件预处理为test.i文件
gcc test.c -E -o test.i

# 2. 编译,生成test.s文件
gcc test.i -S -o test.s

# 3. 汇编,生成test.o文件
gcc test.s -s -o test.o

# 4. 执行
./test.o

# 也可以直接运行下面代码,生成 test.o文件
gcc test.c

在这里插入图片描述

1.2 静态库

(1)什么是库

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

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

  • 文件有两种,静态库动态库共享库),区别是:

    • 静态库在程序的 链接阶段被复制到了程序中;
    • 动态库链接阶段 没有 被复制到程序中,而是程序在 运行 时由系统动态加载到内存中供程序调用。
  • 库的好处:

    • 代码保密
    • 方便部署分发

(2)静态库的制作

  • 命名规则
    • Linux : libxxx.a
      lib : 前缀(固定)
      xxx : 库的名字,自己起
      .a : 后缀(固定)
    • Windows : libxxx.lib
  • 静态库的制作
    • gcc 获得 .o 文件
    • .o 文件打包,使用 ar 工具(archive)
      ar rcs libxxx.a xxx.o xxx.o
      r:将文件插入备存文件中
      c:建立备存文件
      s:索引
# 1. 编译汇编(不链接)获得 `.o` 文件
gcc -c add.c div.c mult.c sub.c

# 2. 将 .o 文件打包
ar rcs libcalc.a add.o sub.o mult.o div.o

在这里插入图片描述

(3)静态库的使用

gcc main.c -o app -I ./include/ -l calc -L ./lib/

在这里插入图片描述

1.3 动态库

(1)动态库的制作

  • 命名规则

    • Linux : libxxx.so
      lib : 前缀(固定)
      xxx : 库的名字,自己起
      .so : 后缀(固定)
    • Windows : libxxx.dll
  • 动态库的制作

    • gcc 获得 .o 文件,得到和位置无关的代码

      gcc -c -fpic/-fPIC a.c b.c
      

      -fpic 用于编译阶段,产生的代码没有绝对地址,全部用 相对地址,这正好满足了共享库的要求,共享库被加载时地址不是固定的。如果不加 -fpic ,那么生成的代码就会与位置有关,当进程使用该 .so 文件时都需要重定位,且会产生成该文件的副本,每个副本都不同,不同点取决于该文件代码段与数据段所映射内存的位置。

    • gcc 得到动态库

      gcc -shared a.o b.o -o libcalc.so
      

      在这里插入图片描述

(2)动态库的使用

gcc main.c -o main -I ./include/ -l calc -L ./lib/ 

# 运行,会报错,找不到共享库
./main
# error while loading shared libraries: libcalc.so: cannot open shared object file: No such file or directory

工作原理

  • 静态库GCC 进行链接时,会把静态库中代码 打包到 可执行程序中

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

  • 程序启动 之后,动态库 会被 动态加载 到内存中,通过 ldd (list dynamic dependencies )命令检查动态库依赖关系

    在这里插入图片描述

  • 如何定位共享库文件呢?
        当系统加载可执行代码时候,能够知道其所依赖的库的名字,但是还需要知道 绝对路径。此时就需要系统的 动态载入器 来获取该绝对路径。对于 elf 格式的可执行程序,是由 ld-linux.so 来完成的,它先后搜索 elf 文件的

    • DT_RPATH 段(无法修改) —> 环境变量 LD_LIBRARY_PATH—> /etc/ld.so.cache 文件列表 —> /lib//usr/lib 目录找到库文件后将其载入内存

(3)解决动态库加载失败问题

修改上面的搜索路径

a. 修改环境变量 LD_LIBRARY_PATH

  • 临时配置

    • 在终端直接配置。(关闭当前会话框,将失效)

      # 原来的拼接上动态库的绝对路径
      export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/rmzh/projects/Linux/lesson04/library/lib
      

      在这里插入图片描述

  • 永久配置

    • 用户级配置

      # 修改 ~/.bashrc 文件
      vim ~/.bashrc
      
      # 在最后面加入:
      export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/rmzh/projects/Linux/lesson04/library/lib
      
      # 保存退出后,使生效
      source ~/.bashrc
      

      在这里插入图片描述

    • 系统级别

      # 修改 /etc/profile 文件
      sudo vim /etc/profile
      
      # 在最后面加入:
      export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/rmzh/projects/Linux/lesson04/library/lib
      
      # 保存退出后,使生效
      source /etc/profile
      

b. 修改 /etc/ld.so.cache 文件

  • 该文件是二进制文件,不能直接修改,可以间接修改

    # 修改 /etc/ld.so.conf 文件
    sudo vim /etc/ld.so.conf
    
    # 加入:
    /home/rmzh/projects/Linux/lesson04/library/lib
    
    # 保存退出后,更新生效
    sudo ldconfig
    

c. 将动态库文件放到 / lib//usr/lib/ 目录下

  • 不推荐使用!
  • 因为这两个目录下本身就包含系统自带的库文件,可能名称会用相同,会覆盖系统文件

1.4 静态库与动态库的对比

(1)程序编译成可执行程序的过程

在这里插入图片描述

  • 预处理:头文件展开、删除注释、宏的替换
  • 编译:编译成汇编代码
  • 汇编:汇编成目标代码
  • 链接:处理静态库和动态库,链接成可执行文件

(2)静态库制作过程

在这里插入图片描述

(3)动态库制作过程

在这里插入图片描述

(4)静态库的优缺点

优点缺点
静态库被打包到应用程序中加载速度快消耗系统资源,浪费内存
发布程序无需提供静态库,移植方便更新、部署、发布麻烦

在这里插入图片描述

(5)动态库的优缺点

优点缺点
可以实现进程间资源共享(共享库)加载速度比静态库慢
更新、部署、发布简单发布程序时需要提供依赖的动态库
可以控制何时加载动态库

在这里插入图片描述

库比较小 的话使用 静态库比较大 就使用 动态库

1.5 Makefile

(1)什么是 Makefile

  • 一个工程中的源文件不计其数,其按类型功能模块分别放在若干个目录中,Makefile 文件 定义了 一系列的规则 来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 Makefile 文件就像一个 Shell 脚本 一样,也可以执行操作系统的命令。
  • Makefile 带来的好处就是 “自动化编译”,一旦写好,只需要一个 make 命令,整个工程完全自动编译,极大的提高了软件开发的效率。 make 是一个命令工具,是一个解释 Makefile 文件中指令的命令工具,一般来说,大多数的 IDE 都有这个命令,比如 DelphimakeVisual C++nmakeLinuxGNUmake

(2)Makefile 文件命名和规则

  • 文件命名
    makefile 或者 Makefile

  • Makefile 规则

    • 一个 Makefile 文件中可以有一个或者多个规则
      目标 … : 依赖 …
      命令(Shell 命令)
      • 目标:最终要生成的文件(伪目标除外)
      • 依赖:生成目标所需要的文件或是目标
      • 命令:通过执行命令对依赖操作生成目标(命令前必须 Tab 缩进
    • Makefile 中的其它规则一般都是为 第一条规则 服务的。
  • 例如:

    # 创建 Makefile 文件
    vim Makefile
    
    # 添加以下内容(第一种)
    app:add.c sub.c mult.c div.c main.c
    	gcc add.c sub.c mult.c div.c main.c -o app
    
    # 保存退出,输入make
    make
    

    在这里插入图片描述

(3)工作原理

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

    • 如果存在,执行命令

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

      # 第二种
      # 该效率优于第一种,如果其中一个依赖改变,只需编译这一个即可
      
      app:add.o sub.o mult.o div.o main.o
      	gcc add.o sub.o mult.o div.o main.o -o app
      	
      add.o:add.c
      	gcc -c add.c -o add.o
      
      sub.o:sub.c
      	gcc -c sub.c -o sub.o
      	
      mult.o:mult.c
      	gcc -c mult.c -o mult.o
      	
      div.o:div.c
      	gcc -c div.c -o div.o
      	
      main.o:main.c
      	gcc -c main.c -o main.o
      
  • 检测更新,在执行规则中的命令时,会比较目标依赖文件的时间修改更新的时间

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

(4)变量

  • 自定义变量
    • 变量名 = 变量值 : var=hello
  • 预定义变量
    • AR : 归档维护程序的名称,默认值为 ar
    • CC : C 编译器的名称,默认值为 cc
    • CXX : C++编译器的名称,默认值为 g++
    • $@ : 目标的完整名称
    • $< : 第一个依赖文件的名称
    • $^ : 所有的依赖文件
  • 获取变量的值
    $(变量名) : $(var)
app:main.c a.c b.c
	gcc -c main.c a.c b.c

# 自动变量只能在规则的命令中使用
app:main.c a.c b.c
	$(CC) -c $^ -o $@
	
# 定义变量
src=add.o sub.o mult.o div.o main.o
target=app
$(target):$(src)
	$(CC) $(src) -o $(target)

(5)模式匹配

add.o:add.c
	gcc -c add.c

sub.o:sub.c
	gcc -c sub.c
	
mult.o:mult.c
	gcc -c mult.c
	
div.o:div.c
	gcc -c div.c
	
main.o:main.c
	gcc -c main.c
  • %.o:%.c
    • % : 通配符,匹配一个字符串
    • 两个 %匹配的是同一个字符串
# 上面的5种都能匹配
%.o:%.c
        gcc -c $< -o $@

(6)函数

  • $(wildcard PATTERN...)

    • 功能:获取指定目录下指定类型的文件列表

    • 参数wildcard 为函数名,PATTERN 指的是某个或多个目录下的对应的某种类型的文件,如果有多个目录,一般使用空格间隔

    • 返回:得到的若干个文件的文件列表,文件名之间使用空格间隔

    • 示例
      $(wildcard *.c ./sub/*.c)
      返回值格式: a.c b.c c.c d.c e.c f.c

      # add.c sub.c mult.c div.c main.c
      src=$(wildcard ./*.c)
      
  • $(patsubst <pattern>, <replacement>, <text>)

    • 功能:查找 <text> 中的单词 (单词以“空格”、“ Tab” 或 “回车” “换行”分隔) 是否符合 模式 <pattern>,如果匹配的话,则以 <replacement> 替换。

    • <pattern> 可以包括通配符 %,表示任意长度的字串。如果 <replacement>中也包含 %,那么 , <replacement> 中的这个 %将是 <pattern> 中的那个 %所代表的字串。 (可以用 \转义,以 \% 来表示真实含义的 % 字符)

    • 返回:函数返回被替换过后字符串

    • 示例
      $(patsubst %.c, %.o, x.c bar.c)
      返回值格式: x.o bar.o

      # 第二种
      # add.c sub.c mult.c div.c main.c
      src=$(wildcard ./*.c)
      objs=$(patsubst %.c, %.o, $(src))
      target=app
      $(target):$(objs)
              $(CC) $(objs) -o $(target)
      
      %.o:%.c
              gcc -c $< -o $@
              
      # 删除.o文件
      # 伪目标
      .PHONY:clean
      clean:
      		rm $(objs) -f
      # make调用在终端输入:make clean
      

      在这里插入图片描述

注:仅供学习参考,如有不足,欢迎指正!

  • 25
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

酷酷的懒虫

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值