首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Windows中使用LNK2019库编译C++代码时出现了链接错误[C++]

在Windows中使用LNK2019库编译C++代码时出现了链接错误[C++]
EN

Stack Overflow用户
提问于 2019-06-14 20:55:41
回答 2查看 632关注 0票数 1
  1. 我试图从Python中调用C++函数。
  2. 我已经成功地生成了一个C++ DLL (*.dll、*.lib和*.h),如果我试图仅仅从另一个C++代码调用它的C++函数,那么我已经测试了DLL库是否工作。(它在C++中工作)
  3. 然而,我正在努力为它做一个python包装。

我在这方面花了超过48个小时,所以任何一种帮助/建议/暗示/批评都是非常感谢的!

我在网上阅读了大部分关于相关内容的文档,尽管我并不完全理解它们。通过调整代码的某些部分并再次编译,问题似乎是链接器无法解决dll头文件(*.h)中声明的外部函数。

知道我测试*.pyx和*.h之间的“连接”可能是有用的,因为如果在调用*.pyx中的api函数时设置较少的参数,错误消息会说参数的数量与标头中的参数不一致。因此,真正的问题是*.pyx和*.dll之间的交互,这应该依赖于*.lib。至少我是这么想的。

由于我不确定*pyx的*.h文件是否应该使用"__declspec(dllimport)“或"__declspec(dllexport)",所以我尝试了两者。他们两个都没有解决这个问题。

换句话说,链接器无法找到api函数(符号)的定义在*.dll中的位置,因为即使我在setup.py中更改了库参数(例如,从库= 'libcds‘到库=’which‘),错误msg也是相同的,即"LNK2019:函数blabla中引用的未解析的外部符号__imp_CalcUpfrontCharge_API .

因此,我怀疑安装文件缺少某些部分,以便让编译知道它应该查找*.lib文件并在dll中找到定义。现在,它似乎忽略了*.lib,因为正如我所说的,即使我完全在扩展名()中删除了库参数,我也得到了相同的错误。

我还试图从源代码构建pyd (不是dll),但也失败了。

代码语言:javascript
复制
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()] 
)
EN

回答 2

Stack Overflow用户

发布于 2019-06-15 20:10:52

好吧,我回来回答我自己的问题。

经过36个小时的努力,我终于在我的Windows7系统上工作了。由于使用C/C++ DLL进行Cython编译需要如此多的细节和技巧,其中任何一个细节和技巧都非常关键,以至于即使缺少一个看似微不足道的步骤也可能导致编译/链接过程的整个失败,因此我将强调我遇到的所有容易出错的缺陷和解决方案:

  1. 您的安装扩展必须遵循如下形状:
代码语言:javascript
复制
    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
    )
  1. 重要的是,如果您总是遇到错误: but 2001/but 2019,请检查以确保在构建DLL时,不仅头文件在导出函数声明的前面有__declspec(dllexport),而且源文件中的函数定义也应该遵循__declspec(dllexport)!原来我在源文件中缺少前缀,所以dll在其他C++项目中工作,但在Cython中不工作!
代码语言:javascript
复制
#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
        );
    }

在源代码中,您有:

代码语言:javascript
复制
    CDSLIB_API double Test(double a)
    {
        double b;
        b = a + 1;
        return b;
    }

测试函数将工作,而CalcUpfrontCharge_API则不能.

  1. 记住用extern "C“包装纯C代码函数的声明
  2. 非常重要的是,如果您的dll是在x86平台中构建的,那么它将永远不会与64位python一起工作!最好的解决方案是使用Visual (我使用了VC2015),在这里您可以将解决方案平台从x86切换到x64。
票数 0
EN

Stack Overflow用户

发布于 2019-06-19 14:41:53

因此,我只是遇到这个问题,使用插件SDK向导,将创建一个插件外壳。它不会只使用shell构建,并且会得到此错误。这将是特定于这种类型的设置,但对我来说,修复是因为我收到了这样的警告:

代码语言:javascript
复制
warning C4335: Mac file format detected: please convert the source file to either DOS or UNIX format

在以正确的格式保存文件后,未解决的外部符号错误消失,我可以构建解决方案。

虽然我知道,这可能不是解决你的情况,我希望这可以帮助某人寻找一个答案。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56605015

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档