gpt4 book ai didi

dependencies - 即使文件已更改,自定义 SCons Builder 也会将依赖项报告为当前依赖项

转载 作者:行者123 更新时间:2023-12-04 04:58:29 26 4
gpt4 key购买 nike

我有一个自定义构建器,它使用一个工具来构建使用源代码和带有 markdown 文档的文本文件的文档。

该工具采用指定所有输入文件和输出选项的配置文件。

运行时,它会在标记为 html 的文件夹中生成文档。

我的构建器有一个扫描仪来查找所有输入文件

和一个用于设置输出目录的发射器。

扫描仪和发射器找到所有需要的文件。但是,当我重建时,它没有检测到输入文件更改。

我制作了一个重现问题的构建器,将以下内容放在一个目录中:

gen_doc.py

import SCons.Builder
import os
import ConfigParser

def _doc_build_function(target, source, env):
#print '***** Builder *****'
config = ConfigParser.SafeConfigParser()
try:
fp = open(str(source[0]), 'r')
config.readfp(fp)
finally:
fp.close()
output_dir = ''
if config.has_option('output_options', 'output_dir'):
output_dir = config.get('output_options', 'output_dir')
input_files = []
if config.has_option('input_options', 'input'):
input_files = config.get('input_options', 'input').split()
if not os.path.exists(output_dir):
os.makedirs(output_dir)

with open(output_dir + os.sep + 'index.html', 'wb') as out_file:
for file in input_files:
try:
in_file = open(file, 'r')
out_file.write(in_file.read())
finally:
in_file.close()


def _doc_scanner(node, env, path):
source = []
config = ConfigParser.SafeConfigParser()
try:
fp = open(str(node), 'r')
config.readfp(fp)
finally:
fp.close()
if config.has_option('input_options', 'input'):
for i in config.get('input_options', 'input').split():
source.append(os.path.abspath(i))
return source

def _doc_emitter(target, source, env):
target = []
config = ConfigParser.SafeConfigParser()
try:
fp = open(str(source[0]), 'r')
config.readfp(fp)
finally:
fp.close()
if config.has_option('output_options', 'output_dir'):
target.append(env.Dir(os.path.abspath(config.get('output_options', 'output_dir'))))
env.Clean(source, env.Dir(os.path.abspath(config.get('output_options', 'output_dir'))))

return target, source


def generate(env):
doc_scanner = env.Scanner(function = _doc_scanner)

doc_builder = SCons.Builder.Builder(
action = _doc_build_function,
emitter = _doc_emitter,
source_scanner = doc_scanner,
single_source = 1
)

env.Append(BUILDERS = {
'gen_doc': doc_builder,
})

def exists(env):
'''Using internal builder'''
return True

SConstruct

env = Environment()
env.Tool('gen_doc', toolpath=['.'])
env.gen_doc('config_doc')

配置文档

[input_options]
input = a.md b.md

[output_options]
output_dir = html

a.md

Hello

b.md

 world

当我运行它时它会产生正确的输出

html 文件夹中的一个文件,其中包含一个名为“index.html”的文件

使用Hello world

当我运行时

scons -n tree=status html

我得到以下信息

scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
scons: `html' is up to date.
E = exists
R = exists in repository only
b = implicit builder
B = explicit builder
S = side effect
P = precious
A = always build
C = current
N = no clean
H = no cache

[E B C ]+-html
[E C ] +-config_doc
[E C ] +-a.md
[E C ] +-b.md
scons: done building targets.

我进去修改b.md文件重新运行

scons -n tree=status html

输出是一样的,它仍然报告 b.md 为当前的,所以文档没有重建。

有没有办法让scons看到scanner看到的源文件的变化,并在文件变化时重建?

更新

我做了一些尝试,我创建了一个虚拟的 Decider,看看我是否能找出为什么没有添加这些文件。

def foo(dependency, target, prev_ni):
print 'dependency = %s' % (dependency)
print 'target = %s' % (target)
return True

在“generate(env)”中我添加了行“env.Decider(foo)”

由 _doc_scanner 添加到树中的文件没有调用 Decider 函数,因此永远不会计算 MD5 哈希。

我该怎么做才能让这些文件调用 Decider?

更新2:

发帖时忘记为发射器添加返回。

更新 3

修改了代码,使其不再调用外部构建器。它现在调用模拟构建器的内部构建器函数。这只是模拟外部构建器的行为。原始构建器操作是 action = 'cd ${SOURCE.dir} && gen_docs ${SOURCE.file}

最佳答案

这是由我认为是 SCons 中的设计错误引起的:如果目录存在,目录节点总是被认为是最新的。

来自 SCons FAQ 的相关部分:

Why is my directory only updated the first time?

Like every other build system, SCons considers a directory used as a target as up-to-date if it exists. The first time you built, the directory wasn't there, so SCons ran the update command. Each time after that, the directory already existed, so SCons considered it up-to-date.

你可以解决这个问题,虽然有点麻烦。对于要参与依赖关系图中的每个目录,您需要创建一个“代表”该目录的虚拟文件。每当您生成目录时写入文件。依赖于文件而不是目录。

可以更新您的代码来执行此操作,因此:

import SCons.Builder
import os
import ConfigParser
import datetime

def _manifest(target):
return os.path.join('.manifest', str(target))

def _touch(path):
dirname = os.path.dirname(path)
if not os.path.exists(dirname):
os.makedirs(dirname)
with open(path, 'wt') as f:
f.write(str(datetime.datetime.now()))

def _doc_build_function(target, source, env):
#print '***** Builder *****'
config = ConfigParser.SafeConfigParser()
try:
fp = open(str(source[0]), 'r')
config.readfp(fp)
finally:
fp.close()
output_dir = ''
if config.has_option('output_options', 'output_dir'):
output_dir = config.get('output_options', 'output_dir')
input_files = []
if config.has_option('input_options', 'input'):
input_files = config.get('input_options', 'input').split()
if not os.path.exists(output_dir):
os.makedirs(output_dir)

with open(output_dir + os.sep + 'index.html', 'wb') as out_file:
for file in input_files:
try:
in_file = open(file, 'r')
out_file.write(in_file.read())
finally:
in_file.close()

for t in target:
_touch(_manifest(t))


def _doc_scanner(node, env, path):
source = []
config = ConfigParser.SafeConfigParser()
try:
fp = open(str(node), 'r')
config.readfp(fp)
finally:
fp.close()
if config.has_option('input_options', 'input'):
for i in config.get('input_options', 'input').split():
source.append(os.path.abspath(i))
return source

def _doc_emitter(target, source, env):
target = []
config = ConfigParser.SafeConfigParser()
try:
fp = open(str(source[0]), 'r')
config.readfp(fp)
finally:
fp.close()
if config.has_option('output_options', 'output_dir'):
target.append(env.Dir(os.path.abspath(config.get('output_options', 'output_dir'))))
env.Clean(source, env.Dir(os.path.abspath(config.get('output_options', 'output_dir'))))

target.extend(map(_manifest, target))

return target, source


def generate(env):
doc_scanner = env.Scanner(function = _doc_scanner)

doc_builder = SCons.Builder.Builder(
action = _doc_build_function,
emitter = _doc_emitter,
source_scanner = doc_scanner,
single_source = 1
)

env.Append(BUILDERS = {
'gen_doc': doc_builder,
})

def exists(env):
'''Using internal builder'''
return True

关于dependencies - 即使文件已更改,自定义 SCons Builder 也会将依赖项报告为当前依赖项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19303409/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com