Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Foreign target toolchain compilation passes -nodefaultrpaths to Clang when linking libcc1 #18

Closed
winterqt opened this issue Feb 18, 2023 · 17 comments

Comments

@winterqt
Copy link

winterqt commented Feb 18, 2023

When building GCC for a foreign target platform on aarch64-darwin (e.g. avr), the following erroneous command is run:

libtool: link: clang++  -o .libs/libcc1.0.so -bundle  .libs/findcomp.o .libs/libcc1.o .libs/libcp1.o .libs/compiler.o .libs/names.o .libs/callbacks.o .libs/connection.o .libs/marshall.o    -Wl,-undefined -Wl,dynamic_lookup -nodefaultrpaths -Wl,-rpath -Wl,@loader_path ../libiberty/pic/libiberty.a   -Wl,-exported_symbols_list,.libs/libcc1-symbols.expsym
clang-11: error: unknown argument '-nodefaultrpaths'

This happens because clang++ isn't aware of the -nodefaultrpaths option added in this branch. This does not happen during native toolchain compilation, or on (probably the most notable) the GCC 11 branch.

@winterqt winterqt changed the title GCC 12 compilation passes -nodefaultrpaths to Clang when linking libcc1 Foreign target toolchain compilation passes -nodefaultrpaths to Clang when linking libcc1 Feb 18, 2023
winterqt added a commit to winterqt/nixpkgs that referenced this issue Feb 18, 2023
There is currently an issue when compiling a foreign toolchain on
aarch64-darwin [0]. Until this is fixed, let's use GCC 11 in this scenario,
where it works.

[0]: iains/gcc-12-branch#18
@iains
Copy link
Owner

iains commented Feb 18, 2023

so you are building a cross from arm64-darwin to avr?

actually, the unpatched GCC-12 branch should work to build cross-compilers from arm64-darwin to some other target (the host-side stuff was committed upstream already).

I will look into what's needed to avoid this issue.

@winterqt
Copy link
Author

winterqt commented Feb 18, 2023

so you are building a cross from arm64-darwin to avr?

Correct, yes.

actually, the unpatched GCC-12 branch should work to build cross-compilers from arm64-darwin to some other target (the host-side stuff was committed already).

I see, would we be better off not applying the patch in the case where only host Darwin is needed, then? I'll test this now.

@iains
Copy link
Owner

iains commented Feb 18, 2023

It would be better to have a consistent branch that works for both native and cross-compilers (I have already tested that the branch builds a native compiler on Linux, but I had not tested a cross from Darwin => something else).

In the short-term, yes you can try upstream - but there are non-arm64 additions too so this needs to be fixed. I have not had any time recently to work on upstreaming more of this ...

@iains
Copy link
Owner

iains commented Feb 18, 2023

BTW, the general recommendation (and a hard requirement when building Ada) would be:

1/ bootstrap a native GCC with the sources you want to use
2/ use that to build the cross compiler.

This is because the host compiler (in this case clang, but it could be some older GCC too, same applies) does not implement the same set of builtins etc. that GCC does and you do not have the bootstrap step to isolate your intended cross from that.

winterqt added a commit to winterqt/nixpkgs that referenced this issue Feb 19, 2023
It seems that the patchset we apply to get some fixes for aarch64-darwin
support [0] breaks in unexpected ways when compiling a foreign toolchain.
Luckily, according to the branch's author [1], the patchset isn't required
for merely using aarch64-darwin as a build system, so let's only apply it
when hostPlatform == aarch64-darwin to fix cross.

[0]: iains/gcc-12-branch#18
[1]: iains/gcc-12-branch#18 (comment)
winterqt added a commit to winterqt/nixpkgs that referenced this issue Feb 19, 2023
It seems that the patchset we apply to get some fixes for aarch64-darwin
support [0] breaks in unexpected ways when compiling a foreign toolchain [1].
Luckily, according to the branch's author [2], the patchset isn't required
for merely using aarch64-darwin as a build system, so let's only apply it
when hostPlatform == aarch64-darwin to fix cross.

