【问题标题】:GPR project where every source file is a main file?每个源文件都是主文件的 GPR 项目?
【发布时间】:2019-03-21 18:54:57
【问题描述】:

我有以下项目结构,其中每个 .adb 文件都是一个独立的可执行文件,不会也不会依赖于其他任何东西:

project/
├── project.gpr
├── bin/
│   ├── bar
│   ├── baz
│   └── foo
├── obj/
│   └── .o's, .ali's, etcetera
└── src/
    ├── bar.adb
    ├── baz.adb
    └── foo.adb

这是project.gpr:

project Project is
   for Source_Dirs use ("src");
   for Object_Dir use "obj";
   for Exec_Dir use "bin";
   for Main use ("src/foo.adb", "src/bar.adb", "src/baz.adb");
end Project;

目前gprbuild 和gprclean 完全符合我的要求,但是src/ 下的文件数量可能会增长到数百个。

有没有办法告诉 GPRbuild src/ 下的每个 .adb 文件都应被视为 Main 目标而不明确列出每个文件?

【问题讨论】:

  • documentation 说您不应该将目录组件放在主文件名中(我知道这不是答案,但是..)
  • 非常感谢,我才刚刚开始学习 Ada 的诀窍。
  • 由于您是从 Ada 开始的,因此您应该记住,Ada 是一种编程语言,而 GNAT 是该语言的特定编译器。 GNAT 如何执行编译的细节,包括它的项目机制、项目文件语言、使用特定文件名的压力、每个文件只有一个编译单元的压力等等,在技术上不是 Ada。你应该尽量区分你正在学习的内容的哪些部分是 Ada,哪些是 GNAT 特定的。

标签: ada gnat


【解决方案1】:

由于您使用 GPR,您可以考虑使用聚合项目。

您为每个要生成的可执行文件定义 1 个 GPR。 然后定义 1 个聚合 GPR 来构建它们。

我相信您非常接近描述的用例 in this link

引用:

大多数情况下,应用程序被组织成模块和子模块,它们非常方便地表示为项目树或图(根项目 A 带有每个模块的项目(例如 B 和 C),而这些项目又带有用于子模块。

通常,模块会构建自己的可执行文件(例如用于测试目的)或库(以便在各种上下文中更容易重用)。

但是,如果您通过 gnatmake 或 gprbuild 构建项目,使用类似于

的语法
    gprbuild -PA.gpr

这只会重建项目 A 的主程序,而不是导入的项目 B 和 C 的主程序。因此,您必须生成多个 gnatmake 命令,每个项目一个,以构建所有可执行文件。这有点不方便,但更重要的是效率低下,因为 gnatmake 需要做重复的工作以确保源是最新的,并且在使用 -j 开关时无法轻松并行编译。

此外,在构建项目时总是会重新构建库。

因此,您可以定义一个将 A、B 和 C 分组的聚合项目 Agg。然后,当您构建时使用

     gprbuild -PAgg.gpr

这将从 A、B 和 C 构建所有主电源。

    aggregate project Agg is
       for Project_Files use ("a.gpr", "b.gpr", "c.gpr");
    end Agg;

当然,你最终会为每个主创建 1 个 GPR 带来一点开销,但明确定义每个构建的工件似乎是相当合乎逻辑的,特别是如果他们愿意

永远不要互相依赖

正如你在问题中所说的那样。

但是,GPR 似乎接受了 GPR 聚合的语法,其中考虑了给定目录中的所有 GPR。见here,特别是here

项目文件:

此属性是强制性的。它指定在聚合中分组的组成 .gpr 文件的列表。该列表可能为空。项目文件可以是除配置或抽象项目外的任何项目;它们可以是其他聚合项目。在对标准项目进行分组时,您可以同时拥有项目导入闭包的根(并且您不需要指定其所有导入的项目),以及闭包中的任何项目。

基本思想是指定所有具有您要构建和链接的主要程序或您要构建的库的项目。您可以指定不使用 Main 属性或 Library_* 属性的项目,结果将构建它们的所有源文件(不仅仅是其他项目需要的源文件)。

[...]

路径还可以包括 * 和 ** 通配模式。后者表示将搜索任何子目录(递归)以查找匹配文件。 ** 模式只能出现在目录部分的最后一个位置(即支持a/**/*.gpr,但不支持**/a/*.gpr)。以** 开头的模式等效于以./** 开头。

目前*模式只允许出现在文件名部分,不允许出现在目录部分。这主要是出于效率原因,以限制所需的系统调用数量。

这里有几个例子:

    for Project_Files use ("a.gpr", "subdir/b.gpr");
    --  two specific projects relative to the directory of agg.gpr

    for Project_Files use ("/.gpr");
    --  all projects recursively

【讨论】:

  • 我可能会误解这一点,但这不只是将在 GPR 中指定每个主文件的负担转移到在聚合 GPR 中指定每个 GPR 吗?还是示例只是这样做,并且有另一种语法,您不必手动指定聚合中的每个 GPR?
  • 答案已相应编辑:似乎可以避免指定每个 .gpr 文件的痛苦。
【解决方案2】:

IIRC,不声明任何Main就相当于让GPRBuild编译所有可用的源文件。

【讨论】:

  • 技术上没错,但是如果没有Main 子句,GPRbuild 只会编译源文件而不执行绑定和链接步骤。所以最终的可执行文件没有被构建。
  • 你可以试试gprbuild -P project src/*.adb - 如果命令行中提到的文件包含潜在的主程序(无参数的子程序),gprbuild 会将它们视为主程序。而且(这里)似乎并不关心目录组件。这会让你需要一个 Makefile。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-13
相关资源
最近更新 更多