Cython cimport из другого каталога - PullRequest
1 голос
/ 28 июня 2019

Для справки, я прочитал следующие вопросы: https://github.com/cython/cython/wiki/PackageHierarchy

https://cython.readthedocs.io/en/latest/src/userguide/sharing_declarations.html#search-paths-for-definition-files

Cython cimport не может найти модуль .pxd

Как заставить cimport работать на Cython?

Ошибка компиляции файла Cython: pxd не найден в пакете

Проблема заключается в следующем. Раньше у меня было множество C, C ++ и Cython, которые сидели в одном каталоге и прекрасно компилировались. Теперь я делю код на 2 директории:

  1. C / C ++ / Cython source для модуля "cpysim"
  2. C / C ++ / код Cython для другого модуля "dut"

Обоснование заключается в том, что модуль cpysim будет многократно использоваться повторно, а модуль dut будет меняться от проекта к проекту. Последний недостаток заключается в том, что один файл в модуле cpysim может быть скомпилирован только со ссылкой на файл в модуле dut, и это вызывает у меня проблемы.

Чтобы было ясно, все компилировалось нормально, когда все было в одном каталоге. Вот как это выглядит сейчас.

<root>
  -- __init__.py
  -- cpysim
    -- __init__.py
    -- __init__.pxd
    -- sim_core.cpp
    -- sim_core.hpp
    -- sim_core.pxd
    ....
    wiretypes.pyx
    <other sources>
  -- dut
    -- wire_names.def
    -- setup_dut.py
    <other sources>

Цель

Компиляция wiretypes.pyx из каталога dut (из setup_dut.py в каталоге dut).

Попробуйте 1

Этот импорт доставляет мне неприятности в wiretypes.pyx

from libcpp cimport bool
from sim_core cimport sigtype_t  # <-- this one
....

Соответствующее содержание setup_dut.py

inc_dirs = ['./', '../', '../cpysim/', '../build', '../dSFMT-src-2.2.3', '../build/include']
....
      Extension("wiretypes",
                ["../cpysim/wiretypes.pyx"],
                language="c++",
                libraries=["cpysim", "ethphy"],
                include_dirs=inc_dirs,
                library_dirs=lib_dirs,
                extra_compile_args=compile_args,
                extra_link_args=link_args),
....
ext = cythonize(extensions,
                gdb_debug=True,
                compiler_directives={'language_level': '3'})

setup(ext_modules=ext,
      cmdclass={'build_ext': build_ext},
      include_dirs=[np.get_include()])

Почему я думаю, что это должно работать: согласно документации, достаточно указать путь для включения заголовка sim_core.pxd. Например, cimport numpy as np работает, когда вы устанавливаете include_dirs=[np.get_include()], np.get_include() просто выплевывает путь. Итак, в inc_dirs я поставил ../cpysim. Когда я компилирую, я получаю

Error compiling Cython file:
------------------------------------------------------------
...
"""
Cython header defining a net.
"""

from libcpp cimport bool
from sim_core cimport sigtype_t
^
------------------------------------------------------------

/Users/colinww/system-model/cpysim/wiretypes.pyx:8:0: 'sim_core.pxd' not found

Попробуйте 2

Я подумал, что, возможно, мне нужно рассматривать каталог cpysim как модуль. Поэтому я добавил __init__.py и изменил импорт в wiretypes.pyx на:

from libcpp cimport bool
cimport cpysim.sim_core as sim_core
Error compiling Cython file:
------------------------------------------------------------
...
"""
Cython header defining a net.
"""

from libcpp cimport bool
cimport cpysim.sim_core as sim_core
       ^
------------------------------------------------------------

/Users/colinww/system-model/cpysim/wiretypes.pyx:8:8: 'cpysim/sim_core.pxd' not found

Так что теперь я в растерянности. Я не понимаю, почему моя первая попытка не сработала, я знаю, что включаемые каталоги передаются должным образом, потому что есть много других заголовков, которые необходимо найти и правильно скомпилировать.

Я думаю, что есть какой-то фундаментальный аспект того, как работает cimport, которого мне не хватает.

1 Ответ

1 голос
/ 29 июня 2019

Кажется, что вы бы перепутали включения с ... включениями.

Создание расширения Cython состоит из двух этапов:

  1. Генерация C-souce-файл из pyx-файла, использующий функцию cythonize и пути к необходимым pxd-файлам в качестве include-путей для Cython-компилятора (точнее cythonize напрямую не вызывает Cython-компилятор - это происходитпозже, когда setup будет выполнено, но ради этого ответа мы притворимся, что cythonized = вызов Cython-компилятора)

  2. Генерация so-файла (или что-либо еще) из сгенерированного C-файла, используя необходимые пути к заголовкам (* .h-файлы, например, numpy's), когда вызывается setup -функция.

Что произойдет, если вы добавите'include_dirs' до Extension?Это используется Cython-Compiler или C-Compiler?

Cython использует каталоги include, переданные в cythonize -функцию, и в вашем случае это ничто (что приводит к [.]), то есть оно должно быть изменено на

ext = cythonize(extensions, include_path=[<path1>, <path2>], ...)

ОднакоCython также использует sys.path для поиска pxd файлов - таким образом, установка sys.path может быть обходным путем (что немного странно, так как каждая манипуляция с sys.path) - в этом случае порядок включений таков:include_directories, sys.path, Cython/Includes (по крайней мере, в большинстве текущих версий ).


Забавно, если используются setuptools без явного вызова cythonize,затем include_dirs используются и Cython- и C-компиляторами, то есть:

from setuptools import setup, Extension

extensions = [Extension("foo", ["foo.pyx"], include_dirs=[<path1>, <path2>])]
setup(name="foo", ext_modules=extensions)

приводит к тому, что path1 и path2 используются обоими, Cython и C-компиляторами.

Однако я не уверен, что приведенное выше решение для установки include_path может быть рекомендовано: оно работает только потому, что setuptools использует (также см. , что ) устарел 'old_build_ext , which sets include_path` здесь :

    ...
    for source in cython_sources:
        ...
        options = CompilationOptions(...
                include_path = includes,  # HERE WE GO!
                ...)
          result = cython_compile(source, options=options,
                                    full_module_name=module_name)
...