[0]: https://github.com/iains/gcc-12-branch
[1]: iains/gcc-12-branch#18
[2]: iains/gcc-12-branch#18 (comment)
winterqt added a commit to winterqt/nixpkgs that referenced this issue Feb 19, 2023
It seems that the patchset we apply to get some fixes for aarch64-darwin
support [0] breaks in unexpected ways when compiling a foreign toolchain [1].
Luckily, according to the branch's author, the patchset isn't required
for merely using aarch64-darwin as the build system [2], so let's only apply
it when hostPlatform == aarch64-darwin to fix cross.

[0]: https://github.com/iains/gcc-12-branch
[1]: iains/gcc-12-branch#18
[2]: iains/gcc-12-branch#18 (comment)
@biergaizi
Copy link

biergaizi commented Feb 19, 2023

This problem seems to also affect Gentoo Prefix's bootstrapping procedure on macOS, during the stage2 bootstarp to build GCC 12.2, -nodefaultrpaths and -nodefaultexport are passed into clang, causing it to fail.

make[3]: Entering directory '/Users/leo/Gentoo/tmp/var/tmp/portage/sys-devel/gcc-12.2.0/work/build/libcc1'
/Users/leo/Gentoo/tmp/bin/bash ./libtool --tag=CXX   --mode=link g++ -m64 -std=gnu++11 -W -Wall  -fvisibility=hidden  -Wl,-undefined,dynamic_lookup -I/Users/leo/Gentoo/tmp/usr/include -pipe -O2 -module -export-symbols /Users/leo/Gentoo/tmp/var/tmp/portage/sys-devel/gcc-12.2.0/work/gcc-12-branch-gcc-12.2-darwin-r0/libcc1/libcc1.sym -Wc,-nodefaultrpaths,-nodefaultexport -Wl,-rpath,@loader_path  '-Wl,-search_paths_first' '-L/Users/leo/Gentoo/tmp/usr/lib' -o libcc1.la -rpath /Users/leo/Gentoo/tmp/usr/lib/ findcomp.lo libcc1.lo libcp1.lo compiler.lo names.lo callbacks.lo connection.lo marshall.lo    -Wc,../libiberty/pic/libiberty.a
libtool: link: sed -e 's,^,_,' < /Users/leo/Gentoo/tmp/var/tmp/portage/sys-devel/gcc-12.2.0/work/gcc-12-branch-gcc-12.2-darwin-r0/libcc1/libcc1.sym > .libs/libcc1-symbols.expsym
libtool: link: g++ -m64 -std=gnu++11  -o .libs/libcc1.0.so -bundle  .libs/findcomp.o .libs/libcc1.o .libs/libcp1.o .libs/compiler.o .libs/names.o .libs/callbacks.o .libs/connection.o .libs/marshall.o   -L/Users/leo/Gentoo/tmp/usr/lib  -m64 -Wl,-undefined -Wl,dynamic_lookup -nodefaultrpaths -nodefaultexport -Wl,-rpath -Wl,@loader_path -Wl,-search_paths_first ../libiberty/pic/libiberty.a   -Wl,-exported_symbols_list,.libs/libcc1-symbols.expsym
clang: error: unknown argument: '-nodefaultrpaths'
clang: error: unknown argument: '-nodefaultexport'
make[3]: *** [Makefile:576: libcc1.la] Error 1
make[3]: Leaving directory '/Users/leo/Gentoo/tmp/var/tmp/portage/sys-devel/gcc-12.2.0/work/build/libcc1'
make[3]: *** Waiting for unfinished jobs....

@iains
Copy link
Owner

iains commented Feb 19, 2023

you say "bootstrapping" - but I am surprised (because libcc1 is not built at stage 1 so it should always be built with GCC for a native (bootstrapped) build).

Please can you be more specific about what build you are performing and with the configure line?

@biergaizi
Copy link

No idea, I'm still investigating the problem. I'll report back if I find anything.

@biergaizi
Copy link

biergaizi commented Feb 19, 2023

BTW, there is a potential of terminology confusion.

The "stage2" I mentioned refers to the Gentoo "stage2" bootstrap, not the GCC "stage2" bootstrap. Like GCC, Gentoo itself uses a similar strategy to install itself on a foreign system.

