对于我的 python 扩展,我有 C(来自嵌入式库)和 C++ 文件,它们被编译并链接在一起。只有 C++ 部分与 Python 接口(通过 SWIG)。这既可以在 Windows 下使用 VS2015,也可以在 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
进行定义。
在使用 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_extension(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)
根据您的平台,您可能需要重载其他编译器类
MSVCCompiler
、CygwinCCompiler
、Mingw32CCompiler
或 BCPPCompiler
。
因为 distutils 花了很长时间来确保所有文件都使用相同的编译器标志进行编译,无论其文件扩展名是 .c 还是 .cpp。因此,即使使用 CFLAGS 和 CXXFLAGS 也不被考虑在内,但 gcc 和 CLang 仍然以不同的方式处理它们。 Visual Studio 只是将所有内容编译为 C++。
我通过接受 C 在大多数情况下仍然是 C++ 的子集并将 C 源文件重命名为 .cpp 来解决我的问题,即使文件包含 C。这个解决方案很丑陋,但我摆脱了 gcc 中的警告以及 CLang 的错误 - 特别是因为这个解决方案再次模糊了 C 和 C++ 之间的语言障碍。
我后来采用的第二个解决方案是从 distutlis 外部的 C 代码创建一个静态库,并将 Python 扩展链接到该静态库。