g++编译so里调用外部so

15 篇文章 0 订阅
11 篇文章 0 订阅

背景

要给甲方爸爸A演示一下公司的产品,但是我们公司的产品,最终都是要跟爸爸们的产品结合在一起的,等于说要把甲方爸爸的代码抽出来编译成一个so,供我们的产品的java代码来调用——这本来是个很常见的场景——但是问题在于,甲方爸爸的这些代码,是在它的另一个乙方儿子上的so的基础上完成的,那么场景就变成了如下:
在这里插入图片描述
之前没有自己搞过这样的逻辑,趁此机会,尝试一下,以此为记;

尝试

PS:因为自己一直做的是C(也会有C++)的开发,所以当前的demo演示里,我们来调用甲方爸爸的so时,用C的程序来代替Java的程序(这里后面另外有一部分工作要做,看看要不要写在本篇里);

g++生成so

test.cpp代码:

#include <stdio.h>
int test_func(int a, int b)
{
	printf("test_func ==> a = %d, b = %d\n", a, b);
	return (a+b);
}

——我有罪,用c风格的代码来伪装C++
test.h:

#ifndef TEST_H_
#define TEST_H_
int test_func(int a, int b);
#endif

编译命令:

g++ test.cpp -fPIC -shared -o libtest.so

注意:

(1)编译生成的so的命名,必须是lib开始的;
(2)编译选项说明:
A、-shared:

该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接,相当于一个可执行文件;

B、-fPIC:

表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的;

g++生成模拟调用的可执行程序

main.cpp代码:

#include <iostream>
#include "test.h"
int main()
{
	test_func(1, 2);
	std::cout<< " after test_func" << std::endl;
	return 1;
}

编译命令:
g++ main.cpp -L. -ltest -o main

注意:

(1)编译选项说明:
A、-L.:

表示要连接的库在当前目录中;

B、-ltest:

编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称;-ltest就等于查找libtest.so的so;

模拟调用的可执行程序调用so

直接执行 ./main,出错:
在这里插入图片描述
出错信息显示没有找到要加载的libtest.so,这里是一个坑;简单来说,就是有的时候,如果通过 -L.指定了从当前执行文件的目录来寻找要加载的so路径时,执行文件有时可以成功加载so,但有的时候就不可以,这种情况下,需要

手动设置LD_LIBRARY_PATH:
export LD_LIBRARY_PATH=/home/admin/cus:$LD_LIBRARY_PATH

手动设置后,成功执行:
在这里插入图片描述
通过ldd来查看生成的main,也可以看到libtest.so已经能够找到了;
至此,第一阶段结束;

在so中链接外部so进行编译

下面在上面的尝试的基础上进行更进一步的测试,在test.cpp里添加对另一个so:libt2sdk.so 里的定义的类的调用;
对应的头文件:t2sdk_interface.h
对应的so:libt2sdk.so
为方便调试,把头文件和so都放在main.cpp的同级目录下;

编译生成新的so

test.cpp代码:
代码量比较大,就不贴代码了,这里include了t2sdk_interface.h,下面是新添加的调用乙方二儿子的so里的接口函数:
在这里插入图片描述
test.h:

#ifndef TEST_H_
#define TEST_H_	
	int test_func(int a, int b);
	int test_func_new(); 
#endif

so的编译命令:
g++ test.cpp -fPIC -shared -o libtest.so -L. -lt2sdk
——与没有链接so时相比,在编译新的so时,就需要指定要链接的libt2sdk.so及其路径;

main.cpp:

#include <iostream>
#include "test.h"

int main()
{
	test_func(1, 2);
	test_func_new();
	std::cout<< " after test_func" << std::endl;
	return 1;
}

main的编译命令不变:
g++ main.cpp -L. -ltest -o main

执行成功:
在这里插入图片描述

总结

1.编译选项的意义(-fPIC、-shared、-L. 。。。。。)
2.注意
A、如果so和最后的可执行文件都是用g++编译的,那么在so所对应的头文件里,不要用 extern “C” 来解释目标函数,因为这是为了把g++编译的so给gcc编译的可执行文件调用,而如果so和可执行文件都是用g++编译的话,两者的编译和命名规则都是统一的,就不必另外进行设置了;
B、哪怕在编译可执行文件时,通过 -L. 说明了链接的so在当前的编译路径下,也会出现编译成功,但是执行时找不到so的问题,需要通过设置LD_LIBRARY_PATH来保证能够找到so:
C、当编译的so(A)里,链接别的so(B)时,在编译A时,就需要通过编译命令来制定B的路径及名称;

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lqw198421

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

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值