我在此上花费了48多个小时,因此非常感谢任何帮助/建议/提示/批评家!
尽管我并不完全了解所有相关内容,但我还是在线阅读了大多数相关文档。通过调整代码的某些部分并再次编译,闻起来像是问题在于链接器无法解析dll头文件(* .h)中声明的外部函数。
知道我测试* .pyx和* .h之间的“连接”是否有效可能很有用,因为如果在* .pyx中调用api函数时输入的参数较少,则错误消息将显示数字的参数与标题中的参数不一致。因此,问题实际上是* .pyx和* .dll之间的相互作用,该相互作用应取决于* .lib。至少我是这样想的。
由于我不确定* pyx的* .h文件是否应使用“ __declspec(dllimport)”或“ __declspec(dllexport)”,因此我尝试了两者。他们俩都没有解决问题。
换句话说,闻起来好像链接器无法在* .dll中找到api函数(符号)的定义所在,因为即使我更改了setup.py中的库参数(例如,来自库= [ 'libcds']到库= ['nonexist']),错误消息相同,即“ LNK2019:函数blabla中引用的未解析的外部符号__imp_CalcUpfrontCharge_API ...
因此,我怀疑安装文件缺少某些部分,让编译知道它应该查找* .lib文件并在dll中找到定义。现在看来,它正在忽略* .lib,因为正如我所说,即使我完全在extension()中删除了libraries参数,我也遇到了同样的错误。
我还尝试从源代码(不是dll)构建pyd,但也失败了。
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()]
)
答案 0 :(得分:0)
好的,我回来回答自己的问题。
在苦苦挣扎了36个小时之后,我终于使它可以在Windows7系统上运行。 由于使用C / C ++ DLL的Cython编译需要太多的细节和技巧,因此其中任何一项都是至关重要的,以至于即使缺少一个看似微不足道的步骤也可能导致编译/链接过程完全失败,我将着重介绍所有容易出错的陷阱我遇到的问题和解决方案:
ext_modules = [
Extension('cdspricer',
['cdspricer.pyx'],
# Note here that the C++ language was specified
# The default language is C
language="c++",
extra_link_args = [],
include_dirs=["N:\Trading\Python\ISDA"],
libraries=['cdslib', 'msvcrt', 'msvcmrt'],
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()] # This gets all the required Numpy core files
)
#ifdef CDSLIB_EXPORTS
#define CDSLIB_API __declspec(dllexport)
#else
#define CDSLIB_API __declspec(dllimport)
#endif
extern "C"
{
CDSLIB_API double CalcUpfrontCharge_API(
char *expiries[], double rates[], double couponRate, double parSpread, double
recoveryRate, char *today1, char *valueDate1, char *effectDate1, char *maturity
);
CDSLIB_API double Test(
double a
);
}
在源代码中,您具有:
CDSLIB_API double Test(double a)
{
double b;
b = a + 1;
return b;
}
Test函数将起作用,而CalcUpfrontCharge_API将不起作用。
答案 1 :(得分:0)
因此,我只是使用将创建插件外壳的插件SDK向导遇到了这个问题。它不会仅使用shell进行构建,并且会出现此错误。特定于这种类型的设置,但对我而言,解决方法是我收到此警告:
warning C4335: Mac file format detected: please convert the source file to either DOS or UNIX format
将文件保存为正确的格式后,未解决的外部符号错误消失了,我可以构建解决方案。
虽然我知道这可能无法解决您的情况,但我希望这可以帮助某人寻找答案。