文章目录

  • GCC 版本
    • 1. c代码中使用dlopen/dlsum动态加载动态库(不使用头文件)
    • 2. c代码中使用类似静态库的调用(使用头文件)
    • 3. so动态库中调用so动态库
  • Cmakelists
    • 1. 以下介绍一种导入动态库的方法:
    • 2.实践:
    • 3. 几个关键名词的区别

GCC 版本

1. c代码中使用dlopen/dlsum动态加载动态库(不使用头文件)

制作so文件

首先先制作制作so文件:libadd_c.so

[ add.c]
int add(int a, int b) {  return a + b;
}

编译:

gcc -shared -fpic -o libadd_c.so add.c
-shared 生成共享目标文件,通常用在建立共享库时
-fpic 作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code),则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意位置,都可以正确的执行。
这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。参考:gcc-4.9.4命令文档

执行编译任务,输出相应的libadd_c.so文件。
编写测试函数

[ test.cpp]
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
int main()
{  int a = 0;  void *handle = dlopen("./libadd_c.so", RTLD_LAZY);  if(!handle)  {   printf("open lib error\n");  cout<<dlerror()<<endl;  return -1;  }   typedef int (*add_t)(int a, int b);  add_t add = (add_t) dlsym(handle, "add");  if(!add)  {   cout<<dlerror()<<endl;  dlclose(handle);  return -1;  }   a = add(4, 4);  printf("a = %d\n",a);  dlclose(handle);  return 0;
}

编译:

g++ test.cpp -ldl -o test

运行
./test
输出为:8

注意:typedef int (*add_t)(int a, int b);声明一个函数指针。
首先你要明白函数指针的概念
int *p(int ,int );//声明一个函数
int (*p)(int ,int);//声明一个函数指针
typedef int(*add_t)(int, int);

就是把这个类型的函数指针的声明变为add_t

在使用动态链接库libadd_c.so文件的时候,主要使用到了四个函数:
(1) dlopen()

函数原型:void *dlopen(const char *libname,int flag);
功能描述:dlopen必须在dlerror,dlsym和dlclose之前调用,表示要将库装载到内存,准备使用。如果要装载的库依赖于其它库,必须首先装载依赖库。如果dlopen操作失败,返回NULL值;如果库已经被装载过,则dlopen会返回同样的句柄。

参数中的libname一般是库的全路径,这样dlopen会直接装载该文件;如果只是指定了库名称,在dlopen会按照下面的机制去搜寻:
a.根据环境变量LD_LIBRARY_PATH查找
b.根据/etc/ld.so.cache查找
c.查找依次在/lib和/usr/lib目录查找。
flag参数表示处理未定义函数的方式,可以使用RTLD_LAZY或RTLD_NOW。RTLD_LAZY表示暂时不去处理未定义函数,先把库装载到内存,等用到没定义的函数再说;RTLD_NOW表示马上检查是否存在未定义的函数,若存在,则dlopen以失败告终。

(2) dlerror()

函数原型:char *dlerror(void);
功能描述:dlerror可以获得最近一次dlopen,dlsym或dlclose操作的错误信息,返回NULL表示无错误。dlerror在返回错误信息的同时,也会清除错误信息。

(3) dlsym()

函数原型:void *dlsym(void *handle, const char *symbol);
功能描述:在dlopen之后,库被装载到内存。dlsym可以获得指定函数(symbol)在内存中的位置(指针)。如果找不到指定函数,则dlsym会返回NULL值。但判断函数是否存在最好的方法是使用dlerror函数。注意:个人感觉从dlsym()寻找到内存中指针位置这个操作还是很麻烦的。

(4) dlclose

函数原型:int dlclose(void *);
功能描述:将已经装载的库句柄减一,如果句柄减至零,则该库会被卸载。如果存在析构函数,则在dlclose之后,析构函数会被调用。

链接:https://www.jianshu.com/p/f055b347f338

2. c代码中使用类似静态库的调用(使用头文件)

这种方式生成的程序会在启动时候就加载so动态库。

方式1:类似静态库的调用(使用头文件)

这种方式生成的程序会在启动时候就加载so动态库。

add.hint add(int x, int y);
add.c#include "add.h"int add(int x, int y) {return (x + y);
}
main.c#include <stdio.h>
#include "add.h"int main()
{int sum = add(7, 8);printf("7+8 = %d\n", sum);return 0;
}

编译so,生成libadd.so。

gcc -shared -o libadd.so add.c

编译main,使用-L./指定add库在当前目录。

gcc -o main main.c -L./ -ladd

