Linux 系统编程----文件编译-库制作

目录

1. gcc编译

1.1 gcc编译过程

 1.2 gcc常用参数

2. 静态库和动态库 

2.1 静态库

2.1.1制作静态库:

2.2 动态库

2.2.1 制作动态库

2.2.2 动态库程序运行修改环境变量配置文件

 3.makefile

3.1 1个规则

ALL

makefile编译(make)时规则:

3.2 2个函数

3.3 3个自动变量

编写完的makefile 测试命令


1. gcc编译

1.1 gcc编译过程

gcc在执行编译工作的时,分为以下四个过程及作用
1.预处理:生成.i的文件
2.编译:   将预处理后的文件转换成汇编语言,生成.s文件
3.汇编:   变为目标代码(机器代码),生成.o的文件
4.连接:   目标代码,生成可执行程序

*****

综上可以在编译时直接执行一条命令

gcc hello.c -o hello    //-o的意思是给生成的可执行文件起别名

gcc hello.c     //默认编译出以a.out为命名的可执行文件    ./a.out  可以执行可执行文件

****

拓展:

链接的主要作用:

  1. 链接库文件
  2. 数据段合并
  3. 数据回填

 1.2 gcc常用参数

-I         指定头文件所在目录位置  
           gcc -I  ./hellodir hello.c  -o  hello(其中头文件hello.h在文件夹hellodir中)
-c         只做预处理,编译,汇编。得到二进制文件

-g         编译时添加调试文件,用于gdb调试

-Wall      显示所有警告信息    gcc hello.c  -o hello -Wall

-D         向程序中“动态”注册宏定义 gcc hello.c ​​​​​​​ -o hello -D MAX=11 

           程序hello.c中的MAX编译时赋值

-l         指定动态库库名

-L         指定动态库路径

2. 静态库和动态库 

静态库在文件中静态展开,所以有多少文件就展开多少次,非常吃内存,100M展开100次,就是1G,但是这样的好处就是静态加载的速度快

使用动态库会将动态库加载到内存,10个文件也只需要加载一次,然后这些文件用到库的时候临时去加载,速度慢一些,但是很省内存

动态库和静态库各有优劣,根据实际情况合理选用即可。但由于计算机的发展,速度可忽略了,使用动态库更多

2.1 静态库

静态库名字以lib开头,以.a结尾

例如:libmylib.a

2.1.1制作静态库:

原文链接:https://blog.csdn.net/zhaojiazb/article/details/129247397

2.2 动态库

  • 机制:代码共享(在程序运行时将程序用到的动态库的函数动态加载到内存中)
  • 优点:节省内存,易于更新(动态链接)(这两点也是使用场景的原因)
  • 缺点:函数调用速度慢

2.2.1 制作动态库

假设有两个文件add.c sub.c需要制作动态库 libmath.so, 然后链接制作的动态库编译hello.c (其中 调用了add 和sub)。

add.c

int add(int a,int b){
    return a+b;
}

 sub.c

int sub(int a,int b){
    return a-b;
 }

 主函数 test.c

  1 # include<stdio.h>
  2 # include<stdlib.h>
  3 # include<string.h>
  4 # include<unistd.h>
  5 # include<pthread.h>
  6 # include"mymath.h"
  7 
  8 int main() {
  9     int a = 15;
 10     int b = 5;
 11     printf("%d - %d = %d\n",a,b,sub(a,b));
 12     printf("%d / %d = %d\n",a,b,div1(a,b));
 13     printf("%d + %d = %d\n",a,b,add(a,b));
 14     return 0;
 15 }

头文件在INC目录下创建ymath.h

  1 #ifndef _MYMATH_H_
  2 #define _MYMATH_H_
  3 
  4 int add(int,int);
  5 int sub(int,int);
  6 int div1(int,int);
  7 
  8 #endif

制作过程如下:

四步骤

1.首先 生成位置无关的.o文件   -fPIC 生产动态库的目标文件(.o文件)必须使用该参数

 gcc -c add.c  sub.c -o add.o sub.o -fPIC

2.其次 使用gcc -shared制作动态库 lib库名.so

