【问题标题】:Python extension: using different compiler flags for a C parts and C++ partsPython 扩展:对 C 部分和 C++ 部分使用不同的编译器标志
【发布时间】:2018-06-01 01:30:11
【问题描述】:

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

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

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

更新:

主要问题是,distutils.ccompiler 不检查 C 或 C++ 的文件扩展名,而是使用 $CC 运行所有内容。即使定义 CXXFLAGS 也无济于事。我会忍受警告,无论是 export 还是 setup.py 文件中使用 os.eniviron 的定义。

更新 2:

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

【问题讨论】:

  • 这个问题要求使用混合 C 和 C++ 代码文件的扩展,而另一个问题不是关于在一个扩展中混合两种语言 - 因此答案对解决这个问题没有帮助。
  • 我已经阅读了您的整个问题,而不仅仅是标题。虽然您的主要问题是如何消除警告/错误,但您在这里提出的问题是如何“单独更改每个文件的编译器标志”。当然,另一个问题的答案不能直接解决您的问题,但只需稍作修改即可,因为唯一的区别是条件。
  • 在 3 年前发布此问题之前,我已经进行了相当多的研究,但显然我没有找到您在此处链接的更老的 Q。我的历史自我(或最近处于相同情况的其他人)将从这个问题和两个答案中受益(包括我自己的,第二部分,这不是对“重复”问题的答案,而只是对此)-指向另一个问题的链接也很有帮助。将 Q 作为重复项关闭会使内容更难找到。
  • 当然,您的不同措辞很有用,但这不是对您的惩罚——它是对其他有同样问题的人的指导。这就是重复项的用途,它们实际上通过在顶部放置一个大粗体消息并防止人们在多个位置写答案来更容易找到。它不会被删除。此评论还添加了指向另一个问题的反向链接。 ;-)

标签: python c++ c gcc setuptools


【解决方案1】:

还有另一个选项是重载 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 = cc_args + cpp_flags

    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

【讨论】:

  • 注意:1.cc_args是一个列表,所以你的代码会返回错误; 2. 预先添加标志是不可取的,因为它们可以被默认的覆盖; 3. 此方法仅适用于 Unix 编译器(及其端口),因为其他编译器不使用 _compile() 方法。
  • @EvgenKo423: 1. 正确,我已将cpp_flags 修改为列表; 2.好的我修改了_cc_args = cpp_flags + cc_args中的操作顺序; 3. 很可能是真的(我自己没试过),但是 OP 明确表示他用gcc 解决了这个问题,即UnixCompiler
【解决方案2】:

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

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

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

【讨论】:

    猜你喜欢
    • 2013-05-16
    • 1970-01-01
    • 2013-03-09
    • 1970-01-01
    • 1970-01-01
    • 2011-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多