【问题标题】:Is there any way to tell make to print better diagnostic information when a failure occurs?有什么方法可以告诉 make 在发生故障时打印更好的诊断信息?
【发布时间】:2021-08-09 23:02:23
【问题描述】:

GNU make 正在生成错误,其根本原因是我无法理解的。

一些简要背景:该项目是一个嵌入式固件。我们在 Windows 主机上进行交叉编译。该构建实际上在 cygwin 环境中运行。我一直在构建该项目一段时间,没有任何问题。这是一个关键点。该项目正在构建中,我没有对项目源或 Makefile 进行任何更改。

几天前我在我的cygwin环境中安装了python3。自从我运行 Cygwin 安装程序以来已经有一段时间了,安装程序建议我更新十几个其他软件包。我不假思索地接受了更新建议。我没有捕获软件包列表或旧版本。我的意思是,会出什么问题?

出了问题:下次我构建这个项目时,make 失败了。这个错误是神秘的,根本原因是我无法理解的。我将 GNU make 从 4.3-1(新版本)降级回 4.2.1-2,但项目仍然无法正常构建。

这是错误:

$ make -j8
compile message for file1.c
compile message for file2.c
...
compile message for fileN.c
make: *** [../../build/rules.mak:407: ../obj/fileN.o] Error 127

错误 127 未在文档中列出:https://www.gnu.org/software/make/manual/html_node/Error-Messages.html

搜索错误 127,我在 SO:Make Error 127 when running trying to compile code 上发现了这个问题。从表面上看,问题看起来很相似,答案帮助我深入研究了问题。该答案中确定的根本原因是执行了与主机架构不匹配的命令。但是 (1) 我不认为根本原因是相同的 - 请参阅下面的详细信息,并且 (2) 如果根本原因相同,则建议的解决方案都不是该项目的可行选项。

这就是为什么我说根本原因难以捉摸:

  1. 如果我再次运行make -j8,make 将毫无问题地构建 fileN.c,但稍后在文件 X 上失败。我可以重复此过程几次,直到一切都构建好,但这不是一个有效的答案,对人类来说也不是或用于自动构建。

  2. 如果我运行 make clean 然后重新开始,make 会因不同的文件而失败,例如文件 N 将构建成功,但在文件 M 或 P 上生成将失败。

  3. 如果我只使用一项作业运行 make -j1,则构建通常会成功且没有错误,但并非总是如此。

  4. make 调用的行号——最初——是一个包含多个命令的 make 宏,因此不清楚哪个命令可能是问题所在。所以我在配方中添加了一些诊断:which dos2unixfile -L dos2unixdos2unix --version,诸如此类。现在,随着这些诊断的添加,当 make 失败时,它有时会在一行上使用像 echo "dos2unix version:" 这样的简单命令生成 127 错误。 echo 怎么会导致错误 127?为什么不执行前两次完全相同的 echo 命令?

我想提请注意最后一点,因为 make 根本没有提供任何有用的诊断信息。

很明显,错误不是执行与主机架构不匹配的命令。 Make 一遍又一遍地执行相同的命令而不会出错。

很明显,问题不在于任何特定的源文件,因为重新运行 make 会产生不同的成功/失败配置文件。

这是一个失败的配方示例。请记住,相同的配方在失败之前会成功数十次。而如果我make clean/make,在处理差异源文件的时候就会失败。

357 define GENERATE_DEPENDENCY
358   @dos2unix -q $(@:.o=.d)
359   @sed -e '/[a-zA-Z]:/ {' \
360       -e 's/\([a-zA-Z]\):[\\\/]/\/cygdrive\/\L\1\//g' \
361       -e 's/\(.\)\\\(.\)/\1\/\2/g' \
362       -e '}' < $(@:.o=.d)  > $(@:.o=.dep)
363   @cp $(@:.o=.dep) $(@:.o=.dp2)
364   @sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
365       -e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.dp2) >> $(@:.o=.d)
366   @rm $(@:.o=.dp2)
367
368 endef
...
404 $(COBJS) : $(OBJOUTPUTDIR)/%.o : %.c $(EVERYTHING_DEPENDS_ON) | $(OBJOUTPUTDIR)
405     $(COMPILEHOOK)
406     $(CC) $(LISTINGFLAG)=$(@:.o=.lst)  -c $(CPPINC) $(CPPFLAGS)  -MD $(call fixpath,$<) -o $@
407     $(GENERATE_DEPENDENCY)

问题似乎根本不在项目中。我什至删除了该项目并提取了在我的 cygwin 升级之前正确构建的项目的新副本。但这并没有解决问题。

我希望我可以回到之前安装的 cygwin,但我没有备份。我什至不知道升级了哪些软件包。

是否有任何命令行选项可以告诉 make 打印更好的故障诊断信息,我将不胜感激。我尝试了“所有调试信息”选项:

$ make -j8 -d > make-output 2>&1

Make 生成了 4.8MB(86K 行)的输出并且构建成功。但这与建立一份工作一样慢,这是非常不可取的。使用make -d 也会使在实际构建问题发生时定位变得复杂。

或者,如果根本原因确实是架构不匹配,是否有某种方法可以让 make 识别错误发生时它试图执行的命令?就目前而言,我不知道哪个命令可能导致问题,或者问题是否确实是架构不匹配。

【问题讨论】:

  • 如果你正在运行make -j8,你可以看到几个istance重叠的消息。错误可能不是来自echo。您在构建中使用什么工具?所有python3.x都将python分配给默认安装的最高python3.xsourceware.org/pipermail/cygwin-announce/2021-May/010038.html
  • 我为另一个项目安装了 python。 Python 不用于构建这个项目——python 安装只是 cygwin 升级的催化剂。我指向echo 的原因是因为make 指向echo。我添加了自己的诊断命令来隔离故障的根本原因。我还添加了 echo 命令来阐明诊断输出。就在那时,make 开始使用 echo 命令在行上报告“错误 127”。

标签: cygwin gnu-make


【解决方案1】:

问题看起来很明显,make 无法找到在 makefile 中指定的命令,因此会引发 127 错误。
不知何故,它无法在 cygwin bin 目录或指定的 PATH 中找到它。
在更新 cygwin 软件包时,可能会发生一些重要的实用程序未安装或具有某些依赖项的新版本
由于您确定的根本原因是在并行处理期间,最好进行测试并通过
-O option 打印正确的并行运行的 make 调用。此选项指示 make 保存输出从它调用的命令中提取并在命令完成后将其全部打印出来。

make -j8 -O

参考链接:https://www.gnu.org/software/make/manual/html_node/Parallel-Output.html

如果您觉得 echo 确实是一个简单的测试代码的问题,我会在其中并行编译文件并使用 ${NUMBER_OF_PROCESSORS},这将占用系统的可用处理器,那么做一个小测试会很好。如果您愿意,可以将其更改为特定值。
另外,我添加了 .SILENT,因此我不需要为所有回显添加 @ 前缀。如果你想调试,你可以评论它#.SILENT

.SILENT:
.PHONY:compile objs test
TARGET = program.exe
CC=gcc
INC = ./inc
SOURCES = file_1.c file_2.c file_3.c file_4.c file_5.c
OBJ_FILES:= $(SOURCES:.c=.o)


objs: $(OBJ_FILES)

%.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@

all: test 

# Enable parallel compilation
compile:
    make -j ${NUMBER_OF_PROCESSORS} -O objs

link : compile $(TARGET)

$(TARGET): $(OBJ_FILES)
    $(CC) $(CFLAGS) $(OBJ_FILES) -o $@

test: link 
    # check echo command
    echo "Executing test script"

执行使用:make test
最好测试一下这是否适合您,以及并行执行或回显命令是否确实存在问题。

编辑
最好按照@matzeri 的建议禁用防病毒软件进行一次测试。

【讨论】:

  • 如果问题仅与 make 并行出现,也有可能是 AV 暂时阻止了对 make 调用的某些程序的访问。 cygwin.com/faq/faq.html#faq.using.bloda 。您可以将 AV 排除在扫描 cygwin 和工作树之外吗?
  • @matrezi 是的,你是对的,但唯一的方法是禁用软件或防病毒软件或告诉防病毒软件不要扫描来自 cygwin 的实用程序。这不能在 cygwin 端但在防病毒端完成
  • 谢谢@Altaf,我添加了 --output-sync 并希望进行更多故障排除。我有一个更好的:一切都正确构建。完全没有错误。我重试了 3 次,每次都正确构建。我不知道根本原因,但我已经在这个问题上烧了四天,所以我很高兴。再次感谢您!
【解决方案2】:

问题在于失败的不是 make。 Make 只是运行您提供给它的任何命令,并且这些命令以非 0 退出代码(在本例中为 127)退出。 Make 有并且可以有,不知道为什么你的命令以非 0 退出代码退出。 make 所能做的就是报告它收到的退出代码。

添加 -d 也无济于事,因为再次生成错误的不是 make。 -d 选项仅在某些东西以您不期望的方式构建(或不构建)时才有用。调试 recipes 时根本没有帮助。

Make 期望它调用的命令本身会生成足够的消息,说明它失败的原因,它会让你弄清楚它。如果它不这样做,那么你将不得不解决这个问题:make 无能为力。

一个问题是在所有配方命令行前加上@ 是一种反模式。告诉 make 不要打印任何关于它正在做什么的事情,就像试图蒙着眼睛调试你的代码一样。不要那样做。如果您希望大部分时间都隐藏您的食谱,但仍然能够出于调试目的显示它们,您可以尝试此处描述的方法:http://make.mad-scientist.net/managing-recipe-echoing/

【讨论】:

  • 好的,让我解开你在说什么。因此,如果 make 报告命令 echo " FILE" 的错误 127,那么 echo 命令返回错误代码 127?这似乎有道理,但也有些不合逻辑。 echo 命令返回错误? echo " file"如何返回错误?
  • 后续:我删除了宏中的所有@前缀。即便如此,make 仍然会在带有 echo 命令的行上报告错误。例如:make: *** [../../build/rules.mak:398: ../obj/fileN.o] Error 127,其中第 398 行是一个简单的回显命令。
  • 是的,完全正确。我无法解释这一点,如果它是间歇性的,并且有时而不是其他时间运行相同的配方,我尤其无法解释它,但据我所知,这不是制造问题。我对 Windows 做的不多,对 cygwin 做的更少,但我只能建议那里有问题。我要说一件事:按照惯例,shell 的退出代码 127 表示“找不到命令”。这绝对是奇怪的。
  • 需要明确的是,echo 可能不是以 127 退出。可能是 shell 以 127 退出,因为它无法运行 echo。我不知道为什么。您可能会考虑一件事,只是为了咯咯笑,在命令中添加一个分号,所以echo "..."; 看看它是否仍然以这种方式失败
  • 愚蠢的问题:/usr/bin/echo 有效吗? cygcheck -c 报告是否适用于所有包?
猜你喜欢
  • 2017-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多