linux下gcc基本操作以及静态库、动态库的制作

c文件编译过程

  • 预编译(展开头文件、去掉注释、宏处理)(.c->.i
  • 编译(.i->.s
  • 汇编 (.s->.o)
  • 链接 (.0->app)

基本指令

gcc

  • -E:预处理将.c文件变为.i文件(其实也是c文件)
  • -S:编译,将.i文件变为.s汇编文件
  • -c:汇编,将.c文件变为.o二进制文件
  • -o:指定名称
  • -ggdb调试的时候需要加
  • -D:在编译的时候指定一个宏
  • -Wall:输出警告信息
  • -On:优化等级,n为等级数目1,2,3只有这三级

为什么要用库

  • 保密:别人想使用你的代码功能,但你不想让别人看见代码细节
  • 方便:只需要知道库文件函数接口,就可以方便使用其功能,不用知道具体细节
  • 说明书:头文件相当于说明书,库函数使用信息基本都可以找到

静态库与动态库的区别

windowslinux中都有库概念,都有静态库、动态库之分。

  • windows
    • 静态库文件为.lib文件,
    • 动态库文件为.dll文件
  • linux
    • 静态库文件为.a文件
    • 动态库文件为.so文件,后面可能跟数字,表明库版本
  • 两者区别
    • 静态库在编译阶段,会加载到程序内部
    • 动态库在程序运行时才会被加载
  • 优缺点
    • 静态库优点:程序依赖性不大,自身就是功能完备的主体
    • 静态库缺点:加入多个程序用到同一个库文件,编译出每个程序都有一份该静态库融入其中,体量巨大。不利于更新,(游戏改动人物轻微细节,就需要对整个程序进行重新编译发布)
    • 动态库优点:程序调用时加载结束时释放,应用灵活占用空间不大,对程序轻微改动时,只需要改变某些库文件即可
    • 动态库缺点:某些库文件丢失可能导致导致程序无法正运行

静态库的制作

命名规则

  • 前缀lib
  • 库名
  • 后缀.a
  • 完整形式 libxxx.a

制作步骤

  • 原材料:.c .cpp
  • c文件生成.o
    • gcc -c xxx.c
  • .o打包
    • ar rcs 静态库的名字 原材料
    • ar rcs libxxx.a *.o
  • 库的使用
    • gcc main.c -I 头文件路径 -L 库路径 -l库名(紧挨着,只写库名前缀尾缀都不要) -o 指定文件名

静态库制作调用举例


//工程目录下有一个main.c文件src、include两个文件夹
root@DESKTOP-FR31BP0:/tmp# ls -l
总用量 16
drwxrwxrwx 0 root root 4096 425 10:22 include
-rw-rw-rw- 1 root root   77 425 10:22 main.c
drwxrwxrwx 0 root root 4096 425 10:40 src


//src目录下有两个.c文件
root@DESKTOP-FR31BP0:/tmp# ls src/
func1.c  func2.c
//include目录下有一个.h头文件
root@DESKTOP-FR31BP0:/tmp# ls include/
head.h


//查看相关的内容
root@DESKTOP-FR31BP0:/tmp# cat src/func1.c
#include <stdio.h>
#include "head.h"
void func1(void)
{
    printf("this is func1\n");
}
root@DESKTOP-FR31BP0:/tmp# cat src/func2.c
#include <stdio.h>
#include "head.h"
void func2(void)
{
    printf("this is func2\n");
}
root@DESKTOP-FR31BP0:/tmp# cat include/head.h
#ifndef _HEAD_H_
#define _HEAD_H_
void func1(void);
void func2(void);
#endif
root@DESKTOP-FR31BP0:/tmp# cd src
root@DESKTOP-FR31BP0:/tmp/src# ls
func1.c  func2.c


//制作静态库第一步将.c文件转化.o文件
root@DESKTOP-FR31BP0:/tmp/src# gcc *.c -I ../include/ -c
root@DESKTOP-FR31BP0:/tmp/src# ls
func1.c  func1.o  func2.c  func2.o


//制作静态库第二部=步将.o文件转化为静态库文件
root@DESKTOP-FR31BP0:/tmp/src# ar rcs libtest.a *.o
root@DESKTOP-FR31BP0:/tmp/src# ls
func1.c  func1.o  func2.c  func2.o  libtest.a
root@DESKTOP-FR31BP0:/tmp/src# cd ..


//调用验证
root@DESKTOP-FR31BP0:/tmp# gcc main.c -o run -I ./include/ -L src/ -l test


//成功编译
root@DESKTOP-FR31BP0:/tmp# ls
include  main.c  run  src


//功能有效
root@DESKTOP-FR31BP0:/tmp# ./run
this is func1
this is func2

动态库的制作

命名规则

  • libxxx.so
  • libxxx.so.n.n.n(n代表数字表示版本)

制作步骤

  • 源文件生成.o
    gcc -c *.c -fpic(fPIC)
  • 打包成动态库
    gcc -shared -o libxxx.so *.o(第一步生成的.o文件)

库的使用

  • 加入现在有以下原料:(a.h libtest.so(动态库和库的头文件)) 、main.c(测试程序)
  • 使用方法与静态库使用方法一致
    gcc main.c -I 头文件路径 -L 库路径 -l库名(紧挨着,只写库名前缀尾缀都不要) -o 指定文件名
  • 调用报错:执行动态库的时候,打不开动态库文件
    对于elf格式的可执行程序,是由ld-linux.so*,它先后搜索elf文件的DT_RPATH段->环境变量LD_LIBRARY_PATH->/etc/ld.so.cache文件列表->/lib/,/usr/lib 目录找到库文件后将其载入内存
  • 解决办法
    -直接将库文件复制到/lib/,/usr/lib目录下
    • 使用环境变量
      • 临时设置
        在终端里面写一个命令:export LD_LIBRARY_PATH=动态库的路径
      • 永久设置
        • 用户级别
          ~/.bashrc用户配置文件里添加上面命令,配置完成重启终端或者 source~/.bashrc
        • 系统级别
          /etc/profile系统配置文件里添加上面命令,配置完成source /etc/profile更新配置文件
    • 更新/etc/ld.so.cache文件列表
      • 找到一个配置文件
        • /etc/ld.so.conf
        • 动态库绝对路径写到里面
      • 执行一个命令
        • ldconfig -v

用法举例

//工程目录结构
root@DESKTOP-FR31BP0:/tmp# ls -l
总用量 20
drwxrwxrwx 0 root root 4096 425 10:22 include
-rw-rw-rw- 1 root root   77 425 10:22 main.c
drwxrwxrwx 0 root root 4096 425 16:34 src
root@DESKTOP-FR31BP0:/tmp# ls include/
head.h
root@DESKTOP-FR31BP0:/tmp# ls src/
func1.c  func2.c


//进入src文件夹进行库的生成
root@DESKTOP-FR31BP0:/tmp# cd src
root@DESKTOP-FR31BP0:/tmp/src# ls
func1.c  func2.c


//将.c文件转化为.o文件
root@DESKTOP-FR31BP0:/tmp/src# gcc -c *.c -I ../include/ -fpic
root@DESKTOP-FR31BP0:/tmp/src# ls
func1.c  func1.o  func2.c  func2.o


//生成动态库文件
root@DESKTOP-FR31BP0:/tmp/src# gcc -shared -o libtest.so *.o
root@DESKTOP-FR31BP0:/tmp/src# ls
func1.c  func1.o  func2.c  func2.o  libtest.so
root@DESKTOP-FR31BP0:/tmp/src# cd ..
root@DESKTOP-FR31BP0:/tmp# ls
include  main.c  src


//编译工程
root@DESKTOP-FR31BP0:/tmp# gcc main.c -o run -I ./include/ -L src/ -l test


//生成了目标程序run
root@DESKTOP-FR31BP0:/tmp# ls
include  main.c  run  src


//运行程序出错
root@DESKTOP-FR31BP0:/tmp# ./run
./run: error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory


//运行其中一种方法,程序成功运行
root@DESKTOP-FR31BP0:/tmp# cp src/libtest.so /lib
root@DESKTOP-FR31BP0:/tmp# ./run
this is func1
this is func2
//其余解决方案自行测试

猜你喜欢

转载自blog.csdn.net/z961968549/article/details/80080665