Subject: bug#22186: Use {C,CPLUS,OBJC}_INCLUDE_PATH instead of CPATH

From: [email-masked] (Ludovic Courtès)
Date: Thu, 17 Dec 2015 22:43:17 +0100

Andy Wingo <[email-masked]> skribis:

> So!  CPATH is like -I but C_INCLUDE_PATH et al are like -isystem.
> Here's the docs for -isystem ("Preprocessor Options"):
>
>     '-isystem DIR'
>          Search DIR for header files, after all directories specified by
>          '-I' but before the standard system directories.  Mark it as a
>          system directory, so that it gets the same special treatment as is
>          applied to the standard system directories.  If DIR begins with
>          '=', then the '=' will be replaced by the sysroot prefix; see
>          '--sysroot' and '-isysroot'.
>
> What is a system directory?  Well, it's searched for after all -I
> includes, but also header files in it are marked as system headers.
> Many warnings are not issued for system headers; search the manual for
> the phrase "system headers".  For example:
>
>     '-Wsystem-headers'
>          Issue warnings for code in system headers.  These are normally
>          unhelpful in finding bugs in your own code, therefore suppressed.
>          If you are responsible for the system library, you may want to see
>          them.
>
> So.  We should be using C_INCLUDE_PATH instead of CPATH, to mark system
> headers as system headers.  Except that C_INCLUDE_PATH only works for C,
> so we need to also set CPLUS_INCLUDE_PATH and OBJC_INCLUDE_PATH.  And
> that's the proposal of this bug :)

The intent of this “system header” classification, AIUI, is to not
bother users with issues in libc headers.

The problem is that if we use C_INCLUDE_PATH & co., every header in the
search path, not just libc’s, would now be considered a system header,
and thus exempt from warnings.  This would be undesirable.

Here’s an experiment:

