如何获取Distutils compile()函数使用的实际命令?

时间:2011-10-28 02:08:17

标签: python distutils

我有一个Distutils setup.py脚本,它使用new_compiler()。compile()来编译测试程序,以确保系统上有某些功能(例如MPI)。

我的问题是有一种情况是compile()调用导致编译器错误,但手动编译相同的小测试程序却没有。错误在标准头文件(mpi.h)中。我所有的实际源文件也都包含这个标题,但它们编译得很好!这个特殊的检查对我来说非常有用,但我需要弄清楚为什么它不应该失败。

所以我的问题是,如何获得ccompiler.compile()使用的实际命令?

3 个答案:

答案 0 :(得分:3)

Adam(Wagner)的评论是正确的开始:您必须通过Distutils源代码进行搜索。有很多抽象级别,所以你必须通过几个不同的文件来跟踪执行,但这里是要点:

  • distutils.ccompiler包括一个抽象类CCompiler,它处理调用实际的编译器。它具有编译器需要执行的各种任务的方法:preprocesscompilelink。除CCompiler之外,compile本身不实现任何这些方法,但即使在那里,它也会将实际的编译器调用委托给方法_compile。因此,您需要检查平台上使用的CCompiler的子类,并查看其_compile的实现。
  • CCompiler有几个不同的子类,每个子类都在自己的包中实现,但“big two”是distutils.unixccompiler.UnixCCompiler(在类UNIX系统上调用本机编译器)和{{ 1}}(调用Visual Studio)。这两个都使用函数distutils.msvccompiler.MSVCCompiler来实际运行外部进程。
  • distutils.spawn.spawn的源代码中,您会注意到每个命令在运行之前都会记录在distutils.spawn.spawn级别。但问题是,这不使用Python的内置日志记录系统;而是使用Distutils在INFO中实现的自定义记录器。
  • 如果您现在查看distutils.log的来源,您会看到有一个设置日志记录级别的函数distutils.log。不幸的是,它与Distutils中的任何其他调试基础结构无关(例如set_verbosity环境变量),因此您需要手动调用

    DISTUTILS_DEBUG
    在运行任何编译命令之前,在安装脚本中的某处

    。一旦这样做,所有编译命令(以及谁知道其他信息)应该打印到标准输出。

答案 1 :(得分:2)

这已经很晚了,但是我发现如何在python中做这个(没有检查日志)以防万一有人想知道:

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()实例。其余参数对于扩展是唯一的,并且取决于您在创建Extension类时提供的arguments,例如sources,include_dirs,define_macros。

如果你想要运行distutils的完整原始命令,我知道的唯一方法(不解析日志)是在所有处理之后的最后一分钟和the spawn function之前获取命令字符串。这是一种令人难以置信的hacky方式:

# 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

更优雅的事情是fork distutils并添加这个功能,但这就像这么多的工作和东西。

答案 2 :(得分: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