C++在Linux上生成动态库并调用接口测试

加减乘除demo代码

项目结构

CPP/

├── calculator.cpp

├── calculator.h

├── main.cpp

头文件

#ifndef CALCULATOR_H
#define CALCULATOR_H#ifdef __cplusplus
extern "C" {#endifdouble add(double a, double b);double subtract(double a, double b);double multiply(double a, double b);double divide(double a, double b);#ifdef __cplusplus
}
#endif#endif // CALCULATOR_H

源文件

#include "calculator.h"
#include <iostream>double add(double a, double b) {return a + b;
}double subtract(double a, double b) {return a - b;
}double multiply(double a, double b) {return a * b;
}double divide(double a, double b) {if (b == 0) {std::cerr << "错误:除数不能为0!" << std::endl;return 0;}return a / b;
}

main.cpp测试

main.cpp,用于测试动态库接口,需要在编译好动态库后进行测试

#include <iostream>
#include "calculator.h"int main() {double a = 8, b = 2;std::cout << "加法: " << add(a, b) << std::endl;std::cout << "减法: " << subtract(a, b) << std::endl;std::cout << "乘法: " << multiply(a, b) << std::endl;std::cout << "除法: " << divide(a, b) << std::endl;return 0;
}

编译动态库

  1. -fPIC:为共享库生成位置无关代码
  2. -shared:生成共享库
  3. -o libcalculator.so:输出为动态库文件
g++ -fPIC -shared calculator.cpp -o libcalculator.so

查看动态库有哪些接口

nm命令

nm -D libcalculator.so

带有 T 的(代表函数定义在库里)

信息比较多可以加grep命令进行过滤

objdump命令

objdump -T libcalculator.so

readelf命令

readelf -Ws libcalculator.so

main.cpp编译

