Як отримати фактичну команду, яку використовує функція distutils compile ()?

У мене є скрипт setup.py Distutils, який використовує new_compiler() compile() для складання тестових програм, щоб забезпечити доступність деяких функцій (наприклад, MPI) у системі.

Моя проблема полягає в тому, що є один випадок, коли виклик compile() викликає помилку компілятора, але компіляція такої ж невеликої програми тестування вручну не є. Помилка у стандартному заголовку (mpi.h). Всі мої фактичні вихідні файли також містять цей заголовок, але вони компілюють добре! Ця конкретна перевірка буде дуже корисною, але мені потрібно з'ясувати, чому вона не працює, коли вона не повинна бути.

Отже, моє запитання: як я можу отримати фактичну команду, яку використовує ccompiler.compile ()?

3
Якщо ви не заперечуєте про те, що багато рядків незрозумілого пітона, ви можете поглянути на джерело Distutils, що є всім python, я вірю. Я трохи потискував, але не зумів знайти для вас правильну відповідь. На моїй машині ccompiler знаходиться тут: /usr/lib64/python2.7/distutils/ccompiler.py
додано Автор Adam Wagner, джерело

3 Відповіді

Коментар Адама (Вагнера) - це правильне місце для початку: треба полювати через вихідний код Distutils. Є багато рівнів абстракції, так що вам доведеться простежити виконання за допомогою декількох різних файлів, але ось це найголовніше:

  • The package distutils.ccompiler includes an abstract class CCompiler which handles invoking the actual compiler. It has methods for the various tasks a compiler needs to perform: preprocess, compile, and link. CCompiler itself does not implement any of these methods except for compile, but even there it delegates the actual compiler invocation to the method _compile. So you need to check the subclass of CCompiler that is used on your platform and look at its implementation of _compile.
  • There are several different subclasses of CCompiler, each implemented in its own package, but the "big two" are distutils.unixccompiler.UnixCCompiler (which invokes the native compiler on a UNIX-like system) and distutils.msvccompiler.MSVCCompiler (which invokes Visual Studio). Both of these use the function distutils.spawn.spawn to actually run the external process.
  • In the source for distutils.spawn.spawn, you'll notice that each command is logged at the level INFO before it is run. But the catch is, this doesn't use Python's builtin logging system; rather it uses Distutils' custom logger implemented in distutils.log.
  • If you now look at the source for distutils.log, you'll see that there is a function set_verbosity which sets the logging level. Unfortunately, it isn't tied to any of the other debugging infrastructure in Distutils (such as the DISTUTILS_DEBUG environment variable), so you'll need to manually call

    distutils.log.set_verbosity(1)
    

    somewhere in your setup script, before any compilation commands are run. Once you do that, all compilation commands (and who knows what other information) should be printed to standard output.

3
додано

Це старанно пізно, але я дізнався, як це зробити зсередини 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 (для об'єктних файлів), коли він фактично починає компілювати.

EDIT: Я протестував це лише на MacOS і Linux, не здається, що це буде працювати на Windows.

EDIT2: Я повинен додати, це не повна команда, а лише аргументи, які перед тим, як distutils обробляє будь-які екземпляри Extension (). Інші аргументи є унікальними для розширення та залежать від аргументів , коли ви створюєте клас розширення, наприклад джерела include_dirs, define_macros.

If you want the full raw command that distutils runs, the only way I know of (without parsing logs) is to grab the command string at the last minute after all the processing and right before the spawn function. Here is an incredibly hacky way of doing it:

# 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 і додати цю функціональність, але це нагадує так багато роботи та речей.

2
додано
Це неправильно. Я просто дав це побачити, щоб побачити, що це виплектило, а потім без sysconfig частини, я запустив компіляцію, але також додав попередні аргументи -v , і це зовсім інший набір аргументів . Системний конфігурація тут створює іншу командну рядок, яка не є корисною для перегляду під час спроби порівняння з альтернативи сценаріями (наприклад, Make, csh, bash тощо) викликом компілятора.
додано Автор searchengine27, джерело
Ні, я на Linux RedHat використовую драйвер компілятора GCC, і це не працює. Це стосується бібліотеки sysconfig , а не ОС. використовуйте distutils.log.set_verbosity (1) без sysconfig і перегляньте свій stdout, а потім виконайте свій спосіб. Спосіб отримання справжньої командного рядка здійснюється шляхом переадресації sys.stdout до мого власного об'єкта cStringIO.StringIO перед тим, як я запускаю CCompiler.compile function, а потім відразу після установки sys.stdout до істинного stdout і скидання мого StringIO до істинного stdout та інших моїх обробників, які не є stdout.
додано Автор searchengine27, джерело
Схоже, що це працює тільки на системах типу Unix. Ви на Windows?
додано Автор sciencectn, джерело
Схоже, MSVCCompiler поміщає аргументи compile в атрибут, який називається "compile_options"
додано Автор sciencectn, джерело
Я думаю, що моя відповідь не була зрозумілою: це загальні аргументи, специфічні для OS перед тим, як він обробляє розширення (я припускаю, ви робите екземпляри розширення, оскільки мова йде про distutils). Ви не можете отримати повну команду, коли вихідні файли та файли об'єктів невідомі. Єдиний спосіб зробити це - перехопити аргумент "cmd" в distutils.spawn.spawn після обробки розширення: bitbucket.org/carljm/python-distutils/src/…
додано Автор sciencectn, джерело
Перегляньте оновлену відповідь для схематичного видалення патча мавпи (що цілком працює)
додано Автор sciencectn, джерело

Окрім того, якщо ви хочете побачити прапор лінувальника, ви можете зробити наступне:

import distutils.sysconfig
import distutils.ccompiler
compiler = distutils.ccompiler.new_compiler()
distutils.sysconfig.customize_compiler(compiler)
print compiler.linker_so   # This gives linker information
1
додано
ІТ КПІ - Python
ІТ КПІ - Python
625 учасників

Канал обговорень про всякі штуки зі світу пайтону. Прохання: 0. мати повагу одне до одного; 1. не матюкатися в сторону людей; 2. не захламляти тред повідомленнями по одному слову;