链接:https://blog.csdn.net/shaosunrise/article/details/81161064

3. so动态库中调用so动态库

add.hint add(int x, int y);
add.c#include "add.h"int add(int x, int y) {return (x + y);
}
sum.hvoid printsum(int a, int b);

sum.c#include "sum.h"
#include <stdio.h>
#include "add.h"void printsum(int a, int b){int sum = add(a, b);printf("%d+%d = %d\n", a, b, sum);
}
main.c#include "sum.h"int main()
{printsum(1, 3);return 0;
}

编译libadd.so

gcc -shared -o libadd.so add.c

编译libsum.so,需要指定libadd.so信息

gcc -shared -o libsum.so sum.c -L. -ladd

编译main,仅需要指定libsum.so

gcc -o main main.c -L. -lsum

main运行的时候同时需要libsum.so 和 linadd.so。
链接:https://blog.csdn.net/shaosunrise/article/details/81161064

Cmakelists

关于Cmakelists的用法,唯一的建议是,访问官方网站:https://cmake.org/cmake/help/v3.0

1. 以下介绍一种导入动态库的方法:

引入so文件CmakeList 配置

1.导入so文件

将so文件拷贝到项目中,路径自己定吧,只要配置的时候不出错就行,我是这样的拷贝到jniLibs文件夹中的。jniLibs下的子文件夹表示的是cpu类型,你可以少建些,但不可以不建,so文件就放在这些文件夹下,每个cpu类型都放。

(注:导入的so文件需要在库名前添加“lib”,即lib库名.so,比如我要导入库名为test的so文件,那么你得将so文件名改为libtest.so再拷贝进项目)

2.配置

add_library( ): .c或者.cpp文件要假如里面;
include_directories( ) :第三库使用到的头文件;

(1)在CMakeLists.txt中添加:

  • add_library()
  • set_target_properties()
  • 通常情况下so文件还会附带.h头文件,这时候需要再加上include_directories()语句来定位头文件的位置
