C++ SO库创建与调用全攻略

C++程序打包成SO库并调用的完整指南

将C++程序打包成共享对象(SO)库(在Linux系统中为.so文件)是一种高效的方式,用于代码复用和模块化开发。本指南将逐步介绍如何创建SO库并从其他程序调用它。整个过程基于Linux环境,使用g++编译器。确保已安装g++和必要的开发工具(如通过sudo apt-get install build-essential安装)。

步骤1: 编写C++库代码

首先,创建一个简单的C++函数作为库的核心功能。例如,我们定义一个加法函数和头文件。

  1. 创建头文件math_utils.h:
c++ 复制代码
#ifndef MATH_UTILS_H
#define MATH_UTILS_H

// 声明加法函数
extern "C" int add(int a, int b);

#endif
  • 使用extern "C"确保函数名不被C++编译器重整(mangling),便于外部调用。
  1. 创建源文件math_utils.cpp:
c++ 复制代码
#include "math_utils.h"

int add(int a, int b) {
    return a + b;
}
步骤2: 编译为SO库

将C++代码编译成动态链接库(.so文件)。使用g++编译器,关键选项包括-fPIC(生成位置无关代码)和-shared(创建共享库)。

  1. 编译命令:
bash 复制代码
g++ -fPIC -shared -o libmathutils.so math_utils.cpp
  • -fPIC: 确保代码可在内存中任意位置加载。
  • -shared: 指定输出为共享库。
  • -o libmathutils.so: 输出文件名,通常以lib前缀开头(如libmathutils.so)。
  1. 验证库文件:
  • 运行ls检查是否生成libmathutils.so。
  • 可选:使用nm -D libmathutils.so查看导出符号,确认add函数存在。
步骤3: 编写调用程序

创建一个C++程序来调用SO库。有两种方式:动态加载(使用dlopen/dlsym)或静态声明(使用头文件)。

  1. 方式一:动态加载(推荐灵活性) 创建main_dynamic.cpp:
c++ 复制代码
#include <iostream>
#include <dlfcn.h>

int main() {
    // 打开SO库
    void* handle = dlopen("./libmathutils.so", RTLD_LAZY);
    if (!handle) {
        std::cerr << "Error: " << dlerror() << std::endl;
        return 1;
    }

    // 获取函数指针
    typedef int (*add_func)(int, int);
    add_func add = (add_func)dlsym(handle, "add");
    if (!add) {
        std::cerr << "Error: " << dlerror() << std::endl;
        dlclose(handle);
        return 1;
    }

    // 调用函数
    int result = add(3, 4);
    std::cout << "Result: " << result << std::endl;

    // 关闭库
    dlclose(handle);
    return 0;
}
  1. 方式二:静态声明(更简单) 创建main_static.cpp:
c++ 复制代码
#include <iostream>
#include "math_utils.h" // 包含头文件

int main() {
    // 直接调用函数
    int result = add(3, 4);
    std::cout << "Result: " << result << std::endl;
    return 0;
}
步骤4: 编译并运行调用程序

根据调用方式编译程序,并链接SO库。

  1. 编译动态加载程序:
bash 复制代码
g++ -o main_dynamic main_dynamic.cpp -ldl
  • -ldl: 链接动态加载库(libdl)。
  1. 编译静态声明程序:
bash 复制代码
g++ -o main_static main_static.cpp -L. -lmathutils
  • -L.: 指定库搜索路径为当前目录。
  • -lmathutils: 链接libmathutils.so(省略lib前缀和.so后缀)。
  1. 运行程序 :
    • 设置库路径(避免error while loading shared libraries):

      bash 复制代码
      export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
    • 执行:

      bash 复制代码
      ./main_dynamic  # 输出: Result: 7
      ./main_static   # 输出: Result: 7
注意事项
  • 路径问题 :确保SO库在LD_LIBRARY_PATH或标准库目录中,否则使用绝对路径。
  • 函数签名 :使用extern "C"避免C++名称重整,确保调用正确。
  • 错误处理 :在动态加载中,检查dlopen和dlsym的返回值。
  • 多文件库 :如果有多个源文件,编译时列出所有文件,如g++ -fPIC -shared -o libexample.so file1.cpp file2.cpp。
  • 兼容性:SO库依赖于系统架构(如x86_64),确保调用程序匹配。
  • 高级用法:可以添加更多函数、类或使用CMake自动化构建。
完整示例代码下载

建议将所有文件放在同一目录:

  • math_utils.h, math_utils.cpp, main_dynamic.cpp, main_static.cpp

通过本指南,您可以轻松打包C++代码为SO库并从其他程序调用,提升代码重用性和性能。如有问题,检查编译错误或调试输出。

相关推荐
sm_926787058 小时前
RFID 标签打印的技术实现要点与二次开发实践
java·大数据·前端·c++·编辑器
by209998 小时前
C++ 多态:同一个基类接口,调用不同的函数
开发语言·c++·经验分享·多态
colinu8 小时前
C++ 异步任务与线程生命周期:`std::async`、`future`、`thread`、`jthread` 与协作式退出
java·jvm·c++
wuminyu9 小时前
ForkJoinPool窃取线程在扫描其他WorkQueue时的随机采样算法与Phase线程挂起唤醒机制解析
java·linux·c语言·jvm·c++
longlongzihan9 小时前
链表找环:Floyd 判圈算法(LeetCode 141 & 142 )
c++·算法·leetcode·链表
liulilittle9 小时前
Linux 下 select 测试函数
linux·服务器·网络·数据库·c++·select·c
无忧.芙桃10 小时前
C++语言原理与实践(十二):list类的底层实现
c++·windows·list
沫璃染墨10 小时前
《Linux工程实践篇(二):线程池实战——从线程安全单例到完整源码实现》
linux·开发语言·c++·单例模式·设计模式·系统架构
有只小白叫岳飒11 小时前
c++智能指针 unique_ptr与函数调用
c++
Leo.yuan11 小时前
Kafka+Flink拼凑,还是FineDataLink 5.0一体化?实时数据处理的两种思路
c++·mfc