gcc -shared -o libmath.so  add.o sub.o

3.然后 编译可执行程序时指定所使用的动态库。

               -L:指定库路径

               -l:指定库名(库名是不带lib和.so的)

               -I(大写i)指定头文件所在目录位置

                               

gcc test.c -o a.out -l mymath -L ./lib  -l math   -I ./incl

4.最后 运行可执行程序

但是这么执行会报错需要,动态链接器(ld-linux.so.2)没有指定的动态库路径(自己制作的动态库的路径)

动态链接器(ld-linux.so.2):在程序运行之后,辅助加载器将动态库加载到内存,这也是动态库节省内存的原因

解决方式:如下修改环境变量配置文件

2.2.2 动态库程序运行修改环境变量配置文件

解决方式【1】 通过环境变量: export LD_LIBRARY_PATH=动态库路径

        ./a.out 成功!!! (临时生效, 终端重启环境变量失效)

        失效的原因是 一个程序会生成一个地址空间,环境变量也在这个空间中,一旦终端关闭,程序失效,地址空间也没了

解决方式【2】 永久生效: 写入 终端配置文件。 .bashrc 建议使用绝对路径。

  • 1) vi ~/.bashrc
  • 2) 写入 export LD_LIBRARY_PATH=动态库路径 保存
  • 3). .bashrc/ source .bashrc / 重启终端 ---> 让修改后的.bashrc生效
  • 4)./a.out 成功!!!

解决方式【3】 拷贝自定义动态库 到 /lib(标准C库所在目录位置)

解决方式【4】 配置文件法

  1. sudo vi /etc/ld.so.conf
  2. 写入 动态库绝对路径 保存
  3. sudo ldconfig -v 使配置文件生效。
  4. ./a.out 成功!!!--- 使用ldd a.out 查看

 3.makefile

命名:只能是makefileMakefile --- make 命令执行该文件内容.

makefile 需要掌握:

  • 1个规则
  • 2个函数
  • 3个自动变量

3.1 1个规则

        目标:依赖条件
        (一个tab缩进)命令

test:test.o add.o sub.o div1.o    #目标文件test依赖test.o add.o sub.o div1.o编译
    gcc test.o add.o sub.o div1.o -o test

test.o:test.c          #test.o依赖于test.c编译
    gcc -c test.c -o test.o

add.o:add.c            #add.o依赖于add.c编译
    gcc -c add.c -o add.o
sub.o:sub.c            #sub.o依赖于sub.c编译
    gcc -c sub.c -o sub.o
div1.o:div1.c
    gcc -c div1.c -o div1.o

  该makefile文件路径下make编译之后执行./test

ALL

使用ALL可以最后写文件终极目标的编译

ALL指定终极目标(也就是最终要编译出的文件)

ALL:test     #指定终极目标test
test.o:test.c
    gcc -c test.c -o test.o
 
add.o:add.c
    gcc -c add.c -o add.o
sub.o:sub.c
    gcc -c sub.c -o sub.o
div1.o:div1.c
    gcc -c div1.c -o div1.o
test:test.o add.o sub.o div1.o    #放在最后编写
    gcc test.o add.o sub.o div1.o -o test

**********

makefile编译(make)时规则:
  1. 目标的时间必须晚于依赖条件的时间,否则,更新目标。
  2. 依赖条件如果不存在,找寻新的规则去产生依赖条件。

修改文件后,文件的修改时间发生变化,会出现目标文件的时间早于作为依赖材料的时间,出现这种情况的文件会重新编译。

例如上面编译后再修改sub.c文件后,sub.o的时间就早于sub.c ,a.out的时间也早于sub.o的时间了,于是重新编译这俩文件了。

**********

3.2 2个函数

src = $(wildcard *.c)                     $(  )代表调用括号内函数的意思

找到当前目录下所有后缀为.c的文件,将文件组成列表赋值给src  例如src=sub.c  add.c  

 obj = $(patsubst %.c,%.o, $(src))

把src变量里所有后缀为.c的文件替换成.o  例如 obj = sub.o add.o 

 例:

src = $(wildcard *.c)  #找到当前目录下所有后缀为.c的文件,将文件组成列表赋值给src
obj = $(patsubst %.c,%.o, $(src)) #把src变量里所有后缀为.c的文件替换成.o

ALL:test

test.o:test.c
    gcc -c test.c -o test.o
add.o:add.c
    gcc -c add.c -o add.o
sub.o:sub.c
    gcc -c sub.c -o sub.o
div1.o:div1.c
    gcc -c div1.c -o div1.o

test:$(obj)          #$(obj)属于自定义变量 意思是使用obj
    gcc $(obj) -o test
clean:                    #删除.o 文件
    -rm -rf $(obj) test   
#rm前面的-,代表出错依然执行。
#比如,待删除文件集合是5个,已经手动删除了1个,就只剩下4个
#然而删除命令里面还是5个的集合,就会有删除不存在文件的问题
#不加这-,就会报错,告诉你有一个文件找不到。
#加了-就不会因为这个报错。

3.3 3个自动变量

  1. $@:    在规则命令中,表示规则中的目标
  2. $< :    在规则命令中,表示规则中的第一个条件,如果将该变量用在模式规则中,它可以将依赖条件列表中的依赖依次取出,套用模式规则
  3. $^ :     在规则命令中,表示规则中的所有条件,组成一个列表,以空格隔开,如果这个列表中有重复项,则去重

模式识别   

这是的makefile就是一个自动化的了,增加.c文件也不需要更改makefile。

src = $(wildcard *.c)        #获取所有.c文件名称 赋值给src
obj = $(patsubst %.c,%.o, $(src)) #src改为.o结尾
ALL:test

%.o:%.c
    gcc -c $< -o $@   #$<代表所有依赖文件即上面的冒号右边的%.c(src)每次取出对应的一个依赖文件
                      #$@代表所有目标文件即冒号左边的%.o(obj)

test:$(obj)
    gcc $^ -o $@      # $^ 等价于冒号右边的$(obj),组成一个列表,以空格隔开,自动去重
clean:
    -rm -rf $(obj) test

 静态模式识别

静态模式识别只能将$(obj)中.o编译出来如果还有其他的obj不会被编译​​​​​​​

src = $(wildcard *.c)        #获取所有.c文件名称 赋值给src
obj = $(patsubst %.c,%.o, $(src)) #src改为.o结尾
ALL:test
myArgs = -Wall -g  #gcc编译的参数


   
$(obj):%.o:%.c
    gcc -c $< -o $@  $(myArgs)  
                      #$<代表所有依赖文件即上面的冒号右边的%.c(src)每次取出对应的一个依赖文件
                      #$@代表所有目标文件即冒号左边的%.o(obj)

test:$(obj)
    gcc $^ -o $@   $(myArgs)   
                      # $^ 等价于冒号右边的$(obj),组成一个列表,以空格隔开,自动去重
clean:
    -rm -rf $(obj) test

makefile文件

****************定义变量  beg****************
src = $(wildcard *.c)        #获取所有.c文件名称 赋值给src
obj = $(patsubst %.c,%.o, $(src)) #src改为.o结尾
myArgs = -Wall -g  #gcc编译的参数
CC = gcc
Target = test
****************定义变量  end****************


****规则语句 程序命令  并且引用变量 beg****
ALL:$(Target)   
$(obj):%.o:%.c
    $(CC) -c $< -o $@  $(myArgs)  
                      #$<代表所有依赖文件即上面的冒号右边的%.c(src)每次取出对应的一个依赖文件
                      #$@代表所有目标文件即冒号左边的%.o(obj)

test:$(obj)
    $(CC) $^ -o $@   $(myArgs)   
                      # $^ 等价于冒号右边的$(obj),组成一个列表,以空格隔开,自动去重
clean:
    -rm -rf $(obj) $(Target)

****规则语句 程序命令  并且引用变量 end****

.PHONY: clean ALL   
测试 makefile clean 命令
make clean -n  
特别情况makefile名称不是makefile或Makefile,执行命令
make -f m6

  • 26
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值