Bug 79885 - --with-build-sysroot= does not get honored throughout the build (fix-includes, CPP, CXXCPP, configure-stage2)
Summary: --with-build-sysroot= does not get honored throughout the build (fix-includes...
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: bootstrap (show other bugs)
Version: unknown
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: build
Depends on: 37036
Blocks:
  Show dependency treegraph
 
Reported: 2017-03-06 02:28 UTC by Jeremy Huddleston Sequoia
Modified: 2022-03-13 22:29 UTC (History)
6 users (show)

See Also:
Host:
Target: darwin
Build:
Known to work:
Known to fail:
Last reconfirmed: 2019-05-21 00:00:00


Attachments
Initial patch (incomplete) (1.52 KB, patch)
2018-12-03 20:04 UTC, Iain Sandoe
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Jeremy Huddleston Sequoia 2017-03-06 02:28:51 UTC
If gcc-6.3.0 is configured with --with-build-sysroot=/Applications/Xcode.app/.../MacOSXXX.sdk, the build will fail unless /usr/include is present on the system as well.  The build fails during fix-includes with the message:

The directory that should contain system headers does not exist:
  /usr/include

I suspect this is because SYSTEM_HEADER_DIR is set to /usr/include rather than $SDKROOT/usr/include.

Perhaps I'm misunderstanding the intention of --with-build-sysroot, but essentially, I want to build gcc against a given macOS SDK, and the system does not contain system headers installed at /.  I'm testing a workaround of defining SYSTEM_HEADER_DIR explicitly, but it would be best if this issue were resolved properly upstream.
Comment 1 Jeremy Huddleston Sequoia 2017-03-06 04:02:11 UTC
And note that I'm not using --with-sysroot because I don't want this to affect the compiler installed by 'make install', just what is used to build gcc itself.
Comment 2 Andrew Pinski 2017-03-06 04:12:27 UTC
(In reply to Jeremy Huddleston Sequoia from comment #1)
> And note that I'm not using --with-sysroot because I don't want this to
> affect the compiler installed by 'make install', just what is used to build
> gcc itself.

You could have used --prefix instead.

I suspect darwin is different for native builds in that the sysroot is always /.
Comment 3 Jeremy Huddleston Sequoia 2017-03-06 06:15:41 UTC
I'm not sure what you mean by using --prefix "instead" ... I'm using --prefix to establish where I want the tools to be installed to.

As an example, if I wanted to install gcc to /opt/gcc6/bin/gcc, I'd use --prefix=/opt/gcc6.  However, the system headers (i.e., /usr/include/stdlib.h) are located in the macOS SDK (not at /usr/include), so it looks like I should be passing  --with-build-sysroot=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk to configure.  Or am I misunderstanding the purpose of this configure option?

Our build system (MacPorts) is already setting up '-isysroot/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk' in CPPFLAGS, CFLAGS, CXXFLAGS, OBJCFLAGS, OBJCXXFLAGS and adding '-Wl,-syslibroot,/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk to LDFLAGS' ... which is sufficient for most other projects, but GCC's a difficult beast to tame.

FWIW, I worked around this by just editing SYSTEM_HEADER_DIR in gcc/Makefile.in before running configure.

Another related issue is that CPP and CXXCPP need to be explicitly set in the environment because the test for discovering them does not use CPPFLAGS and thus fails, so /lib/cpp is used as fallback (which is not correct).
Comment 4 Andrew Pinski 2017-03-06 06:17:42 UTC
Try --with-build-sysroot= instead.
Comment 5 Jeremy Huddleston Sequoia 2017-03-06 06:26:33 UTC
I don't really understand what you mean by "Try --with-build-sysroot= instead." ... --with-build-sysroot=  *is* being used.
Comment 6 Jeremy Huddleston Sequoia 2017-03-06 06:30:56 UTC
Got farther with the Makefile.in edit and setting of CPP and CXXCPP, but failing now because --sysroot=... is not getting passed to xg++ during configure-stage2-gcc:

from gcc/config.log:

configure:6449:  /opt/local/var/macports/build/_Users_jeremy_src_macports_macports-ports_lang_gcc6/libgcc/work/build/./pr
ev-gcc/xg++ ...  conftest.cpp >&5
conftest.cpp:22:19: fatal error: stdio.h: No such file or directory
 #include <stdio.h>
                   ^
compilation terminated.
Comment 7 Jeremy Huddleston Sequoia 2017-03-06 22:53:33 UTC
Retitled to make the issue more clear/generic.

Note that using --with-sysroot, I'm able to get a built compiler, but the result ends up using the configured sysroot as its default sysroot (as one would expect based on the documentation for --with-sysroot).

My understanding is that --with-build-sysroot should behave the same as --with-sysroot *except* that the installed compiler's default is modified by --with-sysroot and not modified by --with-build-sysroot.
Comment 8 Jeffrey Walton 2017-11-10 16:21:24 UTC
I don't know how much of this observation applies, but:

$ ./configure --help | grep sysroot
  --with-sysroot[=DIR]    Search for dependent libraries within DIR (or the
                          compiler's sysroot if not specified).

The description does not say anything about headers; it only says libraries.

I am certainly not advocating for it. In fact, I came across this bug report because a --with-sysroot (not --with-build-sysroot) is not being honored, and headers seem to be the problem.

By the way, when compiling the compiler, I though --host and --target are used. "Build" indicates the machine the tools are running on. So wouldn't that be --with-host-sysroot or --with-target-sysroot?
Comment 9 Jeremy Huddleston Sequoia 2018-09-14 09:46:53 UTC
Because of this issue, gcc only builds if we have the DevSDK ("headers at /" package) installed.  That package is being provided as a workaround for any projects that fail to build without it (and note that GCC is the only project we are aware of that falls into this category).  In some future macOS version, it will cease to be provided.  I strongly encourage you to address this issue as soon as possible to ensure that GCC continues to build with future versions.
Comment 10 Iain Sandoe 2018-12-03 20:04:28 UTC
Created attachment 45146 [details]
Initial patch (incomplete)

rebased experimental patch on trunk at 266733.

I think that we need to be clear about what we're trying to achieve.

===

Here I'm operating on a system
 * without Xcode installed
 * without command line tools in the "usual place" (so mimicing a 'vanilla' system).
 * a non-standard installation of the command line tools places the SDKs in a known place.
 * GCC bootstrap compiler (so that I can build Ada) which, of course, is capable of building code that will run on my build machine.
 * the build machine is Darwin16 / 10.16 and I target 10.10 typically for x86_64 tests and cross-compilers for powerpc-darwin9, Linux and MinGW.

So, without a sysroot, my bootstraps will fail (there are no headers in /usr/include,; it doesn't exist).

Normally, I use --with-sysroot=/path/to/SDK like this (here building on 10.12 for 10.10+):

MACOSX_DEPLOYMENT_TARGET=10.10 /src/gcc-trunk/configure --prefix=/opt/iains/x86_64-apple-darwin16/gcc-trunk-unpatched --target=x86_64-apple-darwin14 --host=x86_64-apple-darwin14 --build=x86_64-apple-darwin14 --with-iconv-prefix=/usr --enable-checking=yes,rtl,tree --enable-lto --disable-nls --with-sysroot=/opt/iains/x86_64-apple-darwin16/gcc-trunk-unpatched/SDKs/darwin14 --enable-version-specific-runtime-libs --with-as=/opt/iains/x86_64-apple-darwin16/gcc-trunk-unpatched/bin/as --with-ld=/opt/iains/x86_64-apple-darwin16/gcc-trunk-unpatched/bin/ld --enable-languages=all,d >conf.txt

MACOSX_DEPLOYMENT_TARGET=10.10 make ... etc.

here, I have my own builds of cctools and ld64 - installed into the prefix.

So .. this will produce a self-contained compiler, 
this :/opt/iains/x86_64-apple-darwin16/gcc-trunk-unpatched/SDKs/darwin14 is a symlink pointing to my command line install.

and that compiler will have a default sysroot of /opt/iains/x86_64-apple-darwin16/gcc-trunk-unpatched/SDKs/darwin14, which can be overidden by passing --sysroot= on the command line (just like clang).

======

Using --with-build-sysroot with the attached patch works (modulo things I need to sort out with Ada)...

MACOSX_DEPLOYMENT_TARGET=10.10 /src/gcc-trunk/configure --prefix=/opt/iains/x86_64-apple-darwin16/gcc-trunk-unpatched --target=x86_64-apple-darwin14 --host=x86_64-apple-darwin14 --build=x86_64-apple-darwin14 --with-iconv-prefix=/usr --enable-checking=yes,rtl,tree --enable-lto --disable-nls --with-build-sysroot=/opt/iains/x86_64-apple-darwin16/gcc-trunk-unpatched/SDKs/darwin14 --enable-version-specific-runtime-libs --with-as=/opt/iains/x86_64-apple-darwin16/gcc-trunk-unpatched/bin/as --with-ld=/opt/iains/x86_64-apple-darwin16/gcc-trunk-unpatched/bin/ld --enable-languages=c,c++,objc,obj-c++ >conf.txt

MACOSX_DEPLOYMENT_TARGET=10.10 make ... etc.

Now the difference here is that the resulting compiler has no default sysroot, and therefore won't work *unless* 
a ) there are headers in the "usual place" (i.e. /usr/include) which I don't think is what you want
b ) --sysroot= is specified on the command line (or isysroot IIRC, I think we made that operate the same way as clang).

So -- I wonder if this is optimum, since the end user is now stuck with having to add --sysroot= to every command line.
If you use --with-sysroot=/path/to/some/default/SDK then I suspect that works tolerably for many cases.

=====

Ideally, we'd be able to make a "foreign" toolchain operate with the DEVELOPER_TOOLDIR= (spelling?) option but I think that's more involved.

packaging for Darwin is a challenge since we allow are users to move stuff where they like, and we are trying to avoid privileged installs, so no "well known places".

As mentioned elsewhere (a more recent PR) one idea is to have a two-layer approach, where we have a symlink to the SDK in some known place to GCC (e.g. ~/.gcc/version/darwinNN) and then take the runtime hit on updating that only when it becomes stale.  I was experimenting with having a set of places to look including (1) /usr/include (2) /A/Configure/Time/SDK/Path (3) xcrun --blah...

(I had a trial implementation a couple of years ago, needs dusting off).

For those of us who build for Darwin8+ it's essential to have some scheme that allows switching SDKs since modern ones don't have support for the older systems.
Comment 11 Jack Howarth 2019-03-01 13:07:27 UTC
Just a reminder that clang solves finding the position of the SDK via xcrun and SDKROOT.

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87243

The compiler stub programs that users run execute the real clang compilers by calling them via the xcrun program which sets the SDKROOT, among other environmental variables, for the clang compiler to use.

ENVIRONMENT
       CPATH
          This   environment   variable   is  modified  by  xcrun  to  include
          /usr/local/include when an explicit SDK is not requested  via  envi-
          ronment variable nor command line argument and neither -nostdinc nor
          -nostdsysteminc are present.

       DEVELOPER_DIR
          Overrides the active developer directory. When DEVELOPER_DIR is set,
          its  value  will be used instead of the system-wide active developer
          directory.

       LIBRARY_PATH
          This  environment  variable  is  modified  by   xcrun   to   include
          /usr/local/lib when an explicit SDK is not requested via environment
          variable nor command line argument and -Z is not being passed to the
          linker.

       SDKROOT
          Specifies  the  default  SDK  to be used when looking up tools (some
          tools may have SDK specific versions).

          This environment variable is also set by xcrun to  be  the  absolute
          path  to  the  user  provided  SDK  (either via SDKROOT or the --sdk
          option), when it is used to invoke a normal  developer  tool  (build
          tools like xcodebuild or make are exempt from this behavior).

          For example, if xcrun is used to invoke clang via:
              xcrun --sdk macosx clang test.c

          then xcrun will provide the full path to the macosx SDK in the envi-
          ronment variable SDKROOT. That in turn will be used by  clang(1)  to
          automatically select that SDK when compiling the test.c file.

       TOOLCHAINS
          Specifies  the  default  toolchain  to be used when looking up tools
          (for tools which are toolchain specific).
Comment 12 Iain Sandoe 2019-05-21 18:15:39 UTC
(In reply to Jack Howarth from comment #11)
> Just a reminder that clang solves finding the position of the SDK via xcrun
> and SDKROOT.

There are a few important points here.

1. We might be able to do some things in a similar manner, but "clang" is not doing all the work you describe - there's effectively a wrapper that's providing input for the clang driver.

2. xcrun is not open-sourced AFAIK, so we have to write an open equivalent / emulate it in some way - the DEVELOPER_DIR etc require to find a suitable executable at a specific path in the toolchain installation.

3. when clang is using a "different" SDK to target a version of MacOS, it is using the runtimes provided by the target MacOS version.  
  GCC on the other hand is providing a series of runtimes and those runtimes are configured on the basis of the version of the system they are intending to target.  Likewise, the fixincludes are run against the sysroot provided at build time (whether it comes from --with-sysroot, or --build-sysroot is immaterial to that).

4. for a number of sub-ranges of system versions we might be able to get away with single copies of the runtimes (build for the oldest version you wish to support).  However, that does not guarantee that all APIs will be carried forward (sometimes they are retired).

5. anything that means N more process launches per source file build seems like we've picked a bad solution - so some form of caching somehow is highly desirable.

For "target=host=build" single user cases, the --with-sysroot version works, and we still have to find a good story for how to handle the more general case.  We've long resisted the notion of having multilibs by system version, but if one really wants to cover the full range of possibilities - then either muliple compilers or some form of system-revision multilib seems unavoidable.

Inactivity on this and related subjects (basically how to build and package GCC for Darwin) should not be taken as meaning we don't care - actually we care very much - it's just that a good solution has yet to be found.
Comment 13 Jeremy Huddleston Sequoia 2019-10-03 05:58:04 UTC
1. clang honors $SDKROOT from the environment if it is not passed via -isysroot on the command line.  That's all gcc needs to do, and then users running 'xcrun gcc' would ge this behavior automatically.

2. xcrun is not OSS, but the primary functionality that you asked for was provided in libxcselect in macOS 10.15, so you wouldn't need to exec xcrun to find the path to the SDK.

3. I cannot decipher your comment "when clang is using a "different" SDK to target a version of MacOS, it is using the runtimes provided by the target MacOS version."  ... that doesn't quite make sense, so please be a bit more specific about which runtime you are referring to (the compiler runtime, the OS runtime)... either way I try to interpret it, it makes no sense, so I'm not sure how to address this comment, sorry.

4. macOS deprecates APIs but will almost never remove them (unless we change architectures ... such as when we removed a bunch of deprecated API when moving from ppc to intel).  Internal / private SPI is subject to removal, but we aim to never remove API as that breaks binary compatibility.
Comment 14 Iain Sandoe 2019-10-12 08:25:53 UTC
(In reply to Jeremy Huddleston Sequoia from comment #13)

I fully understand that a (perhaps the most) common use-case is build=host=target.

However, we want the other use-cases to work (for example, I regularly cross-host x86-64-darwinxx => powerpc-darwin9, and also use native {build!=host=target} crosses (essential when porting Ada across versions).

> 1. clang honors $SDKROOT from the environment if it is not passed via
> -isysroot on the command line.  That's all gcc needs to do, and then users
> running 'xcrun gcc' would ge this behavior automatically.

This ({$SDKROOT} support) is now implemented, but IMO it's dangerous - since that will apply everywhere when no --sysroot/-isysroot is given which could/would break any other case than build=host=target.  It's likely to produce bug reports about cross-builds not working.

> 2. xcrun is not OSS, but the primary functionality that you asked for was
> provided in libxcselect in macOS 10.15, so you wouldn't need to exec xcrun
> to find the path to the SDK.

That's a great addition, we will have to figure out how to incorporate it for the folks that can use 10.15+.

> 3. I cannot decipher your comment "when clang is using a "different" SDK to
> target a version of MacOS, it is using the runtimes provided by the target
> MacOS version."  ... that doesn't quite make sense, so please be a bit more
> specific about which runtime you are referring to (the compiler runtime, the
> OS runtime)... either way I try to interpret it, it makes no sense, so I'm
> not sure how to address this comment, sorry.

when target != host (and target-version < host-version -1) it's safer to use an SDK that's for the actual target (from an earlier Xcode or Command line tools SDK).  This becomes more and more important when the gap between host and target version gets larger.

It is obviously essential when doing crosses from x86_64 => powerpc darwin, since there's no support for powerpc in the current SDKs.  It's now also essential for targeting i686.

So this is just repeating that the OSS use of macOS/Darwin does not necessarily follow the "only version N and N-1 matter" pattern.  Nor are people in a position to use the latest-and-greatest in all cases; one of my fastest machines is a 2008 8core xeon mac pro - which cannot go beyond 10.11.  In fact, many places are unwilling to use bleeding edge for production machines too.

> 4. macOS deprecates APIs but will almost never remove them (unless we change
> architectures ... such as when we removed a bunch of deprecated API when
> moving from ppc to intel).  Internal / private SPI is subject to removal,
> but we aim to never remove API as that breaks binary compatibility.

That's good to know (for the record, I would not sanction the use of an internal API for the GCC port, however tempting it might be).

=== attempt at a summary.

In principle, there are 3 SDKs that could matter (where build, host and target system versions can all be different - analogous to a so-called "Canadian cross").

1) for the build system version (since we build code that must run on the host - the generators, and some of the Ada stuff)

That can be provided by doing CC/CXX="xxx --sysroot=" on the configure line.

2) for the host code.
This is usually expected to be provided by the compiler that is targeting the host.

macOS is an usual case for GCC in that, in principle, we can target all versions with one compiler, where other systems can expect the compiler-for-host to reference an appropriate sysroot-for-host.

we are missing a good way to provide the SDK to the compiler in this case (in fact, I usually just build a cross-compiler with the host macOS as the target and install it in the usual "linux-y" way).

(as an aside) In the 10.5/6 era it all "just worked" because the SDKs included support for all the cross-cases, and there were not really any big gaps in the support.
Now we have a large range of macOS/Darwin versions and the current SDKs won't support building for perfectly sane hardware (e.g. my 8 core Xeon) much less the vintage (powerpc).

3) for the target code.

The usual case is to provide --with-sysroot= 
As noted before, although the provided SDK path becomes the default, it does not prevent it from being overridden by a user's command line --sysroot= [and now also $SDKROOT will override when there's no --sysroot/-isysroot on the command line]

--with-build-sysroot=dir is allowing for the case that the build system wants to provide the build time sys root from a different place than the one given by --with-sysroot=

(so, for example, --with-sysroot=/ ... --with-build-sysroot=/path/to/target/SDK )

https://gcc.gnu.org/install/configure.html describes in more detail.

This option is not working completely (on other platforms too) so the patch listed above is a sketch at trying to improve that (albeit incomplete, it apparently solves some of the issues).
Comment 15 Eric Gallager 2019-11-04 08:07:24 UTC
Another related downstream MacPorts ticket besides the one already under "See Also": https://trac.macports.org/ticket/59113
Comment 16 Andrew Pinski 2021-08-01 18:49:16 UTC
fixincludes is PR 37036.