在python扩展中为C和C ++文件使用不同的编译器标志

时间:2017-12-18 16:53:40

标签: python c++ c gcc setuptools

对于我的python扩展,我有C(来自嵌入式库)和C ++文件,它们被编译和链接在一起。只有C ++部分与Python接口(通过SWIG)。这适用于使用VS2015的Windows和Linux下的gcc。但是,使用gcc,C ++文件需要一组不同的编译器标志(例如-std = c ++ 11,-Wno-reorder)而不是C文件,以避免出现有关C中不正确标志的警告。

setuptools / distutils中是否有一种方法可以单独更改每个文件的编译器标志,例如。基于文件扩展名?

我已使用https://stackoverflow.com/a/36293331/3032680中的自定义构建步骤。

更新

主要问题是,distutils.ccompiler没有检查C或C ++的文件扩展名,而是使用$ CC运行所有内容。即使定义CXXFLAGS也无济于事。我会在{。1}}和setup.py文件中使用export的定义中发出警告。

更新2:

在使用CLang 8.0.0的macOS上,情况变得更糟:尝试使用-std = c ++ 11编译.c文件不是警告,而是错误。

2 个答案:

答案 0 :(得分:0)

因为distutils确保所有文件都使用相同的编译器标志进行编译,而不管文件扩展名为.c或.cpp。因此,即使使用CFLAGS和CXXFLAGS也不予考虑,但gcc和CLang仍然以不同的方式处理它们。 Visual Studio只是将所有内容编译为C ++。

我通过接受C在大多数情况下仍然是C ++的子集并将C-Source文件重命名为.cpp来解决我的问题,即使这些文件包含C.这个解决方案很难看但是我摆脱了警告在gcc和CLang中的错误 - 特别是因为这个解决方案再次模糊了C和C ++之间的语言障碍。

我后面采用的第二个解决方案是在distutlis之外的C代码中创建一个静态库并链接Python extension to that static library

答案 1 :(得分:0)

还有一个选项是重载 distutils 编译器类(比如 unix C 编译器):

import os
from distutils.unixccompiler import UnixCCompiler

cpp_flags = '-std=c++11'

class C_CxxCompiler(UnixCCompiler):
  def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
    _cc_args = cc_args

    # add the C++ flags for source files with extensions listed below
    if os.path.splitext(src)[-1] in ('.cpp', '.cxx', '.cc'):
      _cc_args = cpp_flags + cc_args

    UnixCCompiler._compile(self, obj, src, ext, _cc_args, extra_postargs, pp_opts)

然后重载 distutils.build_ext 命令以在编译进行之前拦截扩展构建并替换编译器:

class BuildC_CxxExtensions(build_ext):
  def build_extensions(self, ext):
    if self.compiler.compiler_type == 'unix':
      # Replace the compiler
      old_compiler = self.compiler
      self.compiler = C_CxxCompiler()

      # Copy its attributes
      for attr, value in old_compiler.__dict__.items():
        setattr(self.compiler, attr, value)
    build_ext.build_extensions(self, ext)

根据您的平台,您可能需要重载其他编译器类 MSVCCompilerCygwinCCompilerMingw32CCompilerBCPPCompiler