Python 扩展:对 C 部分和 C++ 部分使用不同的编译器标志

Python extension: using different compiler flags for a C parts and C++ parts

本文关键字:标志 编译器 扩展 Python C++      更新时间:2023-10-16

对于我的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文件不是警告,而是错误。

还有另一种选择,包括重载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

由于 distutils 在确保所有文件使用相同的编译器标志进行编译方面有很长的路要走,无论其文件扩展名 .c 或 .cpp。因此,即使使用CFLAGS和CXXFLAGS也没有被考虑在内,但gcc和CLang仍然以不同的方式处理它们。Visual Studio只是将所有内容编译为C++。

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

我后来采用的第二个解决方案是从distutlis外部的C代码创建一个静态库,并将Python扩展链接到该静态库。