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

news2025/5/16 16:03:13

加减乘除demo代码

项目结构

CPP/

├── calculator.cpp

├── calculator.h

├── main.cpp

头文件

#ifndef CALCULATOR_H
#define CALCULATOR_H

#ifdef __cplusplus
extern "C" {
    #endif

    double 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_double

calculator.subtract.argtypes = [ctypes.c_double, ctypes.c_double]
calculator.subtract.restype = ctypes.c_double

calculator.multiply.argtypes = [ctypes.c_double, ctypes.c_double]
calculator.multiply.restype = ctypes.c_double

calculator.divide.argtypes = [ctypes.c_double, ctypes.c_double]
calculator.divide.restype = ctypes.c_double

# 测试调用
a = 10.0
b = 2.0

print("加法:", 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: all
	LD_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.coloradmin.cn/o/2333863.html

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

相关文章

前端性能测试工具 —— WebPageTest

测试工具介绍 WebPageTest 是一个用于测量和分析网页性能的工具。它提供了详细的诊断信息&#xff0c;帮助用户了解网页在不同条件下的表现。用户可以选择全球不同的测试地点&#xff0c;使用真实的浏览器&#xff0c;并自定义网络条件进行测试。WebPageTest 还支持核心网络指…

北邮LLMs在导航中的应用与挑战!大模型在具身导航中的应用进展综述

作者&#xff1a;Jinzhou Lin, Han Gao, Xuxiang Feng, Rongtao Xu, Changwei Wang, Man Zhang, Li Guo, Shibiao Xu 单位&#xff1a;北京邮电大学人工智能学院&#xff0c;中国科学院自动化研究所多模态人工智能系统国家重点实验室&#xff0c;中科院空间信息研究所&#xf…

Windows下ElasticSearch8.x的安装步骤

下载ElasticSearch&#xff1a;https://www.elastic.co/downloads/elasticsearch &#xff08;我下载的是目前最新版8.17.4&#xff09;解压ElasticSearch 进入到ElasticSearch的bin目录下双击elasticsearch.bat 弹出控制台并开始执行&#xff0c;在这一步会输出初始账号和密码…

【高性能缓存Redis_中间件】一、快速上手redis缓存中间件

一、铺垫 在当今的软件开发领域&#xff0c;消息队列扮演着至关重要的角色。它能够帮助我们实现系统的异步处理、流量削峰以及系统解耦等功能&#xff0c;从而提升系统的性能和可维护性。Redis 作为一款高性能的键值对数据库&#xff0c;不仅提供了丰富的数据结构&#xff0c;…

AI Agent入门指南

图片来源网络 ‌一、开箱暴击&#xff1a;你以为的"智障音箱"&#xff0c;其实是赛博世界的007‌ ‌1.1 从人工智障到智能叛逃&#xff1a;Agent进化史堪比《甄嬛传》‌ ‌青铜时代&#xff08;2006-2015&#xff09;‌ “小娜同学&#xff0c;关灯” “抱歉&…

海洋大地测量基准与水下导航系列之八我国海洋水下定位装备发展现状

中国国家综合PNT体系建设重点可概括为“51N”&#xff0c;“5”指5大基础设施&#xff0c;包括重点推进下一代北斗卫星导航系统、积极发展低轨导航增强系统、按需发展水下导航系统、大力发展惯性导航系统、积极探索脉冲星导航系统&#xff1b;“1”是实现1个融合发展&#xff0…

谷歌开源代理开发工具包(Agent Development Kit,ADK):让多智能体应用的构建变得更简

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

noscript 标签是干什么的

vue public目录下的 index.html 会有 <noscript> 标签不知道是干吗的。 其实 noscript 标签在不支持或是禁用JavaScript 的浏览器中显示替代的内容。这个元素可以包含任何 HTML 元素。这个标签的用法也非常简单&#xff1a; <noscript><strong>Were sorry …

[创业之路-366]:投资尽职调查 - 尽调核心逻辑与核心影响因素:价值、估值、退出、风险、策略

目录 一、VC投资的本质是冒着不确定性风险进行买卖、生意&#xff0c;为了赚取高额回报 1、VC投资的核心本质 2、VC投资的运作机制 3、VC投资的风险与挑战 4、VC投资的底层逻辑 5、总结&#xff1a;VC投资的本质再定义 二、尽调核心逻辑 1、尽调的含义 2、尽调的逻辑方…

Hyprnote开源程序是一款记录和转录您会议的 AI 记事本。 本地优先且可扩展 。

一、软件介绍 文末提供源码下载学习 Hyprnote开源程序是一款记录和转录您会议的 AI 记事本。 从您的原始会议记录中生成强大的摘要&#xff0c;本地优先且可扩展 。使用开源模型 &#xff08;Whisper & Llama&#xff09; 离线工作&#xff0c;高度可扩展 &#xff0c;由插…

上篇:新能源轻卡城配物流经济/动力模式量化定义(理论篇)——数学暴力破解工程困局

副标题&#xff1a;用微分方程撕开模式切换本质&#xff0c;用传感器数据重构载重真相 引言&#xff1a;为什么轻卡模式定义比乘用车难10倍&#xff1f; 行业现状痛点&#xff1a; 中国新能源轻卡日均载重波动高达300%&#xff08;空载0kg→满载4.5吨&#xff09;某头部车企实…

Ubuntu22环境下,Docker部署阿里FunASR的gpu版本

番外: 随着deepseek的爆火,人工智能相关的开发变得异常火爆,相关的大模型开发很常见的agent智能体需要ASR语音识别的功能,阿里开源的FunASR几乎是把一个商业的项目放给我们使用了。那么我们项目中的生产环境怎么部署gpu版本的语音识别服务呢?经过跟deepseek的一上午的极限…

内网邮箱服务器搭建-详解

目录 一、背景 二、搭建邮箱需要具备的基础知识 1、smtp&#xff08;Simple Mail Transfer Protocol&#xff09; SMTP工作原理 SMTP 命令 SMTP 协议端口 2、pop3&#xff08;Post Office Protocol&#xff09; POP3特点 POP3工作原理 3、imap4&#xff08;Internet M…

使用 LLaMA-Factory 微调 llama3 模型(二)

使用 LLaMA-Factory 微调 llama3 模型 1. LLaMA-Factory模型介绍 https://github.com/hiyouga/LLaMA-FactoryLLaMA-Factory 是一个用于大型语言模型&#xff08;LLM&#xff09;微调的工具&#xff0c;它旨在简化大型语言模型的微调过程&#xff0c; 使得用户可以快速地对模型…

并发编程--条件量与死锁及其解决方案

并发编程–条件量与死锁及其解决方案 文章目录 并发编程--条件量与死锁及其解决方案1.条件量1.1条件量基本概念1.2条件量的使用 2. 死锁 1.条件量 1.1条件量基本概念 在许多场合中&#xff0c;程序的执行通常需要满足一定的条件&#xff0c;条件不成熟的时候&#xff0c;任务…

JAVA SE 自我总结

目录 1. 字面常量 2. 数据类型 3. 变量 4. 类型转换 5. 实参和形参的关系 6. 数组 6.1 数组的概念 6.2 动态初始化 6.3 静态初始化 7. 数据区 ​编辑 8. 数组的拷贝 8.1 赋值拷贝 8.2 方法拷贝 9. 代码块 10. 内部类 10.1 实例内部类 10.2 静态内部类 10.3 …

RAG创建向量数据库:docsearch = FAISS.from_texts(documents, embeddings)

RAG创建向量数据库:docsearch = FAISS.from_texts(documents, embeddings) 代码解释 docsearch = FAISS.from_texts(documents, embeddings) 这行代码主要作用是基于给定的文本集合创建一个向量数据库(这里使用 FAISS 作为向量数据库工具 )。具体说明如下: FAISS :FAISS …

虚幻引擎5-Unreal Engine笔记之“将MyStudent变量设置为一个BP_Student的实例”这句话如何理解?

虚幻引擎5-Unreal Engine笔记之“将MyStudent变量设置为一个BP_Student的实例”这句话如何理解&#xff1f; code review! 文章目录 虚幻引擎5-Unreal Engine笔记之“将MyStudent变量设置为一个BP_Student的实例”这句话如何理解&#xff1f;理解这句话的关键点1.类&#xff08…

鸢尾花分类的6种机器学习方法综合分析与实现

鸢尾花分类的6种机器学习方法综合分析与实现 首先我们来看一下对应的实验结果。 数据准备与环境配置 在开始机器学习项目前&#xff0c;首先需要准备编程环境和加载数据。以下代码导入必要的库并加载鸢尾花数据集&#xff1a; import numpy as np import pandas as pd impo…

vite,Vue3,ts项目关于axios配置

一、安装依赖包 npm install axios -S npm install qs -S npm install js-cookie 文件目录 二、配置线上、本地环境 与src文件同级,分别创建本地环境文件 .env.development 和线上环境文件 .env.production # 本地环境 ENV = development # 本地环境接口地址 VITE_API_URL =…