【问题标题】:How to redirect the output of a utility that generates lots of separate output files?如何重定向生成大量单独输出文件的实用程序的输出?
【发布时间】:2012-01-30 10:55:28
【问题描述】:

我的构建过程使用了大量封闭源代码的第 3 方实用程序。这些工具会生成大量文件,分为三类:我想要的文件、报告和废话。有时我可以选择其中一两个文件的输出目录,但不是全部。其余文件只出现在当前目录或全新的子目录中。大多数不需要的文件都没有记录。这些实用程序的每个新版本中都会出现新的不需要的文件。

有没有办法运行这些实用程序并将所有文件系统操作重定向到某个指定的子目录,在那里我可以在删除其余文件之前复制好文件?我可以更改为子目录来运行这些工具,但这会使事情变得混乱,因为构建过程是相对于项目的根目录的。 (这些工具很难找到正确的文件。)

更新:

我希望得到对文件系统使用某种写时复制方法的答案,以便工具在顶层运行,但所有文件都有效地生成到它们自己的子目录中。如果这不是一个选项,那么我认为下一个最好的方法是更改​​为子目录来运行该工具。然后新的问题变成了如何修复工具的输入,以便工具可以找到正确的源文件?这是不平凡的。要修复的输入示例是配置文件中的命令行参数和文件路径。这似乎是一个容易出错且可能难以解决的问题。

