7

複数のターゲットを生成しようとしていますSCons(番号は不明ですSConscript)。

次のようなディレクトリがあります。

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

ここで、SConscript に を読み込みheaders_list.txt、その内容に基づいてheaders/ディレクトリからファイルを選択します (つまり、 and のみが含まれている可能性がありますHeader1) Header3。関数を使用してソースを生成したいファイルのそれぞれについて。

私はenv.Commandそれを行うために使用しようとしましたが、問題は、呼び出し時に明らかな理由で不明なターゲットリストを指定する必要があることenv.Commandです。

私が考えることができる唯一のことは実行しています:

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

しかし、これは、parse( headers_file )を呼び出すたびに実行されることを意味しsconsます。解析にコストがかかり、ファイルが頻繁に変更されない場合、このステップは簡単にキャッシュできます。

そのキャッシングを実現するために欠落している SConsc コンストラクト/クラス/テクニックは何ですか?

編集:

私の質問はBuild-time decision of SCons targetsに似ているようですが、人工的なダミー ファイルを使用しない手法はありませんか?

targetまた、一時ファイルを使用しても、可変数のターゲットを生成する変数Commandを、それらを反復する2番目のターゲットに渡す方法がわかりません。

編集2:

これは有望に見えます。

4

1 に答える 1

3

私がそれを行うことができる唯一の方法は、を使用することです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.

また、これには私があまり好きではないことが 1 つあります。それは、実行headers_list.txtごとに解析することです。sconsファイルが変更された場合にのみ解析する方法が必要だと思います。手でキャッシュすることもできますが、SCons にそのキャッシュを処理させるためのトリックがあることを願っています。

そして、ファイルを複製しない方法を見つけることができませんでした(aそしてa.c同じです)。1 つの方法は、ソースではなく my_action で単純にライブラリを生成することです (これは、最終的なソリューションで使用したアプローチです)。

于 2013-01-08T13:44:01.843 に答える