Ninja: 将 depfile 绝对路径与清单相对路径混合会破坏重建

创建于 2017-02-24  ·  70评论  ·  资料来源: ninja-build/ninja

忍者手册警告不要使用这种混合物,但它已成为一个严重的限制。

问题是人们希望他们的构建系统使用源文件的绝对路径调用编译器。 这为 IDE 提供了更好的输出,以匹配错误消息并参考原始文件。 它还可能影响调试信息中记录的路径。 但是,这与 ninja 对构建清单中相对路径的偏好相冲突。

这是一个演示该问题的脚本: ninja-bug.bash.txt

最有用的评论

我真的不认为解决方案应该是“在所有其他工具中解决这个问题”。

1924 展示了基于ninja_workdir方法的完整工作修复和测试。 使用它的生成器可以解决上述所有问题。

所有70条评论

抄送: @nico @chaoren

在 CMake 中, issue 16675issue 13894MR 520中有相关讨论。

作为解决方法,您可以显式设置对象输出目录,甚至是“.”。 或“..”,但绝对路径也有效。
ninjatst.bash.txt

@zlolik IIUC 您建议在构建清单( build.ninja )图形节点中放置绝对路径。 当然这有效(并且是 CMake 在源外构建中所做的),但我的观点是 Ninja 不鼓励使用绝对路径,但 IDE 需要在输出中使用它们。

假设编译器给定-c foo.c也可以在 depfile 中生成绝对路径。 如果发生这种情况,那么 Ninja 将无法识别依赖关系,因为这里报告了同样的问题。

解决这个问题需要 Ninja 能够识别相对路径和绝对路径何时是同一个文件,并且内部只有一个图形节点而不是两个。 仅对 depfile 处理这样做可能就足够了,因为要求build.ninja生成器在构建清单中一致地命名路径是合理的。

@bradking首先,我同意你的观点,我们对忍者有问题,我只建议解决方法。
我认为有3个相关问题:

  1. 带有输入绝对/相对路径的逻辑,更多细节在 #1152 中。
  2. 强制输出绝对/相对路径的逻辑。 编译器的问题 - 对编译器说您希望在输出中具有绝对路径的唯一方法是在命令行中使用绝对路径。 不是忍者问题,而是我们的问题。
  3. 解析 depfile 绝对/相对路径的逻辑。 这个问题。

我使用两种解决方法:

  1. build.ninja生成器的路径中使用前缀$p$o来解决前两个问题。 在我的情况下, $p$o不是绝对的,而是相对于当前运行build.ninja生成器的目录。
  2. 使用一些脚本将 depfile 转换为 ninja 兼容路径。 一些编译器甚至需要单独调用来生成 depfile。 但是没有绝对路径问题。

作为参考,我已经在ninja-build邮件列表上启动了一个线程,并提出了一个解决方案。

关于调试和覆盖信息的另一个相关问题:使用具有相对路径的命令还会创建具有相对路径的调试信息文件。 问题是调试文件通常放在目标文件旁边,而不是源文件旁边,所以那里的相对路径引用不存在的文件。

这事有进一步更新吗? 邮件列表线程上没有任何回复...

大家好,

假设编译器给定-c foo.c也可以在 depfile 中生成绝对路径。

IAR v8 的依赖文件只包含绝对路径。

我们在使用 CMake/Ninja/IAR 进行源外构建时遇到了这个问题:最终在 CMake 的二进制目录中生成的文件在 Ninja 清单中是相对的,IAR 输出的 deps 是绝对的。

对我来说,这显然是一个忍者问题:无论如何,同一个文件不应该有两个节点。

我已经阅读了@bradking建议,但我并不真正理解有关符号链接的部分以及为什么不能使用getcwd() 。 你介意详细说明吗?

我不太了解有关符号链接的部分以及为什么不能使用getcwd()

