Subject: bug#37801: Possible insight into issue #30756 #include_next bug

From: Carl Dong <[email-masked]>
Date: Thu, 17 Oct 2019 21:56:44 +0000

Hi all!

TLDR if you just want to know what's the final patch that worked, grep for
"final patch which works is the following"

This is a long email, but it is only long because I want to be very clear and I
include a lot of snippets of code and logs.

I originally wrote my NSIS package (introduced in e214a22007) on top of
7150743522, which was before the GREAT CORE-UPDATES MERGE. However, after
rebasing it over the GREAT CORE-UPDATES MERGE, the package stopped working. My
investigations into this failure has revealed some insights which might be
useful for other cross-compiling packages and for resolving the long-standing
"important" issue #30756.

For some context, the NSIS package is somewhat special. It requires that both
native compilers and mingw-w64 cross-compilers be available, as NSIS is a
program used to create installers meant to be run on Windows.

My original method of achieving this in pre-GREAT CORE-UPDATES MERGE Guix can be
see in e214a22007, whereby I added a 'fix-env phase. In that 'fix-env phase, I
would remove mingw-w64 paths from CPLUS_INCLUDE_PATH, C_INCLUDE_PATH, and
LIBRARY_PATH, and put them in CROSS_CPLUS_INCLUDE_PATH, CROSS_C_INCLUDE_PATH,
and CROSS_LIBRARY_PATH respectively. This way, the native compilers won't think
that the mingw-w64 paths were something they were supposed to use and get
confused.

As part of the GREAT CORE-UPDATES MERGE, it would seem that CPLUS_INCLUDE_PATH
and C_INCLUDE_PATH are no longer set in the build environment. Rather, only
CPATH is set.

Now, you would think that the solution here is just to replace
CPLUS_INCLUDE_PATH and C_INCLUDE_PATH in my 'fix-env phase with CPATH like so:

diff --git a/gnu/packages/installers.scm b/gnu/packages/installers.scm
index c987254d61..9d29e32485 100644
--- a/gnu/packages/installers.scm
+++ b/gnu/packages/installers.scm
@@ -92,7 +92,7 @@
                              ;; CROSS_-prefixed version of env vars
                              (setenv (string-append "CROSS_" env-name)
                                      (filter-delimited-string env-val mingw-path?))))
