Linux静态库与动态库实例详解

Linux静态库与动态库实例详解

1. Linux 下静态链接库编译与使用

首先编写如下代码:

// main.c
#include "test.h"
int main(){
  test();
  return 0;
}

// test.h
#include<iostream>
using namespace std;
void test();

// test.c
#include "test.h"
void test(){
 cout<< "test!" <<endl;
}

然后编译:

1. gcc -c test.c //生成目标文件
2. ar crv libtest.a test.o //生成静态链接库libtest.a
3. g++ -o main main.c -ltest //编译main程序同时链接libtest.a静态库
4. ./main //运行main程序

2. Linux 下动态链接库编译与使用

代码与上述一致。

然后编译:

1. g++ -fPIC -shared -o libtest.so test.c //生成动态链接库libtest.so
2. g++ -o main main.c -ltest //调用动态链接库libtest.so
3. ./main //运行main程序

3. 链接时缺失了相关目标文件(.o)

代码与上述一致。

编译过程如下:

1. gcc -c test.c
2. gcc -c main.c
3. gcc -o main main.o

这时,你会发现,报错了:undefined reference to `test'.

这就是最典型的 undefined reference 错误,因为在链接时发现找不到某个函数的实现文件, 本例中test.o文件中包含了test()函数的实现,所以如果按下面这种方式链接就没事了。

1. gcc -o main main.o test.o
【扩展】:其实上面为了让大家更加清楚底层原因,我把编译链接分开了,下面这样编译
也会报undefined reference错,其实底层原因与上面是一样的。

gcc -o main main.c //缺少test()的实现文件 

需要改成如下形式才能成功,将test()函数的实现文件一起编译。

gcc -o main main.c test.c //ok,没问题了

4. 链接时缺少相关的库文件(.a/.so)

在此,只举个静态库的例子,假设源码与上述一致。

1. 把test.c编译成静态库:
  gcc -c test.c
  sr -rc test.a test.o
  gcc -c main.c

2. 生成可执行程序:
  gcc -o main -main.o

    此时同样出现 undefined reference to `test'报错。其根本原因也是找不到test()函数的实现文
  件,由于该test()函数的实现在test.a这个静态库中的,故在链接的时候需要在其后加入test.a这个
  库,链接命令修改为如下形式即可。
  1. gcc -o main main.c ./test.a

5. 多个库文件链接顺序问题

这种问题也非常的隐蔽,不仔细研究你可能会感到非常地莫名其妙。我们依然回到第3小节所讨论
的问题中,在最后,如果我们把链接的库的顺序换一下,看看会发生什么结果?

1. gcc -o main main.o func.a test.a

我们会得到如下的编译错误:

1. test.a(test.o): In function `test':
2. test.c:(.text+0x13): undefined reference to `func'
3. collect2: ld returned 1 exit status
因此,我们需要注意,在链接命令中给出所依赖的库时,需要注意库之间的依赖顺序,依赖其他库
的库一定要放到被依赖库的前面,这样才能真正避免undefined reference的错误,完成编译链接。

如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

(0)