@sebknzl问题是生成器写入build.ninja的绝对路径可能包含由于某种原因而故意未解析的符号链接。 getcwd()通常返回已解析符号链接的路径。 如果 Ninja 解释构建清单中的相对路径或相对于getcwd()的 depfile,那么它构建的绝对路径可能与构建清单生成器使用的路径不匹配,我们仍然会得到两个节点。

我在您链接的线程中提出的ninja_workdir基本上是告诉忍者生成器用作相对路径的基础。 在实践中realpath(ninja_workdir) == realpath(getcwd())应该始终为真,但这并不意味着ninja_workdir == getcwd() 。 另一种选择是让 Ninja 在创建节点之前对所有内容进行realpath ,但这意味着$in不会扩展到生成器的意图。

@jhasse请查看这个问题以及我的解决方案

为什么不生成一个由CMAKE_NINJA_GENERATOR_OPTION_控制的绝对路径的_build.ninja_

即像这样,它的工作原理:

Claus-MBP:build clausklein$ cat build.ninja 

# project dir
p = /Users/clausklein/Downloads
# object dir
o = /Users/clausklein/Downloads/.ninjatst.build

rule cp
  command = cp $in $out

rule cc
  depfile = $out.d
  deps = gcc
  command = cc -I$o -c $in -o $out -MD -MT $out -MF $out.d

# All absolute paths works
build all: phony $o/foo.o

# All absolute paths works
build $o/foo.h: cp $p/foo.h.in
  IN = $p/foo.h.in

# All absolute paths works
build $o/foo.o: cc $p/foo.c || $o/foo.h
  IN = "$p/foo.c"

default all

Claus-MBP:build clausklein$ 

ninjatst.bash.txt生成

@ClausKlein我们确实尝试过教 CMake 使用绝对路径。 请参阅我在https://github.com/ninja-build/ninja/issues/1251#issuecomment -282322776 中链接的讨论。 我宁愿不添加一个选项,上面写着“以不同的方式做事,修复某些情况并破坏其他情况”。

我们确实需要我在https://github.com/ninja-build/ninja/issues/1251#issuecomment -487618865 中链接的提案中的忍者功能来正确解决这个问题。

好的

那么这个针对 mesonbuild 系统的修复是否也可用;-)

上午 12.03.2020 嗯 12:56 schrieb Brad King [email protected]

@ClausKlein https://github.com/ClausKlein我们确实尝试过教 CMake 使用绝对路径。 请参阅我在 #1251(评论) https://github.com/ninja-build/ninja/issues/1251#issuecomment-282322776中链接的讨论。 我宁愿不添加一个选项,上面写着“以不同的方式做事,修复某些情况并破坏其他情况”。

我们确实需要我在#1251(评论) https://github.com/ninja-build/ninja/issues/1251#issuecomment-487618865中链接的提案中的忍者功能来正确解决这个问题。


你收到这个是因为你被提到了。
直接回复此邮件,在 GitHub 上查看https://github.com/ninja-build/ninja/issues/1251#issuecomment-598146822 ,或取消订阅https://github.com/notifications/unsubscribe-auth/AAN7QWWEDHMDA45DQVPLOUDRHDEVDANCNFSM4DBNL6GA

假设 Ninja 将使用ninja_workdir来匹配 depfile 信息,并且由于符号链接,我们遇到了ninja_workdir != getcwd()的情况。 如果编译器现在使用getcwd()打印绝对路径怎么办?

编译器不应将getcwd()用于任何东西,除非这些东西作为相对路径传入,在这种情况下,构建系统生成器可能需要承担责任。

或者我们可以考虑尝试将ninja_workdirgetcwd()都标准化。

好吧,当给定相对路径时,编译器也不应该在 depfile 中返回绝对路径;)

@ClausKlein我们确实尝试过教 CMake 使用绝对路径。 请参阅我在 #1251(评论)中链接的讨论。 我宁愿不添加一个选项,上面写着“以不同的方式做事,修复某些情况并破坏其他情况”。

当您按照@ClausKlein 的建议使用绝对路径时,到底发生了什么?

