Closed richfelker closed 4 years ago
I get your point and I respect it.
I just wish that musl-cross-make
had a better documentation of how the build process is done.
I initially had planned that mussel
uses a musl-cross-make
style for the build steps, but failed to replicate what musl-cross-make
does with POSIX Dash.
Here's the original script: https://gist.github.com/firasuke/82ee9ed032aaf61af26826e07a3db14d
I've also extracted the steps that mcm
does for a cross compiled toolchain:
all
obj_binutils/.lc_configured
obj_binutils/.lc_built
obj_gcc/.lc_configured
obj_sysroot
obj_sysroot/usr
obj_sysroot/lib32
obj_sysroot/lib64
obj_sysroot/include
obj_gcc/gcc/.lc_built
obj_musl/.lc_configured
obj_sysroot/.lc_headers
obj_gcc/x86_64-linux-musl/libgcc/libgcc.a
obj_musl/.lc_built
musl
obj_sysroot/.lc_libs
obj_gcc/.lc_built
gcc
binutils
all
install
install-kernel-headers
install-musl
install-gcc
install-binutils
install
It shouldn't be this hard to understand musl-cross-make
and I don't mind modifying mussel
to an mcm
styled script written in POSIX Dash as long as it remains a single pass for GCC.
POSIX Dash
Small aside, but there's no such thing as "POSIX Dash". Dash is an implementaton of the standard POSIX shell, but putting #!/usr/bin/dash
in your scripts is not portable and won't run on any system I've used recently. The way you write a portable script is just by only using portable constructs, not by hard-coding a specific implementation's name/pathname.
I've also extracted the steps that mcm does for a cross compiled toolchain: ...
This is good. Basically, for each of those rules, you want to look at what commands it invokes. Binutils is easy and completely independent of libc, so I'll focus on the gcc part. The keys are:
obj_gcc/.lc_configured
- running gcc's configureobj_gcc/gcc/.lc_built
- make all-gcc
to compile gcc but not any target libsobj_musl/.lc_configured
- running musl'c configure using the xgcc
from the above. Note that at this point there is no libgcc.a
; musl doesn't care.obj_sysroot/.lc_headers
- running musl's make install-headers
into build sysrootobj_gcc/x86_64-linux-musl/libgcc/libgcc.a
- running gcc's make all-target-libgcc
with enable_shared=no
forced, to build just libgcc.a
.obj_musl/.lc_built
- building musl (now using libgcc.a
that was just built)obj_sysroot/.lc_libs
- installing musl into sysrootobj_gcc/.lc_built
- running the remainder of the gcc build process to get all target libs (including shared libgcc, libstdc++, etc.)Small aside, but there's no such thing as "POSIX Dash". Dash is an implementaton of the standard POSIX shell, but putting
#!/usr/bin/dash
in your scripts is not portable and won't run on any system I've used recently. The way you write a portable script is just by only using portable constructs, not by hard-coding a specific implementation's name/pathname.
Well it's to indicate that it was written in DASH, and is POSIX compliant nothing more. What's the portable version of a shebang, is it #!/bin/sh
? I don't think such a thing as a portable shebang exists...
This is good. Basically, for each of those rules, you want to look at what commands it invokes. Binutils is easy and completely independent of libc, so I'll focus on the gcc part. The keys are:
obj_gcc/.lc_configured
- running gcc's configureobj_gcc/gcc/.lc_built
-make all-gcc
to compile gcc but not any target libsobj_musl/.lc_configured
- running musl'c configure using thexgcc
from the above. Note that at this point there is nolibgcc.a
; musl doesn't care.obj_sysroot/.lc_headers
- running musl'smake install-headers
into build sysrootobj_gcc/x86_64-linux-musl/libgcc/libgcc.a
- running gcc'smake all-target-libgcc
withenable_shared=no
forced, to build justlibgcc.a
.obj_musl/.lc_built
- building musl (now usinglibgcc.a
that was just built)obj_sysroot/.lc_libs
- installing musl into sysrootobj_gcc/.lc_built
- running the remainder of the gcc build process to get all target libs (including shared libgcc, libstdc++, etc.)
I'll modify mussel back to an mcm style script, and report breakages here.
Also what's with:
obj_sysroot/usr: | obj_sysroot
ln -sf . $@
Wouldn't passing --with-native-system-header-dir=/include
to gcc remove the need for such a symlink? Another solution would be to modify lib64
to ../../lib
and not ../lib
in the t-linux64
file (in GCC's sources) since $XTARGET/bin/ld
is called before bin/$XTARGET-ld
(but that's the uglier one of the solutions).
Also, can you elaborate more on why we're using a build sysroot (obj_sysroot
) in addition to a regular one $SYSROOT
?
Well it's to indicate that it was written in DASH, and is POSIX compliant nothing more. What's the portable version of a shebang, is it #!/bin/sh? I don't think such a thing as a portable shebang exists...
Indeed, POSIX explicitly/intentionally does not specify one, which is annoying. But in practice, #!/bin/sh is how you get a POSIX shell in any relevant real-world environment.
Wouldn't passing --with-native-system-header-dir=/include to gcc remove the need for such a symlink?
Yes, I think so. There's an open issue about this on the mailing list.
Another solution would be to modify lib64...
Yes, you're probably right about that too. It might not even be needed now that we're disabling multilib properly. However generally I prefer working around things gcc's build system does in a black-box manner over applying patchs to GCC, since the latter is less maintainable.
Also, can you elaborate more on why we're using a build sysroot (obj_sysroot) in addition to a regular one $SYSROOT?
This is to make it so that nothing in the build depends on files outside of the build tree. The final install location is supposed to be write-only so that the build isn't affected by files in there from previous builds, manually installed libraries, etc. However it may (probably does) make more sense to "install" binutils and gcc to a temp staging dir under the build dir, and only perform the final make install via cp -a or similar. This would also allow removing some unwanted files that the gcc/binutils install processes create before they get installed. However, it would also require more temp/working space.
Indeed, POSIX explicitly/intentionally does not specify one, which is annoying. But in practice,
#!/bin/sh
is how you get a POSIX shell in any relevant real-world environment.
I see.
Yes, I think so. There's an open issue about this on the mailing list.
Are you referring to this?
Yes, you're probably right about that too. It might not even be needed now that we're disabling multilib properly. However generally I prefer working around things gcc's build system does in a black-box manner over applying patchs to GCC, since the latter is less maintainable.
Ah yes, you're setting this MULTILIB_OSDIRNAMES=
to empty which removes the need for that.
This is to make it so that nothing in the build depends on files outside of the build tree. The final install location is supposed to be write-only so that the build isn't affected by files in there from previous builds, manually installed libraries, etc. However it may (probably does) make more sense to "install" binutils and gcc to a temp staging dir under the build dir, and only perform the final
make install
viacp -a
or similar. This would also allow removing some unwanted files that the gcc/binutils install processes create before they get installed. However, it would also require more temp/working space.
This is probably where my confusion stems from.
I managed to get the mcm-like version of mussel to work up to the point when libgomp
is being built within gcc, then I received the following error
configure:3907: checking whether the C compiler works
3 configure:3929: /home/firasuke/Projects/test2/builds/gcc/./gcc/xgcc -B/home/firasuke/Projects/test2/builds/gcc/./gcc/ -B/x86_64-linux-musl/bin/ -B/x86_64-linux-musl/ lib/ -isystem /x86_64-linux-musl/include -isystem /x86_64-linux-musl/sys-include --sysroot=/home/firasuke/Projects/test2/bsysroot -g -O2 conftest.c >&5
2 /home/firasuke/Projects/test2/builds/binutils/ld/ld-new: cannot find -lgcc_s
1 /home/firasuke/Projects/test2/builds/binutils/ld/ld-new: cannot find -lgcc_s
Also, in the README of musl-cross-make
you state that:
One configured invocation them configures all the GNU toolchain components together in a manner
that does not require any of them to be installed in order for the others to use them.
This is confusing because each package is configured in its own step, and they're not all configured with a single ./configure
invocation as one might infer from the statement above.
Gave it another go, and it seems to fail with the same error as above. It gets pretty far with the build. If we numbered the steps of mcm
as follows:
1- all
2- obj_binutils/.lc_configured
3- obj_binutils/.lc_built
4- obj_gcc/.lc_configured
5- obj_sysroot
6- obj_sysroot/usr
7- obj_sysroot/lib32
8- obj_sysroot/lib64
9- obj_sysroot/include
10- obj_gcc/gcc/.lc_built
11- obj_musl/.lc_configured
12- obj_sysroot/.lc_headers
13- obj_gcc/x86_64-linux-musl/libgcc/libgcc.a
14- obj_musl/.lc_built
15- musl
16- obj_sysroot/.lc_libs
17- obj_gcc/.lc_built
18- gcc
19- binutils
20- all
21- install
22- install-kernel-headers
23- install-musl
24- install-gcc
25- install-binutils
26- install
Then it's failing at step no. 17, which is quite far (the last step that requires building), the step is obj_gcc/.lc_built
and it's failing particularly after successfully building the shared libgcc, when building libgomp
with the error that the C compiler doesn't work, and upon inspecting the config.log
it seems that the ld-new
inside binutils
build directory isn't finding the currently built shared libgcc?
configure:3907: checking whether the C compiler works
configure:3929: /home/firasuke/Projects/test2/builds/gcc/./gcc/xgcc -B/home/firasuke/Projects/test2/builds/gcc/./gcc/ -B/x86_64-linux-musl/bin/ -B/x86_64-linux-musl/ lib/ -isystem /x86_64-linux-musl/include -isystem /x86_64-linux-musl/sys-include --sysroot=/home/firasuke/Projects/test2/bsysroot -g -O2 conftest.c >&5
/home/firasuke/Projects/test2/builds/binutils/ld/ld-new: cannot find -lgcc_s
/home/firasuke/Projects/test2/builds/binutils/ld/ld-new: cannot find -lgcc_s
Could it be because the shared libgcc wasn't installed before attempting to build the other libs (libstdc++-v3
, libgomp
...)?
This is confusing because each package is configured in its own step, and they're not all configured with a single ./configure invocation as one might infer from the statement above.
Thanks for catching that. It's outdated documentation because mcm used to work that way. Eventually it was determined to be fragile and incompatible with any nontrivial amount of version skew between binutils and gcc, and contributors worked out a way to get it to use the newly built binutils without configuring binutils and gcc together in a combined source tree.
The gcc target libs build process should work fine without anything being installed. It's very odd/surprising to me, though, that the command that fails is attempting to use -lgcc_s
internally since it's not present on the command line. Was gcc configured to use shared libgcc by default?
Not really, enable_shared=no
was passed when building libgcc.a
, and that's about it. The configuration is identical to that of mcm
, and I'm unsure why it's trying to find the shared version of libgcc.
I think removing enable_shared=no
allow for both the shared and static versions of libgcc to exist, and would resolve the error above. That, or adding enable_shared=no
when building the final gcc at step 17, which I think is a bad idea.
Ok, removing enable_shared=no
prevented libgcc
from being built at step 13, because it obviously requires a C library to build a shared version:
gcc_s.so.1.tmp ./libgcc_s.so.1 && (echo "/* GNU ld script"; echo " Use the shared library, but some functions are only in"; echo " the static library. */"; echo "GROUP ( libgcc_s.so.1 -lgcc )" ) > ./libgcc_s.so
/home/firasuke/Projects/test2/builds/binutils/ld/ld-new: cannot find crti.o: No such file or directory
/home/firasuke/Projects/test2/builds/binutils/ld/ld-new: cannot find -lc
/home/firasuke/Projects/test2/builds/binutils/ld/ld-new: cannot find crtn.o: No such file or directory
And adding enable_shared=no
to the final GCC built at step 17 also fails with the same error above cannot find -lgcc_s
.
enable_shared=no
should be there only for the early libgcc.a
part. However what I'm confused about is how the command:
/home/firasuke/Projects/test2/builds/gcc/./gcc/xgcc -B/home/firasuke/Projects/test2/builds/gcc/./gcc/ -B/x86_64-linux-musl/bin/ -B/x86_64-linux-musl/ lib/ -isystem /x86_64-linux-musl/include -isystem /x86_64-linux-musl/sys-include --sysroot=/home/firasuke/Projects/test2/bsysroot -g -O2 conftest.c >&5
is causing -lgcc_s
to appear on the link command line (as shown in the error). It should not be linked by default, only as a dependency of other libs or by explicit request.
Regarding this issue, I've:
-ffast-math
entirely-ffast-math
, powerpc
and powerpc64
)The build works for all archs, and it's still a single pass to build GCC.
I have one question though, and I can be confident that the new modifications will fix the broken ABI.
Since musl-headers
is the first package we have, how should it be configured? Is it ok not to pass ARCH
, CC
and CROSS_COMPILE
if all we want are the headers? We're currently passing ARCH=$XTARGET
, CC=gcc
(which is the host's gcc) and we're leaving the value of CROSS_COMPILE
empty, and regardless of the value we provide to ARCH
, the generated config.mak will still use the ARCH
of the host system (so if we were on x86-64
and we wanted to target aarch64
, we would pass ARCH=aarch64
and CC=gcc
and CROSS_COMPILE=
to configure musl-headers initially just to get the headers from musl, we would still get ARCH=x86-64
in the generated config.mak
, is passing these variables required if all we want is the headers? Can't we just do ./configure
(without any variable) then make install-headers
if all we want is the headers?
No, the headers differ per arch. You can skip running configure at all, and do make install-headers ARCH=aarch64
or whatever, and it should work.
Alright, I'm now skipping the configuration of musl-headers
and relying on make ARCH=$XARCH prefix=/usr DESTDIR=$MSYSROOT install-headers
to install musl's headers per targetted arch.
I'm closing this issue as all the changes you proposed have been made.
Thanks for your time and effort.
All three patches (
-ffast-math
, powerpc, and powerpc64) are removing checks for conditions that produce a broken libc. By removing the checks, you're getting yourself (and your users) a broken libc. It will produce seriously wrong results, especially for thestrtod
andprintf
families, and might even be able to produce exploitable buffer overflows in them. It will also produce powerpc toolchains with silently broken ABI.All of these patches should be removed, and the conditions that caused you to add them investigated and fixed. (They're indicative of your cross toolchain procedure not actually working.)