Python 如何获取Distutils compile()函数使用的实际命令?
我有一个Distutils setup.py脚本,它使用new_compiler().compile()编译测试程序,以确保某些功能(如MPI)在系统上可用 我的问题是,有一种情况下,compile()调用会导致编译器错误,但手动编译相同的小测试程序不会。错误在标准标头(mpi.h)中。我所有的实际源文件也包括这个头文件,但它们编译得很好!这个特殊的检查非常有用,但是我需要弄清楚为什么它不应该失败 因此,我的问题是,如何获得ccompiler.compile()使用的实际命令?Adam(Wagner)的注释是正确的起点:您必须搜索Distutils源代码。有很多抽象级别,因此您必须通过几个不同的文件跟踪执行情况,但要点如下:Python 如何获取Distutils compile()函数使用的实际命令?,python,distutils,Python,Distutils,我有一个Distutils setup.py脚本,它使用new_compiler().compile()编译测试程序,以确保某些功能(如MPI)在系统上可用 我的问题是,有一种情况下,compile()调用会导致编译器错误,但手动编译相同的小测试程序不会。错误在标准标头(mpi.h)中。我所有的实际源文件也包括这个头文件,但它们编译得很好!这个特殊的检查非常有用,但是我需要弄清楚为什么它不应该失败 因此,我的问题是,如何获得ccompiler.compile()使用的实际命令?Adam(Wagn
- 包
包含一个抽象类distutils.ccompiler
,该类处理调用实际编译器的操作。它具有编译器需要执行的各种任务的方法:ccompiler
,预处理
,以及编译
链接
本身不实现除CCompiler
之外的任何这些方法,但即使在那里,它也将实际的编译器调用委托给方法compile
。因此,您需要检查平台上使用的\u compile
的子类,并查看其CCompiler
的实现\u compile
有几个不同的子类,每个子类都在自己的包中实现,但“两大类”是CCompiler
(在类UNIX系统上调用本机编译器)和distutils.unixcompiler.unixcompiler
(调用Visual Studio)。两者都使用函数distutils.msvcciler.msvcciler
来实际运行外部进程distutils.spawn.spawn
- 在
的源代码中,您会注意到每个命令在运行之前都记录在distutils.spawn.spawn
级别。但问题是,它没有使用Python的内置日志系统;相反,它使用在INFO
中实现的Distutils自定义记录器Distutils.log
- 如果您现在查看
的源代码,您将看到有一个函数distutils.log
,用于设置日志记录级别。不幸的是,它没有绑定到Distutils中的任何其他调试基础结构(例如set\u verbosity
环境变量),因此您需要手动调用Distutils\u DEBUG
在运行任何编译命令之前,在安装脚本中的某个位置。一旦这样做,所有编译命令(以及谁知道还有什么其他信息)都应该打印到标准输出distutils.log.set_verbosity(1)
import distutils.sysconfig
import distutils.ccompiler
compiler = distutils.ccompiler.new_compiler()
distutils.sysconfig.customize_compiler(compiler)
print compiler.compiler_so # This attribute is what you want
“compiler_so”属性是distutils在编译某些内容时要使用的每个参数的列表。它在实际开始编译时添加文件名和-c
(对于对象文件)
编辑:我只在macOS和Linux上测试过这个,它似乎在Windows上不起作用
EDIT2:我应该补充一点,它不是完整的命令,只是distutils处理任何Extension()实例之前的参数。其余的参数对于扩展是唯一的,并且取决于您在创建扩展类时给出的参数,如源代码、include_dirs、define_macros
如果您想要distutils运行的完整原始命令,我知道的唯一方法(无需解析日志)是在所有处理之后的最后一分钟和之前获取命令字符串。以下是一种令人难以置信的骇客方式:
# Put this at the very top of all your imports
import distutils.spawn
old_spawn = distutils.spawn.spawn
def my_spawn(*args, **kwargs):
print " ".join(args[0]) # <-- this is your command right here
old_spawn(*args, **kwargs)
distutils.spawn.spawn = my_spawn
#将其放在所有导入的最顶端
导入distutils.spawn
old_spawn=distutils.spawn.spawn
def my_spawn(*args,**kwargs):
打印“.join(args[0])#此外,如果希望查看链接器标志,可以执行以下操作:
import distutils.sysconfig
import distutils.ccompiler
compiler = distutils.ccompiler.new_compiler()
distutils.sysconfig.customize_compiler(compiler)
print compiler.linker_so # This gives linker information
如果您不介意浏览许多不熟悉的python代码行,那么可以看看源代码Distutils,我相信它们都是python代码。我翻了一下,但没能为你找到一个好的答案。在我的机器上,ccompiler在这里:/usr/lib64/python2.7/distutils/ccompiler.py这是不正确的。我只是想看看它会吐出什么,然后在没有sysconfig部分的情况下,我运行了一个编译,但还添加了一个pre-args-v
,这是一组完全不同的参数。这里的sysconfig创建了一个不同的命令行,在尝试与编译器的备用脚本(即Make、csh、bash等)调用进行比较时,该命令行没有帮助。看起来这只适用于Unix类型的系统。你在Windows上吗?看起来MSVCCompiler将编译参数放在一个名为“compile_options”的属性中。不,我在Linux RedHat上使用GCC编译器驱动程序,但这不起作用。这与sysconfig
库有关,而与操作系统无关。使用distutils.log.set\u verbosity(1)
而不使用sysconfig
并查看您的标准输出,然后按自己的方式执行。获取真实命令行的方法是,在调用CCompiler.compile
函数之前,将sys.stdout
重定向到我自己的cStringIO.StringIO
对象,然后在将sys.stdout
放入真实的stdout之后,并将我的StringIO
转储到真正的stdout和其他非stdout的处理程序。我认为我的答案不清楚:这些是操作系统在处理扩展之前特定的常规参数(我假设您正在创建扩展实例,因为我们正在讨论distutils)。源文件和目标文件未知时,无法获取完整命令。唯一的方法是拦截参数