【问题讨论】:

    标签: build makefile build-process build-automation


    【解决方案1】:

    让我们考虑一些构建生成的蜉蝣,在这个例子中,我主要考虑的是 ab

    示例:依赖文件

      这方面的一个例子是 gcc 的 **-MD** 或 **-MDD** 标志,它们生成的依赖文件有助于理解自上次构建以来发生的变化。对于开发人员编辑代码,是的,这些很容易被认为是垃圾 - 但是如果您不想每次运行“make”时都必须重新构建_所有内容_,它们至关重要。
      在这种情况下,您可以为您的目标文件使用不同的目标目录,这会将您的依赖文件放在同一个目录中。

    示例:编译的目标文件

      现在,该示例可能与您有关,也可能与您无关,但是工具需要许多类似类型的工件生成才能“正确”工作。如果您想将其发挥到极致,可以类似地查看“.o”文件开发人员试图在混合了“.o”和“.c/.cpp”文件的目录中查找源文件。
      在这种情况下,您可以使用不同的对象目录,这是一种相当标准的模式,在运行 GCC 时,您可以执行类似的操作
      gcc -c 文件.c -o ../objs/file.o

    示例:不,真的,**废话就是废话**

      但是,让我们来看看 **crap** _really_ 的意思是 **crap** 的情况。在构建之后,您永远不想看到在构建过程中生成的“类型”文件,它是随机数据或其他东西,并且*必须*在每次构建时重新生成。
      在这种情况下,只需在构建结束时添加一个步骤,在您的产品成功构建后将其删除。就那么简单。这也是夜间构建中的标准模式,其中中间文件(对象、依赖项等)无关紧要,只要构建正确执行并且您的产品工件通过通常是最低限度的期望,没有非零子任务的结果,所有目标都正确构建并且打包成功。
      在构建失败的情况下,清理蜉蝣的下一步将不会运行,您可以进入并对构建执行事后分析以了解原因并修复它。
      如果这些建议都没有引起你的共鸣,我敦促你更详细地了解你正在使用的工具以及你认为的“废话”,每种构建工具或语言都有自己的风格和策略(即蚂蚁、 maven、make、cmake、gcc、flex、java、perl、python、scones、quake 等等等等),所以如果没有额外的信息,可能很难真正想出一个很好的解释来最好地解决你的问题。

    更新:

    其他可能的解决方案

    unionfs

      如果您使用 Linux 来运行您的构建,那么一种与工具无关的方式来完成您想要的任务是使用 [unionfs][1],您可以在其中将目录“堆叠”在彼此之上。说你有以下目录是相当聪明的:
      /home/登录/src/ /build/login/output_YY_MM_DD
      您可以在 /home/login/src/ 之上透明地执行 /build/yourlogin/some_project_YY_MM_DD 的 unionfs 挂载,但是当您运行构建时,所有生成的文件实际上最终会在 /build/login/output_YY_MM_DD 中 - 这实际上会完成你想要的。但是,同样,只有当您使用 unionfs 运行 Linux 时。 (遗憾的是,这在 NFS 上不起作用,从未尝试过 SMB 但怀疑相同..)
      为此,您必须运行启用了 unionfs 的内核(我相信您必须安装一个补丁包),然后执行以下操作:
      mount -t unionfs -o dirs=/build/login/output_YY_MM_DD/=rw:/home/login/src/=ro

      重定向输出

        只要您确保链中的所有内容都理解这一点,大多数构建工具都支持将其输出作为目标。它通常与“-o output_filename”类似,尽管在您的情况下,对于某些工具(例如 Xilinx 的 reportgen),“-o”实际上是指输出目录。
        请记住,如果您真的只有三种基本类型的输出要处理,您只需要弄清楚是哪些工具生成它们以及如何修改它们的输出位置。
        这种方法的唯一警告是,如果您重新定位一些构建的后续阶段所需的构建蜉蝣,显然它不会存在 - 因此链中的所有内容都需要了解重新定位。这确实很棘手。

      环境变量魔法

        通常,如果您四处挖掘,您会发现环境变量会触发行为,这些行为可能会或可能不会通过配置文件或命令行选项立即可用。例如,Xilinx 的 **Compxlib** 尊重 **USE_OUTPUT_DIR_ENV**,它的功能与名称所暗示的差不多(您指定指向要重定向到的目录的环境变量。
        使用环境变量的好处是,不必通过附加“-o blah”来重新定位和重写所有编译规则以重新定位其他目录,每个支持环境变量的工具都会自动选择它。
        如果您要构建多个架构,但您希望使用来自单个源代码树的源代码,则此技术也很有用。

        提示:相对目录和构建配置变量

        如果你可以在这里粘贴相对目录并使用变量,你可以更动态地处理一些事情
        
        NIGHTLY_BUILD_DIR=.build/${ARCH}
        USE_OUTPUT_DIR_ENV=NIGHTLY_BUILD_DIR
        

        Xilinx 特定

          您应该查看 IDE 工具,以了解可以提供一些高级方法来执行您想要的操作 - 可能通过在 **Edit > Preferences > ISE General > Design Goals & Strategies** 中修改您的 **Design Goals**?不过我不确定。
          PlanAhead 几乎毫无疑问会有一些设置,用于更改工作目录或忽略临时表来为不同目标单独构建。这是一种相当常见的模式。

        忽略文件

          这可能需要做一些事情,但你可能只是“隐藏”你不想看到的废话。 Windows 和 OSX(我假设是 Linux)在使用 GUI 文件浏览工具时都支持机制,这些工具可以根据文件扩展名隐藏文件。或者,如果您使用“ls”或“grep”之类的程序,您可以过滤掉您不想看到的内容。就像源代码控制程序可以配置为忽略 ephemer 一样。
          这方面的几个例子:
          • ls --ignore=*.d
          • rsync --exclude=.svn,*.d
          • grep --exclude=*.d

        【讨论】:

        • 感谢您的建议。这些工具是 Xilinx 命令行实用程序,用于生成下载到 FPGA 的位文件。有些文件真的很垃圾。我认为很多复杂性来自这样一个事实,即 FPGA“流程”从头到尾有许多路径,并且通常需要人工来确定正确的路径。这不是一件容易自动化的事情。
        • 啊,所以在这种情况下,我认为“废话”的含义可能实际上类似于“目标文件”,即如果您的 FPGA 模块不会从一个版本更改为下一个版本 -如果你改变一个单独的模块,你必须重建它吗?如果不是,那么在这种情况下,废话并不意味着废话。但是,您有可能修改您的构建以执行您想要的操作 - 需要回答两个问题,什么生成位文件以及什么决定哪个位文件应该建立? (我在这里安装了 Xilinx 13.1,所以我可能可以做一些假动作......)
        • 看看 Xilinx 命令行工具:xilinx.com/support/documentation/sw_manuals/xilinx11/devref.pdf。这是一个较旧的链接,但界面应该没有太大变化。大约有 20 种不同的实用程序用于生成各种目标文件。工具的输出包括目标文件、报告和废话。如果您非常小心,您可以避免有时必须重新生成目标文件。但通常像 ISE 这样的工具只会重新生成所有内容。像 PlanAhead 这样的工具要复杂一些。 ISE 和 PlanAhead 都封装了命令行工具。
        • 这些都是很好的建议。不幸的是,它们都不适用于我的特定问题。 unionfs 很酷,但非常特定于操作系统,并且有很多限制,就像您指出的那样。重定向输出和环境魔法只有在工具支持的情况下才有效。忽略文件并不能解决工具覆盖其他文件的问题,以防您需要在清理垃圾之间运行多个工具。我认为我的问题的最佳解决方案实际上是 Xilinx 的 PlanAhead 或 ISE GUI,因为它们就是为此而设计的。
        • 使用 PlanAhead 或 ISE 的诀窍是知道哪些文件要保留,哪些不保留在版本控制中。此外,将所有源代码保留在项目目录之外,以尽量减少版本控制问题。我听说有人使用 PlanAhead 来设置项目,然后使用 PlanAhead 项目文件作为输入运行命令行工具,以查找所有依赖项。这似乎是一个很好的解决方案。
        【解决方案2】:

        cd 的每个实用程序编写一个包装脚本到适当的目录并从那里运行实际的实用程序。将这些包装脚本保存在“本地”bin 目录中,然后将此目录放在 $PATH 中。

        如果工具在执行 3rd 方实用程序时使用完整路径,这将失败。

        您可以像这样从命令行在 Makefile 中指定 override the PATH variable

        $ make PATH=foo:$PATH
        

        【讨论】:

        • 是的,但是当我不再从顶级目录执行时,如何修复我的 Makefile 中的路径和每个实用程序的临时脚本?管理这些路径似乎是一个难题。
        【解决方案3】:

        简短的回答:不。如果这些工具必须在项目根目录中运行,那么它们就必须运行在这个位置,如果它们犯规了,那么它们就是这样做的。

        更长的答案:也许。如果他们真的必须在项目根目录中运行,那就这样吧,但可能有一种方法可以自动清理他们的 effluvia。您事先不知道不需要的文件和目录的名称,但如果您知道想要的文件和目录的名称,则可以将它们列入白名单并删除其他所有内容。

        或者,根据您的项目和操作系统的具体情况,您可以创建一个临时目录,其中包含指向项目根目录中文件的符号链接;对于第三方工具,它看起来就像真正的根目录,但是当工作完成后,您可以挑选出好的文件并删除其余的,就像普通的临时文件一样。只要该工具不尝试在预先存在的子目录中创建文件,这将很好地工作 - 换句话说,它可能会工作,但没有承诺。

        【讨论】:

        • 好主意!它需要在 Windows 和 UNIX 上运行,所以我不确定符号链接是否是一种选择。
        • 如果可以,请考虑使用cygwin.com,它会在 Windows 下模拟 posix 兼容的符号链接。额外的好处,如果你的修改是 shell 脚本,你只需要有一组配置文件,其中存储了路径,它可以在两个平台上工作。
        猜你喜欢
        • 2012-07-23
        • 2016-07-16
        • 2021-09-09
        • 2011-08-31
        • 2010-09-29
        • 1970-01-01
        • 2012-03-06
        • 1970-01-01
        相关资源
        最近更新 更多