--8<---------------cut here---------------start------------->8---
$ guix environment --ad-hoc gcc ld-wrapper glibc binutils --container
sh-4.3# gcc -Werror=type-limits -O2 -c sysp.c
In file included from sysp.c:1:0:
/gnu/store/n96gwg9fwmxmz1bhy219v3vvmsjsk7gz-glibc-2.22/include/wchar.h: In function 'wctob':
/gnu/store/n96gwg9fwmxmz1bhy219v3vvmsjsk7gz-glibc-2.22/include/wchar.h:397:47: error: comparison of unsigned expression >= 0 is always true [-Werror=type-limits]
 { return (__builtin_constant_p (__wc) && __wc >= L'\0' && __wc <= L'\x7f'
                                               ^
cc1: some warnings being treated as errors
sh-4.3# echo $CPATH
/gnu/store/lq595bjrgav37b05bmmafigwargasy8k-binutils-2.25.1/include:/gnu/store/n96gwg9fwmxmz1bhy219v3vvmsjsk7gz-glibc-2.22/include:/gnu/store/14xgip7wslikzqfkr67vln0kpcclwy37-linux-libre-headers-3.14.37/include:/gnu/store/0wq6hcbfjh5clyz6pjcqxjkl60rmijjf-gcc-5.2.0/include
sh-4.3# export CPATH=/gnu/store/lq595bjrgav37b05bmmafigwargasy8k-binutils-2.25.1/include:/gnu/store/14xgip7wslikzqfkr67vln0kpcclwy37-linux-libre-headers-3.14.37/include:/gnu/store/0wq6hcbfjh5clyz6pjcqxjkl60rmijjf-gcc-5.2.0/include
sh-4.3# gcc -Werror=type-limits -O2 -c sysp.c
--8<---------------cut here---------------end--------------->8---

Where sysp.c is:

--8<---------------cut here---------------start------------->8---
#include <wchar.h>

int foo () { return 42; }
--8<---------------cut here---------------end--------------->8---

Compare with this:

--8<---------------cut here---------------start------------->8---
$ guix environment --ad-hoc gcc ld-wrapper -e '(@@ (gnu packages commencement) glibc-final)' binutils --container
sh-4.3# gcc -Werror=type-limits -O2 -c sysp.c
sh-4.3# echo $CPATH
/gnu/store/lq595bjrgav37b05bmmafigwargasy8k-binutils-2.25.1/include:/gnu/store/qv7bk62c22ms9i11dhfl71hnivyc82k2-glibc-2.22/include:/gnu/store/lyn2331ilik14yy2jqhndshvxmv9r6w5-linux-libre-headers-3.14.37/include:/gnu/store/0wq6hcbfjh5clyz6pjcqxjkl60rmijjf-gcc-5.2.0/include
--8<---------------cut here---------------end--------------->8---

The lesson here is that, if the libc headers that are in CPATH come from
the libc that GCC was built against, then they do not lose their
system-headerness.

Now, when using ‘gcc-toolchain’, CPATH contains an entry that is a
*symlink* to libc.  So from the point of view of libcpp, these are not
system headers.  Thus:

--8<---------------cut here---------------start------------->8---
$ guix environment --ad-hoc gcc-toolchain --container
sh-4.3# gcc -Werror=type-limits -O2 -c sysp.c
In file included from sysp.c:1:0:
/gnu/store/q7k2dc3ylpjnjlhb59f01bxxab8fjxr6-gcc-toolchain-5.2.0/include/wchar.h: In function 'wctob':
/gnu/store/q7k2dc3ylpjnjlhb59f01bxxab8fjxr6-gcc-toolchain-5.2.0/include/wchar.h:397:47: error: comparison of unsigned expression >= 0 is always true [-Werror=type-limits]
 { return (__builtin_constant_p (__wc) && __wc >= L'\0' && __wc <= L'\x7f'
                                               ^
cc1: some warnings being treated as errors
sh-4.3# echo $CPATH
/gnu/store/q7k2dc3ylpjnjlhb59f01bxxab8fjxr6-gcc-toolchain-5.2.0/include
--8<---------------cut here---------------end--------------->8---

This particular problem with gcc-toolchain in ‘guix environment’ is
solved by this patch:

diff --git a/gnu/packages/commencement.scm b/gnu/packages/commencement.scm
index 73b0ce4..fbf4361 100644
--- a/gnu/packages/commencement.scm
+++ b/gnu/packages/commencement.scm
@@ -794,9 +794,13 @@ COREUTILS-FINAL vs. COREUTILS, etc."
 
                    (let ((out (assoc-ref %outputs "out")))
 
-                     (match %build-inputs
-                       (((names . directories) ...)
-                        (union-build out directories)))
+                     (define (select label)
+                       (assoc-ref %build-inputs label))
+
+                     (union-build out
+                                  (list (select "gcc")
+                                        (select "ld-wrapper")
+                                        (select "binutils")))
 
                      (union-build (assoc-ref %outputs "debug")
                                   (list (assoc-ref %build-inputs
@@ -820,8 +824,9 @@ and binaries, plus debugging symbols in the 'debug' output), and Binutils.")
     (inputs `(("gcc" ,gcc)
               ("ld-wrapper" ,(car (assoc-ref %final-inputs "ld-wrapper")))
               ("binutils" ,binutils-final)
-              ("libc" ,glibc-final)
-              ("libc-debug" ,glibc-final "debug")))))
+              ("libc-debug" ,glibc-final "debug")))
+
+    (propagated-inputs `(("libc" ,glibc-final)))))
 
 (define-public gcc-toolchain-4.8
   (gcc-toolchain gcc-final))

However, this doesn’t help with the case where gcc-toolchain is
installed in a profile.

Libcpp does have a file canonicalization method, enabled by default (see
--enable-canonical-system-headers.)  Specifically, in files.c,
‘find_file_in_dir’ does:

    /* We try to canonicalize system headers.  */
    if (CPP_OPTION (pfile, canonical_system_headers) && file->dir->sysp)
      {
        char * canonical_path = maybe_shorter_path (path);

Unfortunately, ‘maybe_shorter_path’ (which calls ‘lrealpath’ from
libiberty) doesn’t seem to be called for libc headers, presumably
because it’s too late: file->dir->sysp is false.

In summary, so far I can only think of half a solution, which is the
‘gcc-toolchain’ fix above.

Thoughts?

Ludo’.