如何生成多行构建命令?

时间:2009-01-21 17:44:04

标签: python build build-automation scons

在SCons中,我的命令生成器创建了可笑的长命令行。 ID 喜欢能够跨多行拆分这些命令 构建日志中的可读性。

e.g。我有一个类似的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.

使用os.system和os.popen在python shell中执行此操作 - 我得到一个可读的命令字符串,子shell进程将所有行解释为一个命令。

>>> 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脚本中 然后执行shell脚本,因为这将创建字符串 逃避疯狂。

这可能吗?

更新:
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 个答案:

答案 0 :(得分:3)

感谢cournape关于动作与生成器(以及eclipse pydev调试器)的提示,我终于找到了我需要做的事情。您希望将函数作为“动作”传递给“构建器”类,而不是“生成器”。这将允许您直接执行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.

另一个关键部分是要记住,从'generator'切换到'action'意味着你正在构建的目标不再对你传递给子进程shell的实际字符串有一个隐式依赖。您可以通过将字符串添加到环境中来重新创建此依赖关系。

例如,我个人想要的解决方案如下:

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 :(得分:1)

您正在混合两个完全不同的东西:要执行的命令及其在命令行中的表示。默认情况下,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