如何在定义 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 中延迟分配它们。我还可以获得 installegg_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] 获得实际调用的编译器名称,但我还没有检查这是否可靠或可移植。