如果给编译器提供了绝对路径,那么它生成的 depfile 具有绝对路径,并且这些路径与构建清单中的头文件的相对路径不一致,例如生成的头文件。 请参阅本期顶部我的第一篇文章中的ninja-bug.bash.txt链接。 它显示了所发生情况的分步示例,并且纯粹用 Ninja 而非 CMake 来表达。

我读过,但为什么不使用https://github.com/ninja-build/ninja/issues/1251#issuecomment -284533599? 仅仅因为忍者“不鼓励”绝对路径? 如果是这样,这是关于文档更改吗?

build.ninja文件要小得多,无需在任何地方重复绝对路径,这使它们更快。 它们看起来也更好,更容易调试,并且更适合在 shell 中完成构建目标名称的制表符。 IMO 这是忍者的一个很好的建议。 Ninja 只需要更多信息来协调这个案例,这就是我的建议。

@bradking相对路径可能并不总是很短:

build jsoncpp@sha/src_lib_json_json_reader.cpp.o: cpp_COMPILER ../../../../../Users/clausklein/Workspace/cpp/jsoncpp/src/lib_json/json_reader.cpp
 DEPFILE = jsoncpp@sha/src_lib_json_json_reader.cpp.o.d
 ARGS = -Ijsoncpp<strong i="7">@sha</strong> -I. -I../../../../../Users/clausklein/Workspace/cpp/jsoncpp -I../../../../../Users/clausklein/Workspace/cpp/jsoncpp/include -I../../../../../Users/clausklein/Workspace/cpp/jsoncpp/dir1 -I../../../../../Users/clausklein/Workspace/cpp/jsoncpp/dir2 -fdiagnostics-color=always -pipe -Wall -Winvalid-pch -Wnon-virtual-dtor -std=c++17 -O3

我的示例https://github.com/ninja-build/ninja/issues/1251#issuecomment -597877775 看起来更好!

CMake 的生成器有一条规则,即不使用离开构建树的../序列。 在完全非源代码构建中,我们确实使用源代码树的绝对路径和构建树内的相对路径。 后者永远不会从../开始,因为它们位于构建树下。

我知道,它是用_mesonbuild_生成的。 ;-)

但是,为什么不拒绝生成源树呢?

我们可以永远争论相对路径与绝对路径的优点。 忍者不应该对此持固执己见。 这里的问题是协调在单个构建中使用两者的情况。 构建系统生成器不能总是控制工具对路径的作用。 Ninja 应该支持到同一文件的混合绝对/相对路径,并且可以通过我在提案中概述的简单方法来实现。 对于激励用例,更改被隔离到 depfile 解析。

Ninja 应该支持同一文件的混合绝对/相对路径

我同意!

谢谢大家的解释,我开始明白了。

如果 Ninja 会(在遇到 depfile 中的绝对路径时)realpath 同时包含 cwd 和它找到的路径怎么办? 然后它将从 realpathed depfile-path 中删除 realpathed cwd 以获取与生成的标头匹配的相对路径。 那行得通吗?

getcwd()始终已经是真实路径,因此不需要该步骤。 如果 Ninja 要realpath() depfile 提供的绝对路径并检查可以工作的 cwd 前缀。 然而, realpath()是一个可能很昂贵的系统调用,而我提出的ninja_workdir可以通过字符串处理纯粹在内存中协调路径。

还应该允许在另一个方向上混合:构建清单中的绝对路径,但 depfile 中的相对路径。 我认为 Ninja 在解析build.ninja时不应该对每个绝对路径都进行realpath() #$ 。 那可能会很慢。

我们可以使用结果来确定工作目录。 例如:

getcwd(): /var/xyz/build
depfile 条目: /home/foo/build/bar.h
真实路径(depfile 条目): /var/xyz/build/bar.h
相对真实路径: bar.h
从 depfile 条目中删除它: /home/foo/build -> ninja_workdir

这样我们只需要调用一次 realpath。