-                         '("CPLUS_INCLUDE_PATH" "LIBRARY_PATH" "C_INCLUDE_PATH"))))
+                         '("LIBRARY_PATH" "CPATH"))))
                     (add-before 'build 'fix-target-detection
                       (lambda _
                         ;; NSIS target detection is screwed up, manually

However, that does not work. Trying to build this fix results in the curious
error that we encounter in the long-standing "important" issue #30756 (to be
clear, this is an error while in the `build' phase of the nsis-x86_64 package,
not mingw-w64):

In file included from /gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/include/c++/bits/stl_algo.h:59:0,
                 from /gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/include/c++/algorithm:62,
                 from Contrib/InstallOptions/InstallerOptions.cpp:23:
/gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/include/c++/cstdlib:75:15: fatal error: stdlib.h: No such file or directory
 #include_next <stdlib.h>
               ^~~~~~~~~~
compilation terminated.

For some context, here is the full environment-variables file for that failed
build:

export CPATH="/gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/include:/gnu/store/qx7p7hiq90mi7r78hcr9cyskccy2j4bg-zlib-1.2.11/include:/gnu/store/l86azr7r3p5631wj3kk329jl1y1mpjgy-bzip2-1.0.6/include:/gnu/store/lbip9isk25isymvnb159l115xnacb5j8-xz-5.2.4/include:/gnu/store/6jdshxwdrad9mlhcqc9k0g24yw45rqf1-file-5.33/include:/gnu/store/2z9hsww76aag37p40671l9niq5pvvasx-gawk-5.0.1/include:/gnu/store/b5vpfzkr59bpgcsg1k9vvad9h5rwvpgk-make-4.2.1/include:/gnu/store/3hkdiscs4910r75njbrql10znxxn7chk-binutils-2.32/include:/gnu/store/x3jx25cd3q363mr7nbgzrhrv1vza6cf7-gcc-7.4.0/include:/gnu/store/ahqgl4h89xqj695lgqvsaf6zh2nhy4pj-glibc-2.29/include:/gnu/store/7czrqpi0kwazras6pgyx0bhdn89pg0jl-linux-libre-headers-4.19.56/include"
export CROSS_CPATH="/gnu/store/rabx878fijwgg0yl2bfsx0wvw7d7isnj-mingw-w64-x86_64-6.0.0/include"
export CROSS_LIBRARY_PATH="/gnu/store/rabx878fijwgg0yl2bfsx0wvw7d7isnj-mingw-w64-x86_64-6.0.0/lib"
export GUIX_LD_WRAPPER_ALLOW_IMPURITIES="no"
export GUIX_LOCPATH="/gnu/store/mmqp1xqffn6qw6v88i627c2bpbq36fcy-glibc-utf8-locales-2.29/lib/locale"
export HOME="/homeless-shelter"
export LC_ALL="en_US.utf8"
export LIBRARY_PATH="/gnu/store/xiiafbq3c78kxkgv5zr54zpb8r4jz5ii-scons-python2-3.0.4/lib:/gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/lib:/gnu/store/qx7p7hiq90mi7r78hcr9cyskccy2j4bg-zlib-1.2.11/lib:/gnu/store/l86azr7r3p5631wj3kk329jl1y1mpjgy-bzip2-1.0.6/lib:/gnu/store/lbip9isk25isymvnb159l115xnacb5j8-xz-5.2.4/lib:/gnu/store/6jdshxwdrad9mlhcqc9k0g24yw45rqf1-file-5.33/lib:/gnu/store/2z9hsww76aag37p40671l9niq5pvvasx-gawk-5.0.1/lib:/gnu/store/3hkdiscs4910r75njbrql10znxxn7chk-binutils-2.32/lib:/gnu/store/ahqgl4h89xqj695lgqvsaf6zh2nhy4pj-glibc-2.29/lib:/gnu/store/qky1x5bb2jygy58bn6y95ygfsmpakf52-glibc-2.29-static/lib:/gnu/store/mmqp1xqffn6qw6v88i627c2bpbq36fcy-glibc-utf8-locales-2.29/lib"
export NIX_BUILD_CORES="0"
export NIX_BUILD_TOP="/tmp/guix-build-nsis-x86_64-3.04.drv-0"
export NIX_STORE="/gnu/store"
export OLDPWD
export PATH="/gnu/store/xiiafbq3c78kxkgv5zr54zpb8r4jz5ii-scons-python2-3.0.4/bin:/gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/bin:/gnu/store/9nspnmi8prly39p3xx4plvbk9dywhf4y-binutils-cross-x86_64-w64-mingw32-2.32/bin:/gnu/store/cnqpra8vr2l5fz00rr4yj4bp3hr00cfw-tar-1.32/bin:/gnu/store/py3k9zla9fj3z7430v4crqj5pyrsd3qj-gzip-1.10/bin:/gnu/store/l86azr7r3p5631wj3kk329jl1y1mpjgy-bzip2-1.0.6/bin:/gnu/store/lbip9isk25isymvnb159l115xnacb5j8-xz-5.2.4/bin:/gnu/store/6jdshxwdrad9mlhcqc9k0g24yw45rqf1-file-5.33/bin:/gnu/store/58sq8iabw3jkv0fvf95hd7sq2g4xcsnz-diffutils-3.7/bin:/gnu/store/v76scv4n63ip08g119rczh2mrw31zwpd-patch-2.7.6/bin:/gnu/store/g9d3wv1d68iflx57yp3mcp3k3sv8spsl-findutils-4.6.0/bin:/gnu/store/2z9hsww76aag37p40671l9niq5pvvasx-gawk-5.0.1/bin:/gnu/store/afmvfw1yhfal48n1kjq6bk6kcw8sc3db-sed-4.7/bin:/gnu/store/7iyvxhp2g3v3655zqwr6biz2h0lqv7pr-grep-3.3/bin:/gnu/store/9kzrrccpzl6i1sfwb0drb00gi2gwk0x0-coreutils-8.31/bin:/gnu/store/b5vpfzkr59bpgcsg1k9vvad9h5rwvpgk-make-4.2.1/bin:/gnu/store/29jhbbg1hf557x8j53f9sxd9imlmf02a-bash-minimal-5.0.7/bin:/gnu/store/nc5vlidpxbvngalng30nif8nb3j7gfy2-ld-wrapper-0/bin:/gnu/store/3hkdiscs4910r75njbrql10znxxn7chk-binutils-2.32/bin:/gnu/store/x3jx25cd3q363mr7nbgzrhrv1vza6cf7-gcc-7.4.0/bin:/gnu/store/ahqgl4h89xqj695lgqvsaf6zh2nhy4pj-glibc-2.29/bin:/gnu/store/ahqgl4h89xqj695lgqvsaf6zh2nhy4pj-glibc-2.29/sbin"
export PWD="/tmp/guix-build-nsis-x86_64-3.04.drv-0/nsis-3.04-src"
export SHLVL="1"
export SOURCE_DATE_EPOCH="1"
export TEMP="/tmp/guix-build-nsis-x86_64-3.04.drv-0"
export TEMPDIR="/tmp/guix-build-nsis-x86_64-3.04.drv-0"
export TMP="/tmp/guix-build-nsis-x86_64-3.04.drv-0"
export TMPDIR="/tmp/guix-build-nsis-x86_64-3.04.drv-0"
export out="/gnu/store/wnjkbggyv1jgc2ld9yrissdsjqjvnim8-nsis-x86_64-3.04"

So, to get a better understanding of what was going on, I went into the
environment, and ran:

$ x86_64-w64-mingw32-g++ -E -v -xc++ - < /dev/null > /dev/null

Which yielded:

Using built-in specs.
COLLECT_GCC=x86_64-w64-mingw32-g++
Target: x86_64-w64-mingw32
Configured with:
Thread model: win32
gcc version 7.4.0 (GCC)
COLLECT_GCC_OPTIONS='-E' '-v' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
 /gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/libexec/gcc/x86_64-w64-mingw32/7.4.0/cc1plus -E -quiet -v -U_REENTRANT - -mtune=generic -march=x86-64
ignoring nonexistent directory "/no-gcc-local-prefix/include"
ignoring nonexistent directory "/gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/lib/gcc/x86_64-w64-mingw32/7.4.0/../../../../x86_64-w64-mingw32/include"
ignoring nonexistent directory "/mingw/include"
#include "..." search starts here:
#include <...> search starts here:
 /gnu/store/rabx878fijwgg0yl2bfsx0wvw7d7isnj-mingw-w64-x86_64-6.0.0/include
 /gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/include/c++
 /gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/include/c++/x86_64-w64-mingw32
 /gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/include/c++/backward
 /gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/lib/gcc/x86_64-w64-mingw32/7.4.0/include
 /gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/lib/gcc/x86_64-w64-mingw32/7.4.0/include-fixed
End of search list.
COMPILER_PATH=/gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/libexec/gcc/x86_64-w64-mingw32/7.4.0/:/gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/libexec/gcc/x86_64-w64-mingw32/7.4.0/:/gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/libexec/gcc/x86_64-w64-mingw32/:/gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/lib/gcc/x86_64-w64-mingw32/7.4.0/:/gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/lib/gcc/x86_64-w64-mingw32/
CROSS_LIBRARY_PATH=/gnu/store/rabx878fijwgg0yl2bfsx0wvw7d7isnj-mingw-w64-x86_64-6.0.0/lib/:/gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/lib/gcc/x86_64-w64-mingw32/7.4.0/:/gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/lib/gcc/x86_64-w64-mingw32/7.4.0/../../../../x86_64-w64-mingw32/lib/
COLLECT_GCC_OPTIONS='-E' '-v' '-shared-libgcc' '-mtune=generic' '-march=x86-64'

So if we were to look back at the error from before, it seems that
gcc-cross-x86_64-w64-mingw32-7.4.0/include/c++/cstdlib.h was trying to include
the file stdlib.h in directories listed AFTER it in the list of search paths,
BUT stdlib.h actually resides in mingw-w64-x86_64-6.0.0/include, which is before
it in the effective list of search paths.

Note that the reason mingw-w64-x86_64-6.0.0/include is in this list at all is
because of the 'fix-env phase I added, which plucked it from CPATH and plopped
it into CROSS_CPATH.

I also took a look at Ubuntu's x86_64-w64-mingw32-g++ to see how they do it, and
it would seem that mingw-w64-x86_64-6.0.0/include should be the last thing on
that list:

ignoring nonexistent directory "/usr/lib/gcc/x86_64-w64-mingw32/7.3-win32/../../../../x86_64-w64-mingw32/sys-include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-w64-mingw32/7.3-win32/include/c++
 /usr/lib/gcc/x86_64-w64-mingw32/7.3-win32/include/c++/x86_64-w64-mingw32
 /usr/lib/gcc/x86_64-w64-mingw32/7.3-win32/include/c++/backward
 /usr/lib/gcc/x86_64-w64-mingw32/7.3-win32/include
 /usr/lib/gcc/x86_64-w64-mingw32/7.3-win32/include-fixed
 /usr/lib/gcc/x86_64-w64-mingw32/7.3-win32/../../../../x86_64-w64-mingw32/include
End of search list.

So now we know what to fix, but how? My naive first thought was to list all of
the search paths in the order I wanted them in CROSS_CPATH, like so (pretend the
newlines didn't exist):

CROSS_CPATH=
/gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/include/c++
:/gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/include/c++/x86_64-w64-mingw32
:/gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/include/c++/backward
:/gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/lib/gcc/x86_64-w64-mingw32/7.4.0/include
:/gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/lib/gcc/x86_64-w64-mingw32/7.4.0/include-fixed
:/gnu/store/rabx878fijwgg0yl2bfsx0wvw7d7isnj-mingw-w64-x86_64-6.0.0/include

However, that doesn't work, what DID work was instead listing the order in
CROSS_CPLUS_INCLUDE_PATH and leaving CROSS_CPATH alone, resulting in something
like:

CROSS_CPLUS_INCLUDE_PATH=
/gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/include/c++
:/gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/include/c++/x86_64-w64-mingw32
:/gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/include/c++/backward
:/gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/lib/gcc/x86_64-w64-mingw32/7.4.0/include
:/gnu/store/4ahrjqb268ip0j0ic0l1phmixic8zfzj-gcc-cross-x86_64-w64-mingw32-7.4.0/lib/gcc/x86_64-w64-mingw32/7.4.0/include-fixed
:/gnu/store/rabx878fijwgg0yl2bfsx0wvw7d7isnj-mingw-w64-x86_64-6.0.0/include
CROSS_CPATH=/gnu/store/rabx878fijwgg0yl2bfsx0wvw7d7isnj-mingw-w64-x86_64-6.0.0/include

Note that I did try unsetting CROSS_CPATH, which did not work either.
Ultimately, this means that the final patch which works is the following:

diff --git a/gnu/packages/installers.scm b/gnu/packages/installers.scm
index c987254d61..794e9a758f 100644
--- a/gnu/packages/installers.scm
+++ b/gnu/packages/installers.scm
@@ -92,7 +92,20 @@
                              ;; CROSS_-prefixed version of env vars
                              (setenv (string-append "CROSS_" env-name)
                                      (filter-delimited-string env-val mingw-path?))))
-                         '("CPLUS_INCLUDE_PATH" "LIBRARY_PATH" "C_INCLUDE_PATH"))))
+                         '("CPATH" "LIBRARY_PATH"))
+                        (setenv "CROSS_CPLUS_INCLUDE_PATH"
+                                (string-append
+                                 (string-join
+                                  (map
+                                   (lambda (x) (string-append (assoc-ref %build-inputs "xgcc") x))
+                                       `("/include/c++"
+                                         ,(string-append "/include/c++" "/" ,triplet)
+                                         "/include/c++/backward"
+                                         "/lib/gcc/x86_64-w64-mingw32/7.4.0/include"
+                                         "/lib/gcc/x86_64-w64-mingw32/7.4.0/include-fixed"))
+                                  ":")
+                                 ":"
+                                 (getenv "CROSS_CPATH")))))
                     (add-before 'build 'fix-target-detection
                       (lambda _
                         ;; NSIS target detection is screwed up, manually

I'd like some feedback on

1. Whether this hack is sane or not
2. Does this apply to other packages suffering from the long-standing
"important" issue #30756
3. Does this reveal something more fundamentally wrong with how we build our
search paths in the first place that should be addressed
4. How I might improve the readability of my final patch

Cheers,
Carl Dong
[email-masked]
"I fight for the users"