簡體   English   中英

在c ++程序中鏈接cython模塊

[英]link cython module in a c++ program

是否可以使用一些cdef函數構建cython模塊並將生成的共享庫鏈接到C ++程序中?

我嘗試了一個概念驗證:

cymod.pyx:

# distutils: language=c++

from libcpp.string cimport string

cdef public string simple_echo(string test_string):
    return test_string

cpp_test.cpp:

#define PyMODINIT_FUNC void
#include <iostream>
#include "cymod.h"

int main(int argc, char const *argv[])
{
    std::cout << simple_echo("test") << std::endl;
    return 0;
}

setup.py:

from setuptools import setup, Extension
from Cython.Build import cythonize

setup(
    name='cymod',
    ext_modules=cythonize(
        Extension(
            "cymod", ["cymod.pyx"],
        ),
    )
)

cython模塊構建正常,但是當我嘗試構建將使用cython函數的c ++代碼時,我得到:

$ g++ -L. -l:cymod.so cpp_test.cpp -o cpp_test
/tmp/cc48Vc2z.o: In function `main':
cpp_test.cpp:(.text+0x51): undefined reference to `simple_echo'
collect2: error: ld returned 1 exit status

這很奇怪。 生成的頭文件包含它:

cymod.h:

  /* Generated by Cython 0.29.1 */

  #ifndef __PYX_HAVE__cymod
  #define __PYX_HAVE__cymod


  #ifndef __PYX_HAVE_API__cymod

  #ifndef __PYX_EXTERN_C
    #ifdef __cplusplus
      #define __PYX_EXTERN_C extern "C"
    #else
      #define __PYX_EXTERN_C extern
    #endif
  #endif

  #ifndef DL_IMPORT
    #define DL_IMPORT(_T) _T
  #endif

  __PYX_EXTERN_C std::string simple_echo(std::string);

  #endif /* !__PYX_HAVE_API__cymod */

  /* WARNING: the interface of the module init function changed in CPython 3.5. */
  /* It now returns a PyModuleDef instance instead of a PyModule instance. */

  #if PY_MAJOR_VERSION < 3
  PyMODINIT_FUNC initcymod(void);
  #else
  PyMODINIT_FUNC PyInit_cymod(void);
  #endif

  #endif /* !__PYX_HAVE__cymod */

我在cymod.so看到了我的功能:

nm cymod.so| grep simple_echo
0000000000001e50 T simple_echo

注意:我意識到要真正實現這個工作,我需要鏈接python庫並初始化解釋器等。我把它留下來使這一點更短,我得到相同的錯誤。

簡短的回答是我在編譯命令中過早地放置-l參數。 處理庫查找路徑也很重要。 最簡單的方法是使用rpath 我將rpath設置為可執行文件所在的目錄,即.

此外,有必要鏈接python庫並設置包含和庫路徑。 這些可以在編譯時通過使用python-config實用程序的輸出來確定。 這是最終完成這個技巧的編譯命令:

g++ cpp_test.cpp -o cpp_test -L. -l:cymod.so $(python-config --libs) $(python-config --includes) $(python-config --cflags) -Wl,-rpath,"\$ORIGIN"

我還將c ++文件更新為#include "Python.h"並添加了對Py_Initialize()Py_Finalize()initcymod()

#include <iostream>
#include "Python.h"
#include "cymod.h"

int main(int argc, char *argv[])
{
    Py_Initialize();
    initcymod();
    std::cout << simple_echo("test") << std::endl;
    Py_Finalize();
    return 0;
}

注意:調用initcymod()是必要的,但python2是特定的。 在python3上你應該調用PyImport_AppendInittab("cymod", PyInit_cymod); Py_Initialize()之前。 cymod部分是模塊名稱,替換您的模塊名稱。

感謝@ead提供有關此主題的文檔的信息鏈接https://cython.readthedocs.io/en/latest/src/userguide/external_C_code.html#using-cython-declarations-from-c以及他對相關問題https://stackoverflow.com/a/45424720/2069572

在閱讀鏈接文檔時,我遇到了這個:

注意在某些操作系統(如Linux)上,也可以首先以常規方式構建Cython擴展,然后將鏈接到生成的.so文件,如動態庫。 請注意,這不是便攜式的,所以應該避免。

事實證明,你不應該做我想做的事情。

相反,我應該做的是運行:

cython --cplus cymod.pyx

然后用生成的cymod.cpp文件編譯cpp_test.cpp 無需鏈接cython共享庫,事實證明這樣做並不是一個好主意。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM