Dependencies 即使文件已更改,自定义SCons生成器也会将依赖项报告为当前依赖项
我有一个自定义生成器,它使用一个工具来使用源代码和带有标记文档的文本文件构建文档 该工具采用一个配置文件,指定所有输入文件和输出选项 运行时,它会在标记为html的文件夹中生成文档 我的生成器有一个扫描仪来查找所有输入文件 和一个发射器来设置输出目录 扫描仪和发射器可以找到所需的所有文件。但是,当我重建时,它不会检测到输入文件的更改 我已经生成了一个生成器,它复制了问题,并将以下内容放在一个目录中:Dependencies 即使文件已更改,自定义SCons生成器也会将依赖项报告为当前依赖项,dependencies,build-automation,scons,Dependencies,Build Automation,Scons,我有一个自定义生成器,它使用一个工具来使用源代码和带有标记文档的文本文件构建文档 该工具采用一个配置文件,指定所有输入文件和输出选项 运行时,它会在标记为html的文件夹中生成文档 我的生成器有一个扫描仪来查找所有输入文件 和一个发射器来设置输出目录 扫描仪和发射器可以找到所需的所有文件。但是,当我重建时,它不会检测到输入文件的更改 我已经生成了一个生成器,它复制了问题,并将以下内容放在一个目录中: gen_doc.py import SCons.Builder import os import
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')
config\u doc
[input_options]
input = a.md b.md
[output_options]
output_dir = html
a.md
Hello
world
b.md
Hello
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报告为当前,因此不会重建文档
有没有办法让SCON看到扫描程序看到的源文件的更改,并在文件更改时重新生成
更新
我做了一个小游戏,我创建了一个虚拟决策器,看看我是否能找到为什么没有添加这些文件
def foo(dependency, target, prev_ni):
print 'dependency = %s' % (dependency)
print 'target = %s' % (target)
return True
在“生成(环境)”中,我添加了行“环境决策器(foo)”
由_doc_scanner添加到树中的文件没有调用Decider函数,因此永远不会计算MD5哈希
我该怎么做才能让这些文件称为决策者
更新2:
制作帖子时忘记添加发射器的返回值
更新3
修改代码,使其不再调用外部生成器。现在,它调用一个内部生成器函数来模拟生成器。这只是模拟外部生成器的行为。原始生成器操作是
action='cd${SOURCE.dir}&&gen_docs${SOURCE.file}
发射器未返回修改的目标源列表
有关更多信息,请参阅:
emitter函数应返回已修改的目标列表
应建立的目标和将建立目标的来源
这是由我认为sCONS中的设计错误引起的:如果目录存在,目录节点总是被认为是最新的。 以下文件的相关章节:
为什么我的目录只在第一次更新? 与其他所有构建系统一样,SCons认为用作目标的目录是最新的(如果存在)。第一次构建时,目录不在那里,因此SCons运行update命令。此后的每一次,目录都已经存在,因此SCons认为它是最新的 你可以解决这个问题,尽管这有点痛苦。对于要参与依赖关系图的每个目录,需要创建一个“表示”该目录的虚拟文件。无论何时生成目录,都要写入文件。依赖于文件而不是目录 您的代码可以更新以执行此操作,因此:导入SCons.Builder
导入操作系统
导入配置分析器
导入日期时间
def_清单(目标):
返回os.path.join('.manifest',str(目标))
def_触摸屏(路径):
dirname=os.path.dirname(路径)
如果不存在os.path.exists(目录名):
os.makedirs(dirname)
打开(路径“wt”)作为f:
f、 写入(str(datetime.datetime.now())
定义文档构建功能(目标、源、环境):
#打印“******生成器******”
config=ConfigParser.SafeConfigParser()
尝试:
fp=开放(str(源代码[0]),'r')
config.readfp(fp)
最后:
fp.close()
输出_dir=''
如果config.has_option('output_options','output_dir'):
output\u dir=config.get('output\u options','output\u dir')
输入_文件=[]
如果config.has_option('input_options','input'):
input\u files=config.get('input\u options','input').split()
如果操作系统路径不存在(输出目录):
os.makedirs(输出目录)
打开(output_dir+os.sep+'index.html','wb')作为输出文件:
对于输入_文件中的文件:
尝试:
in_file=open(文件'r')
out\u file.write(in\u file.read())
最后:
in_file.close()中
对于目标中的t:
_触摸(_manifest(t))
def_doc_扫描仪(节点、环境、路径):
来源=[]
config=ConfigParser.SafeConfigParser()
尝试:
fp=打开(str(节点),'r')
config.readfp(fp)
最后:
fp.close()
如果config.has_option('input_options','input'):
对于config.get('input_options','input').split()中的i:
source.append(os.path.abspath(i))
返回源
def_doc_发射器(目标、源、环境):
目标=[]
config=ConfigParser.SafeConfigParser()
尝试:
fp=开放(str(源代码[0]),'r')
config.readfp(fp)
最后:
fp.close()
如果config.has_option('output_options','output_dir'):
append(env.Dir(os.path.abspath(config.get('output\u options','output\u Dir')))
env.Clean(source,env.Dir(os.path.abspath(config.get('output\u options','output\u Dir')))
扩展(映射(_清单,目标))
返回目标、源
def生成(环境):
doc\u scanner=env.scanner(函数=\u doc\u scanner)
doc_builder=SCons.builder.builder(
action=\u doc\u build\u函数,
发射器=_doc_发射器,
source\U scanner=文档\U scanner,
单源=1
)
环境附加(生成器={
“gen_doc”:文档生成器,
})
def存在(环境):
“使用内部生成器”
返回真值
我提供的代码你是对的。这是重新处理问题的错误。(正如我在便条中所说)我的原创