编写执行外部命令和python函数的自定义构建器

时间:2014-12-27 10:36:56

标签: scons

我正在寻找一个自定义的SCons Builder:

  1. 执行外部命令以生成foo.temp
  2. 然后执行python函数来操作foo.temp并生成最终输出文件
  3. 我已经提到了以下两个部分,但我不确定正确的方法来粘合"他们在一起。

    我知道Command接受了要采取的行动清单。但是如何正确处理该中间文件?理想情况下,中间文件对用户是不可见的 - 整个构建器似乎是原子操作的。


    在这里,我提出的似乎正在发挥作用。但是,.bin文件不会自动删除。

    from SCons.Action import Action
    from SCons.Util import is_List
    from SCons.Script import Delete
    
    _objcopy_builder = Builder(
            action = 'objcopy -O binary $SOURCE $TARGET',
            suffix = '.bin',
            single_source = 1
            )
    
    def _add_header(target, source, env):
        source = str(source[0])
        target = str(target[0])
    
        with open(source, 'rb') as src:
            with open(target, 'wn') as tgt:
                tgt.write('MODULE\x00\x00')
                tgt.write(src.read())
        return 0
    
    _addheader_builder = Builder(
            action = _add_header,
            single_source = 1
            )
    
    def Elf2Mod(env, target, source, *args, **kw):
        def check_one(x, what):
            if not is_List(x):
                x = [x]
            if len(x) != 1:
                raise StopError('Only one {0} allowed'.format(what))
            return x
        target = check_one(target, 'target')
        source = check_one(source, 'source')
    
        # objcopy a binary file
        binfile = _objcopy_builder.__call__(env, source=source, **kw)
    
        # write the module header
        _addheader_builder.__call__(env, target=target, source=binfile, **kw)
    
        # delete the intermediate binary file
        # TODO: Not working
        Delete(binfile)
    
        return target
    
    def generate(env):
        """Add Builders and construction variables to the Environment."""
        env.AddMethod(Elf2Mod, 'Elf2Mod')
        print 'Added Elf2Mod to env {0}'.format(env)
    
    def exists(env):
        return True
    

1 个答案:

答案 0 :(得分:4)

通过指定操作列表,确实可以使用Command builder来完成,如下所示:

Command('foo.temp', 'foo.in',
        ['your_external_action',
         your_python_function])

请注意foo.in是来源,您应该相应地命名。但是如果你提到foo.temp是内部的,那么这种方法可能不是最好的方法。

我认为更灵活的另一种方法是将Custom BuilderGenerator和/或Emitter一起使用。

Generator是一个Python函数,您可以在其中执行实际工作,在您的情况下将调用外部命令,并调用Python函数。

使用Emitter可以对源和目标进行微调控制。我使用BuilderEmitter(和Generator)一次使用Thrift输入IDL文件进行C ++和Java代码生成。我必须阅读并处理Thrift输入文件以确切地知道代码生成了哪些文件(哪些是实际目标),而Emitter是执行此类操作的最佳/唯一方式。如果您的特定用例不是那么复杂,您可以跳过Emitter并在调用构建器中列出您的源/目标。但是,如果您希望foo.temp对最终用户透明,那么您将需要一个发射器。

当使用带有Generator和Emitter的Custom Builder时,SCons每次都会调用发射器来计算源和依赖关系,以了解是否需要调用Generator。只有在其中一个目标被视为较旧的源时,才会调用生成器。

有许多示例显示如何在自定义生成器中使用生成器和发射器,因此我不会在此列出代码,但如果您需要语法等方面的帮助,请告诉我。