main.cpp会在编译的过程中去动态链接libcalculator.so

  1. -L.:告诉编译器去当前目录查找库文件
  2. -lcalculator:链接名为 libcalculator.so 的库(省略前缀 lib 和扩展名 .so
g++ main.cpp -L. -lcalculator -o main

执行测试程序

运行程序前,设置动态库路径

  1. LD_LIBRARY_PATH 是 Linux 下指定“运行时动态库查找路径”的环境变量
  2. . 代表当前目录
  3. $LD_LIBRARY_PATH 是保留已有路径
#设置环境变量
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH

上面代码的意思是:请系统在当前目录找动态库,然后再去默认路径找

系统默认会查找这些路径

  1. /lib
  2. /usr/lib

永久添加路径

更新系统的动态链接库缓存,也就是告诉系统有哪些 .so 库、它们在哪儿,以便程序运行时可以找到这些库。

sudo ldconfig
什么时候用?
  1. 安装了新的 .so 动态库
  2. .so 文件放到了非标准路径下(比如 /usr/local/lib/opt/mylibs
  3. 修改了 /etc/ld.so.conf/etc/ld.so.conf.d/ 下的配置

运行程序

./main

运行程序前,为什么要设置动态库路径

因为你用的是 动态链接库(**.so**** 文件),程序运行时需要知道这个库在哪里**。编译的时候你告诉了编译器怎么找到它(-L.),但运行时要靠系统的**动态链接器(ld.so)**来加载 .so 文件。

如果 .so 不在系统默认的路径里(比如 /lib, /usr/lib),就需要你手动告诉它去哪里找。

python调用

test_calculator.py

import ctypes
import os# 加载动态库
lib_path = os.path.abspath("libcalculator.so")
calculator = ctypes.CDLL(lib_path)# 设置参数和返回类型
calculator.add.argtypes = [ctypes.c_double, ctypes.c_double]
calculator.add.restype = ctypes.c_doublecalculator.subtract.argtypes = [ctypes.c_double, ctypes.c_double]
calculator.subtract.restype = ctypes.c_doublecalculator.multiply.argtypes = [ctypes.c_double, ctypes.c_double]
calculator.multiply.restype = ctypes.c_doublecalculator.divide.argtypes = [ctypes.c_double, ctypes.c_double]
calculator.divide.restype = ctypes.c_double# 测试调用
a = 10.0
b = 2.0print("加法:", calculator.add(a, b))
print("减法:", calculator.subtract(a, b))
print("乘法:", calculator.multiply(a, b))
print("除法:", calculator.divide(a, b))

测试调用

  1. export LD_LIBRARY_PATH=CPP:$LD_LIBRARY_PATH
  2. python3 test_calculator.py

Makefile生成动态库

# Makefile for building libcalculator.so shared library# 编译器
CXX = g++# 编译选项
CXXFLAGS = -fPIC -Wall -Wextra -O2# 目标名称
TARGET = libcalculator.so# 源码文件
SRC = calculator.cpp# 头文件
HEADER = calculator.h# 输出路径(当前目录)
OBJ = $(SRC:.cpp=.o)# 默认目标
all: $(TARGET)# 生成共享库
$(TARGET): $(OBJ)$(CXX) -shared -o $@ $^# 编译cpp为.o文件
%.o: %.cpp $(HEADER)$(CXX) $(CXXFLAGS) -c $< -o $@# 清理生成的文件
clean:rm -f $(OBJ) $(TARGET).PHONY: all clean

运行make

Makefile一起生成动态库和可执行程序

# 编译器
CXX = g++# 编译选项
CXXFLAGS = -fPIC -Wall -Wextra -O2# 生成共享库的目标
LIB_NAME = libcalculator.so# 可执行文件名
EXEC = main# 源文件
LIB_SRC = calculator.cpp
MAIN_SRC = main.cpp# 对应的中间目标
LIB_OBJ = $(LIB_SRC:.cpp=.o)
MAIN_OBJ = $(MAIN_SRC:.cpp=.o)# 默认目标
all: $(LIB_NAME) $(EXEC)# 生成共享库
$(LIB_NAME): $(LIB_OBJ)$(CXX) -shared -o $@ $^# 编译 main,链接动态库
$(EXEC): $(MAIN_OBJ) $(LIB_NAME)$(CXX) -o $@ $(MAIN_OBJ) -L. -lcalculator# 通用规则:.cpp -> .o
%.o: %.cpp$(CXX) $(CXXFLAGS) -c $< -o $@# 运行程序
run: allLD_LIBRARY_PATH=. ./$(EXEC)# 清理
clean:rm -f *.o $(LIB_NAME) $(EXEC).PHONY: all run clean

运行make

用CMakeLists管理

项目结构

CPP/

├── calculator.cpp

├── calculator.h

├── main.cpp

└── CMakeLists.txt

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(CalculatorProject)# 设置 C++ 标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)# 输出到 build 目录下的 bin 和 lib 子目录
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)# 添加库(生成 libcalculator.so)
add_library(calculator SHARED calculator.cpp)# 添加可执行文件
add_executable(main main.cpp)# 链接共享库
target_link_libraries(main PRIVATE calculator)# 设置头文件搜索路径
target_include_directories(main PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_include_directories(calculator PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})

使用方法

  1. mkdir build && cd build
  2. cmake …
  3. cmake --build .

目录结构

CPP/

├── calculator.cpp

├── calculator.h

├── main.cpp

├── CMakeLists.txt

└── build/

├── bin/│   └── main└── lib/└── libcalculator.so

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/77677.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

离线密码生成器:安全可靠的密码管理解决方案

离线密码生成器&#xff1a;安全可靠的密码管理解决方案 在当今数字时代&#xff0c;我们每天都需要使用各种网站和应用程序&#xff0c;每个账户都需要一个强密码来保护我们的个人信息和隐私。然而&#xff0c;记住多个复杂的密码几乎是不可能的任务。今天&#xff0c;我要向…

ChatRex: Taming Multimodal LLM for Joint Perception and Understanding 论文理解和翻译

一、TL&#xff1b;DR MLLM在感知方面存在不足&#xff08;远远比不上专家模型&#xff09;&#xff0c;比如Qwen2-VL在coco上recall只有43.9%提出了ChatRex&#xff0c;旨在从模型设计和数据开发两个角度来填补这一感知能力的缺口ChatRex通过proposal边界框输入到LLM中将其转…

自动驾驶技术-相机_IMU时空标定

自动驾驶技术-相机_IMU时空标定 时间延迟 时间延迟 参考链接1、2 相机主要分为全局和卷帘快门相机&#xff0c;从触发到成像的过程包括&#xff1a;复位时间、AE()曝光时间、读出时间 全局快门如下图所示 卷帘快门如下图所示 相机录制视频时&#xff0c;为了保持固定频率&am…

Vue3 + Vite + TS,使用 Web Worker,web worker进阶 hooks

worker 具体通讯方式 1.由 web page 发送消息- worker.postMessage(发送数据) 2.web worker 接收消息并执行相关逻辑- onmessage (e) > { 接收数据并处理逻辑postMessage(传递处理后的数据)} 3.由 web page 监听 worker 消息&#xff0c;包括&#xff1a;- 处理数据的监听…

AIDD-人工智能药物设计-AI 精准预测蛋白质变构位点

Allo-PED: AI 精准预测蛋白质变构位点 目录 Allo-PED 框架融合蛋白质语言模型与结构特征,显著提高了变构位点预测的准确性和泛化能力。EcoFoldDB 利用蛋白质结构信息,为宏基因组提供了精确且可扩展的生态功能注释新方法,显著提升了对未知微生物功能的认知。上下文分子适配(…

1558 找素数

1558 找素数 ⭐️难度&#xff1a;中等 &#x1f31f;考点&#xff1a;质数 &#x1f4d6; &#x1f4da; import java.util.Scanner; import java.util.Arrays;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);int a sc.…

Nacos 提供了哪些服务的保护机制?

当面试官问这个问题时&#xff0c;大家一定要保持头脑清醒&#xff0c;不要被带跑偏了&#xff0c;Nacos 本身的核心定位是服务发现和配置管理中心&#xff0c;它并不直接提供像服务熔断、服务限流、服务降级、请求重试 这类完整的、开箱即用的客户端/网关级服务保护&#xff0…

【家政平台开发(38)】解锁家政平台国际化密码:多语言支持开发实战

> 本【家政平台开发】专栏聚焦家政平台从 0 到 1 的全流程打造。从前期需求分析,剖析家政行业现状、挖掘用户需求与梳理功能要点,到系统设计阶段的架构选型、数据库构建,再到开发阶段各模块逐一实现。涵盖移动与 PC 端设计、接口开发及性能优化,测试阶段多维度保障平台质…

DirectX12 - 基本知识 - 图形驱动的本质

这里是SunshineBooming&#xff0c;GPU公司一枚小小的Driver工程师&#xff0c;主要工作是写DirectX12 Driver&#xff0c;我会持续更新这个DX12 Spec系列&#xff0c;可能比较冷门&#xff0c;但是都是干货和工作中的心得体会&#xff0c;有任何GPU相关的问题都可以在评论区互…

selenium元素获取

from selenium import webdriver from selenium.webdriver.common.by import Bydriver webdriver.Chrome()driver.maximize_window()#最大化窗口 #隐式等待 driver.implicitly_wait(10)#打开网页 driver.get("https://www.zhipin.com/beijing/?kacity-sites-101010100&q…

生物化学笔记:医学免疫学原理15 超敏反应过敏反应(I型[蚊虫叮咬]+II型[新生儿溶血症、突眼型甲亢]+III型+IV型)

超敏反应 每个人都可能发生的过敏问题&#xff1a;被蚊子咬后起包 I型超敏反应 II型超敏反应 新生儿溶血症分为Rh血型不合和ABO血型不合两种情况。Rh血型不合通常从第二胎开始更容易发病&#xff0c;因为母体初次接触Rh阳性胎儿的红细胞后会产生抗D抗体&#xff0c;而这个致敏…

【android bluetooth 框架分析 02】【Module详解 2】【gd_shim_module 模块介绍】

1. 背景 上一章节 我们介绍了 module_t 的 大体框架 &#xff0c;本节内容我们就选择 我们的 gd_shim_module 模块为例子&#xff0c;具体剖析一下&#xff0c;它里面的逻辑。 static const char GD_SHIM_MODULE[] "gd_shim_module";// system/main/shim/shim.cc …

【包管理器】主流包管理器_对比_应用场景

不定期更新&#xff0c;建议关注收藏点赞。 链接&#xff1a; npm专题 目录 主流包管理器简介对比 主流包管理器简介 主流的包管理器其实有不少&#xff0c;不同语言和平台都有各自的一套系统。 前端&#xff08;JavaScript/TypeScript&#xff09; 名称简介开发者特点npmNo…

参照Spring Boot后端框架实现序列化工具类

本文参照Jackson实现序列化工具类&#xff0c;旨在于简化开发 JacksonUtil.class public class JacksonUtil {private JacksonUtil() {}/*** 单例*/private final static ObjectMapper OBJECT_MAPPER;static {OBJECT_MAPPER new ObjectMapper();}private static ObjectMappe…

Rust入门之迭代器(Iterators)

Rust入门之迭代器&#xff08;Iterators&#xff09; 本文已同步本人博客网站 本文相关源码已上传Github 前言 迭代器&#xff08;Iterators&#xff09;是 Rust 中最核心的工具之一&#xff0c;它不仅是遍历集合的抽象&#xff0c;更是 Rust 零成本抽象&#xff08;Zero-Co…

若依框架二次开发——RuoYi-AI 本地部署流程

文章目录 项目环境安装后端1. 下载项目2. 使用 IDEA 导入项目3. 配置 Maven4. 配置 Maven settings.xml5. 初始化数据库6. 启动 Redis7. 修改数据库配置8. 启动后端服务安装管理端1. 下载管理端项目2. 安装依赖3. 启动管理端4. 修改管理端配置安装用户端1. 下载用户端项目2. 安…

精品推荐-最新大模型MCP核心架构及最佳实践资料合集(18份).zip

精品推荐-最新大模型MCP核心架构及最佳实践资料合集&#xff0c;共18份。 1、2025年程序员必学技能&#xff1a;大模型MCP核心技术.pdf 2、MCP 架构设计剖析&#xff1a;从 Service Mesh 演进到 Agentic Mesh.pdf 3、MCP 架构设计深度剖析&#xff1a;使用 Spring AI MCP 四步…

DataWorks智能体Agent发布!基于MCP实现数据开发与治理自动化运行

在传统的数据开发工作中&#xff0c;企业用户或者开发者常常需要进行繁琐的配置、复杂的代码撰写、反复的性能调优和大量重复性的操作&#xff0c;才能实现数据开发、数据集成和数据治理等工作&#xff0c;效率十分低下。 近日&#xff0c;阿里云大数据开发治理平台DataWorks基…

IDEA 中右侧没有显示Maven

IDEA 中右侧没有显示Maven 1. 检查 Maven 项目是否正确加载 现象 • 项目是 Maven 项目&#xff0c;但右侧没有 Maven 工具窗口。 • 项目根目录下有 pom.xml&#xff0c;但 IDEA 没有识别为 Maven 项目。 解决方法 手动重新加载 Maven 项目&#xff1a; • 在 IDEA 中&…

罗技K860键盘

罗技蓝牙键盘的顶部功能键F1-F12的原本功能 单击罗技键盘的功能键时&#xff0c;默认响应的是键盘上面显示的快进、调节音量等功能。改变回F1~F12原本功能&#xff0c;同时按下 fn和esc组合键