【问题标题】:SCons to generate variable number of targetsSCons 生成可变数量的目标
【发布时间】:2012-12-06 21:33:44
【问题描述】:

我正在尝试让SCons 生成多个目标(编号未知,直接在SConscript 中)。

我有这样的目录:

headers/
  Header1.h
  Header2.h
  Header3.h
  Header4.h
meta/
  headers_list.txt

现在我希望 SConscript 读取 headers_list.txt,基于它的内容从 headers/ 目录中挑选文件(即它可能只包含 Header1Header3),对于我想使用一些生成源的每个功能。

我一直在尝试使用env.Command 来做到这一点,但问题是它需要调用者指定目标列表,由于显而易见的原因在调用env.Command 时不知道。

我唯一能想到的就是跑步:

for header in parse( headers_file ):
    source = mangle_source_name_for_header( header )
    env.Command( source, header, generator_action )

但这意味着我每次调用scons 时都会运行parse( headers_file )。 如果解析成本高且文件不经常更改,则可以轻松缓存此步骤。

我缺少什么 SConsc 构造/类/技术来实现缓存?

编辑:

看来我的问题类似于Build-time determination of SCons targets,但是没有人工虚拟文件的技术吗?

此外,即使使用临时文件,我也看不出我应该如何将 target 变量从生成可变数量的目标的 Command 传递到第二个将迭代它们的目标。

编辑 2:

This 看起来很有希望。

【问题讨论】:

    标签: python code-generation scons


    【解决方案1】:

    我发现我能做到的唯一方法是使用emitter。 下面的示例由 3 个文件组成:

    ./
    |-SConstruct
    |-src/
    | |-SConscript
    | |-source.txt
    |-build/
    

    SConstruct

    env = Environment()
    
    dirname = 'build'
    VariantDir(dirname, 'src', duplicate=0)
    
    Export('env')
    
    SConscript(dirname+'/SConscript')
    

    src/SConscript

    Import('env')
    
    def my_emitter( env, target, source ):
        data = str(source[0])
        target = []
        with open( data, 'r' ) as lines:
            for line in lines:
               line = line.strip()
               name, contents = line.split(' ', 1)
               if not name: continue
    
               generated_source  = env.Command( name, [], 'echo "{0}" > $TARGET'.format(contents) )
               source.extend( generated_source )
               target.append( name+'.c' )
    
        return target, source
    
    def my_action( env, target, source ):
        for t,s in zip(target, source[1:]):
            with open(t.abspath, 'w') as tf:
                with open(s.abspath, 'r') as sf:
                    tf.write( sf.read() )
    
    SourcesGenerator = env.Builder( action = my_action, emitter = my_emitter )
    generated_sources = SourcesGenerator( env, source = 'source.txt' )
    
    lib = env.Library( 'functions', generated_sources )
    

    src/source.txt

    a int a(){}
    b int b(){}
    c int c(){}
    d int d(){}
    g int g(){}
    

    输出

    $ scons
    scons: Reading SConscript files ...
    scons: done reading SConscript files.
    scons: Building targets ...
    echo "int a(){}" > build/a
    echo "int b(){}" > build/b
    echo "int c(){}" > build/c
    echo "int d(){}" > build/d
    echo "int g(){}" > build/g
    my_action(["build/a.c", "build/b.c", "build/c.c", "build/d.c", "build/g.c"], ["src/source.txt", "build/a", "build/b", "build/c", "build/d", "build/g"])
    gcc -o build/a.o -c build/a.c
    gcc -o build/b.o -c build/b.c
    gcc -o build/c.o -c build/c.c
    gcc -o build/d.o -c build/d.c
    gcc -o build/g.o -c build/g.c
    ar rc build/libfunctions.a build/a.o build/b.o build/c.o build/d.o build/g.o
    ranlib build/libfunctions.a
    scons: done building targets.
    

    还有一件事我不太喜欢,那就是在每次执行 scons 时解析 headers_list.txt。我觉得只有在文件更改时才应该有一种方法来解析它。我可以手动缓存它,但我仍然希望有一些技巧可以让 SCons 为我处理缓存。

    而且我找不到不复制文件的方法(aa.c 相同)。 一种方法是简单地在 my_action 而不是源中生成库(这是我在最终解决方案中使用的方法)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-08
      • 1970-01-01
      相关资源
      最近更新 更多