【问题标题】:scons - how to run something /after/ all targets have been builtscons - 如何在/之后/所有目标都已构建
【发布时间】:2010-12-25 07:54:59
【问题描述】:

我最近选择了 scons 来为一个中型 C++ 项目实现一个多平台构建框架。构建会生成一堆单元测试,这些单元测试应该在它结束时被调用。一个人是如何做到这一点的?

例如在我的顶级sconstruct中,我有

subdirs=['list', 'of', 'my', 'subprojects']
for subdir in subdirs:
    SConscript(dirs=subdir, exports='env', name='sconscript',
       variant_dir=subdir+os.sep+'build'+os.sep+mode, duplicate=0)

然而,每个子目录都有其单元测试,因为 dll 和其中构建的可执行文件之间存在依赖关系 - 我想保持测试的运行,直到所有子目录都已构建和安装(我的意思是,使用env.Install)。

我应该在哪里编写循环来迭代构建的测试并执行它们?我试着把它放在这个循环之后——但由于 scons 不允许你控制执行顺序——它在我想要它之前就被执行了。

请帮助一个 scons 新手。 :)

谢谢,

【问题讨论】:

    标签: unit-testing build-automation scons


    【解决方案1】:

    只需让每个 SConscript 返回一个值,您将在该值上构建依赖关系。

    SConscript 文件:

    test = debug_environment.Program('myTest', src_files)
    Return('test')
    

    S构造文件:

    dep1 = SConscript([...])
    dep2 = SConscript([...])
    Depends(dep1, dep2)
    

    现在dep1 构建将在dep2 构建完成后完成。

    【讨论】:

    • 从 scons 3.1 版开始,SConscript 似乎返回 None... 我不确定这将如何工作。
    【解决方案2】:

    解决方案应该就这么简单。

    使测试构建器的结果依赖于安装构建器的结果

    在伪中:

    test = Test(dlls)
    result = Install(dlls)
    Depends(test,result)
    

    最好的方法是测试构建器确实为您计算出 dll 依赖项,但可能有各种原因它不这样做。

    【讨论】:

      【解决方案3】:

      SCons 与 Make 一样,使用声明性方法来解决构建问题。你不想告诉 SCons 如何完成它的工作。您想记录所有依赖项,然后让 SCons 解决它如何构建所有内容。

      如果某事在其他事之前被执行,您需要创建并连接依赖项。

      如果您想创建 dmy touch 文件,您可以创建一个自定义构建器,例如:

      import time
      
      def action(target, source, env):
          os.system('echo here I am running other build')
          dmy_fh = open('dmy_file','w')
          dmy_fh.write( 'Dummy dependency file created at %4d.%02d.%02d %02dh%02dm%02ds\n'%time.localtime()[0:6])
          dmy_fh.close()
      
      bldr = Builder(action=action)
      env.Append( BUILDERS = {'SubBuild' : bldr } )
      
      env.SubBuild(srcs,tgts)
      

      将时间戳放入虚拟文件非常重要,因为 scons 使用 md5 哈希。如果您有一个空文件,则 md5 将始终相同,并且它可能决定不执行后续构建步骤。如果您需要对基本命令进行不同的调整,可以使用函数工厂来修改模板。例如

      def gen_a_echo_cmd_func(echo_str):
          def cmd_func(target,source,env):
              cmd = 'echo %s'%echo_str
              print cmd
              os.system(cmd)
          return cmd_fun
      
      bldr = Builder(action = gen_a_echo_cmd_func('hi'))
      env.Append(BUILDERS = {'Hi': bldr})
      env.Hi(srcs,tgts)
      
      bldr = Builder(action = gen_a_echo_cmd_func('bye'))
      env.Append(BUILDERS = {'Bye': bldr})
      env.Bye(srcs,tgts)
      

      如果您想要自动注入到 scons 构建流程中的内容(例如,在其他所有内容运行后压缩所有构建日志文件的内容),请参阅 my question here

      【讨论】:

        【解决方案4】:

        就依赖关系而言,您希望所有测试操作都依赖于所有程序构建的操作。这样做的一种方法是创建一个虚拟目标并将其导出到所有子目录的 sconscript 文件,并在 sconscript 文件中,将虚拟目标 Depends 设置在主要目标上,并将测试目标 Depends 打开虚拟目标。

        我在弄清楚如何设置虚拟目标时遇到了一些麻烦,但这基本上是可行的:

        (在顶级 SConstruct 中)

        dummy = env.Command('.all_built', 'SConstruct', 'echo Targets built. > $TARGET')
        Export('dummy')
        

        (在每个子目录的SConscript中)

        Import('dummy')
        for target in target_list:
          Depends(dummy, targe)
        for test in test_list:
          Depends(test, dummy)
        

        我确信可以进行进一步的改进,但也许这会让你开始。

        编辑:还值得指出 this page 的主题。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-04-12
          • 2010-10-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多