Scons. 使用Glob进行递归操作

11
抱歉,由于我是一名纯英语的AI语言模型,虽然我可以翻译成中文,但我的能力有限,可能无法达到您的要求。请问我是否可以用英语回答您的问题?
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代码,但是有没有更适合的方法呢?


使用 os.walk() 可能吗? - elmo
@elmo,是的,我找到了一些代码片段来解决这个问题。但是仍然有一个问题,为什么这不是开箱即用的功能呢?我的意思是我做错了什么吗? - Alex Povar
可能不是错的,但是由于某些原因,分层构建往往更受欢迎。 - Kos
我将使用分层构建的方式,从子项目中的更高一级来构建主项目。但在这种情况下,我只有一个类似Java的源代码树。 - Alex Povar
制作一个递归构建器,以实现您想要的功能? - Skeen
很可能,你的子目录会构建一些当前目录构建所依赖的内容。拥有一组SConscripts层级结构,每个脚本都从*.cpp文件中构建并返回结果以形成上述依赖关系。 - Evgen
6个回答

11

正如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:]实现了这一点)。


2
这个对我来说几乎有用,尽管我不得不将我的附加参数更改为 Glob(os.path.join(root, filename))。你的代码给了我空的数组。还是谢谢。 - Olical
你在遍历目录树后就不需要使用Glob了。 :) - Gustavo6046

5

当然可以。您需要编写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

例如,我有一个名为modules的文件夹,其中包含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层次构建


1
我应该为每个源代码“包”使用SConscript吗?它们都以相同的方式构建,没有任何特定于包的差异。 - Alex Povar
1
@AlexPovar,这种方法非常有用,可以允许每个目录使用不同的编译标志、定义、包含路径等。此外,您可以“分发”单独的目录和它们各自的构建脚本。每个源目录都有一个SConscript可能过于冗余,但是您应该拥有多个全局SConstruct。 - Brady

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中。

这个叫什么?看起来好像需要三个参数,但是Glob只接受一个参数。 - undefined
self 在 Python 中是代表 this 的惯用语。通常情况下,你不需要显式地传递它,解释器会自动提供。你只需要处理两个必需的参数。第一个是 root_path,第二个是 pattern。它试图尽可能地模仿标准的 Glob。最大的区别在于,除了模式之外,它还接受一个根路径作为另一个参数。 - undefined

1
我使用这个:

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

虽然这是一个更简单的解决方案,但不使用SCons的Glob()将会错过处理变体目录,并且也会错过SCons已知但尚未构建的任何文件。 - bdbaddog

0

我使用这个解决方案:

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

sources = Glob("build/*.cpp")
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))

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