小人。使用 Glob 进行递归

问题描述 投票:0回答:6

我使用 scons 几天了,有点困惑。为什么没有内置工具用于从给定根开始递归构建源?让我解释: 我有这样的源码倾向:

src
    Core
       folder1
       folder2
           subfolder2_1
    Std
       folder1

..等等。这棵树可能会更深。

现在我用这样的结构来构建它:

sources = Glob('./builds/Std/*/*.cpp')
sources = sources + Glob('./builds/Std/*.cpp')
sources = sources + Glob('./builds/Std/*/*/*.cpp')
sources = sources + Glob('./builds/Std/*/*/*/*.cpp')

这看起来并不那么完美。当然,我可以写一些Python代码,但是 有更合适的方法吗?

scons
6个回答
10
投票

正如 Torsten 已经说过的,SCons 中没有“内部”递归 Glob()。你需要自己写点东西。我的解决方案是:

import fnmatch
import os

matches = []
for root, dirnames, filenames in os.walk('src'):
  for filename in fnmatch.filter(filenames, '*.c'):
    matches.append(Glob(os.path.join(root, filename)[len(root)+1:]))

我想强调的是,你在这里需要 Glob() (而不是 python 中的 glob.glob() ),尤其是当你使用 VariantDir() 时。另外,当您使用 VariantDir() 时,不要忘记将绝对路径转换为相对路径(在示例中,我使用 [len(root)+1:] 实现了这一点)。


6
投票

当然。 您需要编写 python 包装器来遍历目录。你可以在 stackoverflow 上找到很多食谱。 这是我的简单函数,它返回当前目录中的子目录列表(并忽略以“.”-点开头的隐藏目录)

def getSubdirs(abs_path_dir) :  
    lst = [ name for name in os.listdir(abs_path_dir) if os.path.isdir(os.path.join(abs_path_dir, name)) and name[0] != '.' ]
    lst.sort()
    return lst

例如,我的目录模块包含 foo、bar、ice。

corePath = 'abs/path/to/modules'
modules = getSubdirs(corePath)
# modules = [bar, foo, ice]
for module in modules :
  sources += Glob(os.path.join(corePath, module, '*.cpp'))

您可以改进 getSubdirs 函数,添加递归并深入到子目录。


3
投票

Glob() SCons 函数没有递归的能力。

如果将 Python 代码更改为使用 list.extend() 函数,效率会更高,如下所示:

sources = Glob('./builds/Std/*/*.cpp')
sources.extend(Glob('./builds/Std/*.cpp'))
sources.extend(Glob('./builds/Std/*/*/*.cpp'))
sources.extend(Glob('./builds/Std/*/*/*/*.cpp'))

不像您那样尝试递归,而是在每个子目录中都有一个 SConscript 脚本,并在根 SConstruct 中使用 SConscript() 函数调用每个脚本,这是很常见的。这称为 SCons 分层构建


2
投票

这是我的递归版本

Glob

from SCons.Environment import Base as BaseEnvironment

def __RGlob(self, root_path, pattern, ondisk=True, source=False, strings=False, exclude=None):
    result_nodes = []
    paths = [root_path]
    while paths:
        path = paths.pop()
        all_nodes = self.Glob(f'{path}/*', ondisk=ondisk, source=source, exclude=exclude)
        paths.extend(entry for entry in all_nodes if entry.isdir() or (entry.srcnode() and entry.srcnode().isdir())) # `srcnode()` must be used because `isdir()` doesn't work for entries in variant dirs which haven't been copied yet.
        result_nodes.extend(self.Glob(f'{path}/{pattern}', ondisk=ondisk, source=source, strings=strings, exclude=exclude))
    return sorted(result_nodes)
BaseEnvironment.RGlob = __RGlob

它尝试尽可能模仿标准

Glob
。最大的区别在于,除了模式之外,还采用根路径作为另一个参数。然后将该模式应用于该根路径及其中的每个子目录。

此代码将函数

RGlob
添加到基础环境中,这意味着您将能够在之后创建的每个环境中调用它。粘贴此内容的最佳位置可能是文件
site_scons/site_init.py


1
投票

我用这个:

srcdir = './'
sources = [s for s in glob2.glob(srcdir + '**/*.cpp') if "/." not in s]

0
投票

我使用这个解决方案:

env = Environment()
build_dir = 'build'
src_dir = 'src'
env.VariantDir(build_dir, src_dir, duplicate=0)
env = SConscript("SConstruct")

sources = []
for root, dirnames, filenames in os.walk(src_dir):
    root = root[len(src_dir)+1:]
    for dir in dirnames:
        p = os.path.join(build_dir, root, dir, '*.cpp')
        sources.extend(Glob(p))
© www.soinside.com 2019 - 2024. All rights reserved.