10
votes

Désactiver la sortie lors de la compilation des distunes

J'ai un script Setup.py qui doit sonder le compilateur pour certaines choses comme le support pour TR1, la présence de Windows.h (pour ajouter NominMax Définir), etc. Je fais ces chèques en créant un programme simple et Essayer de la compiler avec la classe de compilateur de Distutils. La présence / manque d'erreurs est ma réponse.

Cela fonctionne bien, mais cela signifie que les messages d'erreur laids de compilateur sont imprimés sur la console. Existe-t-il un moyen de supprimer les messages d'erreur lorsque la fonction compile est appelée manuellement?

Voici ma fonction qui tente de compiler le programme, qui élimine maintenant les messages d'erreur par Tuyautage Le flux d'erreur dans un fichier (répondit à ma propre question): xxx

Voici une fonction qui utilise ce qui précède pour vérifier la présence d'un en-tête. xxx


4 commentaires

Le tutoriel scipe docs.cipy.org/doc / Scipey / Référence / Tutoriel / ... demande la même question. Assurez-vous de mettre à jour ceci si vous le comprenez.


Je pensais que c'était le genre de chose autoconf / automake a été fait pour.


@George, Autoconf n'est pas la python Way ™. Il est également limité aux systèmes de type UNIX. Les modules Python ont généralement un script Setup.py qui utilise des distutilles pour construire / s'installer, de sorte qu'il fonctionne n'importe où python fonctionne. De plus, Python est extrêmement difficile sur les compilateurs et les options de construction, comme vous ne pouvez utiliser que le même compilateur Python a été construit avec. Distutils fait la bonne chose pour vous sur n'importe quel système que votre extension est installée.


@AgF, j'ai trouvé un moyen de faire la redirection de flux avec OS.DUP2 qui semble fonctionner. Je ne l'ai pas encore essayé sur Windows, mais je pense que cela devrait y travailler aussi.


5 Réponses :


1
votes

Je suis assez nouveau à la programmation et à Python, alors ignorez-le si c'est une suggestion stupide, mais que vous ne pouvez pas simplement relouer les messages d'erreur dans un fichier texte au lieu de l'écran / la fenêtre interactive / quoi que ce soit?

i 'm à peu près sûr que j'ai lu quelque part que vous pouvez faire quelque chose comme p> xxx pré>

à nouveau, désolé je répète quelque chose que vous savez déjà, mais si le problème est que vous voulez les erreurs quand Il s'appelle par une autre fonction (automatisée) et aucune erreur lorsqu'il est manuellement manuel, vous ne pouvez pas simplement ajouter un argument de mot-clé comme compile (arg1, arg2, manuel = true), puis sous votre "sauf:" Vous ajoutez p>

if manual == False: print errors to console/interactive window
else: print to error  


3 commentaires

C'était aussi ma première idée, mais le problème est que Sys.SsderR est le flux d'erreur du programme Python, et non le compilateur. Le compilateur est un processus distinct qui n'hérite pas le changement.


Si vous avez une idée de savoir comment dire des distutiles de frayer le compilateur de manière à ce que le nouveau flux d'erreur soit enregistré, je suis toutes les oreilles.


En fait, j'ai trouvé un moyen de le faire. Un uppote pour vous pour la poussée pour rechercher plus.



5
votes

Le commentaire de Zac m'a suscité de regarder un peu plus et j'ai trouvé que Mercurial's Setup.py Script a une méthode de travail pour son approche. Vous ne pouvez pas simplement attribuer le flux car le changement ne sera pas hérité par le processus du compilateur, mais apparemment Python a notre bon ami DUP2 () code> sous la forme de OS.DUP2 () code>. Cela permet aux mêmes shenanigans du niveau du système d'exploitation que nous connaissons tous et que nous aimons tous, qui sont hérités aux processus d'enfants.

La fonction de Mercurial redirige vers / dev / null, mais pour garder la compatibilité de Windows, je viens de rediriger vers un fichier, puis supprimez-le. P>

QUOTH Mercurial: P>

