【问题标题】:Scons recompiles my codeScons 重新编译我的代码
【发布时间】:2015-10-09 23:06:17
【问题描述】:

我在我的项目中使用 scons。问题是我必须调用 scons 两次才能使构建达到 scons 不会重新编译任何东西的状态。我的构建顺序如下:

  1. 调用 bison 生成 .cpp 和 .hh 文件以包含在 C++ 编译中。
  2. 调用C++编译器将C++编译成二进制。

问题是 scons 在运行 bison 之前计算依赖关系,此时自动生成的 .hh 文件不存在。下次我运行 scons 时,它会检测到 .hh 文件的新依赖关系并重新编译。野牛运行并生成头文件后如何告诉scons做依赖链?

这是一个演示问题的示例 SConscript。

Program(target = 'hello', source = 'hello.cpp')    
CXXFile (source='parser.yy', target=['parser.cc'])    
Depends('hello.cpp', 'parser.cc')

这是使用 --tree=prune 选项 1 运行 scons 的输出。时间:

scons --tree=prune

scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
bison -o parser.cc parser.yy
g++ -o hello.o -c hello.cpp
g++ -o hello hello.o
+-.
  +-SConstruct
  +-hello
  | +-hello.o
  | | +-hello.cpp
  | | | +-parser.cc
  | | |   +-parser.yy
  | | |   +-/usr/local/bin/bison
  | | +-hello.h
  | | +-/bin/g++
  | +-/bin/g++
  +-[hello.cpp]
  +-hello.h
  +-[hello.o]
  +-[parser.cc]
  +-parser.yy

scons: done building targets.

这是第二次运行的输出。您可以看到 scons 仅在第二次运行时才找到对 bison 生成的 .hh 文件的依赖关系,这就是它重新编译的原因。

# scons --tree=prune
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
g++ -o hello.o -c hello.cpp
+-.
  +-SConstruct
  +-hello
  | +-hello.o
  | | +-hello.cpp
  | | | +-parser.cc
  | | |   +-parser.yy
  | | |   +-/usr/local/bin/bison
  | | +-hello.h
  | | +-parser.hh
  | | +-location.hh
  | | +-stack.hh
  | | +-position.hh
  | | +-/bin/g++
  | +-/bin/g++
  +-[hello.cpp]
  +-hello.h
  +-[hello.o]
  +-location.hh
  +-[parser.cc]
  +-parser.hh
  +-parser.yy
  +-position.hh
  +-stack.hh
scons: done building targets.

hello.cpp 看起来像这样:

#include "hello.h"
#include "parser.hh"

int main() {
        return 0;
}

还有 hello.h:

#define foo 1

这里是 parser.yy 。这 4 个文件 hello.cpp、hello.h、parser.yy 和 SConscript 应该构成一个完整的工作示例来演示该问题。

 {
%}
%start input
%defines
%skeleton "lalr1.cc"
%locations
%initial-action
{
    @$.begin.filename = @$.end.filename = &driver.streamname;
};
%define api.value.type {double}
%token NUM 
%left '-' '+' 
%left '*' '/' 
%precedence NEG 
%right '^'    
%% 
input:
  %empty
| input line
;
line:
  '\n'
| exp '\n'  { printf ("\t%.10g\n", $1); }
;
exp:
  NUM                { $$ = $1;           }   
;
%%

【问题讨论】:

  • 尝试让你的目标依赖于生成的文件,program = Program(...); env.Depends(program, generated_sources);
  • 尝试运行:scons --tree=prune 并粘贴或粘贴结果。 SCons 不需要头文件就知道它会在那里。这就是发射器的用途。这是一条陈旧的路径,因此很可能是一些小问题导致它无法正常工作。
  • 上面我添加了运行 scons 的输出,使用 --tree=prune 选项 1st。时间和第二次。您可以看到 scons 仅在第二次运行时才找到对 bison 生成的 .hh 文件的依赖关系。
  • 你也可以发一份hello.cpp 的逐字副本吗?我不清楚您实际上是如何将生成的解析器源包含到您的程序中的。你尝试直接包含parser.yy,还是标题parser.hh
  • 添加了 hello.cpp 和 hello.h 代码。它们实际上只是演示问题的最小可编译文件。

标签: c++ bison scons


【解决方案1】:

为了正确检测到您的bison/yacc 调用也在创建头文件,SCons 需要设置“-d”命令行标志。然后相应的发射器自动将头文件添加到目标列表中,并且它作为源文件hello.cpp 的隐式依赖被包含在内,而无需通过Depends() 指定显式依赖。 以下SConstruct 对我来说似乎可以正常工作:

env = Environment(YACCHXXFILESUFFIX='.hh',
                  YACCFLAGS=['-d'])

env.CXXFile('parser.cc', 'parser.yy')
env.Program('hello', 'hello.cpp')

注意我如何实例化一个命名的构建环境env,这样我就可以更轻松地操作它的设置。文件后缀的设置是必须的,因为无论出于何种原因,SCons 中默认为*.hpp

您可以在用户指南 (http://scons.org/doc/production/HTML/scons-user.html) 中找到有关上述环境变量的更多信息,尤其是在附录 A“构造变量”中。

关于附加文件location.hhstack.hhposition.hh,最新版本的SCons'yacc工具不支持它们。在我看来,yacc/bison 的最新版本似乎添加了新的关键字,如@9​​87654336@,目前尚未解析这些关键字以发出正确的目标列表。如果您希望对此进行更改,请访问我们的用户邮件列表scons-users@scons.org(另请参阅http://scons.org/lists.php),描述您的问题并提供有关所需关键字语法的更多信息。然后,我们可以尝试通过扩展 yacc 工具来帮助您和所有其他用户。

【讨论】:

  • 感谢您的输入,但它仍然会重新编译 C++ 文件。如果你发出 'scons --debug=explain' 它告诉它正在重新编译,因为它发现了 location.hh、stack.hh 和 position.hh 的新依赖项
  • 我没有看到这些文件在 SConstruct 中生成。他们来自哪里?此外,它们不包含在您的主“hello.cpp”文件中,那么为什么 SCons 应该将它们添加为隐式依赖项?您当前的信息状态没有真正意义,这意味着它似乎不完整。请提供一个完整的最小工作示例 (MWE) 来演示您的实际问题。
  • 我添加了一个虚拟野牛文件“parser.yy”。这与 hello.cpp、hello.h 和 SConscript 文件一起应该完成了一个演示问题的工作示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-29
  • 1970-01-01
相关资源
最近更新 更多