During stage1, a minimal set of tools is built outside Gentoo, these tools are used together with host tools to create a base environment. During stage2, basic packages are rebuilt and installed within Gentoo, and during stage3 the system is also rebuilt globally. If I get it correctly, during Gentoo stage1 and stage2 bootstrap, GCC's own 3-stage bootstrap is disabled, only the first bootstrap pass is performed until Gentoo stage3.

I'm still not sure if it's a problem in the Gentoo bootstrap script or a problem in GCC Darwin. But the symptom is similar, so at least there's a direction for investigating it...

@iains
Copy link
Owner

iains commented Feb 19, 2023

Are you trying to build a cross-compiler from Linux to arm64-darwin? (if so, then that seems a possibly slightly different case, but plausibly affected) .. if yes, please post the configure line and I'll add that to the cases to investigate - unfortunately the short-term workaround will be no good for a cross from Linux targeting arm64 Darwin (you absolutely need the branches here to target arm64 darwin).. If you are targeting x86_64 Darwin .. then you can use the unpatched release branch.

@ProgramComputer
Copy link

ProgramComputer commented Feb 19, 2023

I have a similar issue on darwin-arm64 branch.

This was the error.
libtool: link: g++ -std=gnu++11 -o .libs/libcc1.0.so -bundle .libs/findcomp.o .libs/libcc1.o .libs/libcp1.o .libs/compiler.o .libs/names.o .libs/callbacks.o .libs/connection.o .libs/marshall.o -Wl,-undefined -Wl,dynamic_lookup -nodefaultrpaths -Wl,-rpath -Wl,@loader_path ../libiberty/pic/libiberty.a -Wl,-exported_symbols_list,.libs/libcc1-symbols.expsym clang: error: unknown argument: '-nodefaultrpaths'

I ran the below.

