Подтвердить что ты не робот

Создание ctypes-основанной библиотеки C с distutils

Следуя этой рекомендации, я написал собственную библиотеку расширений C для оптимизации части модуля Python через ctypes. Я выбрал ctypes над написанием родной библиотеки CPython, потому что это было быстрее и проще (всего несколько функций со всеми жесткими петлями внутри).

Теперь я попал в ловушку. Если я хочу, чтобы моя работа была легко установлена ​​с помощью distutils с помощью python setup.py install, тогда distutils должен иметь возможность создавать мою общую библиотеку и устанавливать ее (предположительно в /usr/lib/myproject). Однако это не модуль расширения Python, и, насколько я могу судить, distutils не могут этого сделать.

Я нашел несколько ссылок на людей других людей с этой проблемой:

Я знаю, что я могу сделать что-то родное, а не использовать distutils для разделяемой библиотеки или использовать мою дистрибутивную систему. Меня беспокоит то, что это ограничит удобство использования, поскольку не все смогут легко установить его.

Итак, мой вопрос: каков наилучший способ распространения разделяемой библиотеки с distutils, которая будет использоваться ctypes, но в остальном является OS-native, а не модулем расширения Python?

Не стесняйтесь отвечать одним из вышеперечисленных хаков, если вы можете расширить его и обосновать, почему это лучший способ. Если нет ничего лучше, по крайней мере, вся информация будет находиться в одном месте.

4b9b3361

Ответ 1

Документация distutils здесь гласит, что:

Расширение C для CPython - это общая библиотека (например,.so файл в Linux,.pyd в Windows), которая экспортирует функцию инициализации.

Таким образом, единственная разница в простой общей библиотеке, по-видимому, является функцией инициализации (помимо разумного соглашения об именах файлов, я не думаю, что у вас есть проблемы). Теперь, если вы посмотрите на distutils.command.build_ext, вы увидите, что он определяет метод get_export_symbols(), который:

Возвращает список символов, которые необходимо экспортировать совместно используемому расширению. Это либо использует "ext.export_symbols", либо, если оно не указано, "PyInit_" + имя_модуля. Только для Windows, где файл .pyd(DLL) должен экспортировать модуль "PyInit_".

Таким образом, использование его для простых разделяемых библиотек должно работать готово, кроме как в Окна. Но это также легко исправить. Возвращаемое значение get_export_symbols() передается на distutils.ccompiler.CCompiler.link(), в документации указано:

'export_symbols' - это список символов, которые будет экспортироваться совместно используемой библиотекой. (Это кажется актуальным только для Windows.)

Таким образом, добавление функции инициализации к символам экспорта сделает трюк. Для этого вам просто нужно тривиально переопределить build_ext.get_export_symbols().

Кроме того, вы можете упростить имя модуля. Вот полный пример подкласса build_ext, который может создавать модули ctypes, а также модули расширения:

from distutils.core import setup, Extension
from distutils.command.build_ext import build_ext


class build_ext(build_ext):

    def build_extension(self, ext):
        self._ctypes = isinstance(ext, CTypes)
        return super().build_extension(ext)

    def get_export_symbols(self, ext):
        if self._ctypes:
            return ext.export_symbols
        return super().get_export_symbols(ext)

    def get_ext_filename(self, ext_name):
        if self._ctypes:
            return ext_name + '.so'
        return super().get_ext_filename(ext_name)


class CTypes(Extension): pass


setup(name='testct', version='1.0',
      ext_modules=[CTypes('ct', sources=['testct/ct.c']),
                   Extension('ext', sources=['testct/ext.c'])],
      cmdclass={'build_ext': build_ext})

Ответ 2

Некоторые пояснения здесь:

  • Это не библиотека, основанная на "ctypes". Это просто стандартная библиотека C, и вы хотите установить ее с distutils. Если вы используете C-расширение, ctypes или cython, чтобы обернуть эту библиотеку, не имеет значения для вопроса.

  • Поскольку библиотека, по-видимому, не является общей, но просто содержит оптимизацию для вашего приложения, рекомендация, к которой вы ссылаетесь, не относится к вам, в вашем случае, вероятно, проще написать C-расширение или используйте Cython, и в этом случае ваша проблема будет устранена.

Для фактического вопроса вы всегда можете использовать свою собственную команду distutils, и на самом деле одно из обсуждений, связанных с такой командой, OOF2 build_shlib, что делает то, что вы хотите. В этом случае, хотя вы хотите установить специальную библиотеку, которая действительно не используется совместно, а затем, я думаю, вам не нужно ее устанавливать в /usr/lib/yourproject, но вы можете установить ее в каталог пакета в /usr/lib/python -xx/site-packages/yourmodule вместе с вашими файлами python. Но я не уверен на 100%, поэтому вам придется попробовать.