如何在定义 cython 扩展之前识别编译器?
How to identify compiler before defining cython extensions?
我正在构建一个独立于平台的 cython 项目,我想在其中根据所使用的编译器传递编译器参数。我可以猜测基于平台的编译器,或者假设它与用于 Python 的编译器相同,但不能保证匹配。通常我将 cmdclass
arg 注入 setuptool 的设置方法并包装安装或 build_ext 命令以检查内部状态。但在这种情况下,我必须在到达包装器之前对扩展模块进行 cythonize。
在 cythonizing 扩展模块之前,有什么方法可以确定 setup.py 中的编译器吗?
在 cython 论坛上发帖并在 distutils 中搜索相关问题后,我发现 this post 展示了如何将编译器参数移动到 build_ext 赋值中。如果我随后从扩展 class 中删除所有编译器参数,我现在可以按照预期在命令 class 中延迟分配它们。我还可以获得 install
和 egg_info
命令 classes 来调用我的 build_ext 的新版本。
from setuptools.command.build_ext import build_ext
BUILD_ARGS = defaultdict(lambda: ['-O3', '-g0'])
for compiler, args in [
('msvc', ['/EHsc', '/DHUNSPELL_STATIC']),
('gcc', ['-O3', '-g0'])]:
BUILD_ARGS[compiler] = args
class build_ext_compiler_check(build_ext):
def build_extensions(self):
compiler = self.compiler.compiler_type
args = BUILD_ARGS[compiler]
for ext in self.extensions:
ext.extra_compile_args = args
build_ext.build_extensions(self)
...
setup(
...
cmdclass={ 'build_ext': build_ext_compiler_check })
第一个答案的简单变体:
from setuptools import setup, Extension
from distutils.command.build_ext import build_ext
myextension = Extension(
name = 'packagename',
sources = [
'source/debugger.cpp',
],
include_dirs = [ 'source' ],
)
class build_ext_compiler_check(build_ext):
def build_extensions(self):
compiler = self.compiler.compiler_type
# print('\n\ncompiler', compiler)
if not 'msvc' in compiler:
for extension in self.extensions:
if extension == myextension:
extension.extra_compile_args.append( '-O0' )
extension.extra_compile_args.append( '-std=c++11' )
super().build_extensions()
setup(
name = 'packagename',
version = __version__,
ext_modules= [ myextension ],
)
(抱歉,由于缺少积分无法发表评论)
不幸的是,答案 有点误导,因为 build_ext 实例的 self.compiler.compiler_type
是 'unix',而不是 'gcc'(“distutils compiler_class").
即从这个 defaultdict 字典中查找
BUILD_ARGS = defaultdict(lambda: ['-O3', '-g0'])
for compiler, args in [
('msvc', ['/EHsc', '/DHUNSPELL_STATIC']),
('gcc', ['-O3', '-g0'])]:
BUILD_ARGS[compiler] = args
通常不会到达 'gcc' 条目,而是 总是 回退到 defaultdict 的默认值(lambda 函数)。
也就是说,只要默认选项与 'gcc' 选项保持一致,在大多数情况下您可能不会注意到这一点。例如。 clang 似乎理解与 gcc 相同的选项。
看起来您可以通过 self.compiler.compiler[0]
获得实际调用的编译器名称,但我还没有检查这是否可靠或可移植。
我正在构建一个独立于平台的 cython 项目,我想在其中根据所使用的编译器传递编译器参数。我可以猜测基于平台的编译器,或者假设它与用于 Python 的编译器相同,但不能保证匹配。通常我将 cmdclass
arg 注入 setuptool 的设置方法并包装安装或 build_ext 命令以检查内部状态。但在这种情况下,我必须在到达包装器之前对扩展模块进行 cythonize。
在 cythonizing 扩展模块之前,有什么方法可以确定 setup.py 中的编译器吗?
在 cython 论坛上发帖并在 distutils 中搜索相关问题后,我发现 this post 展示了如何将编译器参数移动到 build_ext 赋值中。如果我随后从扩展 class 中删除所有编译器参数,我现在可以按照预期在命令 class 中延迟分配它们。我还可以获得 install
和 egg_info
命令 classes 来调用我的 build_ext 的新版本。
from setuptools.command.build_ext import build_ext
BUILD_ARGS = defaultdict(lambda: ['-O3', '-g0'])
for compiler, args in [
('msvc', ['/EHsc', '/DHUNSPELL_STATIC']),
('gcc', ['-O3', '-g0'])]:
BUILD_ARGS[compiler] = args
class build_ext_compiler_check(build_ext):
def build_extensions(self):
compiler = self.compiler.compiler_type
args = BUILD_ARGS[compiler]
for ext in self.extensions:
ext.extra_compile_args = args
build_ext.build_extensions(self)
...
setup(
...
cmdclass={ 'build_ext': build_ext_compiler_check })
第一个答案的简单变体:
from setuptools import setup, Extension
from distutils.command.build_ext import build_ext
myextension = Extension(
name = 'packagename',
sources = [
'source/debugger.cpp',
],
include_dirs = [ 'source' ],
)
class build_ext_compiler_check(build_ext):
def build_extensions(self):
compiler = self.compiler.compiler_type
# print('\n\ncompiler', compiler)
if not 'msvc' in compiler:
for extension in self.extensions:
if extension == myextension:
extension.extra_compile_args.append( '-O0' )
extension.extra_compile_args.append( '-std=c++11' )
super().build_extensions()
setup(
name = 'packagename',
version = __version__,
ext_modules= [ myextension ],
)
(抱歉,由于缺少积分无法发表评论)
不幸的是,答案 self.compiler.compiler_type
是 'unix',而不是 'gcc'(“distutils compiler_class").
即从这个 defaultdict 字典中查找
BUILD_ARGS = defaultdict(lambda: ['-O3', '-g0'])
for compiler, args in [
('msvc', ['/EHsc', '/DHUNSPELL_STATIC']),
('gcc', ['-O3', '-g0'])]:
BUILD_ARGS[compiler] = args
通常不会到达 'gcc' 条目,而是 总是 回退到 defaultdict 的默认值(lambda 函数)。
也就是说,只要默认选项与 'gcc' 选项保持一致,在大多数情况下您可能不会注意到这一点。例如。 clang 似乎理解与 gcc 相同的选项。
看起来您可以通过 self.compiler.compiler[0]
获得实际调用的编译器名称,但我还没有检查这是否可靠或可移植。