python调用c++动态库.so和静态库.a

项目场景:隐私保护联邦学习代码实现

我目前在实现一个隐私保护联邦学习论文的代码,其中联邦学习的模型训练用python写的代码,隐私保护用c++写的(一种同态加密算法)代码。我的目标是将密码算法用于加密联邦学习每轮训练得到的梯度信息。因此,考虑python调用c++实现。

近一周都在度娘上搜索学习,发现介绍最多的python调用c++方法是将c++函数暴露c语言接口(供后续python调用),再将cpp文件编译为so动态链接库,python端用ctypes调用,这个方法最简单。然而实际实现的时候,遇到很多令人吐血的问题,还好最后终于调用成功了。这里详细记录一下我遇到的问题和解决方案,附参考。


问题描述与解

首先了解到:
(1)对于python,ctypes只能load动态库;
(2)静态库可以被动态库链接,而后给python调用,但是静态库在编译过程中没有加–fPIC参数,就不可以被动态库链接;
(3)我的C++代码调用了NTL库和GMP库(这两个也是c++库),但是这两个库的静态库libntl.a和libgmpxx.a, libgmp.a在编译时都没用–fPIC参数编译,所有我在动态库链接静态库时报错“undefined symbol”。

解决方案:重新编译NTL和GMP库,生成带PIC的静态库文件

对于NTL库,修改其makefile文件中的CXXFLAGS如下:

# CXXFLAGS=-g -O2   # 原来的
CXXFLAGS = -g -fPIC # 修改后的
# Flags for the C++ compiler

然后在makefile文件夹路径下开启终端,输入make clobber(makefile中有提示,删去已有的.o文件等), 然后make,重新生成ntl.a (或者libntl.a) 文件,拷贝出来,备用。

$make clobber
$make

对于GMP库,我在官网下载的包里没有找到makefile文件,它是在configure时生成makefile
因此需要在安装时指定-fPIC。
GMP的安装:安装GMP 之前需要先安装m4 (不然会出错)

$sudo apt-get install m4

然后安装GMP,带上pic

$./configure --enable-cxx --with-pic //https://blog.csdn.net/icesnowjank/article/details/111171028
$make
$make check
$make install

我在make install时出错“cannot create directory Permission denied”,我记得第一次装的时候没这个问题。这个小问题可以参考 这里 的方案解决。

安装好后,终端会提示GMP安装到了哪里,一般在usr/local里,进入这个文件夹下,拷贝出libgmpxx.a和libgmp.a两个静态库,备用。

接下来,编译自己写的c++项目的静态库。
参考 这里(暴露接口函数,在代码中使用extern关键字将代码包裹起来,让编译器以C语言的方式编译), 这里(静态库生成、打包、解包等)和 这里(注意动态库生成顺序问题)。

具体地,在你的cpp或这h文件中写入形如这样的extern语句(为了方便展示,我直接复制了我的部分代码了):

extern "C" {
    MKTestScheme mkTestScheme; // 定义一个自己写的MKTestScheme类 mkTestScheme
    void testMKEncodeBatch(long logN, long logP, long logQ, long logq0, long logSlots, long slots2, long CLIENT, bool isComplex, long numAgg) {
        mkTestScheme.testMKEncodeBatch(logN, logP, logQ, logq0, logSlots, slots2, CLIENT, isComplex, numAgg);
    }
    void testMKEncryptBatch(long logN, long logP, long logQ, long logq0, long logSlots, long slots2, long CLIENT, bool isComplex, long numAgg) {
        mkTestScheme.testMKEncryptBatch(logN, logP, logQ, logq0, logSlots, slots2, CLIENT, isComplex, numAgg);
    }
	void testMKPackEncrypt(long logN, long logP, long logQ, long logq0, long logSlots, long slots2, long CLIENT, bool isComplex, long numAgg, long numClients) {
		mkTestScheme.testMKPackEncrypt(logN, logP, logQ, logq0, logSlots, slots2, CLIENT, isComplex, numAgg, numClients);
	}
	void testMKPackEncryptADD() {
		mkTestScheme.testMKPackEncryptADD();
	}
}

我extern写在了cpp文件里。这里还要注意一点就是cpp对应的.h文件中所include的头文件需要写成public继承形式(其他的未暴露接口函数的cpp文件的.h文件也是一样操作):

#ifndef MKHE_MKTESTSCHEME_H_
#define MKHE_MKTESTSCHEME_H_

#include <NTL/BasicThreadPool.h>
#include <NTL/RR.h>
#include <NTL/ZZ.h>

#include "StringUtils.h"
#include "TimeUtils.h"
#include "MKScheme.h"

using namespace std;
using namespace NTL;

class MKTestScheme:public StringUtils, public TimeUtils, public MKScheme {
public:

	static void testMKEncodeBatch(long logN, long logP, long logQ, long logq0, long logSlots, long slots2, long CLIENT, bool isComplex, long numAgg);
	static void testMKEncryptBatch(long logN, long logP, long logQ, long logq0, long logSlots, long slots2, long CLIENT, bool isComplex, long numAgg);
	
	static void testMKPackEncrypt(long logN, long logP, long logQ, long logq0, long logSlots, long slots2, long CLIENT, bool isComplex, long numAgg, long numClients);
	static void testMKPackEncryptADD();
};

#endif

至此,开始编译自己写的c++项目的静态库:找到cpp文件所在文件夹,打开终端,输入:

$g++ -c -fPIC file1.cpp file2.cpp file3.cpp ... //将自己写的cpp文件全部编译为.o文件
$ar crU libmine.a *.o //所有.o文件打包为.a文件(可选,供后续移植解包使用o文件)

所有静态库打包为动态库

将上面生成的libntl.a, libgmpxx.a, libgmp.a, libmine.a 全部拷贝出来,放在新建的一个文件夹里,并在此文件夹下打开终端,执行下面命令,将所有静态库打包为动态库:

$ar x libntl.a //拆包
$ar x libgmpxx.a
$ar x libgmp.a
$ar x libmine.a
$ar crU libXXX.a *.o //所有.o文件打包为libXXX.a文件
$ranlib libXXX.a  // 更新库的符号索引表
$ar x libXXX.a 
$g++ -o libencryption.so -shared -fPIC *.o

最后一步啦,哈哈哈

拷贝动态库libencryption.so所在路径,进入python程序,新建py文件,写动态库的调用代码:

import ctypes
dll = ctypes.cdll.LoadLibrary
lib = dll('/home/xxx/HE_encryption/build/libencryption.so') // 括号里输入拷贝的路径
lib.testMKPackEncryptADD()  // 调用自己写的c++代码中暴露的函数

运行成功,和在c++中执行结果一样,哈哈哈。接下来,我要去研究c++暴露接口函数的优化问题了。

  • 8
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值