# Sets the minimum version of CMake required to build the native library.cmake_minimum_required(VERSION 3.4.1)# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.#将指定的源文件生成链接文件,然后添加到工程中去
add_library(
#设置lib的名字native-lib
#设置lib的类型 共享型  还有STATIC、和MODULESHARED#源码的相对路径src/main/cpp/native-lib.cpp)
#这个地方是 系统已经集成了很多lib,然后需要find以下 作为声明,表示你要用这些lib
find_library(
#自己起一个 lib的名称log-lib#lib的文件名log )#将目标文件与库文件进行链接
target_link_libraries( # Specifies the target library.native-lib# Links the target library to the log library# included in the NDK.${log-lib} )
add_library(test-lib SHARED IMPORTED)
set_target_properties(test-libPROPERTIES IMPORTED_LOCATION${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libtest-lib.so)set(distribution_DIR ../../../../libs)
#添加lib,SHARED类型,是IMPORTED 引入的库
add_library( libyuvSHAREDIMPORTED)
#设置 库的属性   里面是名称 ,属性:引入地址把我们的真实地址填写进去
set_target_properties( libyuvPROPERTIES IMPORTED_LOCATION${distribution_DIR}/armeabi-v7a/libyuv.so)target_link_libraries( native-lib#指定链接库libyuv# Links the target library to the log library# included in the NDK.${log-lib} )

STATIC:表示静态的.a的库。
SHARED:表示.so的库。
${CMAKE_SOURCE_DIR}:表示CMake.txt的当前文件夹路径。
${ANDROID_ABI}:编译时会自动根据CPU架构去选择相应的库。

3.调用

导入so文件相当于你“实现”了方法,还需要“声明”。

链接:https://blog.csdn.net/carryworld/article/details/75026171

2.实践:

2.1、创建我的共享库:MySharedLib

CMakeLists.txt
library.h
library.cpp

在CMakeLists.txt所在的目录中:

cmake ./
make

2.2.so 共享库的使用(被可执行项目调用)

创建一个名为test的可执行项目
CMakeLists.txt

按照这个顺序来导入so

1、include_directories( )
2、add_library( )
3、set_target_properties( )
4、add_executable(hello main.cpp)
5、target_link_libraries( )

也可以按照这个顺序来导入so

1、include_directories( )
2、link_libraries()
3、add_executable(hello main.cpp)
4、target_link_libraries( )

代码参考我的仓库例子:

https://github.com/HiYx/study-repository-myself-cmake-practice-moment-V1-cmakelist/tree/main/code/ch04_solib

3. 几个关键名词的区别

这里介绍常用的指令

  • include_directories
  • add_library + set_target_properties
  • target_link_libraries
  • link_directories
  • link_libraries (已经废弃)

该笔记主要参考了cmake官网给的教程,如有需要请访问以下网址:
https://cmake.org/cmake/help/v3.1/

1、include_directories
只是告诉CMake这个位置可能有 .h 头文件,输入的是path

2、link_directories (不一定需要)
只是告诉CMake这个位置可能有lib,输入的是path。

该指令的作用主要是指定要链接的库文件的路径,该指令有时候不一定需要。因为find_package和find_library指令可以得到库文件的绝对路径。不过你自己写的动态库文件放在自己新建的目录下时,可以用该指令指定该目录的路径以便工程能够找到。

例子如下:

link_directories(lib
)

3、 add_library + set_target_properties

该指令的主要作用就是将指定的源文件生成链接文件,然后添加到工程中去。

add_library(<name> [STATIC | SHARED | MODULE][EXCLUDE_FROM_ALL][source1] [source2] [...])
  • 其中表示库文件的名字,该库文件会根据命令里列出的源文件来创建。而STATIC、SHARED和MODULE的作用是指定生成的库文件的类型。STATIC库是目标文件的归档文件,在链接其它目标的时候使用。SHARED库会被动态链接(动态链接库),在运行时会被加载。MODULE库是一种不会被链接到其它目标中的插件,但是可能会在运行时使用dlopen-系列的函数。默认状态下,库文件将会在于源文件目录树的构建目录树的位置被创建,该命令也会在这里被调用。

  • 而语法中的source1 source2分别表示各个源文件。

如果add_library 只写了属性,则通过 set_target_properties 设置 库的属性 里面是名称 ,属性:引入地址把我们的真实地址填写进去

3、target_link_libraries
要CMake去生成target,并链接对应的库。输入的是二进制文件名或着已经生成但未link的target。target_link_libraries需要指定target并且调用linker

即按照header file + .lib + .dll方式隐式调用

通过add_executable()和add_library()指令生成已经创建的目标文件。

4、link_libraries
已经废弃:https://cmake.org/cmake/help/v3.0/command/link_libraries.html

target_link_libraries 与link_libraries 也就是这个两个函数的作用应该差不多
一个区别是:
target_link_libraries 要在 add_executable 之后
link_libraries 要在 add_executable 之前

附,三个有效的cmakelist.txt的例子

target_link_libraries 版

cmake_minimum_required(VERSION 3.12)include_directories("/usr/local/Cellar/vips/8.6.0/include")
include_directories("/usr/local/Cellar/glib/2.54.2/lib/glib-2.0/include")
include_directories("/usr/local/Cellar/glib/2.54.2/include/glib-2.0")link_directories("/usr/local/Cellar/glib/2.54.2/lib")
link_directories("/usr/local/opt/gettext/lib")
link_directories("/usr/local/Cellar/vips/8.6.0/lib")add_executable(vipc main.c)target_link_libraries(vipc vips)
target_link_libraries(vipc glib-2.0)
target_link_libraries(vipc gobject-2.0)

link_libraries版:

cmake_minimum_required(VERSION 3.12)include_directories("/usr/local/Cellar/vips/8.6.0/include")
include_directories("/usr/local/Cellar/glib/2.54.2/lib/glib-2.0/include")
include_directories("/usr/local/Cellar/glib/2.54.2/include/glib-2.0")link_directories("/usr/local/Cellar/glib/2.54.2/lib")
link_directories("/usr/local/opt/gettext/lib")
link_directories("/usr/local/Cellar/vips/8.6.0/lib")link_libraries(vips)
link_libraries(glib-2.0)
link_libraries(gobject-2.0)add_executable(vipc main.c)

Cmakelists 与gcc 调用so库文件,几个名词解释相关推荐

  1. linux下Qt调用C++库文件(.so)程序实现

    文章目录 主要内容 一.编程环境及实现方法 二.项目实现 1.创建项目 2.导入库文件 三.项目中遇到的问题 总结 主要内容 如标题所示,在linux下使用qtcreator创建项目调用C++库文件, ...

  2. qt linux 调用外部库文件 (safenet加密狗开发一)

    一加密狗开发基本原理: 经过我的探索,加密狗的基本原理就是每个加密狗有不同的id,根据加密狗的id生成独一无二的库文件,然后再在程序中加入vendorcode文件,比对插入的加密狗和code文件,如果 ...

  3. linux python qt 安装目录,Linux 下QT调用Python库文件 以及Linux 安装Python3.8开发环境 问题...

    最近想运用linux系统下Qt来实现c++ 与python的混合编程,linux系统会自带python2.7版本或者python3.5版本(深度linux). Qt调用python文件需要在pro文件 ...

  4. qt linux 添加库文件路径,Linux下Qt调用共享库文件.so

    jvm--4垃圾收集 6. 垃圾收集GC (1)当需要排查各种内存溢出,内存泄漏等问题,当GC成为系统达到更高性能的瓶颈时,我们就需要对这些自动化的GC进行监控和调节. (2)PC计数器.本地方法栈. ...

  5. java 动态库_java调用dll动态库文件的一般总结

    前一段时间,在项目需求中,需要调用一下第三方的动态库文件,下面是本人一些尝试的经历. 首先需要明白的是,在java中是不能直接调用动态库文件的,因为动态库文件是使用c或是c++编写的,作为一种跨   ...

  6. Ubuntu下gcc的静态库与动态库的生成与使用

    目录 LInux中函数库的类型 一.用gcc生成.a静态库 1.编辑生成例子程序 hello.h .hello.c和main.c 2.将hello.c编译成.o文件 3.由.o文件创建静态库 4.在程 ...

  7. Linux库文件使用与编译

    介绍在Linux下使用静态库.共享库.动态库的方法. Linux库文件 静态库 在Linux中,以.a为后缀,如libtest.a 直接拷贝函数到二进制映像文件 只需要运行二进制文件,可以直接运行 共 ...

  8. 用gcc编译生成动态链接库*.so文件的方法。

    linux下文件的类型是不依赖于其后缀名的,但一般来讲: .o,是目标文件,相当于windows中的.obj文件 .so 为共享库,是shared object,用于动态连接的,和dll差不多 .a为 ...

  9. 用gcc编译生成动态链接库*.so文件的方法

    linux下文件的类型是不依赖于其后缀名的,但一般来讲: .o,是目标文件,相当于windows中的.obj文件 .so 为共享库,是shared object,用于动态连接的,和dll差不多 .a为 ...

  10. linux 环境变量文件_应急响应系列之Linux库文件劫持技术分析,有点硬核哟

    0×01 菜逼阶段 Linux库文件劫持这种案例在今年的9月份遇到过相应的案例,当时的情况是有台服务器不断向个可疑IP发包,尝试建立连接,后续使用杀软杀出木马,重启后该服务器还是不断的发包,使用net ...

最新文章

  1. cmake,CMakeLists.txt,make,makefile的关系
  2. php 重载进程,关于php-fpm与nginx进程重载
  3. FFmpeg实现将图片转换为视频
  4. mysql数据库技术_MySQL数据库技术(13)[组图]_MySQL
  5. 全网首发:首个安卓摄像头预览加显示的项目
  6. Word论文排版教程
  7. html代码实现简单的简历模板
  8. mac2600r_水星MAC2600R路由器
  9. Mission Planner中级应用(APM或PIX飞控)3——APM飞控安装双GPS测试 APM双GPS
  10. linux删除不了777文件,Linux使用着需要理解chmod -r 777文件权限
  11. 99 Bottles Of Beer
  12. win10系统设置选择电源键按钮功能设置步骤
  13. Steam项目推进 (一) ——项目情况简述
  14. 爬虫数据储存—CSV文件
  15. 扩展数组方法 给数组原形链追加方法(原型链中的this)
  16. 软件工程技术--第一章 概述
  17. element自定义邮箱和手机号校验规则
  18. form表单的submit()和onsubmit()的区别
  19. HTML+CSS+JS网页设计期末课程大作业 web前端开发技术 web课程设计 后台管理系统。
  20. 青玉案.元夕-2023

热门文章

  1. HTML5学习总结(1)——HTML5基础知识
  2. ArcMAP 使用绘图工具添加注记
  3. 自己闲着没事整理的人工智能的思维导图
  4. Nginx根据url参数匹配跳转
  5. 伦巴时间步的动作要领_成人拉丁舞_伦巴、恰恰、桑巴舞、牛仔舞、斗牛舞
  6. txt.导入c语言,分求C语言问题解决——关于TXT文件导入(第二贴,能给出的这个100和另外的100一起拿走!)...
  7. js使用html5,JS使用H5实现图片预览功能
  8. java 弹幕游戏_java弹幕小游戏1.0版本
  9. canal与mysql高可用_canal 高可用介绍(4)
  10. mysql自增主键 php_MySQL的自增ID(主键) 用完了的解决方法