如何在SCons Glob结果中进行筛选过滤?

4

有时候我希望在SCons的Glob结果中排除某些特定的源文件。通常这是因为我想使用不同的选项编译该源文件。类似于这样:

objs = env.Object(Glob('*.cc'))
objs += env.Object('SpeciallyTreatedFile.cc', CXXFLAGS='-O0')

当然,这会给SCons带来一个问题:
scons: *** Two environments with different actions were specified
       for the same target: SpeciallyTreatedFile.o

通常我会使用以下习语来解决这个问题:

objs = env.Object([f for f in Glob('*.cc')
  if 'SpeciallyTreatedFile.cc' not in f.path])

但这很丑陋,如果有多个文件要被过滤掉,情况会变得更加糟糕。

有没有更清晰的方法来做到这一点呢?

2个回答

7

我厌烦了在多个地方重复使用[f for f in Glob ...]表达式,所以我编写了以下辅助方法并将其添加到构建环境中:

import os.path

def filtered_glob(env, pattern, omit=[],
  ondisk=True, source=False, strings=False):
    return filter(
      lambda f: os.path.basename(f.path) not in omit,
      env.Glob(pattern))

env.AddMethod(filtered_glob, "FilteredGlob");

现在我只需编写
objs = env.Object(env.FilteredGlob('*.cc',
  ['SpeciallyTreatedFile.cc', 'SomeFileToIgnore.cc']))
objs += env.Object('SpeciallyTreatedFile.cc', CXXFLAGS='-O0')

使用这种模式,编写类似于将正则表达式过滤器用作omit参数而不是简单文件名列表的内容会很容易,但对于我的当前需求,这种方式运行良好。

我没有看到其他更好的方法。所以,你走在正确的道路上。只需使用排除过滤器实现自己的Glob即可。 - Torsten
我需要一个可以处理正则表达式而不是通配符模式的Glob变体。我需要收集具有不同扩展名长度的源文件:.c.f.cpp.adb等,而Glob无法在一次遍历中处理这些文件。我应该使用os.listdirfiltermap-env.File来完成这个任务,还是您有更好的建议? - Nordlöw

2

这是一个老问题,但仍然值得更新,因为它仍然出现在搜索结果中。

SCons 2.3.5引入了exclude关键字参数到Glob函数中,使得以下语句现在有效:

objs = env.Object(Glob('*.cc'), exclude=['SpeciallyTreatedFile.cc'])
objs += env.Object('SpeciallyTreatedFile.cc', CXXFLAGS='-O0')

由于exclude接收一个列表,因此可以包括许多排除项,并且排除列表本身可能包含与glob相同类型的通配符。用户文档列出了以下示例:

sources = Glob('*.cpp', exclude=['os_*_specific_*.cpp']) + Glob('os_%s_specific_*.cpp'%currentOS)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接