- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个自定义构建器,它使用一个工具来构建使用源代码和带有 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/
我正在为 scons 扩展一个命令,但来源不完整。一些 xml pdf 文档不存在。 根据 scons wiki,我可以使用scons -i (--ignore-errors,忽略为重建文件而执行的命
在构建我的程序时,区分不存在的文件和空文件很重要。但是,scons 似乎对它们一视同仁,并且在源文件从这些状态之一更改为另一种状态时忽略了重建目标。 逐步示例: 第 0 步: 构造 foo = Com
我正在使用 scons 构建两个项目。一个效果很好,而另一个(更复杂的)项目非常令人沮丧。这是我在为第二个项目运行 scons 时看到的: S time scons scons: Reading SC
我最近从 make 转换为 SCons。我通常在 make 中做的一件事是有一个从源文件生成预处理源的方法,其中包含将应用于正常构建的所有编译器选项。这对于确定 header 的包含方式很有用。 在
我有一个使用 scons 构建的大型 C++ 项目。 它的构建速度很慢,我想进行一些更改以使其构建速度更快。 现在我想集中我的时间来加速构建中最慢的部分。 如何确定哪些文件需要最长的编译时间? 最佳答
我想对所有 .o 做一些后期处理文件(例如由 Object 或 StaticObject Builders 生成的文件),无论用户使用什么 Builder。 我试图像这样“覆盖”或“ Hook ”基础
更新作为构建一部分的文件内容的正确 SCONS 方法是什么? 我使用 SCONS 来构建一个相当大的项目。但是为了一个简单的问题,假设它看起来像这样: env.Program("foo", ["foo
我不想使用 scons --n,我想看看某些东西是如何构建的,而不是现在如何构建。 我认为它可以以某种方式使用 .sconsdblite。 有人做过吗? 最佳答案 SCons man pages解释了
我正在尝试让 SCons 检查我需要的 git 存储库(并希望使该存储库保持最新状态)。问题是我必须告诉它 git repo 包含哪些文件才能在构建中使用它们,如果我这样做,SCons 将在尝试克隆它
我需要作为自定义构建器的一部分按顺序运行两个程序。 其中一个程序我被困住了,无法处理绝对/相对路径,因此我必须使用构建器的 chdir=1 选项才能运行其操作与目标位于同一目录中。 第二个是位于项目的
我正在尝试建立一个涉及代码生成器的构建系统。在生成器运行之前,生成的确切文件是未知的,但我希望能够通过模式匹配运行进一步的构建步骤(在具有某些扩展名的所有文件上运行一些程序)。这可能吗? 这里涉及代码
我有一个简单的项目构建系统,我使用SCons将其组合在一起。 。该项目有相当多的源文件,我认为在构建过程中显示某种进度信息将是用户友好的。 SCons 提供了诸如 CXXCOMSTR 之类的构造变量,
我正在为不同的编译器使用 scons。vc10 和瑞萨编译器。如果我使用 env.program(---) 编译程序,我得到的链接标志为 “链接/nologo/subsystem:console/pd
我有一个分层构建,它使用 SConscript 递归地声明构建目标;所以我事先不知道目标。每个构建都会产生一些额外的文件,比如 *.err *.out ,这些文件不在目标中。当我运行 scons -c
我正在使用 scons 来构建一个项目。效果很好。但是我们的构建命令只是将结果输出到标准输出,我需要让它对我们的软件团队更有用一点。 以下是我想要的行为,按优先顺序排列。有人可以帮我实现它们吗? 没有
我的团队正在创建一个基于 SCons 的构建系统。我们在自己的 site_scons/site_tools 文件夹中创建了一堆辅助类。 我的任务是使用 pyunit 在我们的代码上创建和运行测试。测试
我有一个自定义构建器如下 my_builder = Builder(action = ['mytool' + env['TESTFLAG'] + ' $SOURCE -o $TARGET')],
我有一个仅包含头文件的库,其中包含一个文件夹层次结构和一堆 .hpp我想安装的文件。我的问题是,该 scons 不会将该文件夹复制到构建文件夹中。 这是我的目录布局的样子: root SConst
我正在使用 scons 为一个较大的软件项目实现构建系统。有一个目录结构将各个库和程序的代码分离到它们自己的目录中。使用我们现有的 make 系统,我可以在单个程序目录中执行“make clean”,
默认情况下,SCons 似乎会查看用于构建程序的“配方”并从中提取隐式依赖项。例如假设我的 SConstruct 包含: Command('foo', 'foocreator.py', '/usr/b
我是一名优秀的程序员,十分优秀!