Linux下动静态库的打包与使用指南(C/C++)

yizhihongxing

Linux下动静态库的打包与使用指南(C/C++)

什么是库

在软件开发中,我们常常会将一些常用的代码封装成函数或类。如果这些函数或类需要在多个程序中使用,那么将其打包成一个库以供其他程序调用就是一个不错的选择。库分为动态库和静态库两种类型。

静态库和动态库的区别

  • 静态库

静态库是指在程序编译时,代码就已经被编译进了可执行文件中。因此,可执行文件体积较大,但是在程序运行时,不需要加载其他 DLL 文件,直接运行即可。这就保证了程序运行的稳定性。

  • 动态库

与静态库不同,动态库在程序运行时才会被加载。这样,可执行文件不需要包含整个库代码,减小了可执行文件的体积。但是,程序运行时,若是要使用到动态库中的函数代码,就需要先找到动态库所在的位置,然后再去加载其中的函数代码,这样会稍微增加程序启动的时间,但是这样会减少内存的使用,节省硬盘空间。

静态库的打包与使用

静态库打包

静态库可以通过 gcc 命令行进行打包:

$ gcc -c -o mylib.o mylib.c  //这里是将源文件编译为目标文件的语句
$ ar -r libmylib.a mylib.o   //将编译好的目标文件打包成静态库的语句
  • -c 表示编译源文件
  • -o mylib.o 表示将源文件编译为目标文件
  • ar -r 表示将目标文件打包为静态库
  • libmylib.a 表示静态库的名称

静态库使用

静态库使用方法,可以在 gcc 命令行中添加 -lmylib 的参数,其中 -l 表示连接操作(链接器),后面接静态库的名称(去掉前面的"lib"和后面的".a")。例如:

$ gcc -o myapp myapp.c -lmylib

这个命令将会将 myapp.c 编译为目标文件 myapp,并将 myapp 和库中的函数一起连接,生成可执行文件。

动态库的打包与使用

动态库打包

动态库同样可以通过 gcc 命令行进行打包,不过需要特别标注:

$ gcc -fPIC -shared -o libmylib.so mylib.c
  • -fPIC 表示生成与位置无关的代码(PIC)。
  • -shared 表示生成动态库。
  • -o libmylib.so 表示生成的动态库名称。

动态库使用

动态库使用方法类似于静态库的使用,使用 -lmylib 的参数,不过需要加上 -L 和库文件所在目录的路径。

例如,若库文件在 /usr/local/lib 目录下,可以使用下面的命令运行程序:

$ gcc -o myapp myapp.c -L/usr/local/lib -lmylib

实例说明

  • 静态库实例说明

在示例代码中,我们假设存在一个 mylib.c 文件,包含如下代码:

int square(int n) { return n * n; }

使用下面的命令编译 mylib.c 文件并打包生成静态库 libmylib.a:

$ gcc -c -o mylib.o mylib.c
$ ar -r libmylib.a mylib.o

然后,我们可以再编写一个主程序 myapp.c,用来调用 mylib 中的函数:

#include <stdio.h>

int square(int); //声明静态库中的函数

int main(int argc, char *argv[]) {
  int n = 5;
  printf("%d的平方为%d\n", n, square(n)); //调用静态库中的函数
  return 0;
}

最后,使用下面的命令编译 myapp.c 文件:

$ gcc -o myapp myapp.c -L. -lmylib

其中,-L. 表示将当前目录加入到库文件的搜索路径。-lmylib 表示链接到 libmylib.a 静态库文件。

执行 myapp 程序:

$ ./myapp

输出结果为:5的平方为25。

  • 动态库实例说明

继续以 mylib.c 为例。我们可以使用下面的命令编译 mylib.c 文件并生成动态库 libmylib.so:

$ gcc -fPIC -shared -o libmylib.so mylib.c

然后,我们可以再编写一个主程序 myapp.c,用来调用 mylib 中的函数:

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

typedef int (*f_type)(int); //声明函数指针类型

int main(int argc, char *argv[]) {
  void *handle;
  char *error;
  int (*f)(int);
  int n = 5;
  handle = dlopen("./libmylib.so", RTLD_LAZY);
  if (!handle) {
    fprintf(stderr, "%s\n", dlerror());
    exit(EXIT_FAILURE);
  }
  dlerror();
  f = (f_type)dlsym(handle, "square");
  if ((error = dlerror()) != NULL) {
    fprintf(stderr, "%s\n", error);
    exit(EXIT_FAILURE);
  }
  printf("%d的平方为%d\n", n, (*f)(n));
  dlclose(handle);
  return 0;
}

编译并执行:

$ gcc -o myapp myapp.c -ldl
$ ./myapp

