Создание 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?
Не стесняйтесь отвечать одним из вышеперечисленных хаков, если вы можете расширить его и обосновать, почему это лучший способ. Если нет ничего лучше, по крайней мере, вся информация будет находиться в одном месте.
Ответы
Ответ 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%, поэтому вам придется попробовать.