- Я пытался вызывать функции C ++ в dll из Python.
- Я успешно создал C ++ DLL (* .dll, * .lib и * .h), и у меня есть тест, что библиотека DLL работает, если я пытаюсь вызывать ее функции API только из другого кода C ++.(это работает в C ++)
- Однако я изо всех сил пытаюсь сделать вокруг него оболочку Python.
Я потратил на это более 48 часов, поэтому я очень ценю любую помощь / совет / подсказку / критику !!
Я прочитал большинство доступных документов о связанных материалахонлайн, хотя я не полностью понимаю их все.Изменяя некоторую часть кода и снова компилируя, пахнет тем, что проблема в том, что компоновщик не может разрешить внешние функции, объявленные в заголовочном файле dll (* .h).
Вероятно, полезно знать, что я проверяю, работает ли "соединение" между * .pyx и * .h, потому что, если при вызове функции api в * .pyx я добавлю меньше аргументов, появится сообщение об ошибке.скажем, количество параметров не совпадает с указанным в заголовке.так что проблема на самом деле заключается во взаимодействии * .pyx и * .dll, которое должно зависеть от * .lib.По крайней мере, так я думаю.
Поскольку я не уверен, должен ли файл * .h для * pyx использовать «__declspec (dllimport)» или «__declspec (dllexport)», я попробовал оба варианта.Ни один из них не решил проблему.
Другими словами, он пахнет так, будто компоновщик не может найти, где находится определение функции API (символа) в * .dll, потому что даже если я изменю аргументы библиотекв файле setup.py (например, из library = ['libcds'] to library = ['nonexist']) ошибка msg та же, что и "LNK2019: неразрешенный внешний символ __imp_CalcUpfrontCharge_API, на который ссылается функция blabla ...
Так что я подозреваю, что в установочном файле отсутствует какая-то часть, чтобы компиляция знала, что должна найти файл * .lib и найти определение в dll. Сейчас кажется, что он игнорирует * .lib, потому что, как ясказал, что даже если я полностью вычеркну аргумент библиотеки в extension (), я получу ту же ошибку.
Я также пытался собрать pyd из исходного кода (не dll), но также потерпел неудачу.
it is as simple as this (updated CDS_API macro):
libcds.h
#ifdef CDS_EXPORTS
#define CDS_API __declspec(dllexport)
#else
#define CDS_API __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C"
{
#endif
CDS_API double CalcUpfrontCharge_API(
char *expiries[], double rates[], double couponRate, double
parSpread, double recoveryRate, char *today1, char *valueDate1, char
*effectDate1, char *maturity
);
#ifdef __cplusplus
}
#endif
cdspricer.pyx
# distutils: language = c++
# distutils: libraries = libcds
# distutils: include_dirs = .
# distutils: library_dirs = .
cimport numpy as np
from libc.stdlib cimport malloc, free
from libcpp.vector cimport vector
from libcpp.string cimport string
from libc.string cimport strcpy, strlen
cdef extern from "libcds.h":
double CalcUpfrontCharge_API(
char *expiries[], double rates[], double couponRate, double
parSpread, double recoveryRate, char *today1, char *valueDate1, char
*effectDate1, char *maturity);
def CalcUpfrontCharge(vector[char *] expiries,
vector[double] rates,
double couponRate,
double parSpread,
double recoveryRate,
string today,
string valueDate,
string effectDate,
string maturity
):
some logic...
cdef double res = CalcUpfrontCharge_API(c_expiries, c_rates, couponRate,
parSpread, recoveryRate, today1, valueDate1, effectDate1, maturity1)
return res
setup.py
import setuptools
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
import numpy as np
ext_modules = [
Extension('cdspricer',
['cdspricer.pyx'],
# Note here that the C++ language was specified
# The default language is C
language="c++",
depends = ['N:\Trading\Python\ISDA\libcds.lib'],
extra_link_args = [],
include_dirs=["N:\Trading\Python\ISDA"],
libraries=['libcds'],
library_dirs=["N:\Trading\Python\ISDA"])
]
setup(
name = 'cdspricer',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules,
extra_compile_args=["-O3", "-Wall"],
include_dirs=[np.get_include()]
)