输出结果为:5的平方为25。

这里需要注意一下,使用动态库时,需要使用 dlopen() 函数打开库文件,使用 dlsym() 函数获取指向被调用函数的指针,使用 dlclose() 函数关闭库文件。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Linux下动静态库的打包与使用指南(C/C++) - Python技术站

(0)
上一篇 2023年5月23日
下一篇 2023年5月23日

相关文章

  • C语言循环结构详解

    C语言循环结构详解 什么是循环结构? 循环结构是计算机编程语言中最重要的结构之一,它允许程序重复执行一次或多次某个代码块。 在C语言中,循环结构主要有以下三种: for循环结构 while循环结构 do…while循环结构 for循环结构 for循环结构是最常用的循环结构之一,在需要重复执行N次的情况下,使用for循环比较便捷。 for循环结构的语法格式…

    C 2023年5月23日
    00
  • C++中函数指针详解及代码分享

    关于“C++中函数指针详解及代码分享”的完整攻略,我为大家总结如下: 1. 什么是函数指针? 函数指针是一个指向函数的指针变量。函数指针可以像普通函数一样被调用,其语法形式为: 返回值类型 (*指针变量名)(参数列表); 其中,指针变量名可以被赋值为相同参数列表和返回类型的函数地址。可以使用函数指针来传递函数作为参数、实现回调函数等。 举个例子,假如我们有一…

    C 2023年5月24日
    00
  • C# 崩溃异常中研究页堆布局的详细过程

    C# 崩溃异常中研究页堆布局的详细过程 什么是页堆布局? 页堆布局(Page Heap)是一种用于内存管理的技术。它增强了堆管理器的动态检查,防止发生常见的堆错误,如覆盖内存、缓冲区溢出等。在页堆布局技术中,每一个页都被存储为一个不可变的空间大小,使得每一个堆分配都在一个匹配的页边界上发生。 页堆布局引发的异常 如果一个应用程序没有正确地使用内存,那么它很容…

    C 2023年5月23日
    00
  • C++中的vector容器对象学习笔记

    C++中的vector容器对象学习笔记 什么是vector容器对象? vector容器对象在C++中被定义为动态数组。它可以容纳许多类类型对象(int、double、bool、char等)。和其他数组不同的是,vector容器对象在创建后,可以根据需要动态地调整大小。这意味着可以动态添加或删除元素。 如何定义并初始化vector容器对象? 定义vector需…

    C 2023年5月23日
    00
  • C语言实现最全自动售货机

    C语言实现最全自动售货机的攻略 介绍 自动售货机是一种非常实用的设备,能够自动完成商品的销售和付款收取。在实际中,我们可以用C语言的编程知识来实现一个自动售货机,以供学习和使用。 基本功能 自动售货机的基本功能是:选择商品、投币、找零、出货。接下来,我们来详细讲解C语言如何实现这些功能。 选择商品 定义一个数组来存储售货机中的商品,每个商品包括商品名、价格和…

    C 2023年5月23日
    00
  • C++反射的一种实现方法详解

    C++反射的一种实现方法详解 什么是反射 反射是一种程序可以检查其自身状态的能力,并能够根据自身状态的不同行为作出相应的改变的能力。C++作为一门静态类型语言,本身并没有内置的反射机制,但通过一些技巧,我们可以模拟出类似反射的能力。 实现反射的核心技巧 实现反射的核心在于获取类的信息,包括类名、成员函数名、成员变量名等等,以及根据这些信息调用对应的对象或函数…

    C 2023年5月23日
    00
  • 尼尔机械纪元结局如何选 全结局条件图文介绍

    关于尼尔机械纪元结局的选择及全结局条件,我会通过以下几个方面进行详细讲解: 结局种类及选择方法 全结局条件概述 示例说明 1. 结局种类及选择方法 尼尔机械纪元共有5种结局,分别是A B C D E,其中A~D为主结局,E为非正式结局。为了触发每个结局,你需要在游戏中做出不同的选择。以下是各个结局的选择步骤: A结局:完成E机器人的任务,选择消除“人机分离”…

    C 2023年5月22日
    00
  • c++ 面向对象设计五大原则

    当设计面向对象的程序时,我们需要遵循五个相关原则,也被称为“SOLID”原则。以下是这些原则的详细介绍和示意: 单一职责原则(Single Responsibility Principle) 一个类应该有一个单一职责。也就是说,一个类只应该有一项引起它的变化的原因。应该将每个职责分配给具有单独职责的不同类。 示例:我们考虑编写一个计算器类。如果我们将计算逻辑…

    C 2023年5月22日
    00
合作推广
合作推广
分享本页
返回顶部