我认为一般情况下自动派生ninja_workdir是不可能的。 我们如何知道包含符号链接的原始逻辑路径中有多少逻辑组件对应于 workdir? 我们可以通过一次获取一个组件来做到这一点,直到它的真实路径与 cwd 匹配,但这感觉很hacky并且容易出错。 信任碰巧看起来像这样的第一个符号链接感觉很冒险。 此外,我们必须在遇到的每个绝对路径上运行 realpath() 直到以这种方式解决。

构建系统生成器确切地知道它在生成构建语句中的绝对路径和build.ninja中的命令行时使用的工作目录的逻辑路径。 因此,它是 workdir 路径最可靠的信息来源。 我们只需要一种将这些信息传达给 Ninja 的方法,因此我提出ninja_workdir绑定。

我不确定我是否理解,对不起。 你能举一个我的检测逻辑不起作用的例子吗?

如果构建系统生成器在构建树中放置一个符号链接(指向构建树中的其他位置或完全指向外部),它可能会中断:

getcwd(): /var/xyz/build
depfile 条目: /home/foo/build/subdir-link/bar.h
真实路径(depfile 条目): /var/xyz/build/subdir-real/bar.h
相对真实路径: subdir-real/bar.h
从 depfile 条目中删除它:???

CMake 不这样做,但通常构建系统生成器可以。

即使我们愿意说不支持,检测仍然可能面临:

getcwd(): /var/xyz/build
1000 个 depfile 条目: /home/foo/ext-lib/bar{1,2,...}.h
1000 真实路径(depfile 条目): /var/xyz/ext-lib/bar{1,2,...}.h
1000 个相对真实路径:在 cwd 下没有

现在想象一下,它出现在 1000 个源的 depfile 中并且从来没有命中。 那是 100 万个 realpath() 调用,与此启发式不匹配。 每次重建源并重新解析其 depfile 时,都会重复这种情况。

构建树中的符号链接-> 是的,我们不能真正支持它,无论如何它都会导致各种其他问题(没有到处都是真实路径)。

第二个例子听起来很不自然。 通常 depfiles 以本地依赖项开头,而不是系统头文件。

如果确实是性能问题,我们可以将工作目录缓存在.ninja_deps中吗?

在源外构建中,很少有 depfile 条目甚至会指向构建树。 这将很常见:

getcwd(): /var/xyz/build
1000 个 depfile 条目:/home/foo/project-source/bar{1,2,...}.h
1000 个真实路径(depfile 条目):/var/xyz/project-source/bar{1,2,...}.h
1000 个相对真实路径:在 cwd 下没有

Ninja 必须在所有这些上调用realpath()以防万一,或者维护某种结果表以避免实际的系统调用。 它无法提前知道何时会遇到解析为 cwd 的符号链接路径,甚至不知道它是否会找到。

鉴于目前在 depfile 中混合绝对路径和真实路径不起作用,我看不出这将如何“非常普遍”?

即使不使用符号链接或混合路径,我的示例中形式的 depfile 也已经很常见了。 我的大部分构建树中都有它们。 Ninja 无法提前知道是否需要启发式,因此它必须阻止realpath()系统调用以防万一。

也许我误解了你的例子。 您是指一个包含 3000 个条目的 depfile,还是每个包含 1000 个条目的 depfile 的 3 个单独示例?

我的意思是 1000 个 depfile 条目分布在任意数量的 depfile 中。 它可能是一个。 可能很多。 一个项目中可能有 10000 个条目。 它们的路径可以指向文件系统上的任何位置,并且可能会或可能不会真正指向构建树。

你能举一个例子CMakeLists.txt导致这样的路径混合(不必是 1000,每个只有一个)?

很难在CMakeLists.txt文件中显示,因为 CMake 目前在大多数情况下都注意避免混合路径。 但是,CMake 的问题跟踪器中存在一些问题,即如果没有 Ninja 解决此问题,则无法解决这些问题。 参见例如CMake 问题 13894 。 用户希望能够为编译器提供绝对路径,即使是构建树中的源(可能包括目录),或者在进行源内构建时也是如此。 这适用于 CMake 的 Makefile 生成器。 如果我们使用 Ninja 执行此操作,则 depfile 会返回绝对路径,并且它们与build.ninja中的相对路径不匹配。 也许我们可以为所有事情切换到绝对路径,但正如上面所讨论的,我们不应该这样做。

