加减乘除demo代码
项目结构
CPP/
├── calculator.cpp
├── calculator.h
├── main.cpp
头文件
c
#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
源文件
c
#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,用于测试动态库接口,需要在编译好动态库后进行测试
c
#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;
}
编译动态库
-fPIC
:为共享库生成位置无关代码-shared
:生成共享库-o libcalculator.so
:输出为动态库文件
c
g++ -fPIC -shared calculator.cpp -o libcalculator.so

查看动态库有哪些接口
nm命令
c
nm -D libcalculator.so
带有 T
的(代表函数定义在库里)

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

objdump命令
c
objdump -T libcalculator.so

readelf命令
c
readelf -Ws libcalculator.so

main.cpp编译
main.cpp会在编译的过程中去动态链接libcalculator.so
-L.
:告诉编译器去当前目录查找库文件-lcalculator
:链接名为libcalculator.so
的库(省略前缀lib
和扩展名.so
)
c
g++ main.cpp -L. -lcalculator -o main

执行测试程序
运行程序前,设置动态库路径
LD_LIBRARY_PATH
是 Linux 下指定"运行时动态库查找路径"的环境变量.
代表当前目录$LD_LIBRARY_PATH
是保留已有路径
c
#设置环境变量
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
上面代码的意思是:请系统在当前目录找动态库,然后再去默认路径找
系统默认会查找这些路径
- /lib
- /usr/lib
永久添加路径
更新系统的动态链接库缓存 ,也就是告诉系统有哪些 .so
库、它们在哪儿,以便程序运行时可以找到这些库。
c
sudo ldconfig
什么时候用?
- 安装了新的
.so
动态库 - 把
.so
文件放到了非标准路径下(比如/usr/local/lib
、/opt/mylibs
) - 修改了
/etc/ld.so.conf
或/etc/ld.so.conf.d/
下的配置
运行程序
c
./main

运行程序前,为什么要设置动态库路径
因为你用的是 动态链接库( **.so**
** 文件),程序运行时需要知道这个库 在哪里**。编译的时候你告诉了编译器怎么找到它(-L.
),但运行时要靠系统的**动态链接器(ld.so
)**来加载 .so
文件。
如果 .so
不在系统默认的路径里(比如 /lib
, /usr/lib
),就需要你手动告诉它去哪里找。
python调用
test_calculator.py
c
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))
测试调用
- export LD_LIBRARY_PATH=CPP:$LD_LIBRARY_PATH
- python3 test_calculator.py

Makefile生成动态库
c
# 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一起生成动态库和可执行程序
c
# 编译器
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
c
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})
使用方法
- mkdir build && cd build
- cmake ...
- cmake --build .
目录结构
CPP/
├── calculator.cpp
├── calculator.h
├── main.cpp
├── CMakeLists.txt
└── build/
├── bin/
│ └── main
└── lib/
└── libcalculator.so