Создание библиотеки C на основе ctypes с помощью distutils

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

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

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

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

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

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


person Robie Basak    schedule 25.12.2010    source источник


Ответы (3)


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

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

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

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

Таким образом, использование его для простых общих библиотек должно работать из коробки, за исключением Windows. Но это тоже легко исправить. Возвращаемое значение 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})
person memeplex    schedule 16.01.2016
comment
Как могло быть так с setuptools, если оно устарело? - person chmike; 18.02.2021

Я установил минимальный рабочий пакет python с расширением ctypes здесь: https://github.com/himbeles/ctypes-example, который работает в Windows, Mac, Linux.

  • Используется подход memeplex выше, заключающийся в перезаписи build_ext.get_export_symbols() и принуждении расширения библиотеки быть одинаковым (.so) для всех операционных систем. .
  • Кроме того, директива компилятора в исходном коде c / c ++ обеспечивает правильный экспорт символов разделяемой библиотеки в случае Windows и Unix.
  • В качестве бонуса бинарные колеса автоматически компилируются действием GitHub для всех операционных систем :-)
person lsrggr    schedule 25.11.2020

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

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

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

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

person Lennart Regebro    schedule 25.12.2010