更改 Cython 对 .so 文件的命名规则
Change Cython's naming rules for .so files
我正在使用 Cython 从 Python 模块中生成一个共享对象。编译输出写入 build/lib.linux-x86_64-3.5/<Package>/<module>.cpython-35m-x86_64-linux-gnu.so
。是否有更改命名规则的选项?我希望文件被命名为 <module>.so
没有解释器版本或 arch 附录。
似乎 setuptools
没有提供更改或完全删除后缀的选项。奇迹发生在 distutils/command/build_ext.py
:
def get_ext_filename(self, ext_name):
from distutils.sysconfig import get_config_var
ext_path = ext_name.split('.')
ext_suffix = get_config_var('EXT_SUFFIX')
return os.path.join(*ext_path) + ext_suffix
看来我需要添加一个 post-build 重命名操作。
2016 年 8 月 12 日更新:
好吧,我实际上忘记了 post 解决方案。实际上,我通过重载内置 install_lib
命令来实现重命名操作。逻辑如下:
from distutils.command.install_lib import install_lib as _install_lib
def batch_rename(src, dst, src_dir_fd=None, dst_dir_fd=None):
'''Same as os.rename, but returns the renaming result.'''
os.rename(src, dst,
src_dir_fd=src_dir_fd,
dst_dir_fd=dst_dir_fd)
return dst
class _CommandInstallCythonized(_install_lib):
def __init__(self, *args, **kwargs):
_install_lib.__init__(self, *args, **kwargs)
def install(self):
# let the distutils' install_lib do the hard work
outfiles = _install_lib.install(self)
# batch rename the outfiles:
# for each file, match string between
# second last and last dot and trim it
matcher = re.compile('\.([^.]+)\.so$')
return [batch_rename(file, re.sub(matcher, '.so', file))
for file in outfiles]
现在你所要做的就是重载setup
函数中的命令:
setup(
...
cmdclass={
'install_lib': _CommandInstallCythonized,
},
...
)
不过,我对重载标准命令不满意;如果您找到更好的解决方案,post 它,我会接受您的回答。
此行为已在 distutils 包中定义。 distutils 使用 sysconfig 和 "EXT_SUFFIX" 配置变量:
# Lib\distutils\command\build_ext.py
def get_ext_filename(self, ext_name):
r"""Convert the name of an extension (eg. "foo.bar") into the name
of the file from which it will be loaded (eg. "foo/bar.so", or
"foo\bar.pyd").
"""
from distutils.sysconfig import get_config_var
ext_path = ext_name.split('.')
ext_suffix = get_config_var('EXT_SUFFIX')
return os.path.join(*ext_path) + ext_suffix
以Python 3.5开头的"EXT_SUFFIX"变量包含平台信息,例如“.cp35-win_amd64”.
我写了下面的函数:
def get_ext_filename_without_platform_suffix(filename):
name, ext = os.path.splitext(filename)
ext_suffix = sysconfig.get_config_var('EXT_SUFFIX')
if ext_suffix == ext:
return filename
ext_suffix = ext_suffix.replace(ext, '')
idx = name.find(ext_suffix)
if idx == -1:
return filename
else:
return name[:idx] + ext
和自定义build_ext命令:
from Cython.Distutils import build_ext
class BuildExtWithoutPlatformSuffix(build_ext):
def get_ext_filename(self, ext_name):
filename = super().get_ext_filename(ext_name)
return get_ext_filename_without_platform_suffix(filename)
用法:
setup(
...
cmdclass={'build_ext': BuildExtWithoutPlatformSuffix},
...
)
解决方法很简单,只需要在build_ext.py
中改一行
def get_ext_filename(self, ext_name):
from distutils.sysconfig import get_config_var
ext_path = ext_name.split('.')
ext_suffix = get_config_var('EXT_SUFFIX')
return os.path.join(*ext_path) + ext_suffix
将ext_suffix = get_config_var('EXT_SUFFIX')
改为
ext_suffix = ".so"
或 ".pyd"
Windows
就是这样,您再也不用担心输出名称了
我正在使用 Cython 从 Python 模块中生成一个共享对象。编译输出写入 build/lib.linux-x86_64-3.5/<Package>/<module>.cpython-35m-x86_64-linux-gnu.so
。是否有更改命名规则的选项?我希望文件被命名为 <module>.so
没有解释器版本或 arch 附录。
似乎 setuptools
没有提供更改或完全删除后缀的选项。奇迹发生在 distutils/command/build_ext.py
:
def get_ext_filename(self, ext_name):
from distutils.sysconfig import get_config_var
ext_path = ext_name.split('.')
ext_suffix = get_config_var('EXT_SUFFIX')
return os.path.join(*ext_path) + ext_suffix
看来我需要添加一个 post-build 重命名操作。
2016 年 8 月 12 日更新:
好吧,我实际上忘记了 post 解决方案。实际上,我通过重载内置 install_lib
命令来实现重命名操作。逻辑如下:
from distutils.command.install_lib import install_lib as _install_lib
def batch_rename(src, dst, src_dir_fd=None, dst_dir_fd=None):
'''Same as os.rename, but returns the renaming result.'''
os.rename(src, dst,
src_dir_fd=src_dir_fd,
dst_dir_fd=dst_dir_fd)
return dst
class _CommandInstallCythonized(_install_lib):
def __init__(self, *args, **kwargs):
_install_lib.__init__(self, *args, **kwargs)
def install(self):
# let the distutils' install_lib do the hard work
outfiles = _install_lib.install(self)
# batch rename the outfiles:
# for each file, match string between
# second last and last dot and trim it
matcher = re.compile('\.([^.]+)\.so$')
return [batch_rename(file, re.sub(matcher, '.so', file))
for file in outfiles]
现在你所要做的就是重载setup
函数中的命令:
setup(
...
cmdclass={
'install_lib': _CommandInstallCythonized,
},
...
)
不过,我对重载标准命令不满意;如果您找到更好的解决方案,post 它,我会接受您的回答。
此行为已在 distutils 包中定义。 distutils 使用 sysconfig 和 "EXT_SUFFIX" 配置变量:
# Lib\distutils\command\build_ext.py
def get_ext_filename(self, ext_name):
r"""Convert the name of an extension (eg. "foo.bar") into the name
of the file from which it will be loaded (eg. "foo/bar.so", or
"foo\bar.pyd").
"""
from distutils.sysconfig import get_config_var
ext_path = ext_name.split('.')
ext_suffix = get_config_var('EXT_SUFFIX')
return os.path.join(*ext_path) + ext_suffix
以Python 3.5开头的"EXT_SUFFIX"变量包含平台信息,例如“.cp35-win_amd64”.
我写了下面的函数:
def get_ext_filename_without_platform_suffix(filename):
name, ext = os.path.splitext(filename)
ext_suffix = sysconfig.get_config_var('EXT_SUFFIX')
if ext_suffix == ext:
return filename
ext_suffix = ext_suffix.replace(ext, '')
idx = name.find(ext_suffix)
if idx == -1:
return filename
else:
return name[:idx] + ext
和自定义build_ext命令:
from Cython.Distutils import build_ext
class BuildExtWithoutPlatformSuffix(build_ext):
def get_ext_filename(self, ext_name):
filename = super().get_ext_filename(ext_name)
return get_ext_filename_without_platform_suffix(filename)
用法:
setup(
...
cmdclass={'build_ext': BuildExtWithoutPlatformSuffix},
...
)
解决方法很简单,只需要在build_ext.py
中改一行
def get_ext_filename(self, ext_name):
from distutils.sysconfig import get_config_var
ext_path = ext_name.split('.')
ext_suffix = get_config_var('EXT_SUFFIX')
return os.path.join(*ext_path) + ext_suffix
将ext_suffix = get_config_var('EXT_SUFFIX')
改为
ext_suffix = ".so"
或 ".pyd"
Windows
就是这样,您再也不用担心输出名称了