scons:如何处理动态目标? [英] scons: How to deal with dynamic targets?

查看:154
本文介绍了scons:如何处理动态目标?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试自动化使用sconsPDF转换为png文件的工作.用于转换的工具是ImageMagick中的convert.

这是原始命令行:

  1. convert input.pdf temp/temp.png
  2. convert temp/*.png -append output.png

第一个命令将为PDF文件中的每一页生成一个PNG文件,因此第一个命令的 target 是一个动态文件列表.

这是我正在使用的SConstruct文件:

convert = Builder(action=[
    Delete("${TARGET.dir}"),
    Mkdir("${TARGET.dir}"),
    "convert $SOURCE $TARGET"])
combine = Builder(action="convert $SOURCE -append $TARGET")

env = Environment(BUILDERS={"Convert": convert, "Combine": combine})

pdf = env.PDF("input.tex")
pngs = env.Convert("temp/temp.png", pdf) # I don't know how to specify target in this line
png = env.Combine('output.png', pngs)
Default(png)

代码pngs = env.Convert("temp/temp.png", pdf)实际上是错误的,因为目标是多个文件,在执行env.Convert之前我不知道有多少文件,因此最终的output.png仅包含PDF文件的第一页.

任何提示都值得赞赏.

更新:

我刚刚发现我可以使用命令convert input.pdf -append output.png避免两步转换.

我仍然很好奇当中间临时文件列表事先未知并且需要动态目标列表时如何处理这种情况.

解决方案

如果您想知道如何完成您提出的原始(转换和合并)情况,建议您使用

以下是构建脚本的大致概念:

def convert_emitter(source, target, env):
    # both and source and target will be a list of nodes
    # in this case, the target will be empty, and you need
    # to calculate all of the generated targets based on the
    # source pdf file. You will need to open the source file 
    # with standard python code. All of the targets will be
    # removed when cleaned (scons -c)
    target = [] # fill in accordingly
    return (target, source)

# Optionally, you could supply a function for the action
# which would have the same signature as the emitter
convert = env.Builder(emitter=convert_emitter,
                      action=[
                         Delete("temp"),
                         Mkdir("temp"),
                         "convert $SOURCE $TARGET"])
env.Append(BUILDERS={'Convert' : convert})

combine = env.Builder(action=convert_action, emitter=combine_emitter)
env.Append(BUILDERS={'Combine' : combine})

pdf = env.PDF('input.tex')
# You can omit the target in this call, as it will be filled-in by the emitter
pngs = env.Convert(source=pdf)
png = env.Combine(target='output.png', source=pngs)

I'm trying to automate my work of converting PDF to png file with scons. The tool used for my conversion is convert from ImageMagick.

Here's the raw command line:

  1. convert input.pdf temp/temp.png
  2. convert temp/*.png -append output.png

The first command will generate one PNG file for each page in PDF file, so the target of the first command is a dynamic file list.

Here's the SConstruct file I'm working on:

convert = Builder(action=[
    Delete("${TARGET.dir}"),
    Mkdir("${TARGET.dir}"),
    "convert $SOURCE $TARGET"])
combine = Builder(action="convert $SOURCE -append $TARGET")

env = Environment(BUILDERS={"Convert": convert, "Combine": combine})

pdf = env.PDF("input.tex")
pngs = env.Convert("temp/temp.png", pdf) # I don't know how to specify target in this line
png = env.Combine('output.png', pngs)
Default(png)

The code pngs = env.Convert("temp/temp.png", pdf) actually is wrong since the target is multiple files that I don't know how many before env.Convert is executed, so the final output.png only contains the first page of the PDF file.

Any hint is appreciated.

UPDATE:

I just found that I can use command convert input.pdf -append output.png to avoid the two-step conversion.

Still I'm curious how to handle the scenario when the intermediate temporary file list is unknown beforehand and requires a dynamic target list.

解决方案

If you want to know how to do the original (convert and combine) situation you proposed, I would suggest creating a builder with a SCons Emitter. The emitter allows you to modify the list of source and target files. This works nicely for generated files that dont exist with a clean build.

As you mentioned, the convert step will generate multiple targets, the trick is you need to be able to "calculate" those targets in the emitter based on the source. For example, recently I created a wsdl2java builder and was able to do some simple wsdl parsing in the emitter to calculate all of the target java files to be generated (the source being the wsdl).

Here is a general idea of what the build scripts should look like:

def convert_emitter(source, target, env):
    # both and source and target will be a list of nodes
    # in this case, the target will be empty, and you need
    # to calculate all of the generated targets based on the
    # source pdf file. You will need to open the source file 
    # with standard python code. All of the targets will be
    # removed when cleaned (scons -c)
    target = [] # fill in accordingly
    return (target, source)

# Optionally, you could supply a function for the action
# which would have the same signature as the emitter
convert = env.Builder(emitter=convert_emitter,
                      action=[
                         Delete("temp"),
                         Mkdir("temp"),
                         "convert $SOURCE $TARGET"])
env.Append(BUILDERS={'Convert' : convert})

combine = env.Builder(action=convert_action, emitter=combine_emitter)
env.Append(BUILDERS={'Combine' : combine})

pdf = env.PDF('input.tex')
# You can omit the target in this call, as it will be filled-in by the emitter
pngs = env.Convert(source=pdf)
png = env.Combine(target='output.png', source=pngs)

这篇关于scons:如何处理动态目标?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