Ctypes 在使用 CMake 创建的共享库中找不到符号

作者:编程家 分类: c++ 时间:2025-08-15

使用CMake创建共享库是在C/C++开发中常见的一种方式。然而,有时候在使用Ctypes(Python的外部函数库)调用这些共享库时,会遇到找不到符号的问题。本文将介绍这个问题的原因,并提供解决方案。

## 问题描述

当我们使用CMake创建一个共享库时,经常会将一些函数或变量声明为extern "C",以便在C++代码中正确地导出它们。这样做的目的是为了使这些函数和变量在共享库中能够被其他编程语言(如Python)调用。

然而,当我们使用Ctypes调用这个共享库时,有时会遇到一个错误,提示找不到符号。这意味着Python无法找到共享库中声明的函数或变量。

## 问题原因

这个问题通常是由于Ctypes对共享库的符号解析方式与CMake生成的共享库的符号解析方式不一致造成的。

CMake生成的共享库在链接时会使用一种叫做"symbol versioning"的技术,它会在符号名中添加一些额外的信息,以便在链接时能够正确地解析符号。然而,Ctypes并不支持这种符号解析方式,因此导致了找不到符号的问题。

## 解决方案

要解决这个问题,我们可以在CMakeLists.txt文件中添加一些额外的配置,以禁用symbol versioning。这样做的目的是使CMake生成的共享库的符号解析方式与Ctypes兼容。

下面是一个示例的CMakeLists.txt文件:

cmake

cmake_minimum_required(VERSION 3.12)

project(mylibrary)

set(CMAKE_CXX_STANDARD 11)

add_library(mylibrary SHARED mylibrary.cpp)

# Disable symbol versioning

set_property(TARGET mylibrary PROPERTY

NO_SYSTEM_FROM_IMPORTED 1)

在这个示例中,我们通过设置`NO_SYSTEM_FROM_IMPORTED`属性来禁用symbol versioning。这样生成的共享库将不再包含额外的符号信息,从而与Ctypes兼容。

## 示例代码

下面是一个使用CMake创建共享库,并通过Ctypes调用的示例代码:

首先,创建一个名为mylibrary.cpp的C++源文件,其中包含一个简单的函数定义:

cpp

#include

extern "C" {

void hello() {

std::cout << "Hello from mylibrary!" << std::endl;

}

}

然后,使用CMake生成共享库:

bash

$ mkdir build

$ cd build

$ cmake ..

$ make

接下来,创建一个名为test.py的Python脚本,使用Ctypes调用共享库中的函数:

python

from ctypes import cdll

mylibrary = cdll.LoadLibrary('./libmylibrary.so')

mylibrary.hello()

运行test.py脚本,应该能够正确输出"Hello from mylibrary!"。

##

使用CMake创建共享库是一种常见的开发方式,但在使用Ctypes调用这些共享库时可能会遇到找不到符号的问题。本文介绍了这个问题的原因,并提供了一个解决方案。通过禁用CMake生成的共享库的symbol versioning,我们可以使其与Ctypes兼容,从而成功调用共享库中的函数和变量。希望本文对解决类似问题的开发者有所帮助。