加减乘除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;
}
编译动态库
-fPIC
:为共享库生成位置无关代码-shared
:生成共享库-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
-L.
:告诉编译器去当前目录查找库文件-lcalculator
:链接名为libcalculator.so
的库(省略前缀lib
和扩展名.so
)
g++ main.cpp -L. -lcalculator -o main
执行测试程序
运行程序前,设置动态库路径
LD_LIBRARY_PATH
是 Linux 下指定“运行时动态库查找路径”的环境变量.
代表当前目录$LD_LIBRARY_PATH
是保留已有路径
#设置环境变量
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
上面代码的意思是:请系统在当前目录找动态库,然后再去默认路径找
系统默认会查找这些路径
- /lib
- /usr/lib
永久添加路径
更新系统的动态链接库缓存,也就是告诉系统有哪些 .so
库、它们在哪儿,以便程序运行时可以找到这些库。
sudo ldconfig
什么时候用?
- 安装了新的
.so
动态库 - 把
.so
文件放到了非标准路径下(比如/usr/local/lib
、/opt/mylibs
) - 修改了
/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))
测试调用
- export LD_LIBRARY_PATH=CPP:$LD_LIBRARY_PATH
- 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})
使用方法
- mkdir build && cd build
- cmake …
- cmake --build .
目录结构
CPP/
├── calculator.cpp
├── calculator.h
├── main.cpp
├── CMakeLists.txt
└── build/
├── bin/│ └── main└── lib/└── libcalculator.so