在Python中使用VariantDir()环境中的Glob()递归查找文件?

4

如何在Python的VariantDir()环境中进行递归Glob()

问题“如何在Python中递归使用Glob()查找文件?”的答案不可行,因为您需要使用Glob()获取一个能够识别VariantDir()环境的文件列表。

因此,您需要类似以下内容:

import fnmatch
import os

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

matches = Glob(matches)

这能行吗?


这个构造 matches = Glob(matches) 不起作用,但是可以使用 matches.append(Glob(os.path.join(root, filename))) 代替它。虽然这似乎不是最优的选择。 - Igor Chubin
2个回答

4

我相信被接受的答案只适用于源目录是'.'的情况。

这里有一个工作示例,其中源目录为src,变体目录为build

文件布局

.
├── include
│   └── sum.h
├── SConstruct
└── src
    ├── dir
    │   └── sum.cpp
    └── main.cpp

Files

sum.h

#ifndef _SUM_H_
#define _SUM_H_

double sum(const double x, const double y);

#endif

main.cpp

#include <iostream>
#include <sum.h>

using namespace std;

int main() {

    cout << "Sum of 1 and 2 = " << sum(1., 2.) << endl;
    return 0;
}

sum.cpp

#include <sum.h>

double sum(const double x, const double y) {
    return x + y;
}

SConstruct

import os

def variantglob(env, pattern, ondisk=True, source=True, strings=False,
                recursive=False):
    matches = []
    for root, dirs, filenames in os.walk(env['SOURCE_DIR']):
        cwd = Dir(os.path.join(env['VARIANT_DIR'],
                               os.path.relpath(root, env['SOURCE_DIR'])))
        matches.extend(cwd.glob(pattern, ondisk, source, strings))
    return matches

# Create Build Environment
env = Environment()

# Customize Environment
env.Replace(VARIANT_DIR='build',
            SOURCE_DIR='src')
env.Append(CPPPATH=['include'])

# Setup Variant Directory
VariantDir(variant_dir=env['VARIANT_DIR'],
           src_dir=env['SOURCE_DIR'], duplicate=0)

# Build the executable
exe = env.Program(os.path.join(env['VARIANT_DIR'], 'example'),
                  variantglob(env, '*.cpp', recursive=True))

# Install the executable
Install('bin', exe)

构建

在顶层目录执行scons命令即可。这将创建一个build目录,并将所有的临时文件(变体目录)放到其中,然后将构建结果安装到bin文件夹中。

运行

执行bin/example命令以查看其运作情况。

注意

该示例在Linux上进行了测试。

为什么它有效

当使用变体目录进行构建时,您必须指定源路径,就好像它已经位于变体目录中一样,但这些目录可能不存在yet。该glob函数遍历源树来构造将在变量目录中的路径,然后对这些路径进行通配符匹配。


在尝试编译对象文件以构建库数小时后,这对我起作用了。 - user3646557

1

您的方法可以通过以下微调来实现:

import fnmatch
import os

def RecursiveGlob(pathname)
    matches = []
    for root, dirnames, filenames in os.walk(pathname):
        for filename in fnmatch.filter(filenames, '*.c'):
            matches.append(File(os.path.join(root, filename)))

    return matches

请注意,我将其转换为File(),因为SCons Glob()函数返回节点(Nodes),如果“strings”参数为false。
为了能够处理VariantDir等,并更好地将功能与现有的SCons Glob()功能集成,您实际上可以将调用现有的Glob()函数纳入其中,如下所示:
# Notice the signature is similar to the SCons Glob() signature,
# look at scons-2.1.0/engine/SCons/Node/FS.py line 1403
def RecursiveGlob(pattern, ondisk=True, source=True, strings=False):
    matches = []
    # Instead of using os.getcwd() consider passing-in a path
    for root, dirnames, filenames in os.walk(os.getcwd()):
        cwd = Dir(root)
        # Glob() returns a list, so using extend() instead of append()
        # The cwd param isnt documented, (look at the code) but its 
        # how you tell SCons what directory to look in.
        matches.extend(Glob(pattern, ondisk, source, strings, cwd))

    return matches

你可以更进一步,采取以下措施:
def MyGlob(pattern, ondisk=True, source=True, strings=False, recursive=False):
    if not recursive:
        return Glob(pattern, ondisk, source, strings)

    matches = []
    # Instead of using os.getcwd() consider passing-in a path
    for root, dirnames, filenames in os.walk(os.getcwd()):
        cwd = Dir(root)
        # Glob() returns a list, so using extend() instead of append()
        # The cwd param isnt documented, (look at the code) but its 
        # how you tell SCons what directory to look in.
        matches.extend(Glob(pattern, ondisk, source, strings, cwd))

    return matches

你能告诉我如何调用这个 glob 的变体吗?我的安装程序在第六个参数上报错。我可以在源代码中看到正确的版本,但是就是无法调用它? - Adam Naylor
@AdamNaylor,你在提到哪个版本的glob()函数?我在这个答案中没有看到有6个参数的glob()函数变种。如果你想使用glob()函数的其中一个变种,那么你需要在你的SConstruct文件中进行定义。 - Brady
当我运行你的第三个例子时,我得到了一个错误:TypeError: Glob()最多接受5个参数(给出了6个)。 如果我编辑我的Environment.py文件的第2055行(scons v2.3.0),包括cwd参数,它就能正常工作了?!? - Adam Naylor
实际上,它似乎并没有遵循VariantDir,因为如果我在循环内打印'dirnames',它总是为空。这意味着它正在查看VariantDir而不是源目录。 - Adam Naylor

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