我正在尝试导入一个c++函数,以便在MacOS上的Python(3.9(中使用。我的项目有以下结构,
.
├── CMakeLists.txt
├── cmake-build-debug
│ ├── CMakeCache.txt
│ ├── CMakeFiles
│ ├── Testing
│ ├── build.ninja
│ ├── cmake_install.cmake
│ └── libDENCLUS.dylib
├── denclus.py
├── library.cpp
└── library.h
将CMakeLists.txt作为
cmake_minimum_required(VERSION 3.22)
project(DENCLUS)
set(CMAKE_CXX_STANDARD 14)
add_library(DENCLUS SHARED library.cpp)
头文件,
#ifndef DENCLUS_LIBRARY_H
#define DENCLUS_LIBRARY_H
extern "C" void hello();
#endif //DENCLUS_LIBRARY_H
源文件,
#include "library.h"
#include <iostream>
void hello() {
std::cout << "Hello, World!" << std::endl;
}
和python文件
from ctypes.util import find_library
import ctypes
import os
cwd = os.getcwd()
lib = f'{cwd}/cmake-build-debug/libDENCLUS.dylib'
if find_library(lib):
libx = ctypes.cdll.LoadLibrary(lib)
libx.hello()
else:
raise OSError("Could not find lib.")
ctypesfind_library
返回None
,并且如果我指定到.dylib
文件的绝对路径,或者如果我将其称为find_library(DENCLUS)
或任何类似的排列,则不执行调用函数hello
的后续块。如何获取python代码来查找库并调用函数?
编辑:
我可以在if块之外调用c++函数。我认为MacOS上的find_library
有问题。
根据[Python.Docs]:ctypes-查找共享库(emphasis是我的(:
ctypes.util.find_library(名称(
尝试查找库并返回路径名name是没有任何前缀(如lib(、后缀(如
.so
、.dylib
或版本号(的库名称(这是用于posix链接器选项-l的形式(。如果找不到库,则返回None
。
这就是find_library返回None的原因。
同样的资源也指出(尽管我不一定同意(:
如果用ctypes包装共享库,可能会更好地在开发时确定共享库名称,并将其硬编码到包装模块中,而不是在运行时使用find_library((来定位库。
百万美元的问题:如果库的路径已知,为什么需要调用find_library?这毫无意义,因为它只是违背了它的目的。
简单使用:
import ctypes as ct
import os
cwd = os.getcwd()
lib_path = f"{cwd}/cmake-build-debug/libDENCLUS.dylib"
lib = ct.cdll.LoadLibrary(lib_path)
hello = lib.hello
# @TODO: !!! Define argtypes ans restype for any function called via CTypes !!!
hello.argtypes = ()
hello.restype = None
hello()
关于@TODO(即使在这种特殊情况下没有必要(,请检查从Python通过ctypes调用的[SO]:C函数返回的值不正确(@CristiFati的答案(。
如果出于某种原因(目前我还不知道(,你有使用find_library的冲动,下面是如何做到的:
os.environ["DYLD_LIBRARY_PATH"] = os.pathsep.join((os.environ.get("DYLD_LIBRARY_PATH", ""), os.path.join(os.getcwd(), "cmake-build-debug")))
lib_path = ct.util.find_library("DENCLUS")
# ...