也许你可以试试这个测试https://github.com/ClausKlein/build-performance/commit/8013836486e3a459474eb374f6c3da5e20983443

此处显示的问题基于https://github.com/ninja-build/ninja/issues/1251#issue -210080507
它会根据需要生成尽可能多的目标。 即 2 个征服者,每个有 2 个源文件:

PWD=/Users/clausklein/Workspace/build-performance/build

rule cp
  command = cp $in $out

rule cc
  depfile = $out.d
  deps = gcc
  command = gcc -c -I$PWD $IN -o $out $FLAGS -MMD -MT $out -MF $out.d

rule link
  command = gcc -o $out $in $LINK_PATH $LINK_LIBRARIES

build foo: phony foo.h
build foo.h: cp foo.h.in

build bin/main0.o: cc /Users/clausklein/Workspace/build-performance/build/subdir0/main.c || foo.h
  IN = /Users/clausklein/Workspace/build-performance/build/subdir0/main.c
build /Users/clausklein/Workspace/build-performance/build/subdir0/file0.o: cc /Users/clausklein/Workspace/build-performance/build/subdir0/file0.c || foo.h
  IN = /Users/clausklein/Workspace/build-performance/build/subdir0/file0.c

build bin/main1.o: cc /Users/clausklein/Workspace/build-performance/build/subdir1/main.c || foo.h
  IN = /Users/clausklein/Workspace/build-performance/build/subdir1/main.c
build /Users/clausklein/Workspace/build-performance/build/subdir1/file0.o: cc /Users/clausklein/Workspace/build-performance/build/subdir1/file0.c || foo.h
  IN = /Users/clausklein/Workspace/build-performance/build/subdir1/file0.c

build bin/main0: link bin/main0.o /Users/clausklein/Workspace/build-performance/build/subdir0/file0.o 
build bin/main1: link bin/main1.o /Users/clausklein/Workspace/build-performance/build/subdir1/file0.o 

build all: phony foo bin/main0 bin/main1 
default all

这适用于 CMake 的 Makefile 生成器。

Make 如何处理符号链接问题?

Make 如何处理符号链接问题?

Makefile 生成器当前没有使用 depfiles 并进行自己的近似扫描。 这可能会作为向 Makefile 生成器添加 C++20 模块支持的一部分进行更新,此时 depfile 路径的解释必须与此处建议的内容类似地进行协调。

一种选择是暂时跳过ninja_workdir并至少教 Ninja 协调混合路径,假设getcwd()是顶部。 这样至少混合路径将在常见的无符号链接情况下工作。 然后可以添加ninja_workdir以支持以后更复杂的情况。

请有人解决这个问题。 因为这个,我很生气。

我将 ARM-GCC 与 CMake 和 VSCode 一起使用。 当我使用源代码构建时,路径是相对于“构建”目录(而不是根目录)的,这导致 VSCode 不再能够解析路径,这意味着你不能只单击命令行窗口中的路径,相反,您必须自己找到每个文件。 当我使用 CMake out-of-tree build 时,它会破坏 Eclipse 的“IntelliSense”,并使 CMake 子项目出现问题。 我现在的解决方案是使用 MakeFiles,因为它默认使用绝对路径。 但是 Ninja 更好,它产生更好的可读文件(rules.ninja...),并且命令行上的构建输出更好。 Make 在多线程上下文中在命令行上输出警告时存在问题,这意味着多个警告是交错的。 这导致我构建单线程,这又是非常烦人的。

请有人解决这个问题。 因为这个,我很生气。

我将 ARM-GCC 与 CMake 和 VSCode 一起使用。 当我使用源内构建时,路径相对于“构建”目录...

有一个解决方法:选择源树之外的构建目录! 即_$TMPDIR/..._

谢谢ClausKlein,但解决方法是源外构建,但我需要树中的文件,因为它被其他脚本引用。 这也是一个非标准的构建要求。

我现在的解决方案是,将 CMake 更改为始终使用绝对路径。 我不明白为什么没有这个选项。 但是,如果其他人需要这个,这里是 CMake v3.18.1 的补丁:

@@ -241,7 +241,7 @@ void cmNinjaTargetGenerator::AddIncludeFlags(std::string& languageFlags,
   // Add include directory flags.
   std::string includeFlags = this->LocalGenerator->GetIncludeFlags(
     includes, this->GeneratorTarget, language,
-    language == "RC", // full include paths for RC needed by cmcldeps
+    true, // full include paths for RC needed by cmcldeps
     false, config);
   if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
     std::replace(includeFlags.begin(), includeFlags.end(), '\\', '/');
@@ -1133,8 +1133,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
   const std::string& fileConfig, bool firstForConfig)
 {
   std::string const language = source->GetLanguage();
-  std::string const sourceFileName =
-    language == "RC" ? source->GetFullPath() : this->GetSourceFilePath(source);
+  std::string const sourceFileName = source->GetFullPath();
   std::string const objectDir = this->ConvertToNinjaPath(
     cmStrCat(this->GeneratorTarget->GetSupportDirectory(),
              this->GetGlobalGenerator()->ConfigDirectory(config)));

注意,有一个 cmake 补丁,但请参阅https://github.com/ninja-build/ninja/issues/1251

我们需要一个忍者补丁!

在我的上一条评论中,我展示了 CMake 使用绝对路径而不是相对路径的补丁。 事实证明这是一个坏主意,因为它破坏了与 Ninja 的自定义 CMake 头依赖关系(例如,生成的头文件依赖于 .json 文件)。 猜猜这个问题源于这里的这个问题,我太愚蠢了,无法理解。

如果有人对此感兴趣,我现在将 Ninja 与相对路径一起使用。 我为 VSCode 创建了一个扩展,以便能够单击集成终端内的相对路径。 延期

@GrandChris太棒了! 有没有机会让它在Output选项卡中工作?

@weliveindetail随意在https://github.com/GrandChris/TerminalRelativePath/issues上创建一个新问题,并详细描述您的用例。 但是 VSCode 中的输出选项卡的行为与集成终端不同,我认为没有 api 可以扩展这方面的行为。

好,谢谢。 最终,可点击的相对路径可能应该在 VSCode 或 CMake 扩展中解决。 会在他们身边ping通。

作为参考,这在CMake Issue 21865中再次出现。 这是另一个不容易(可能?)使 depfile 发现的依赖项使用与build.ninja完全相同的路径表示的情况的示例。

1917 将上面提出的ninja_workdir绑定添加为单独有用的功能。 合并后,我可以跟进解决此问题。

@jhasse我想提出一个可接受的解决方案来解决这个问题。 ninja_workdir解决了这个问题。 我已经在上面论证了我的情况。 你有什么其他的建议?

正如您所指出的问题(将 depfile 绝对路径与清单相对路径混合会破坏重建)是设计使然。 我认为我们应该创建更具体的问题,因为我们已经在讨论中触及了几个问题(例如符号链接构建目录)。

对于最初评论中的两个用例,我的替代方案是:

这为 IDE 提供了更好的输出,以匹配错误消息并参考原始文件。

要么修复 IDE,要么将/FC-fabs-path-diagnostics传递给编译器。

它还可能影响调试信息中记录的路径。

这也应该由编译器修复。 我建议查看-fdebug-prefix-map ,但我不确定问题到底出在哪里。

这是一个演示该问题的脚本:ninja-bug.bash.txt

不是真的,它展示了忍者当前的行为。 两个问题

  1. “我的 IDE 无法将编译器的输出与正确的文件匹配”
  2. “我需要调试信息中的绝对路径”

需要进一步解释。 否则,这对我来说似乎是一个XY 问题(X 是“混合绝对路径和相对路径”,Y 是 1. 或 2.)。

我真的不认为解决方案应该是“在所有其他工具中解决这个问题”。

1924 展示了基于ninja_workdir方法的完整工作修复和测试。 使用它的生成器可以解决上述所有问题。

我也不是,因为我不认为这些是解决方法。

这不是 GNU gcc 选项!

上午 05.03.2021 um 16:58 schrieb Jan Niklas Hasse [email protected]

修复 IDE,或通过 /FC https://docs.microsoft.com/de-de/cpp/build/reference/fc-full-path-of-source-code-file-in-diagnostics或 -fabs-路径诊断https://reviews.llvm.org/D23816到编译器。

它还可能影响调试信息中记录的路径。

这是一个演示该问题的脚本:ninja-bug.bash.txt

不是真的,它展示了忍者当前的行为。

您引用的我的帖子承认这是目前记录在案的行为。
本期的目的是通过以下方式质疑设计
演示它不服务的一类用例。

这两个问题……(1)……(2)……需要进一步解释。

这些只是两个更容易解决的问题示例
将绝对路径传递给工具。 绝对路径并非不合理
仅仅因为在特定情况下可以使用其他解决方案
问题(使用某些供应商提供的工具的特定功能)。
绝对路径有助于解决一大类此类问题而无需更新
到生态系统的其他部分。 正如我之前发布的

我们可以永远争论相对路径与绝对路径的优点。 忍者应该
不要固执己见。 这里的问题是协调案例
两者都在一个构建中使用。 构建系统生成器不能总是
控制工具对路径的作用。

在复杂的现实世界构建系统中,可以有任意数量的层
脚本、包装器、工具等(来自各种供应商)之间的
构建文件生成器以build.ninja写入的路径和实际路径
Ninja 在 depfile 中遇到。 有时一个给定的文件可以被
来自未直接从build.ninja给出路径的工具的 depfile。
为了让 depfiles 在 Ninja 的当前设计下工作,整个工具
必须准确地告诉堆栈build.ninja生成器选择如何表达
构建语句上的那些路径,并具有保留或转换它们的功能
他们以同样的方式。 这在一般情况下是不可处理的。

Ninja 可以通过一个小的设计更改来解决这个问题:协调一个
depfile 中的绝对路径与build.ninja中的相对路径(反之亦然
反之亦然)。 我不是要协调任意路径到同一个文件,只是为了
认识到 depfile 中的/path/to/some/filesome/file中的相同
构建文件/path/to/build.ninja

这种设计更新是有先例的。 当忍者刚开始时,希望
是不是ninja总是会以完全相同的方式遇到路径
构建文件生成器写入的逐字节表示
build.ninja 。 运行git blame -M -C -w -- src/util.cc并查看历史记录
CanonicalizePath以查看遇到的一系列案例
设计理念必须放松。 这是另一类此类情况。

问题是我不同意

忍者不应该对此持固执己见。

首先。

这在一般情况下是不可处理的。

那么具体的问题是什么? 对不起,我有点困惑。

我首先不同意“忍者不应该对此固执己见”......那么具体问题是什么?

这不是关于任何一个特定问题,而是关于使用绝对路径更容易解决的一整类问题。 开发人员为什么想要将绝对路径传递给他们的工具并不重要,只要他们想使用绝对路径,无论出于何种原因适用于他们的特定情况。 构建系统的存在是为了为其用户服务,而不是为了制定政策。 Ninja 应该是构建系统的汇编语言,但无法使用混合样式的路径来表达构建系统。

Ninja 对上游变更的政策是,问题应该由构建文件生成器解决,而不是 Ninja 上游,如果它们可以在不损失效率的情况下解决的话。 在这种情况下,从构建文件生成器提供通用ninja_workdir风格的 depfile 路径协调的唯一方法是在每个生成 depfile 的命令之后注入一个额外的命令来修改 depfile 中的路径以匹配忍者加载之前的构建文件。 该额外命令将有其自己的运行时成本,远远高于#1924 所做的( ninja进程内的少量额外内存查找)。 因此,在 Ninja 上游提供通用对账更有效,因此也是包含的候选者。

即使您确实对所有内容都使用绝对路径,而不是混合绝对路径和相对路径,也存在令人讨厌的人体工程学问题。 如果用户要求ninja重新生成特定的输出文件而不是虚假目标,例如ninja out/my_executableninja out/foo/bar.o ,他们必须记住传递绝对路径,或忍者将失败并出现令人困惑的“未知目标”错误。 相反的问题也存在:当 build.ninja 文件使用相对路径时,用户可能会要求 ninja 重建绝对路径。

在我维护的一个 Ninja 生成器工具中,我通过让每个build语句都包含相对路径及其对应的绝对路径作为输出来解决这个问题。 它有效,但它真的感觉像是解决忍者限制的黑客。 (编辑:另外,如果 build.ninja 只使用相对路径,因此在移动到不同的绝对路径后仍然可以工作,添加绝对路径别名会破坏这种能力。)

诚然,这与 depfile 并不完全相同,但它表明 Ninja 通常应该更加了解绝对路径与相对路径等价。

@comex谢谢,这是一个有效的担忧。 你能为此开一个新问题吗?

开发人员为什么想要将绝对路径传递给他们的工具并不重要 [...]

我不同意。

在这种情况下,提供通用ninja_workdir风格的 depfile 路径协调的唯一方法 [...]

为什么你首先需要ninja_workdir风格的和解呢?

为什么你首先需要 ninja_workdir 风格的协调呢?

它允许开发人员在build.ninja中使用相对路径,同时仍然通过他们无法控制的工具处理在 depfile 中生成的绝对路径。 否则,他们可能会被迫在build.ninja中使用绝对路径,以适应此类工具以及 ninja 的设计限制。 我的提议并没有阻止使用相对路径。 它可以更多地使用它们。

我已经打开 #1925 来实现与 #1924 相同的对账,但没有ninja_workdir绑定。 这将协调 depfile 路径的决定与支持具有符号链接的逻辑 workdir 路径的决定区分开来。

[...] 在 depfile 中通过他们无法控制的工具生成的绝对路径。

有这种工具的例子吗?

我们不可能预测世界上每个人使用的所有工具的行为。 即使对于我们控制的工具,我们已经在上面讨论了几种使用绝对路径很容易解决的情况,但需要特定于工具的选项并且需要非常小心地使用相对路径来解决。 出于类似的原因,CMake 在某些情况下更喜欢绝对路径。 我有几个关于 Ninja 生成器没有这样做的错误报告,而所有其他生成器都这样做。 我曾多次花费数小时追踪依赖关系问题,却发现这是另一个与构建清单路径不一致的 depfile 路径实例。 这些工具提供了 Ninja 捕获依赖项所需的信息,但 Ninja 忽略了它。

您的立场让人认为相对路径普遍更好。 其他人有不同的看法,即在某些情况下绝对路径更好。 我不认为它是传播相对路径的构建工具的地方。

我的提议为 Ninja 添加了少量基础设施。 它有什么伤害? 没有它会使更大的成本外部化。

是的,这是真的!

并且使用绝对路径,cmake 能够消除重复的编译器包含路径。
这再次减少了构建时间。

上午 09.03.2021 um 19:20 schrieb Brad King [email protected]

我不认为它是传播相对路径的构建工具的地方。

我针对 Qt 的快速编译器生成的 cpp 文件和启用统一构建所面临的问题设置了 CMake 问题。 我在当地的调查表明,ninja 是迄今为止最快的构建系统,但在这个星座中它是不可靠的。 现在我面临的问题是如何找到解决方法或证明构建时间增加的合理性。

CMake 刚刚遇到了一个循环依赖问题,直到最近,这个 Ninja 问题才掩盖了这个问题。 如果这个问题得到了解决,我们会更快地发现 CMake 问题。

此页面是否有帮助?
0 / 5 - 0 等级