I'm trying to set up a build system involving a code generator. The exact files generated are unknown until after the generator is run, but I'd like to be able to run further build steps by pattern matching (run some program on all files with some extension). Is this possible?
Some of the answers here involving code generation seem to assume that the output is known or a listing of generated files is created. This isn't impossible in my case, but I'd like to avoid it since it makes things more complicated.
https://bitbucket.org/scons/scons/wiki/DynamicSourceGenerator seems to indicate that it's possible to add additional targets during Builder actions, but while I could get the build to run and list the generated files, any build steps introduced don't run.
https://bitbucket.org/scons/scons/wiki/NonDeterministicDependencies uses Scanners to add build steps. I put a glob(...) in a scanner, and it succeeds in detecting the generated files, but the files are inexplicably deleted before it actually runs the dependent step.
Is this use case possible? And why is SCons deleting my generated files?
An example generator, constructs 3 files (not easily known to the build system) and puts them in the argument folder
echo "echo 1" > $1/gen1.txt
echo "echo 2" > $1/gen2.txt
echo "echo 3" > $1/gen3.txt
Just sets up a variant_dir
SConscript('SConscript', variant_dir='build')
The goal is for it to:
env = Environment()
env.Append(BUILDERS = {'ExampleCompiler' :
Builder(action=[Copy('$TARGET', '$SOURCE'),
Chmod('$TARGET', 0755)])})
generator = env.ExampleCompiler('generator', 'source')
env.Append(BUILDERS = {'GeneratorRun' :
Builder(action=[Mkdir('$TARGET'),
'$SOURCE $TARGET'])})
generated_dir = env.GeneratorRun(Dir('generated'), generator)
Everything's fine up to here, where all the targets are explicitly known to the build system ahead of time.
Attempting to use this block of code to glob over the generated files causes SCons to delete (!!) the generated files:
for generated in generated_dir[0].glob('*.txt'):
generated_run = env.ExampleCompiler(generated.abspath + '.sh', generated)
Attempting to use an action to update the build tree results in additional actions not being run:
def generated_scanner(target, source, env):
for generated in source[0].glob('*.txt'):
print "scanned " + generated.abspath
generated_target = env.ExampleCompiler(generated.abspath + '.sh', generated)
Alias('TopLevelAlias', generated_target)
env.Append(BUILDERS = {'GeneratedOperation' :
Builder(action=[generated_scanner])})
dummy = env.GeneratedOperation(generated_dir[0].File('#dummy'), generated_dir)
Alias('TopLevelAlias', dummy)
The Alias operations are suggested in above dynamic source generator guide, but don't seem to do anything. The prints do execute and indicate that the action gets run.
答案 0 :(得分:0)
SCons可以在特殊文件扩展名上运行一些构建模式。对于C / CPP文件,这是首选方案,例如:
env = Environment()
env.Program('main', Glob('*.cpp'))
作为构建系统,SCons的主要任务是完成最少量的工作,使您的所有目标都是最新的。这使得上面描述的用例变得复杂,因为不清楚如何达到“稳定”的情况,即不添加生成的文件并构建所有目标。 通过直接使用简单的Python脚本可能会更好......我真的不知道在这种情况下如何使用SCons(或任何其他构建系统)是关键任务。
编辑:
在某些时候,您必须告诉SCons有关已创建的文件(上例中的*.txt
),并且为了正确跟踪所有依赖项,必须完成*.txt
文件列表。这是SCons中的发射器的任务,它负责返回生成器调用的结果目标和源文件的列表。请注意,在SCons的“解析”阶段,这些文件不必在物理上存在。另请查看我对Scons: create late targets的回答,其中有更详细的说明。
一旦你有一个合适的发射器(参见https://bitbucket.org/scons/scons/wiki/ToolsForFools,“使用发射器”),你应该可以使用Glob('*.txt')
调用,它将自动检测和跟踪你创建的文件。 / p>
最后,在我们的页面“Talks and Slides”(https://bitbucket.org/scons/scons/wiki/TalksAndSlides)上,您可以在PyCon FR.2014中找到我的演讲,“为什么SCons不慢”,这简要解释了SCons如何在内部工作。这可能有助于更好地理解这个问题并提出完整的解决方案。