linux qt编译c语言共享库

Qt 专栏收录该内容
47 篇文章 2 订阅

Qt Creator支持编译生成c++库,打开新建工程,根据创建向导,能够很快生成c++共享库的工程

创建向导上显示的是c++的库,c语言的库也同样能够生成,下面对生成c语言的共享库做个介绍

生成c共享库

1.首先按生成c++库的方式生成工程,过程就不罗列了,根据要求自行选择

创建完成后,生成以下几个文件

其中testclib是默认生成的类,TestClib_global.h是生成库需要的宏

2.把testclib.cpp后缀改为.c

3.删掉默认的类,添加自己的接口,每个接口前面添加导出库的宏,把global头文件内的宏拷贝到接口头文件中,这样后续调用不用包含global头文件了,如果是有多个.h的接口,建议还是保留global的方式

#ifndef TESTCLIB_H
#define TESTCLIB_H

#if defined(_MSC_VER) || defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
#  define Q_DECL_EXPORT __declspec(dllexport)
#  define Q_DECL_IMPORT __declspec(dllimport)
#else
#  define Q_DECL_EXPORT     __attribute__((visibility("default")))
#  define Q_DECL_IMPORT     __attribute__((visibility("default")))
#endif

#if defined(TESTCLIB_LIBRARY)
#  define TESTCLIB_EXPORT Q_DECL_EXPORT
#else
#  define TESTCLIB_EXPORT Q_DECL_IMPORT
#endif

TESTCLIB_EXPORT int add(int a, int b);

#endif // TESTCLIB_H
#include "testclib.h"

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

4.执行编译,在编译生成目录即生成相应的库,可以看到生成4个.so文件

其中libTestClib.so libTestClib.so.1 libTestClib.so.1.0都是libTestClib.so.1.0.0软链接

为什么会有这么多个,想要知道其中的原因,首先来了解Linux共享库的命名规则

Linux共享库的命名规则

libname.so.x.y.z

前缀lib,中间是库的名字和后缀.so,后面的三个数字组成版本号,“x”表示主版本号,“y”表示此版本号,“z”表示发布版本号,这个三个版本号的具体含义:

  1. 主版本号:表示库的重大升级,不同版本号的库之间是不兼容的,依赖与旧的版本号的程序要改动相应的部分,并且重新编译。才可以在新版的共享库中运行,或者系统必须保留旧版的共享库,使得那些依赖于旧版共享库的程序能够正常运行
  2. 次版本号:表示库的增量升级,即增加一些新的接口符号,并保持原有的符号不变,在主版本号相同的情况下,高的此版本号的库向后兼容低的次版本好的库。
  3. 发布版本号:表示库的一些错误的修正和性能的改进等,并不添加任何新的接口,也不对接口进行更改,相同主,次版本好的共享库,不同发布版本号之间完全兼容。

也有部分不遵守上述规定的共享库,如glibc,它的c语言库的命名就是libc-x.y.z.so,glibc包含许多组件,C语言库只是其中一个,动态链接器也是glibc的一部分 ,它的命名:

ld-x.y.z.so

编译使用共享库时,例如GCC 使用 -l 参数链接共享库libxxx.so.2.1.1,只需要-lxxxxxx 就是共享库的连接名,编译器会根据当前环境,在相关路径查找最新版本的xxx

所以使用时我们需要libTestClib.so、libTestClib.so.1、libTestClib.so.1.0.0这三个库,其中libTestClib.so用来对应-lxxx的名称,-l的链接方式无法对应库名称带了版本号的共享库。libTestClib.so.1是libTestClib.so.1.0.0的soname,指定了soname后,ld链接器链接时都是通过soname的库进行链接,这样做是方便兼容,如果主版本库不变,比如更新了libTestClib.so.1.2.2,那只需让libTestClib.so.1重新指向libTestClib.so.1.2.2即可,程序还是通过libTestClib.so.1进行调用,关于soname的使用,可以查阅相关资料进一步了解,这里简单做个说明。

使用命令查看libTestClib.so.1.0.0

readelf -d libTestClib.so.1.0.0

可以看到libTestClib.so.1.0.0的soname为libTestClib.so.1

隐式调用共享库

>新建一个c工程

>在工程目录下新建lib文件夹,把上面提到的三个库复制出来,当然直接四个都拷也没事

>添加头文件到工程中

>Pro文件链接库

LIBS += -L$$PWD/lib –lTestClib

qmake +编译即可

调用的时候通过尝试只使用libTestClib.so.1 libTestClib.so.1.0.0, 会提示找不到库文件

:-1: error: cannot find –lTestClib

:-1: error: collect2: error: ld returned 1 exit status

通过只调用libTestClib.so.1.0.0,并改名为libTestClib.so,链接编译能够通过,但运行时会报错找不到共享库libTestClib.so.1

error while loading shared libraries: libTestClib.so.1: cannot open shared object file: No such file or directory

使用-l的方式链接,带有soname的共享库目前发现只能把三个都拷贝过来才能使用

显示调用共享库

如果是使用dlopen通过显示的方式加载共享库,那就没有上述的问题,只使用libTestClib.so.1.0.0就可以了,当然用libTestClib.so.1也可以,但libTestClib.so.1.0.0也还需要保留

#include <stdio.h>
#include "testclib.h"
#include <dlfcn.h>

typedef int (*testAdd) (int, int);

int main()
{
    printf("Hello World!\n");

    void * handle = dlopen("xxx/libTestClib.so.1", RTLD_NOW);
    if(handle == NULL) {
        return -1;
    }

    testAdd add = dlsym(handle,"add");

    int ret = add(1, 2);
    printf("add: %d", ret);

    return 0;
}

pro文件还需链接dl库

LIBS += -ldl

不然会报错找不到dlopen

采用非soname的方式

使用Qt Creator编出来的库采用的是soname这种方式,我们也可以自己用命令行生成libname.so的形式,而不区分什么主版本次版本

在Qt Creator下方输出栏找到编译输出窗口

可以看到执行的命令

g++ -shared -Wl,-soname,libTestClib.so.1 -o libTestClib.so.1.0.0 testclib.o

去掉soname参数

g++ -shared -o libTestClib.so testclib.o

因为已经编译过生成.o文件,在编译目录下执行上述命令即可生成libTestClib.so

这样只需使用libTestClib.so,把之前那三个库删掉,使用新生成的libTestClib.so一样能够使用

如果没特殊要求按这种方式也可以,毕竟我们的宗旨是能用能运行就对了

结语

通过查看/usr/lib下的库基本都是用第一种方式,这种方式目的就是解决库更新冲突、兼容问题,对于程序链接这一块我也不是很熟,看自己的需要来选择就好了。

以上是Linux下c语言生成共享库的方法,c++步骤也是一样的,只不过c++一般使用类的方式,按照Qt Creator向导生成创建即可。Qt是跨平台的,只要处理好平台相关的代码,同一个代码工程在windows下也能直接编译生成windows的库

  • 0
    点赞
  • 2
    评论
  • 4
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

©️2022 CSDN 皮肤主题:技术黑板 设计师:CSDN官方博客 返回首页

打赏作者

芒果黑

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值