From 34636efceda7a89d6f0bb66d63e422fd1f215da3 Mon Sep 17 00:00:00 2001 From: Sergei Trofimovich Date: Mon, 18 Jul 2022 13:11:48 +0100 Subject: [PATCH] gcc: pass --with-build-sysroot=/ for gcc builds Without this change cross-built gcc fails to detect stack protector style: $ nix log -f pkgs/stdenv/linux/make-bootstrap-tools-cross.nix powerpc64le.bootGCC | fgrep __stack_chk_fail checking __stack_chk_fail in target C library... no checking __stack_chk_fail in target C library... no It happens because gcc treats search paths differently: https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/configure.ac;h=446747311a6aec3c810ad6aa4190f7bd383b94f7;hb=HEAD#l2458 if test x$host != x$target || test "x$TARGET_SYSTEM_ROOT" != x || test x$build != x$host || test "x$with_build_sysroot" != x; then ... if test "x$with_build_sysroot" != "x"; then target_header_dir="${with_build_sysroot}${native_system_header_dir}" elif test "x$with_sysroot" = x; then target_header_dir="${test_exec_prefix}/${target_noncanonical}/sys-include" 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 By passing --with-build-sysroot=/ we trick cross-case to use `target_header_dir="${with_sysroot}${native_system_header_dir}"` which makes it equivalent to non-cross `target_header_dir="${with_build_sysroot}${native_system_header_dir}"` Tested the following setups: - cross-compiler without libc headers (powerpc64le-static) - cross-compiler with libc headers (powerpc64le-debug) - cross-build compiler with libc headers (powerpc64le bootstrapTools) Before the change only 2 of 3 compilers detected libc headers. After the change all 3 compilers detected libc headers. For darwin we silently ignore '-syslibroot //' argument as it does not introduce impurities. While at it dropped mingw special case for no-libc build. Before the change we passed both '--without-headers --with-native-system-headers-dir' for no-libc gcc-static builds. This tricked darwin builds to find sys/sdt.h and fail inhibid_libc builds. Now all targets avoid passing native headers for gcc-static builds. While at it fixed correct headers passing to --with-native-system-headers-dir= in host != target case: we were passing host's headers where intention was to pass target's headers. Noticed the mismatch as a build failure on pkgsCross.powernv.stdenv.cc on darwin where `sys/sdt.h` is present in host's headers (libSystem) but not target's headers (`glibc`). Co-authored-by: Adam Joseph <54836058+amjoseph-nixpkgs@users.noreply.github.com> --- .../bintools-wrapper/ld-wrapper.sh | 5 ++++ .../compilers/gcc/common/configure-flags.nix | 26 +++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/pkgs/build-support/bintools-wrapper/ld-wrapper.sh b/pkgs/build-support/bintools-wrapper/ld-wrapper.sh index f8bddabbc68713c..86a741602201007 100644 --- a/pkgs/build-support/bintools-wrapper/ld-wrapper.sh +++ b/pkgs/build-support/bintools-wrapper/ld-wrapper.sh @@ -50,6 +50,11 @@ if [[ "${NIX_ENFORCE_PURITY:-}" = 1 && -n "${NIX_STORE:-}" n+=1; skip "$p2" elif [ "$p" = -dynamic-linker ] && badPath "$p2"; then n+=1; skip "$p2" + elif [ "$p" = -syslibroot ] && [ $p2 == // ]; then + # When gcc is built on darwin --with-build-sysroot=/ + # produces '-syslibroot //' linker flag. It's a no-op, + # which does not introduce impurities. + n+=1; skip "$p2" elif [ "${p:0:1}" = / ] && badPath "$p"; then # We cannot skip this; barf. echo "impure path \`$p' used in link" >&2 diff --git a/pkgs/development/compilers/gcc/common/configure-flags.nix b/pkgs/development/compilers/gcc/common/configure-flags.nix index bebf91114d702f6..d6884eb8ba6355a 100644 --- a/pkgs/development/compilers/gcc/common/configure-flags.nix +++ b/pkgs/development/compilers/gcc/common/configure-flags.nix @@ -111,8 +111,30 @@ let "--with-mpc=${libmpc}" ] ++ lib.optional (libelf != null) "--with-libelf=${libelf}" - ++ lib.optional (!(crossMingw && crossStageStatic)) - "--with-native-system-header-dir=${lib.getDev stdenv.cc.libc}/include" + ++ lib.optionals (!crossStageStatic) [ + (if libcCross == null + then "--with-native-system-header-dir=${lib.getDev stdenv.cc.libc}/include" + else "--with-native-system-header-dir=${lib.getDev libcCross}${libcCross.incdir or "/include"}") + # gcc builds for cross-compilers (build != host) or cross-built + # gcc (host != target) always apply the offset prefix to disentangle + # target headers from build or host headers: + # ${with_build_sysroot}${native_system_header_dir} + # or ${test_exec_prefix}/${target_noncanonical}/sys-include + # or ${with_sysroot}${native_system_header_dir} + # While native build (build == host == target) uses passed headers + # path as is: + # ${native_system_header_dir} + # + # Nixpkgs uses flat directory structure for both native and cross + # cases. As a result libc headers don't get found for cross case + # and many modern features get disabled (libssp is used instead of + # target-specific implementations and similar). More details at: + # https://github.com/NixOS/nixpkgs/pull/181802#issuecomment-1186822355 + # + # We pick "/" path to effectively avoid sysroot offset and make it work + # as a native case. + "--with-build-sysroot=/" + ] # Basic configuration ++ [