~/Downloads/gccarm/configure --with-gmp=/opt/homebrew/Cellar/gmp/6.2.1_1 --with-mpfr=/opt/homebrew/Cellar/mpfr/4.2.0 --with-mpc=/opt/homebrew/Cellar/libmpc/1.3.1 --with-isl=/opt/homebrew/Cellar/isl/0.25 --build=aarch64-apple-darwin20 --target=aarch64-apple-darwin20 \
--prefix="/usr/local" \
--disable-multilib \
--disable-libssp \
--disable-libstdcxx \
--enable-languages=c,fortran \
--with-ld="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" \
AR="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar" \
LD="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" \
AS="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/as" \
RANLIB="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib" \
NM="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/nm" \
AR_FOR_TARGET="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar" \
LD_FOR_TARGET="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" \
AS_FOR_TARGET="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/as" \
RANLIB_FOR_TARGET="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib" \
REAL_LD_FILE_NAME="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" \
NM_FOR_TARGET="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/nm" \
LIPO="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo" \
LIPO_FOR_TARGET="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo" \
CFLAGS_FOR_TARGET="-miphoneos-version-min=14.0" \
CXXFLAGS_FOR_TARGET="-miphoneos-version-min=14.0"\
LDFLAGS_FOR_TARGET="-miphoneos-version-min=14.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk -lSystem"\
--with-native-system-header-dir=/usr/include \
--with-sysroot=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk```

@iains
Copy link
Owner

iains commented Feb 19, 2023

Hmmm... as noted unless you are building a cross-compiler libcc1 should be built with GCC and therefore it should understand the options.

@fxcoudert ... I have some dim memory of clang being used to link GCC output .. could this be related?

(I am wondering why there is suddenly a bunch of similar reports) :)

clearly there is a problem to be fixed - but at the moment I have not enough information to narrow down what we want to work (it might be we have to detect whether the compiler supports the options in the libcc1 configure ... )

@biergaizi
Copy link

biergaizi commented Feb 19, 2023

I have some dim memory of clang being used to link GCC output .. could this be related?

Yes, I've now determined the problem is caused when clang is used to link GCC output. So this is not a GCC issue, but a downstream issue, though it's triggered by the upstream change. Basically, although it's not guaranteed, passing GCC output into clang actually worked in GCC 12.1.0 and earlier versions, before the incompatible linker options nodefaultrpaths and nodefaultexport were introduced in commit 07d831a and released in GCC 12.2.0.

As a result, some non-standard build procedures, whether unintentionally (probably @ProgramComputer's case) or intentionally (in the case of Gentoo prefix, it's used to simplify the process of building the toolchain during the early stage in a Gentoo installation), as the developers says:

*"Apple clang version "*|*"Apple LLVM version "*)
# recent binutils-apple are hard to build (C++11
# features, and cmake build system) so avoid going
# there, the system ld is good enough to bring us to
# stage3, after which the @system set will take care of
# the rest
linker=sys-devel/native-cctools
;;

So the lesson for our downstream users is: after GCC 12.2.0, GCC must be used all the time for linking and it should not be mixed with other compilers such as Apple's LLVM/clang. Though, for Gentoo, I think I'm going to use the workaround of disabling ENABLE_DARWIN_AT_RPATH during the initial toolchain compilation to maintain the current hack, so that no incompatible linker options are used.

Are you trying to build a cross-compiler from Linux to arm64-darwin? (if so, then that seems a possibly slightly different case, but plausibly affected).

No, it's not a cross-compile. The actual reason of this error has been explained above.

@iains
Copy link
Owner

iains commented Feb 19, 2023

It is probably a bit strong to say " after GCC 12.2.0, GCC must be used all the time for linking and it should not be mixed with others" we can be more flexible with some thinking, I am sure.

firstly, IMO we can adjust the configuration of libcc1 to determine if the options are supported and not use them if so (with the assumption that clang will not add the default stuff anyway so that is a NOP there anyway). In this specific case

OTOH, using clang as the linker is only going to work for arbitrary exes if it adds the runpaths as GCC does - otherwise you are forced to have a non-relocatable installation and to re-write the runtime library paths as described below. That's kinda sad, in a way, macOS has generally the policy that the user can drag and drop stuff around....

So, depending on your distribution, using fixed paths might/might not be problematic.

AFAIU, the home-brew mechanism:

  • uses the @rpaths for building (where it is needed to allow the compiler to find the correct libraries during the build - since DYLD_LIBRARY_PATH gets filtered out by /bin/sh).
  • then re-writes the library IDs to the install paths.

I (more than) half expect you to run into difficulties on modern macOS (10.11+) without the @rpaths used at build time.

I agree that making a fixed install is the path of least resistance, but would still aim to make GCC a good macOS citizen w.r.t to installation in non-super-user locations and by drag and drop.

@biergaizi
Copy link

biergaizi commented Feb 19, 2023

I (more than) half expect you to run into difficulties on modern macOS (10.11+) without the @rpaths used at build time.

In the particular case of installing Gentoo Prefix, the hardcoded rpath version of GCC would only be used in the initial stage of system installation temporarily, and it would later be overwritten in later stages with a proper version. Thus it's not a problem in this particular case. Also, moving the root directory of Gentoo Prefix is not officially supported anyway, so we have get-out-of-jail-free card...

But I fully agree, hardcoding rpath in general is not a good idea and mixing clang and GCC will inevitably cause this problem.

@ArsenArsen
Copy link
Contributor

hmm, shouldn't accepting fixed location during (gcc) stage 1 of bootstrap be OK, since later stages should compile a driver that acts well enough to handle rpaths correctly? stage1 would get thrown out anyway, and not be relocated during a single build

@iains
Copy link
Owner

iains commented Feb 19, 2023

an aside (for the Linux folks on this thread)....

You need to remember that macOS (from OSX 10.0) has "two level" library names. This means that the library name [from 10.0...10.4, at least] always includes its runpath + it's name (/path/to/libname.dylib). This, in turn, gets built into depending DSOs so that a separate runpath is not needed.

After 10.4, there is a second option where the library can be named @rpath/libname.dylib and the runpath can be supplied as a separate entity in the depending DSOs.

To work around the fixed runpath (original model) we used to use DYLD_LIBRARY_PATH to override the runpath mechanism and find the libraries in the build directories (otherwise they'd need to be installed to be found which is a non-starter for building toolchains).

After 10.11, Apple altered a lot of the system infrastructure such that DYLD_LIBRARY_PATHs are not passed through, but stripped from the environment (this is to prevent security exploits where bogus libraries are inserted). NOTE: DYLD_LIBRARY_PATH still works in a single command, it's just filtered by a bunch of system exes (including, significantly, /bin/sh which is hardwired in the auto-* tools). This breaks GCC's build (either subtly by mis-configuring target libs) or violently in the case we add a target lib that is not already installed somewhere on the system.

i tried a bunch of ways around this, but in the end the best solution is to shift to using the second approved runpath mechanism - since that allows us to build libraries that are neutral about their install position. We then ensure that the depending DSOs get runpaths suitable for their use (in the build dirs during build, or in the installed position after installation). This is done by the driver providing the runpaths based on where it is ...

So stage1 .. or N is not significant - we always use the newly-built GCC to build target libs (even for a cross-compiler)

We want to suppress addition of build-time runpaths into built libs that have dependent GCC DSOs (which is what one option is about - the other is about use of emulated TLS).

So, in general, clang will not be a suitable [automatic] link mechanism for GCC when the @rpath mechanism is used, since it has no [automatic] way to know the installed runpath for the libraries (of course, that can be added manually to the link-lines -- -Wl,-rpath,/blah/blah - the mechanism in use is perfectly within Apple's designs).

===

@rpath has had some bad press, IMO unwarranted, it's a reasonable design AFAICS and the bad experiences are mostly caused by folks not understanding what they needed to do .. but then fixed installations are easier to grok.

If one wants to support built applications that can be dragged & dropped or otherwise relocated by the end user, then @rpath and embedding them in the app bundle is neater than requiring admin privs to install some libraries in a common place.

HTH explanation-wise.

winterqt added a commit to winterqt/nixpkgs that referenced this issue Feb 21, 2023
It seems that the patchset we apply to get some fixes for aarch64-darwin
support [0] breaks in unexpected ways when compiling a foreign toolchain [1].
Luckily, according to the branch's author, the patchset isn't required
for merely using aarch64-darwin as the build system [2], so let's only apply
it when hostPlatform == aarch64-darwin to fix cross.

[0]: https://github.com/iains/gcc-12-branch
[1]: iains/gcc-12-branch#18
[2]: iains/gcc-12-branch#18 (comment)
winterqt added a commit to NixOS/nixpkgs that referenced this issue Feb 26, 2023
It seems that the patchset we apply to get some fixes for aarch64-darwin
support [0] breaks in unexpected ways when compiling a foreign toolchain [1].
Luckily, according to the branch's author, the patchset isn't required
for merely using aarch64-darwin as the build system [2], so let's only apply
it when hostPlatform == aarch64-darwin to fix cross.

[0]: https://github.com/iains/gcc-12-branch
[1]: iains/gcc-12-branch#18
[2]: iains/gcc-12-branch#18 (comment)
iains added a commit that referenced this issue May 9, 2023
It also breaks cross compiler builds when the build compiler does
not support the -nodefaultpaths option (etc.)  This is issue #18 on
the arm64 gcc-12 branch.

Signed-off-by: Iain Sandoe <iain@sandoe.co.uk>

libcc1/ChangeLog:

	* Makefile.am: Do not use @rpath for libcc1.
	* Makefile.in: Regnerate.
	* configure: Regenerate.
	* configure.ac: Do not use @rpath for libcc1.
@iains
Copy link
Owner

iains commented May 26, 2023

should be fixed in 12.3-darwin-r0

@iains iains closed this as completed May 26, 2023
tm-drtina pushed a commit to awakesecurity/nixpkgs that referenced this issue Apr 27, 2024
It seems that the patchset we apply to get some fixes for aarch64-darwin
support [0] breaks in unexpected ways when compiling a foreign toolchain [1].
Luckily, according to the branch's author, the patchset isn't required
for merely using aarch64-darwin as the build system [2], so let's only apply
it when hostPlatform == aarch64-darwin to fix cross.

[0]: https://github.com/iains/gcc-12-branch
[1]: iains/gcc-12-branch#18
[2]: iains/gcc-12-branch#18 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants