build2 / build2

build2 build system
MIT License
564 stars 13 forks source link

CLANG: Inconsistent C Compiler Behavior with "missing" <angled> includes #351

Open wroyca opened 6 months ago

wroyca commented 6 months ago

Build2 doesn't propagate Clang C diagnostics in situations where some files are not found with \<angled> includes. Instead, it returns error: inconsistent C compiler behavior.

Example:

> bdep new -l c -t exe hello
> find hello -type f -name "hello.c" -execdir touch hello.h \; -execdir sed -i '/#include <stdio.h>/a\#include <hello.h>' {} \;
> b hello/ config.c=clang
error: inconsistent C compiler behavior
  info: run the following two commands to investigate
  info: clang -I/home/wroy/hello -I/home/wroy/hello -finput-charset=UTF-8 -w -x c -MQ ^ -MD -E -frewrite-includes -MF - -o /home/wroy/hello/hello/hello.o.i /home/wroy/hello/hello/hello.c
  info: clang -I/home/wroy/hello -I/home/wroy/hello -finput-charset=UTF-8 -w -x c -MQ ^ -M -MG /home/wroy/hello/hello/hello.c
  info: while extracting header dependencies from hello/hello/c{hello}
  info: while applying rule c.compile to update hello/hello/obje{hello}
  info: while applying rule c.link to update hello/hello/exe{hello}
  info: while applying rule build.alias to update hello/dir{hello/}
  info: while applying rule build.alias to update dir{hello/}
info: failed to update dir{hello/}

Running the command manually, we get the proper diagnostic:

> clang -I/home/wroy/hello -I/home/wroy/hello -finput-charset=UTF-8 -w -x c -MQ ^ -MD -E -frewrite-includes -MF - -o /home/wroy/hello/hello/hello.o.i /home/wroy/hello/hello/hello.c
/home/wroy/hello/hello/hello.c:2:10: error: 'hello.h' file not found with <angled> include; use "quotes" instead
    2 | #include <hello.h>
      |          ^~~~~~~~~
      |          "hello.h"

Note that GCC works well when faced with the same situation:

> b hello/ config.c=gcc
error: header hello.h not found and no rule to generate it
  info: failure deferred to compiler diagnostics
  info: re-run with --verbose=4 for more information
  info: while extracting header dependencies from hello/hello/c{hello}
  info: while applying rule c.compile to update hello/hello/obje{hello}
  info: while applying rule c.link to update hello/hello/exe{hello}
  info: while applying rule build.alias to update hello/dir{hello/}
  info: while applying rule build.alias to update dir{hello/}
c hello/hello/c{hello} -> hello/hello/obje{hello}
/home/wroy/hello/hello/hello.c:2:10: fatal error: hello.h: No such file or directory
    2 | #include <hello.h>
      |          ^~~~~~~~~
compilation terminated.
boris-kolpackov commented 5 months ago

Yes, I can reproduce this. Appears to be specific to C since the same example but for C++ does the right thing. Will look, thanks.

boris-kolpackov commented 5 months ago

Ok, this turned out to be a Clang bug: https://github.com/llvm/llvm-project/issues/77589

The only workaround that I can think of is to write the dependency information into a temporary file rather than stdout and only act upon it if Clang exists with 0 status. But that's both inefficient and more involved, so let's see what the Clang folks say.