2014-12-27 64 views
4

我期待編寫自定義SCons的生成器,一個自定義生成器:編寫執行外部命令和Python功能

  1. 執行一個外部命令產生foo.temp
  2. 然後執行一個Python函數操作foo.temp並生成最終的輸出文件

我已經提到了以下兩節,但我不確定將它們「粘合」在一起的正確方法。

我知道Command接受的採取的措施清單。但我該如何正確處理該中間文件?理想情況下,中間文件對用戶是不可見的 - 整個Builder似乎都是以原子方式運行的。


這是我想出來的,似乎工作。但是.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 

回答

3

這的確可以用做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對最終用戶透明,那麼你需要一個發射器。

當使用具有生成器和發射器的自定義生成器時,每次由SCons調用發射器來計算源和依賴關係以知道是否需要調用生成器。只有當其中一個目標被認爲比源頭更老時纔會調用Generator。

,以說明如何使用自定義生成器發電機和發射無數的例子,所以我不會在這裏列出的代碼,但讓我知道,如果你需要的語法幫助等

+0

感謝您的輸入。我已經寫了一個似乎在工作的僞造者(看我的編輯)。但我不確定這是否正確。在生成不同的頭文件時也需要原始的ELF文件。 –

+0

我意識到更簡單的解決方案可能是放寬「不可見的中間文件」要求,並且只生成一個.bin作爲構建的一部分。然後使用.elf和.bin生成自定義模塊。 –

+0

或者,由於操作邏輯上.elf - > .module,應該使用發射器來指示.bin文件是副作用嗎? –