# simplified version of distutils.ccompiler.CCompiler.has_function
# that actually removes its temporary files.
def hasfunction(cc, funcname):
    tmpdir = tempfile.mkdtemp(prefix='hg-install-')
    devnull = oldstderr = None
    try:
        try:
            fname = os.path.join(tmpdir, 'funcname.c')
            f = open(fname, 'w')
            f.write('int main(void) {\n')
            f.write('    %s();\n' % funcname)
            f.write('}\n')
            f.close()
            # Redirect stderr to /dev/null to hide any error messages
            # from the compiler.
            # This will have to be changed if we ever have to check
            # for a function on Windows.
            devnull = open('/dev/null', 'w')
            oldstderr = os.dup(sys.stderr.fileno())
            os.dup2(devnull.fileno(), sys.stderr.fileno())
            objects = cc.compile([fname], output_dir=tmpdir)
            cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
        except:
            return False
        return True
    finally:
        if oldstderr is not None:
            os.dup2(oldstderr, sys.stderr.fileno())
        if devnull is not None:
            devnull.close()
        shutil.rmtree(tmpdir)


5 commentaires

Joli. Je vais uppoter quand j'ai des votes. Merci de m'avoir pinging. Quelle version de python êtes-vous sur vous - avez-vous vraiment besoin de essayer ? Pouvez-vous utiliser Essayer: trucs in Essayez sauf: renvoyer false else: retour vrai finalement: finalement ? Ou est-ce dans la version mercuriale et vous ne l'avez tout simplement pas changé?


Ce code est directement de la source de Mercurial, pas la mienne. Notez qu'ils redirigent vers / dev / null qui vont briser les fenêtres. Je vais mettre à jour ma fonction dans la question


Je suis sur le côté opposé de la clôture où je veux rediriger ces erreurs de compilateur dans un cadre de journalisation. Cette réponse a au moins l'avoir à un point où je peux le faire (au lieu de / dev / null, je rediriget STDERR à un fichier réel, puis lisez-le quand j'aurai terminé), mais je ne suis pas un grand fan de le faire Par ici. Je me demande s'il serait simplement plus facile d'appeler quelque chose comme sous-processus.popen et invoquer le compilateur manuellement parce que je suis assez certain que je peux capturer (ou jeter) stdout / stardr beaucoup plus facile de cette façon, et < Code> Compiler semble moins et moins utile, plus j'essaie de l'utiliser.


@ RechercheRengine27 Que diriez-vous d'utiliser le système de tuyau de Python pour créer un tuyau, puis utilisez os.dup2 pour rediriger la sortie du compilateur sur le tuyau. Vous pouvez alors simplement lire le tuyau.


Cela aurait été une meilleure idée, mais mon interpréteur python segfault quand j'essaie de importer des pipes lol. C'est un autre problème cependant



2
votes

@Adam Je veux juste souligner qu'il y a / dev / null équivalent sur Windows. C'est "Nul" mais la bonne pratique est de l'obtenir de Os.Devnull


0 commentaires

0
votes

fonctionne en mode silencieux Aide du tout? setup.py -q Construire

Pas une réponse directe à votre question, mais liée à votre cas d'utilisation: il existe une commande de configuration dans les distutilles conçues pour être sous-classée et utilisée pour vérifier les fonctionnalités C. Ce n'est pas encore documenté, vous devez lire la source.


2 commentaires

Je n'ai pas essayé le mode silencieux, mais c'est une commande qui sera dirigée par l'utilisateur, pas par moi. Donc, je ne veux pas demander à l'utilisateur d'utiliser le mode silencieux car ils ne le seront tout simplement pas. C'est bien d'entendre qu'ils travaillent sur quelque chose à la question de Query C, mais je ne vais pas abandonner ma solution de travail sale-mais-travail pour une cible mobile sans papiers qui ne fonctionne que dans certains endroits.


config est une commande de distutils existante, pas une cible mobile. Ce sont juste les documents manquants.



3
votes

Voici un Contexte Manager que j'ai récemment écrit et trouvé utile, parce que je Avoir eu le même problème avec distutils.commiler. CcCompiler.has_function code> pendant que vous travaillez sur PYMSSQL . J'allais utiliser votre approche (Nice, merci pour le partage!) Mais je pensais que cela pouvait être fait avec moins de code et serait plus général et flexible si j'avais utilisé un Contexte Manager . Voici ce que j'ai proposé:

with stdchannel_redirected(sys.stderr, os.devnull):
    if compiler.has_function('clock_gettime', libraries=['rt']):
        libraries.append('rt')


0 commentaires