使用 distutils 编译时禁用输出
我有一个 setup.py 脚本,需要探测编译器的某些内容,例如对 TR1 的支持、windows.h 的存在(添加 NOMINMAX 定义)等。我通过创建一个简单的程序并尝试编译来进行这些检查它与 Distutils 的 Compiler 类一起使用。存在/不存在错误就是我的答案。
这很有效,但这意味着编译器的丑陋错误消息会打印到控制台。有没有办法在手动调用 compile
函数时抑制错误消息?
这是我尝试编译程序的函数,它现在通过将错误流传输到文件来消除错误消息(回答了我自己的问题):
def see_if_compiles(program, include_dirs, define_macros):
""" Try to compile the passed in program and report if it compiles successfully or not. """
from distutils.ccompiler import new_compiler, CompileError
from shutil import rmtree
import tempfile
import os
try:
tmpdir = tempfile.mkdtemp()
except AttributeError:
# Python 2.2 doesn't have mkdtemp().
tmpdir = "compile_check_tempdir"
try:
os.mkdir(tmpdir)
except OSError:
print "Can't create temporary directory. Aborting."
sys.exit()
old = os.getcwd()
os.chdir(tmpdir)
# Write the program
f = open('compiletest.cpp', 'w')
f.write(program)
f.close()
# redirect the error stream to keep ugly compiler error messages off the command line
devnull = open('errors.txt', 'w')
oldstderr = os.dup(sys.stderr.fileno())
os.dup2(devnull.fileno(), sys.stderr.fileno())
#
try:
c = new_compiler()
for macro in define_macros:
c.define_macro(name=macro[0], value=macro[1])
c.compile([f.name], include_dirs=include_dirs)
success = True
except CompileError:
success = False
# undo the error stream redirect
os.dup2(oldstderr, sys.stderr.fileno())
devnull.close()
os.chdir(old)
rmtree(tmpdir)
return success
这是一个使用上面的函数来检查标头是否存在的函数。
def check_for_header(header, include_dirs, define_macros):
"""Check for the existence of a header file by creating a small program which includes it and see if it compiles."""
program = "#include <%s>\n" % header
sys.stdout.write("Checking for <%s>... " % header)
success = see_if_compiles(program, include_dirs, define_macros)
if (success):
sys.stdout.write("OK\n");
else:
sys.stdout.write("Not found\n");
return success
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
Zac 的评论促使我多看一些,我发现 Mercurial 的 setup.py 脚本有一个适用于他的方法的工作方法。您不能只分配流,因为编译器进程不会继承更改,但显然 Python 有我们的好朋友
dup2()
,其形式为os.dup2()
。这允许我们都知道和喜爱的相同操作系统级流恶作剧,这些恶作剧确实会继承到子进程。Mercurial 的函数重定向到 /dev/null,但为了保持 Windows 兼容性,我只是重定向到一个文件,然后将其删除。
Mercurial 说道:
Zac's comment spurred me to look a bit more and I found that Mercurial's setup.py script has a working method for his approach. You can't just assign the stream because the change won't get inherited by the compiler process, but apparently Python has our good friend
dup2()
in the form ofos.dup2()
. That allows the same OS-level stream shenanigans that we all know and love, which do get inherited to child processes.Mercurial's function redirects to /dev/null, but to keep Windows compatibility I just redirect to a file then delete it.
Quoth Mercurial:
这是我最近编写的一个上下文管理器,它很有用,因为我有与
distutils.ccompiler.CCompiler.has_function
在处理 pymssql。我本来打算使用你的方法(很好,感谢分享!),但后来我想,如果我使用 上下文管理器。这是我想到的:我创建此内容的上下文位于 这篇博文。我想和你的差不多。
它使用我向您借用的代码来进行重定向(例如:
os.dup2
等),但我将其包装在上下文管理器中,因此它更通用且可重用。我在 setup.py 中像这样使用它:
Here's a context manager that I recently wrote and found useful, because I was having the same problem with
distutils.ccompiler.CCompiler.has_function
while working on pymssql. I was going to use your approach (nice, thanks for sharing!) but then I thought that it could be done with less code and would be more general and flexible if I used a context manager. Here's what I came up with:The context for why I created this is at this blog post. Pretty much the same as yours I think.
This uses code that I borrowed from you to do the redirection (e.g.:
os.dup2
, etc.), but I wrapped it in a context manager so it's more general and reusable.I use it like this in a
setup.py
:@Adam 我只是想指出 Windows 上有 /dev/null 等效项。它是“NUL”,但好的做法是从 os.devnull 获取它
@Adam I just want to point out that there is /dev/null equivalent on Windows. It's 'NUL' but good practice is to get it from os.devnull
我对编程和Python还很陌生,所以如果这是一个愚蠢的建议,请忽略它,但是你不能将错误消息重新路由到文本文件而不是屏幕/交互式窗口/其他什么吗?
我很确定我在某处读过您可以做类似的事情
,抱歉,我可能会重复您已经知道的事情,但如果问题是您希望在由另一个函数(自动)调用时出现错误,并且在运行时没有错误手册,你不能只添加一个像compile(arg1, arg2, manual=True)这样的关键字参数,然后在你的“除了:”下添加
然后当它被程序调用而不是手动时你只需用编译(arg1,arg2,manual=False)以便它重定向到该文件。
I'm pretty new to programming and python, so disregard this if it's a stupid suggestion, but can't you just reroute the error messages to a text file instead of the screen/interactive window/whatever?
I'm pretty sure I read somewhere you can do something like
Again, sorry I'm probably repeating something you already know, but if the problem is you WANT the errors when it's called by another function (automated) and no errors when it's ran manual, can't you just add a keyword argument like compile(arg1, arg2, manual=True ) and then under your "except:" you add
Then when it's called by the program and not manually you just call it with compile(arg1,arg2, manual=False) so that it redirects to the file.
在安静模式下运行有帮助吗? setup.py -q build
不是对您的问题的直接答案,但与您的用例相关:distutils 中有一个配置命令,它被设计为子类化并用于检查 C 功能。它还没有记录,你必须阅读源代码。
Does running in quiet mode help at all? setup.py -q build
Not a direct answer to your question, but related to your use case: there is a config command in distutils that’s designed to be subclassed and used to check for C features. It’s not documented yet, you have to read the source.