When bootstrapping a cross toolchain with GCC and glibc, it's desirable to keep down the number of GCC builds needed: to be able to build an initial static-only C-only GCC, use that to build glibc, and then build the full compiler with the resulting glibc. The aim is that if glibc were then rebuilt with the full compiler, the results would be identical to the glibc built with the initial compiler. (See <https://sourceware.org/ml/libc-alpha/2012-03/msg00960.html> for more on how ideally this might work; really it should only be target libraries that need rebuilding, not the compiler at all.)
In support of this, I put various changes into glibc 2.17, and other changes into GCC 4.8 to make static libgcc sufficiently similar in an initial bootstrap build and a full build so as not to affect the resulting glibc binaries (see <http://gcc.gnu.org/ml/gcc-patches/2012-08/msg01219.html> and <http://gcc.gnu.org/ml/gcc-patches/2012-08/msg01462.html>). However, while this solved the problem of stable bootstrapped glibc binaries with just two GCC builds for ARM, it did not do so for all architectures. Specifically, for architectures with architecture-specific stack-protector code in GCC, the first bootstrap GCC gets configured thinking glibc lacks the corresponding glibc support, meaning it is configured in a way incompatible with building glibc (but compatible with installing glibc headers if you do a three-compiler bootstrap, with a second compiler built after glibc was configured with the first compiler to install glibc headers, that second compiler used to build glibc, and a third compiler built after that). That can be worked around by setting gcc_cv_libc_provides_ssp=yes when configuring GCC, but setting an internal configure variable like that shouldn't be needed. Instead, this patch provides a properly documented configure option --with-glibc-version to use to specify the minimum glibc version a given compiler will target, for this case and also for more obscure cases where the autodetection may not work (e.g. if a sysroot headers suffix is used so the headers aren't found in the location expected by the configure tests). Different configure tests detected and used glibc versions in different ways. The stack-protector test checked for a glibc version number in headers, the long-double-128 test checked for target architecture and __LONG_DOUBLE_MATH_OPTIONAL, and the gnu-unique-object test used ldd --version and so only worked at all for native toolchains. After this patch, the configure script sets up glibc_version_major and glibc_version_minor variables (from the configure option if used, or headers if not used), and all those tests use those variables (in addition to whatever tests not of glibc version numbers are still relevant - __LONG_DOUBLE_MATH_OPTIONAL is kept as a fallback in the long-double-128 tests because uClibc defines it but pretends to be glibc 2.2). Thus, a documented configure option can be used to get correct stack-protector support in a bootstrap compiler, while the fixed gnu-unique-object test works for cross compilation. Any future cases where GCC needs to know the target glibc version number can also use the same configuration logic. Note that this patch does *not* address the --enable-initfini-array differences between native and cross compilation. I believe Thomas intends to deal with those (in GCC and elsewhere in the toolchain). I think there the correct default is to enable the feature by default for ELF targets (since it's about using a standard feature of ELF) and then blacklist (if necessary with version number checks) particular targets found to be broken, without doing anything special for native tools. Bootstrapped with no regressions on x86_64-unknown-linux-gnu. OK to commit? 2013-11-06 Joseph Myers <jos...@codesourcery.com> * acinclude.m4 (GCC_GLIBC_VERSION_GTE_IFELSE): New configure macro. * configure.ac: Determine target_header_dir earlier. (--with-glibc-version): New configure option. Use GCC_GLIBC_VERSION_GTE_IFELSE in enable_gnu_unique_object, gcc_cv_libc_provides_ssp and gcc_cv_target_ldbl128 tests. * configure: Regenerate. * doc/install.texi (--enable-gnu-unique-object): Don't refer to native toolchains for default. (--with-glibc-version): Document. Index: gcc/acinclude.m4 =================================================================== --- gcc/acinclude.m4 (revision 204453) +++ gcc/acinclude.m4 (working copy) @@ -561,3 +561,18 @@ dnl Make sure that build_exeext is looked for AC_DEFUN([gcc_AC_BUILD_EXEEXT], [ ac_executable_extensions="$build_exeext"]) +dnl GCC_GLIBC_VERSION_GTE_IFELSE(MAJOR, MINOR, IF-TRUE, IF-FALSE) +dnl ------------------------------------------------------------- +dnl If the target glibc version ($glibc_version_major.$glibc_version_minor) +dnl is at least MAJOR.MINOR, call IF-TRUE, otherwise call IF-FALSE. +AC_DEFUN([GCC_GLIBC_VERSION_GTE_IFELSE], +[ +if test $glibc_version_major -gt $1 \ + || ( test $glibc_version_major -eq $1 && test $glibc_version_minor -ge $2 ); +then + : + $3 +else + : + $4 +fi]) Index: gcc/configure.ac =================================================================== --- gcc/configure.ac (revision 204453) +++ gcc/configure.ac (working copy) @@ -4306,6 +4306,50 @@ gcc_GAS_CHECK_FEATURE([.lcomm with alignment], gcc [AC_DEFINE(HAVE_GAS_LCOMM_WITH_ALIGNMENT, 1, [Define if your assembler supports .lcomm with an alignment field.])]) +if test x$with_sysroot = x && test x$host = x$target \ + && test "$prefix" != "/usr" && test "x$prefix" != "x$local_prefix" \ + && test "$prefix" != "NONE"; then + AC_DEFINE_UNQUOTED(PREFIX_INCLUDE_DIR, "$prefix/include", +[Define to PREFIX/include if cpp should also search that directory.]) +fi + +if test x$host != x$target || test "x$TARGET_SYSTEM_ROOT" != x; then + if test "x$with_headers" != x; then + target_header_dir=$with_headers + elif test "x$with_sysroot" = x; then + target_header_dir="${test_exec_prefix}/${target_noncanonical}/sys-include" + elif test "x$with_build_sysroot" != "x"; then + target_header_dir="${with_build_sysroot}${native_system_header_dir}" + elif test "x$with_sysroot" = xyes; then + target_header_dir="${test_exec_prefix}/${target_noncanonical}/sys-root${native_system_header_dir}" + else + target_header_dir="${with_sysroot}${native_system_header_dir}" + fi +else + target_header_dir=${native_system_header_dir} +fi + +# Determine the version of glibc, if any, used on the target. +AC_MSG_CHECKING([for target glibc version]) +AC_ARG_WITH([glibc-version], + [AS_HELP_STRING([--with-glibc-version=M.N], + [assume GCC used with glibc version M.N or later])], [ +if [echo "$with_glibc_version" | grep '^[0-9][0-9]*\.[0-9][0-9]*$']; then + glibc_version_major=`echo "$with_glibc_version" | sed -e 's/\..*//'` + glibc_version_minor=`echo "$with_glibc_version" | sed -e 's/.*\.//'` +else + AC_MSG_ERROR([option --with-glibc-version requires a version number M.N]) +fi], [ +glibc_version_major=0 +glibc_version_minor=0 +[if test -f $target_header_dir/features.h \ + && glibc_version_major_define=`$EGREP '^[ ]*#[ ]*define[ ]+__GLIBC__[ ]+[0-9]' $target_header_dir/features.h` \ + && glibc_version_minor_define=`$EGREP '^[ ]*#[ ]*define[ ]+__GLIBC_MINOR__[ ]+[0-9]' $target_header_dir/features.h`; then + glibc_version_major=`echo "$glibc_version_major_define" | sed -e 's/.*__GLIBC__[ ]*//'` + glibc_version_minor=`echo "$glibc_version_minor_define" | sed -e 's/.*__GLIBC_MINOR__[ ]*//'` +fi]]) +AC_MSG_RESULT([$glibc_version_major.$glibc_version_minor]) + AC_ARG_ENABLE(gnu-unique-object, [AS_HELP_STRING([--enable-gnu-unique-object], [enable the use of the @gnu_unique_object ELF extension on glibc systems])], @@ -4319,16 +4363,8 @@ Valid choices are 'yes' and 'no'.]) ;; [.type foo, '$target_type_format_char'gnu_unique_object],, # We need to unquote above to to use the definition from config.gcc. # Also check for ld.so support, i.e. glibc 2.11 or higher. - [[if test x$host = x$build -a x$host = x$target && - ldd --version 2>/dev/null && - glibcver=`ldd --version 2>/dev/null | sed 's/.* //;q'`; then - glibcmajor=`expr "$glibcver" : "\([0-9]*\)"` - glibcminor=`expr "$glibcver" : "[2-9]*\.\([0-9]*\)"` - glibcnum=`expr $glibcmajor \* 1000 + $glibcminor` - if test "$glibcnum" -ge 2011 ; then - enable_gnu_unique_object=yes - fi - fi]])]) + [GCC_GLIBC_VERSION_GTE_IFELSE([2], [11], [enable_gnu_unique_object=yes], )] + )]) if test x$enable_gnu_unique_object = xyes; then AC_DEFINE(HAVE_GAS_GNU_UNIQUE_OBJECT, 1, [Define if your assembler supports @gnu_unique_object.]) @@ -4816,49 +4852,19 @@ if test x"$gcc_cv_ld_sysroot" = xyes; then [Define if your linker supports --sysroot.]) fi -if test x$with_sysroot = x && test x$host = x$target \ - && test "$prefix" != "/usr" && test "x$prefix" != "x$local_prefix" \ - && test "$prefix" != "NONE"; then - AC_DEFINE_UNQUOTED(PREFIX_INCLUDE_DIR, "$prefix/include", -[Define to PREFIX/include if cpp should also search that directory.]) -fi - -if test x$host != x$target || test "x$TARGET_SYSTEM_ROOT" != x; then - if test "x$with_headers" != x; then - target_header_dir=$with_headers - elif test "x$with_sysroot" = x; then - target_header_dir="${test_exec_prefix}/${target_noncanonical}/sys-include" - elif test "x$with_build_sysroot" != "x"; then - target_header_dir="${with_build_sysroot}${native_system_header_dir}" - elif test "x$with_sysroot" = xyes; then - target_header_dir="${test_exec_prefix}/${target_noncanonical}/sys-root${native_system_header_dir}" - else - target_header_dir="${with_sysroot}${native_system_header_dir}" - fi -else - target_header_dir=${native_system_header_dir} -fi - # Test for stack protector support in target C library. AC_CACHE_CHECK(__stack_chk_fail in target C library, gcc_cv_libc_provides_ssp, [gcc_cv_libc_provides_ssp=no case "$target" in *-*-linux* | *-*-kfreebsd*-gnu | *-*-knetbsd*-gnu) - [# glibc 2.4 and later provides __stack_chk_fail and + # glibc 2.4 and later provides __stack_chk_fail and # either __stack_chk_guard, or TLS access to stack guard canary. - if test -f $target_header_dir/features.h \ + GCC_GLIBC_VERSION_GTE_IFELSE([2], [4], [gcc_cv_libc_provides_ssp=yes], [ + [if test -f $target_header_dir/features.h \ && $EGREP '^[ ]*#[ ]*define[ ]+__GNU_LIBRARY__[ ]+([1-9][0-9]|[6-9])' \ $target_header_dir/features.h > /dev/null; then - if $EGREP '^[ ]*#[ ]*define[ ]+__GLIBC__[ ]+([1-9][0-9]|[3-9])' \ - $target_header_dir/features.h > /dev/null; then - gcc_cv_libc_provides_ssp=yes - elif $EGREP '^[ ]*#[ ]*define[ ]+__GLIBC__[ ]+2' \ - $target_header_dir/features.h > /dev/null \ - && $EGREP '^[ ]*#[ ]*define[ ]+__GLIBC_MINOR__[ ]+([1-9][0-9]|[4-9])' \ - $target_header_dir/features.h > /dev/null; then - gcc_cv_libc_provides_ssp=yes - elif $EGREP '^[ ]*#[ ]*define[ ]+__UCLIBC__[ ]+1' \ + if $EGREP '^[ ]*#[ ]*define[ ]+__UCLIBC__[ ]+1' \ $target_header_dir/features.h > /dev/null && \ test -f $target_header_dir/bits/uClibc_config.h && \ $EGREP '^[ ]*#[ ]*define[ ]+__UCLIBC_HAS_SSP__[ ]+1' \ @@ -4870,7 +4876,7 @@ AC_CACHE_CHECK(__stack_chk_fail in target C librar && $EGREP '^[ ]*#[ ]*define[ ]+__BIONIC__[ ]+1' \ $target_header_dir/sys/cdefs.h > /dev/null; then gcc_cv_libc_provides_ssp=yes - fi] + fi]]) ;; *-*-gnu*) # Avoid complicated tests (see @@ -4913,11 +4919,12 @@ case "$target" in [AS_HELP_STRING([--with-long-double-128], [use 128-bit long double by default])], gcc_cv_target_ldbl128="$with_long_double_128", - [[gcc_cv_target_ldbl128=no + [GCC_GLIBC_VERSION_GTE_IFELSE([2], [4], [gcc_cv_target_ldbl128=yes], [ + [gcc_cv_target_ldbl128=no grep '^[ ]*#[ ]*define[ ][ ]*__LONG_DOUBLE_MATH_OPTIONAL' \ $target_header_dir/bits/wordsize.h > /dev/null 2>&1 \ && gcc_cv_target_ldbl128=yes - ]]) + ]])]) ;; esac if test x$gcc_cv_target_ldbl128 = xyes; then Index: gcc/configure =================================================================== --- gcc/configure (revision 204453) +++ gcc/configure (working copy) @@ -915,6 +915,7 @@ with_plugin_ld enable_gnu_indirect_function enable_initfini_array enable_comdat +with_glibc_version enable_gnu_unique_object enable_linker_build_id with_long_double_128 @@ -1680,6 +1681,8 @@ Optional Packages: both] --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-plugin-ld=[ARG] specify the plugin linker + --with-glibc-version=M.N + assume GCC used with glibc version M.N or later --with-long-double-128 use 128-bit long double by default --with-gc={page,zone} this option is not supported anymore. It used to choose the garbage collection mechanism to use with @@ -17913,7 +17916,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 17916 "configure" +#line 17919 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -18019,7 +18022,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 18022 "configure" +#line 18025 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -26386,6 +26389,60 @@ $as_echo "#define HAVE_GAS_LCOMM_WITH_ALIGNMENT 1" fi +if test x$with_sysroot = x && test x$host = x$target \ + && test "$prefix" != "/usr" && test "x$prefix" != "x$local_prefix" \ + && test "$prefix" != "NONE"; then + +cat >>confdefs.h <<_ACEOF +#define PREFIX_INCLUDE_DIR "$prefix/include" +_ACEOF + +fi + +if test x$host != x$target || test "x$TARGET_SYSTEM_ROOT" != x; then + if test "x$with_headers" != x; then + target_header_dir=$with_headers + elif test "x$with_sysroot" = x; then + target_header_dir="${test_exec_prefix}/${target_noncanonical}/sys-include" + elif test "x$with_build_sysroot" != "x"; then + target_header_dir="${with_build_sysroot}${native_system_header_dir}" + elif test "x$with_sysroot" = xyes; then + target_header_dir="${test_exec_prefix}/${target_noncanonical}/sys-root${native_system_header_dir}" + else + target_header_dir="${with_sysroot}${native_system_header_dir}" + fi +else + target_header_dir=${native_system_header_dir} +fi + +# Determine the version of glibc, if any, used on the target. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for target glibc version" >&5 +$as_echo_n "checking for target glibc version... " >&6; } + +# Check whether --with-glibc-version was given. +if test "${with_glibc_version+set}" = set; then : + withval=$with_glibc_version; +if echo "$with_glibc_version" | grep '^[0-9][0-9]*\.[0-9][0-9]*$'; then + glibc_version_major=`echo "$with_glibc_version" | sed -e 's/\..*//'` + glibc_version_minor=`echo "$with_glibc_version" | sed -e 's/.*\.//'` +else + as_fn_error "option --with-glibc-version requires a version number M.N" "$LINENO" 5 +fi +else + +glibc_version_major=0 +glibc_version_minor=0 +if test -f $target_header_dir/features.h \ + && glibc_version_major_define=`$EGREP '^[ ]*#[ ]*define[ ]+__GLIBC__[ ]+[0-9]' $target_header_dir/features.h` \ + && glibc_version_minor_define=`$EGREP '^[ ]*#[ ]*define[ ]+__GLIBC_MINOR__[ ]+[0-9]' $target_header_dir/features.h`; then + glibc_version_major=`echo "$glibc_version_major_define" | sed -e 's/.*__GLIBC__[ ]*//'` + glibc_version_minor=`echo "$glibc_version_minor_define" | sed -e 's/.*__GLIBC_MINOR__[ ]*//'` +fi +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibc_version_major.$glibc_version_minor" >&5 +$as_echo "$glibc_version_major.$glibc_version_minor" >&6; } + # Check whether --enable-gnu-unique-object was given. if test "${enable_gnu_unique_object+set}" = set; then : enableval=$enable_gnu_unique_object; case $enable_gnu_unique_object in @@ -26427,18 +26484,19 @@ $as_echo "$gcc_cv_as_gnu_unique_object" >&6; } if test $gcc_cv_as_gnu_unique_object = yes; then # We need to unquote above to to use the definition from config.gcc. # Also check for ld.so support, i.e. glibc 2.11 or higher. - if test x$host = x$build -a x$host = x$target && - ldd --version 2>/dev/null && - glibcver=`ldd --version 2>/dev/null | sed 's/.* //;q'`; then - glibcmajor=`expr "$glibcver" : "\([0-9]*\)"` - glibcminor=`expr "$glibcver" : "[2-9]*\.\([0-9]*\)"` - glibcnum=`expr $glibcmajor \* 1000 + $glibcminor` - if test "$glibcnum" -ge 2011 ; then - enable_gnu_unique_object=yes - fi - fi + +if test $glibc_version_major -gt 2 \ + || ( test $glibc_version_major -eq 2 && test $glibc_version_minor -ge 11 ); +then + : + enable_gnu_unique_object=yes +else + : + fi + fi +fi if test x$enable_gnu_unique_object = xyes; then @@ -27015,32 +27073,6 @@ $as_echo "#define HAVE_LD_SYSROOT 1" >>confdefs.h fi -if test x$with_sysroot = x && test x$host = x$target \ - && test "$prefix" != "/usr" && test "x$prefix" != "x$local_prefix" \ - && test "$prefix" != "NONE"; then - -cat >>confdefs.h <<_ACEOF -#define PREFIX_INCLUDE_DIR "$prefix/include" -_ACEOF - -fi - -if test x$host != x$target || test "x$TARGET_SYSTEM_ROOT" != x; then - if test "x$with_headers" != x; then - target_header_dir=$with_headers - elif test "x$with_sysroot" = x; then - target_header_dir="${test_exec_prefix}/${target_noncanonical}/sys-include" - elif test "x$with_build_sysroot" != "x"; then - target_header_dir="${with_build_sysroot}${native_system_header_dir}" - elif test "x$with_sysroot" = xyes; then - target_header_dir="${test_exec_prefix}/${target_noncanonical}/sys-root${native_system_header_dir}" - else - target_header_dir="${with_sysroot}${native_system_header_dir}" - fi -else - target_header_dir=${native_system_header_dir} -fi - # Test for stack protector support in target C library. { $as_echo "$as_me:${as_lineno-$LINENO}: checking __stack_chk_fail in target C library" >&5 $as_echo_n "checking __stack_chk_fail in target C library... " >&6; } @@ -27052,18 +27084,19 @@ else *-*-linux* | *-*-kfreebsd*-gnu | *-*-knetbsd*-gnu) # glibc 2.4 and later provides __stack_chk_fail and # either __stack_chk_guard, or TLS access to stack guard canary. + +if test $glibc_version_major -gt 2 \ + || ( test $glibc_version_major -eq 2 && test $glibc_version_minor -ge 4 ); +then + : + gcc_cv_libc_provides_ssp=yes +else + : + if test -f $target_header_dir/features.h \ && $EGREP '^[ ]*#[ ]*define[ ]+__GNU_LIBRARY__[ ]+([1-9][0-9]|[6-9])' \ $target_header_dir/features.h > /dev/null; then - if $EGREP '^[ ]*#[ ]*define[ ]+__GLIBC__[ ]+([1-9][0-9]|[3-9])' \ - $target_header_dir/features.h > /dev/null; then - gcc_cv_libc_provides_ssp=yes - elif $EGREP '^[ ]*#[ ]*define[ ]+__GLIBC__[ ]+2' \ - $target_header_dir/features.h > /dev/null \ - && $EGREP '^[ ]*#[ ]*define[ ]+__GLIBC_MINOR__[ ]+([1-9][0-9]|[4-9])' \ - $target_header_dir/features.h > /dev/null; then - gcc_cv_libc_provides_ssp=yes - elif $EGREP '^[ ]*#[ ]*define[ ]+__UCLIBC__[ ]+1' \ + if $EGREP '^[ ]*#[ ]*define[ ]+__UCLIBC__[ ]+1' \ $target_header_dir/features.h > /dev/null && \ test -f $target_header_dir/bits/uClibc_config.h && \ $EGREP '^[ ]*#[ ]*define[ ]+__UCLIBC_HAS_SSP__[ ]+1' \ @@ -27076,6 +27109,7 @@ else $target_header_dir/sys/cdefs.h > /dev/null; then gcc_cv_libc_provides_ssp=yes fi +fi ;; *-*-gnu*) # Avoid complicated tests (see @@ -27131,12 +27165,22 @@ case "$target" in if test "${with_long_double_128+set}" = set; then : withval=$with_long_double_128; gcc_cv_target_ldbl128="$with_long_double_128" else - gcc_cv_target_ldbl128=no + +if test $glibc_version_major -gt 2 \ + || ( test $glibc_version_major -eq 2 && test $glibc_version_minor -ge 4 ); +then + : + gcc_cv_target_ldbl128=yes +else + : + + gcc_cv_target_ldbl128=no grep '^[ ]*#[ ]*define[ ][ ]*__LONG_DOUBLE_MATH_OPTIONAL' \ $target_header_dir/bits/wordsize.h > /dev/null 2>&1 \ && gcc_cv_target_ldbl128=yes fi +fi ;; esac Index: gcc/doc/install.texi =================================================================== --- gcc/doc/install.texi (revision 204453) +++ gcc/doc/install.texi (working copy) @@ -1751,7 +1751,7 @@ linker for all final links. @var{choice} can be on @itemx --disable-gnu-unique-object Tells GCC to use the gnu_unique_object relocation for C++ template static data members and inline function local statics. Enabled by -default for a native toolchain with an assembler that accepts it and +default for a toolchain with an assembler that accepts it and GLIBC 2.11 or above, otherwise disabled. @item --enable-lto @@ -1773,6 +1773,18 @@ produce shorter header file paths in diagnostics a files, but these changed header paths may conflict with some compilation environments. Enabled by default, and may be disabled using @option{--disable-canonical-system-headers}. + +@item --with-glibc-version=@var{major}.@var{minor} +Tell GCC that when the GNU C Library (glibc) is used on the target it +will be version @var{major}.@var{minor} or later. Normally this can +be detected from the C library's header files, but this option may be +needed when bootstrapping a cross toolchain without the header files +available for building the initial bootstrap compiler. + +If GCC is configured with some multilibs that use glibc and some that +do not, this option applies only to the multilibs that use glibc. +However, such configurations may not work well as not all the relevant +configuration in GCC is on a per-multilib basis. @end table @subheading Cross-Compiler-Specific Options -- Joseph S. Myers jos...@codesourcery.com