Как я могу генерировать многострочные команды сборки? - PullRequest
3 голосов
/ 21 января 2009

В SCons мои генераторы команд создают смехотворно длинные командные строки. Я бы хотелось бы иметь возможность разделить эти команды на несколько строк для удобочитаемость в журнале сборки.

например. У меня есть SConscipt, как:

import os

# create dependency
def my_cmd_generator(source, target, env, for_signature):
    return r'''echo its a small world after all \
        its a small world after all'''

my_cmd_builder = Builder(generator=my_cmd_generator, suffix = '.foo')

env = Environment()
env.Append( BUILDERS = {'MyCmd' : my_cmd_builder } )

my_cmd = env.MyCmd('foo.foo',os.popen('which bash').read().strip())
AlwaysBuild(my_cmd)

Когда он выполняется, я получаю:

scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
echo its a small world after all \
its a small world after all
its a small world after all
sh: line 1: its: command not found
scons: *** [foo.foo] Error 127
scons: building terminated because of errors.

Выполнение этого в оболочке python с помощью os.system и os.popen работает - я получаю читаемую командную строку, а процесс под-оболочки интерпретирует все строки как одну команду.

>>> import os
>>> cmd = r'''echo its a small world after all \
... its a small world after all'''
>>> print cmd
echo its a small world after all \
its a small world after all
>>> os.system( cmd)
its a small world after all its a small world after all
0

Когда я делаю это в SCons, он выполняет каждую строку по одной, что не то, что я хочу.

Я также хочу избежать встраивания моих команд в shell-скрипт и затем выполнить сценарий оболочки, потому что это создаст строку избегая безумия.

Возможно ли это?

UPDATE:
cournape,
Спасибо за подсказку о $ CCCOMSTR. К сожалению, я не использую ни один из языков, которые SCons поддерживает из коробки, поэтому я создаю свой собственный генератор команд. Используя генератор, как я могу заставить SCons делать:

echo its a small world after all its a small world after all' 

но печать

echo its a small world after all \
    its a small world after all

Ответы [ 2 ]

3 голосов
/ 06 февраля 2009

Благодаря совету Курнапе о действиях и генераторах (и отладчике затмения pydev) я наконец понял, что мне нужно делать. Вы хотите передать свою функцию классу Builder как «действие», а не «генератор». Это позволит вам фактически выполнить вызов os.system или os.popen напрямую. Вот обновленный код:

import os

def my_action(source, target, env):
    cmd = r'''echo its a small world after all \
        its a small world after all'''
    print cmd
    return os.system(cmd)

my_cmd_builder = Builder(
    action=my_action,  # <-- CRUCIAL PIECE OF SOLUTION
    suffix = '.foo')

env = Environment()
env.Append( BUILDERS = {'MyCmd' : my_cmd_builder } )

my_cmd = env.MyCmd('foo.foo',os.popen('which bash').read().strip())

Этот файл SConstruct выдаст следующий вывод:

scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
my_action(["foo.foo"], ["/bin/bash"])
echo its a small world after all \
        its a small world after all
its a small world after all its a small world after all
scons: done building targets.

Другой важный момент - помнить, что переключение с «генератора» на «действие» означает, что цель, которую вы создаете, больше не имеет неявной зависимости от фактической строки, которую вы передаете оболочке подпроцесса. Вы можете заново создать эту зависимость, добавив строку в вашу среду.

Например, решение, которое я лично хочу, выглядит так:

import os

cmd = r'''echo its a small world after all \
        its a small world after all'''

def my_action(source, target, env):
    print cmd
    return os.system(cmd)

my_cmd_builder = Builder(
    action=my_action,
    suffix = '.foo')

env = Environment()
env['_MY_CMD'] = cmd  # <-- CREATE IMPLICIT DEPENDENCY ON CMD STRING
env.Append( BUILDERS = {'MyCmd' : my_cmd_builder } )

my_cmd = env.MyCmd('foo.foo',os.popen('which bash').read().strip())
1 голос
/ 04 февраля 2009

Вы смешиваете две совершенно разные вещи: команду, которую нужно выполнить, и ее представление в командной строке. По умолчанию scons печатает командную строку, но если вы разбиваете командную строку, вы меняете выполняемые команды.

Теперь у scons есть механизм для изменения напечатанных команд. Они регистрируются для экземпляров Action, и доступно множество по умолчанию:

env = Environment()
env['CCCOMSTR']  = "CC                 $SOURCE"
env['CXXCOMSTR'] = "CXX                $SOURCE"
env['LINKCOM']   = "LINK               $SOURCE"

Будет печатать, предполагая только источники C и CXX:

CC    foo.c
CC    bla.c
CXX   yo.cc
LINK  yo.o bla.o foo.o
...