相关推荐

  • Linux环境g++编译GDAL动态库操作方法

    一.编译步骤 解压下载的GDAL源程序,并在命令行中切换到解压目录. tar -xzvf gdal-2.1.3.tar.gz cd gdal-2.1.3 GDAL可通过configure来实现一些自定义配置,可通过./configure –h命令来查看.--prefix=path表示设置GDAL的make install后的build目录,里面有生成的头文件和动态库.输入如下命令: ./configure --prefix=/root/Test/gdalbuild 这时可以发现目录中新生成了GD

  • linux生成(加载)动态库静态库和加载示例方法

    动态库的生成: 1./*mysum.c*/ 复制代码 代码如下: #include <stdio.h>#include "src.h" int sum(int a,int b){return (a+b);} 2./*mysum.h*/ 复制代码 代码如下: #ifndef __SRC_H__#define __SRC_H__ int sum(int a,int b); #endif 3./*main.c*/ 复制代码 代码如下: #include <stdio.h&g

  • Linux动态库函数的详解

    Linux动态库函数的详解 加载动态库 void *dlopen(const char *filename, int flag); flag的可能值: RTLD_LAZY RTLD_NOW RTLD_GLOBAL RTLD_LOCAL RTLD_NODELETE (since glibc 2.2) RTLD_NOLOAD (since glibc 2.2) RTLD_DEEPBIND 这些flag的具体含义可使用man查看 返回动态库中最近的一次错误 char *dlerror(void); 根

  • 解决Linux程序编译链接动态库版本的相关问题

    前言 不同版本的动态库可能会不兼容,如果程序在编译时指定动态库是某个低版本,运行是用的一个高版本,可能会导致无法运行.Linux上对动态库的命名采用libxxx.so.a.b.c的格式,其中a代表大版本号,b代表小版本号,c代表更小的版本号,我们以Linux自带的cp程序为例,通过ldd查看其依赖的动态库 $ ldd /bin/cp linux-vdso.so.1 => (0x00007ffff59df000) libselinux.so.1 => /lib64/libselinux.so.1

  • 浅谈Linux C语言动态库及静态库

    假设在math目录下已编辑好add.c sub.c div.c mul.c func_point.c文件,func_point.c为包含main()的源文件! 动态库的制作: 方法一: gcc -c -fPIC add.c sub.c div.c mul.c //-c表示生成.o目标文件,-f后加一些编译选项,PIC表示与位置无关 gcc -shared -o libmymath.so add.o sub.o mul.o div.o//创建共享库mymath,添加add.o,sub.o,mul.

  • linux 程序、动态库、静态库内部添加版本号和编译时间详解

    给程序和库添加版本号和库,有利于维护和升级. 当然你可以在文件名上体现,比如有个程序叫 yun,文件名写为 yun_1.0.2,但这个需要每次手动维护,而且不能100%确保当前程序就是那个版本.所以,把版本号体现在程序内部,是一个不错的选择. ----------------------------- 我是做法分割线 ------------------------------- 一.可执行程序 程序内部定义版本宏,然后 main 函数通过 -v 参数,打印版本号和编译时间,代码如下: 注:__

  • Linux下g++编译与使用静态库和动态库的方法

    在windows环境下,我们通常在IDE如VS的工程中开发C++项目,对于生成和使用静态库(*.lib)与动态库(*.dll)可能都已经比较熟悉,但是,在linux环境下,则是另一套模式,对应的静态库(*.a)与动态库(*.so)的生成与使用方式是不同的.刚开始可能会不适应,但是用多了应该会习惯这种使用,因为步骤上并没有VS下配置那么繁琐. 下面就分别总结下linux下生成并使用静态库与动态库的方法:(由于是C++项目,所以编译器用的g++,但是与gcc的使用是相通的) 首先是准备工作,把我们需

  • 深入探讨Linux静态库与动态库的详解(一看就懂)

    库从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行.库分静态库和动态库两种. 一.静态库和动态库的区别1. 静态函数库这类库的名字一般是libxxx.a:利用静态函数库编译成的文件比较大--空间,因为整个函数库的所有数据都会被整合进目标代码中,他的优点就显而易见了,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去了.当然这也会成为他的缺点,因为如果静态函数库改变了,那么你的程序必须重新编译.2. 动态函数库这类库的名字一般是libxxx.so;相对于静态

  • 分析Windows和Linux动态库

    摘要:动态链接库技术实现和设计程序常用的技术,在Windows和Linux系统中都有动态库的概念,采用动态库可以有效的减少程序大小,节省空间,提高效率,增加程序的可扩展性,便于模块化管理.但不同操作系统的动态库由于格式 不同,在需要不同操作系统调用时需要进行动态库程序移植.本文分析和比较了两种操作系统动态库技术,并给出了将Visual C++编制的动态库移植到Linux上的方法和经验. 1.引言 动态库(Dynamic Link Library abbr,DLL)技术是程序设计中经常采用的技术.

  • JavaScript静态作用域和动态作用域实例详解

    静态作用域指的是一段代码,在它执行之前就已经确定了它的作用域,简单来说就是在执行之前就确定了它可以应用哪些地方的作用域(变量). 动态作用域–函数的作用域是在函数调用的时候才决定的 JavaScript采用的是词法作用域即静态作用域: // 静态作用域: var a = 10; function fn() { var b = 1; console.log(a + b); } fn(); // 11 在创建fn函数时的时候就已经确定了它可以作用哪些变量,如果函数fn里面有变量a就直接操作变量a,

  • Android Studio打包.so库到apk中实例详解

    Android Studio打包.so库到apk中实例详解 由于在原来的ADT的Eclipse环境中,用ndk_build工具生成了相应的各个.so库文件之后,eclipse工具就会自动把这些库导入到apk中.而Android Studio目前为止(1.1.0版本)还无法做到那么自动,但是我们可以通过以下方式进行. 首先在Android Studio工程的app目录下创建整个jni目录,jni目录里写Android.mk.Application.mk以及各类C/C++和汇编源文件.然后跟原来一样

  • Linux 下C语言连接mysql实例详解

    Linux 下C语言连接mysql实例详解 第一步: 安装mysql, 参考:http://www.jb51.net/article/39190.htm 第二步: 安装mysql.h函数库 sudo apt-get install libmysqlclient-dev 执行之后就可以看到/usr/include/MySQL目录了 然后开始我们的链接. 首先看我的数据库 mysql> show databases; +--------------------+ | Database | +----

  • Spring静态代理和动态代理代码详解

    本节要点: Java静态代理 Jdk动态代理 1 面向对象设计思想遇到的问题 在传统OOP编程里以对象为核心,并通过对象之间的协作来形成一个完整的软件功能,由于对象可以继承,因此我们可以把具有相同功能或相同特征的属性抽象到一个层次分明的类结构体系中.随着软件规范的不断扩大,专业化分工越来越系列,以及OOP应用实践的不断增多,随之也暴露了一些OOP无法很好解决的问题. 现在假设系统中有三段完全相似的代码,这些代码通常会采用"复制"."粘贴"方式来完成,通过这种方式开发

  • Linux 全能系统监控工具dstat的实例详解

    全能系统监控工具dstat dstat 是一个可以取代vmstat,iostat,netstat和ifstat这些命令的多功能产品.dstat克服了这些命令的局限并增加了一些另外的功能,增加了监控项,也变得更灵活了.dstat可以很方便监控系统运行状况并用于基准测试和排除故障. dstat可以让你实时地看到所有系统资源,例如,你能够通过统计IDE控制器当前状态来比较磁盘利用率,或者直接通过网络带宽数值来比较磁盘的吞吐率(在相同的时间间隔内). dstat将以列表的形式为你提供选项信息并清晰地告诉

  • Linux上的文件搜索命令实例详解

    locate 基础了解 在centos7上默认没有locate命令,需要先手动安装.安装步骤:http://www.cnblogs.com/feanmy/p/7676717.html locate命令搜索的后台数据库路径:/var/lib/mlocate/mlocate.db ls -hl /var/lib/mlocate total 1.2M -rw-r----- 1 root slocate 1.2M Oct 16 14:36 mlocate.db 更新数据库使用updatedb,配置文件为

  • Linux 中常用的Rpm命令实例详解

    rpm命令是RPM软件包的管理工具.rpm原本是Red Hat Linux发行版专门用来管理Linux各项套件的程序,由于它遵循GPL规则且功能强大方便,因而广受欢迎.逐渐受到其他发行版的采用.RPM套件管理方式的出现,让Linux易于安装,升级,间接提升了Linux的适用度. 语法 rpm(选项)(参数) 选项 -a:查询所有套件: -b<完成阶段><套件档>+或-t <完成阶段><套件档>+:设置包装套件的完成阶段,并指定套件档的文件名称: -c:只列出

  • Linux 中fork的执行的实例详解

    Linux 中fork的执行的实例详解 先看看一段fork的程序 int main() { pid_t pid; 语句 a; pid = fork(); 语句 b; } 1.当程序运行到 pid = fork()时,这个进程马上分裂(fork的中文意思)成两个进程,我们称为父进程和子进程,子进程是父进程的副本,副本的意思是子进程把父进程的数据空间,堆和栈都复制一遍给自己用,这要求在内存给子进程分配和父进程同样大的存储空间,这样,父,子进程拥有相同的数据,但不会共享存储空间,他们只是共享正文段.

  • Linux 查看空间使用情况的实例详解

    Linux 查看空间使用情况的实例详解 在日常的Linux巡检中,我们会遇到文件系统目录使用空间很高的情况,例如如下利用"df -h "查看到根目录空间使用超过80%.而我们仅仅知道是根目录空间使用过高,这样是不够的.还需要知道是目录还是文件让根目录空间使用过高.通常我们使用的命令是"du -sh *". 第一步:查看Linux系统的文件系统使用情况,如下可以看到根目录"/"已经使用81%. [root@hostname ~]# df -h Fi

  • JAVA 静态的单例的实例详解

    JAVA  静态的单例的实例详解 实现代码: public class Printer { private Printer(){ } public static Printer newInstance(){ return CreatePrinter.mPrinter; } private static class CreatePrinter{ private final static Printer mPrinter = new Printer(); } } 因为静态的单例对象没有作为类的成员变

随机推荐