python3Packages.tensorflow: fix `GLIBCXX_3.4.30' not found

Make tensorflow (and a bunch of ther things) use CUDA-compatible
toolchain. Introduces cudaPackages.backendStdenv

+88 -69
+20 -34
pkgs/development/compilers/cudatoolkit/common.nix
··· 11 11 , fetchurl 12 12 , fontconfig 13 13 , freetype 14 - , gcc 14 + , gcc # :: String 15 15 , gdk-pixbuf 16 16 , glib 17 17 , glibc ··· 22 22 , perl 23 23 , python3 24 24 , requireFile 25 - , stdenv 25 + , backendStdenv # E.g. gcc11Stdenv, set in extension.nix 26 26 , unixODBC 27 27 , xorg 28 28 , zlib 29 29 }: 30 30 31 - stdenv.mkDerivation rec { 31 + backendStdenv.mkDerivation rec { 32 32 pname = "cudatoolkit"; 33 33 inherit version runPatches; 34 34 ··· 146 146 147 147 # Fix builds with newer glibc version 148 148 sed -i "1 i#define _BITS_FLOATN_H" "$out/include/host_defines.h" 149 - 150 - # Ensure that cmake can find CUDA. 149 + '' + 150 + # Point NVCC at a compatible compiler 151 + # FIXME: redist cuda_nvcc copy-pastes this code 152 + # Refer to comments in the overrides for cuda_nvcc for explanation 153 + # CUDA_TOOLKIT_ROOT_DIR is legacy, 154 + # Cf. https://cmake.org/cmake/help/latest/module/FindCUDA.html#input-variables 155 + '' 151 156 mkdir -p $out/nix-support 152 - echo "cmakeFlags+=' -DCUDA_TOOLKIT_ROOT_DIR=$out'" >> $out/nix-support/setup-hook 153 - 154 - # Set the host compiler to be used by nvcc. 155 - # FIXME: redist cuda_nvcc copy-pastes this code 156 - 157 - # For CMake-based projects: 158 - # https://cmake.org/cmake/help/latest/module/FindCUDA.html#input-variables 159 - # https://cmake.org/cmake/help/latest/envvar/CUDAHOSTCXX.html 160 - # https://cmake.org/cmake/help/latest/variable/CMAKE_CUDA_HOST_COMPILER.html 161 - 162 - # For non-CMake projects: 163 - # FIXME: results in "incompatible redefinition" warnings ...but we keep 164 - # both this and cmake variables until we come up with a more general 165 - # solution 166 - # https://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html#compiler-bindir-directory-ccbin 167 - 168 157 cat <<EOF >> $out/nix-support/setup-hook 169 - 170 - cmakeFlags+=' -DCUDA_HOST_COMPILER=${gcc}/bin' 171 - cmakeFlags+=' -DCMAKE_CUDA_HOST_COMPILER=${gcc}/bin' 158 + cmakeFlags+=' -DCUDA_TOOLKIT_ROOT_DIR=$out' 159 + cmakeFlags+=' -DCUDA_HOST_COMPILER=${backendStdenv.cc}/bin' 160 + cmakeFlags+=' -DCMAKE_CUDA_HOST_COMPILER=${backendStdenv.cc}/bin' 172 161 if [ -z "\''${CUDAHOSTCXX-}" ]; then 173 - export CUDAHOSTCXX=${gcc}/bin; 162 + export CUDAHOSTCXX=${backendStdenv.cc}/bin; 174 163 fi 175 - 176 - export NVCC_PREPEND_FLAGS+=' --compiler-bindir=${gcc}/bin' 164 + export NVCC_PREPEND_FLAGS+=' --compiler-bindir=${backendStdenv.cc}/bin' 177 165 EOF 178 - 179 166 180 167 # Move some libraries to the lib output so that programs that 181 168 # depend on them don't pull in this entire monstrosity. ··· 212 199 213 200 # The path to libstdc++ and such 214 201 # 215 - # NB: 216 - # 1. "gcc" (gcc-wrapper) here is what's exposed as cudaPackages.cudatoolkit.cc 217 - # 2. "gcc.cc" is the unwrapped gcc 218 - # 3. "gcc.cc.lib" is one of its outputs 219 - "${gcc.cc.lib}/lib64" 202 + # `backendStdenv` is the cuda-compatible toolchain that we pick in 203 + # extension.nix; we hand it to NVCC to use as a back-end, and we link 204 + # cudatoolkit's binaries against its libstdc++ 205 + "${backendStdenv.cc.cc.lib}/lib64" 220 206 221 207 "$out/jre/lib/amd64/jli" 222 208 "$out/lib64" ··· 286 272 popd 287 273 ''; 288 274 passthru = { 289 - cc = gcc; 275 + cc = backendStdenv.cc; 290 276 majorMinorVersion = lib.versions.majorMinor version; 291 277 majorVersion = lib.versions.majorMinor version; 292 278 };
+16 -3
pkgs/development/compilers/cudatoolkit/extension.nix
··· 7 7 # Version info for the classic cudatoolkit packages that contain everything that is in redist. 8 8 cudatoolkitVersions = final.lib.importTOML ./versions.toml; 9 9 10 + finalVersion = cudatoolkitVersions.${final.cudaVersion}; 11 + 12 + # Exposed as cudaPackages.backendStdenv. 13 + # We don't call it just "stdenv" to avoid confusion: e.g. this toolchain doesn't contain nvcc. 14 + # Instead, it's the back-end toolchain for nvcc to use. 15 + # We also use this to link a compatible libstdc++ (backendStdenv.cc.cc.lib) 16 + # Cf. https://github.com/NixOS/nixpkgs/pull/218265 for context 17 + backendStdenv = prev.pkgs."${finalVersion.gcc}Stdenv"; 18 + 10 19 ### Add classic cudatoolkit package 11 - cudatoolkit = buildCudaToolkitPackage ((attrs: attrs // { gcc = prev.pkgs.${attrs.gcc}; }) cudatoolkitVersions.${final.cudaVersion}); 20 + cudatoolkit = buildCudaToolkitPackage (finalVersion // { inherit backendStdenv; }); 12 21 13 22 cudaFlags = final.callPackage ./flags.nix {}; 14 23 15 - in { 16 - inherit cudatoolkit cudaFlags; 24 + in 25 + { 26 + inherit 27 + backendStdenv 28 + cudatoolkit 29 + cudaFlags; 17 30 }
+4 -7
pkgs/development/compilers/cudatoolkit/redist/build-cuda-redist-package.nix
··· 1 1 { lib 2 - , stdenv 2 + , backendStdenv 3 3 , fetchurl 4 4 , autoPatchelfHook 5 5 , autoAddOpenGLRunpathHook ··· 11 11 let 12 12 arch = "linux-x86_64"; 13 13 in 14 - stdenv.mkDerivation { 14 + backendStdenv.mkDerivation { 15 15 inherit pname; 16 16 inherit (attrs) version; 17 17 ··· 33 33 # autoPatchelfHook will search for a libstdc++ and we're giving it a 34 34 # "compatible" libstdc++ from the same toolchain that NVCC uses. 35 35 # 36 - # E.g. it might happen that stdenv=gcc12Stdenv, but we build against cuda11 37 - # that only "supports" gcc11. Linking against gcc12's libraries we might 38 - # sometimes actually sometimes encounter dynamic linkage errors at runtime 39 36 # NB: We don't actually know if this is the right thing to do 40 - cudatoolkit.cc.cc.lib 37 + backendStdenv.cc.cc.lib 41 38 ]; 42 39 43 40 dontBuild = true; ··· 51 48 runHook postInstall 52 49 ''; 53 50 54 - passthru.stdenv = stdenv; 51 + passthru.stdenv = backendStdenv; 55 52 56 53 meta = { 57 54 description = attrs.name;
+1 -2
pkgs/development/compilers/cudatoolkit/redist/overrides.nix
··· 24 24 25 25 cuda_nvcc = prev.cuda_nvcc.overrideAttrs (oldAttrs: 26 26 let 27 - inherit (prev.cudatoolkit) cc; 27 + inherit (prev.backendStdenv) cc; 28 28 in 29 29 { 30 30 # Point NVCC at a compatible compiler ··· 44 44 postInstall = (oldAttrs.postInstall or "") + '' 45 45 mkdir -p $out/nix-support 46 46 cat <<EOF >> $out/nix-support/setup-hook 47 - cmakeFlags+=' -DCUDA_TOOLKIT_ROOT_DIR=$out' 48 47 cmakeFlags+=' -DCUDA_HOST_COMPILER=${cc}/bin' 49 48 cmakeFlags+=' -DCMAKE_CUDA_HOST_COMPILER=${cc}/bin' 50 49 if [ -z "\''${CUDAHOSTCXX-}" ]; then
+4 -4
pkgs/development/libraries/science/math/cudnn/generic.nix
··· 1 1 { 2 - stdenv, 2 + backendStdenv, 3 3 lib, 4 4 zlib, 5 5 useCudatoolkitRunfile ? false, 6 6 cudaVersion, 7 7 cudaMajorVersion, 8 - cudatoolkit, # if cuda>=11: only used for .cc 8 + cudatoolkit, # For cuda < 11 9 9 libcublas ? null, # cuda <11 doesn't ship redist packages 10 10 autoPatchelfHook, 11 11 autoAddOpenGLRunpathHook, ··· 26 26 maxCudaVersion, 27 27 }: 28 28 assert useCudatoolkitRunfile || (libcublas != null); let 29 - inherit (cudatoolkit) cc; 29 + inherit (backendStdenv) cc; 30 30 inherit (lib) lists strings trivial versions; 31 31 32 32 # majorMinorPatch :: String -> String ··· 46 46 then cudatoolkit 47 47 else libcublas; 48 48 in 49 - stdenv.mkDerivation { 49 + backendStdenv.mkDerivation { 50 50 pname = "cudatoolkit-${cudaMajorVersion}-cudnn"; 51 51 version = versionTriple; 52 52
+5 -3
pkgs/development/libraries/science/math/tensorrt/generic.nix
··· 1 1 { lib 2 - , stdenv 2 + , backendStdenv 3 3 , requireFile 4 4 , autoPatchelfHook 5 5 , autoAddOpenGLRunpathHook ··· 18 18 assert lib.assertMsg (lib.strings.versionAtLeast cudnn.version fileVersionCudnn) 19 19 "This version of TensorRT requires at least cuDNN ${fileVersionCudnn} (current version is ${cudnn.version})"; 20 20 21 - stdenv.mkDerivation rec { 21 + backendStdenv.mkDerivation rec { 22 22 pname = "cudatoolkit-${cudatoolkit.majorVersion}-tensorrt"; 23 23 version = fullVersion; 24 24 src = requireFile rec { ··· 45 45 46 46 # Used by autoPatchelfHook 47 47 buildInputs = [ 48 - cudatoolkit.cc.cc.lib # libstdc++ 48 + backendStdenv.cc.cc.lib # libstdc++ 49 49 cudatoolkit 50 50 cudnn 51 51 ]; ··· 73 73 "$out/lib/libnvinfer_plugin.so.${mostOfVersion}" \ 74 74 "$out/lib/libnvinfer_builder_resource.so.${mostOfVersion}" 75 75 ''; 76 + 77 + passthru.stdenv = backendStdenv; 76 78 77 79 meta = with lib; { 78 80 # Check that the cudatoolkit version satisfies our min/max constraints (both
+34 -12
pkgs/development/python-modules/tensorflow/default.nix
··· 32 32 }: 33 33 34 34 let 35 + originalStdenv = stdenv; 36 + in 37 + let 38 + # Tensorflow looks at many toolchain-related variables which may diverge. 39 + # 40 + # Toolchain for cuda-enabled builds. 41 + # We want to achieve two things: 42 + # 1. NVCC should use a compatible back-end (e.g. gcc11 for cuda11) 43 + # 2. Normal C++ files should be compiled with the same toolchain, 44 + # to avoid potential weird dynamic linkage errors at runtime. 45 + # This may not be necessary though 46 + # 47 + # Toolchain for Darwin: 48 + # clang 7 fails to emit a symbol for 49 + # __ZN4llvm11SmallPtrSetIPKNS_10AllocaInstELj8EED1Ev in any of the 50 + # translation units, so the build fails at link time 51 + stdenv = 52 + if cudaSupport then cudaPackages.backendStdenv 53 + else if originalStdenv.isDarwin then llvmPackages_11.stdenv 54 + else originalStdenv; 35 55 inherit (cudaPackages) cudatoolkit cudnn nccl; 36 56 in 37 57 ··· 44 64 let 45 65 withTensorboard = (pythonOlder "3.6") || tensorboardSupport; 46 66 67 + # FIXME: migrate to redist cudaPackages 47 68 cudatoolkit_joined = symlinkJoin { 48 69 name = "${cudatoolkit.name}-merged"; 49 70 paths = [ ··· 56 77 ]; 57 78 }; 58 79 80 + # Tensorflow expects bintools at hard-coded paths, e.g. /usr/bin/ar 81 + # The only way to overcome that is to set GCC_HOST_COMPILER_PREFIX, 82 + # but that path must contain cc as well, so we merge them 59 83 cudatoolkit_cc_joined = symlinkJoin { 60 - name = "${cudatoolkit.cc.name}-merged"; 84 + name = "${stdenv.cc.name}-merged"; 61 85 paths = [ 62 - cudatoolkit.cc 86 + stdenv.cc 63 87 binutils.bintools # for ar, dwp, nm, objcopy, objdump, strip 64 88 ]; 65 89 }; ··· 175 199 ''; 176 200 }) else _bazel-build; 177 201 178 - _bazel-build = (buildBazelPackage.override (lib.optionalAttrs stdenv.isDarwin { 179 - # clang 7 fails to emit a symbol for 180 - # __ZN4llvm11SmallPtrSetIPKNS_10AllocaInstELj8EED1Ev in any of the 181 - # translation units, so the build fails at link time 182 - stdenv = llvmPackages_11.stdenv; 183 - })) { 202 + _bazel-build = buildBazelPackage.override { inherit stdenv; } { 184 203 name = "${pname}-${version}"; 185 204 bazel = bazel_5; 186 205 ··· 211 230 flatbuffers-core 212 231 giflib 213 232 grpc 214 - icu 233 + # Necessary to fix the "`GLIBCXX_3.4.30' not found" error 234 + (icu.override { inherit stdenv; }) 215 235 jsoncpp 216 236 libjpeg_turbo 217 237 libpng 218 238 lmdb-core 219 - pybind11 239 + (pybind11.overridePythonAttrs (_: { inherit stdenv; })) 220 240 snappy 221 241 sqlite 222 242 ] ++ lib.optionals cudaSupport [ ··· 301 321 302 322 TF_NEED_CUDA = tfFeature cudaSupport; 303 323 TF_CUDA_PATHS = lib.optionalString cudaSupport "${cudatoolkit_joined},${cudnn},${nccl}"; 304 - GCC_HOST_COMPILER_PREFIX = lib.optionalString cudaSupport "${cudatoolkit_cc_joined}/bin"; 305 - GCC_HOST_COMPILER_PATH = lib.optionalString cudaSupport "${cudatoolkit_cc_joined}/bin/gcc"; 306 324 TF_CUDA_COMPUTE_CAPABILITIES = lib.concatStringsSep "," cudaCapabilities; 325 + 326 + # Needed even when we override stdenv: e.g. for ar 327 + GCC_HOST_COMPILER_PREFIX = lib.optionalString cudaSupport "${cudatoolkit_cc_joined}/bin"; 328 + GCC_HOST_COMPILER_PATH = lib.optionalString cudaSupport "${cudatoolkit_cc_joined}/bin/cc"; 307 329 308 330 postPatch = '' 309 331 # bazel 3.3 should work just as well as bazel 3.1
+4 -4
pkgs/test/cuda/cuda-library-samples/generic.nix
··· 1 - { lib, stdenv, fetchFromGitHub 1 + { lib, backendStdenv, fetchFromGitHub 2 2 , cmake, addOpenGLRunpath 3 3 , cudatoolkit 4 4 , cutensor ··· 35 35 in 36 36 37 37 { 38 - cublas = stdenv.mkDerivation (commonAttrs // { 38 + cublas = backendStdenv.mkDerivation (commonAttrs // { 39 39 pname = "cuda-library-samples-cublas"; 40 40 41 41 src = "${src}/cuBLASLt"; 42 42 }); 43 43 44 - cusolver = stdenv.mkDerivation (commonAttrs // { 44 + cusolver = backendStdenv.mkDerivation (commonAttrs // { 45 45 pname = "cuda-library-samples-cusolver"; 46 46 47 47 src = "${src}/cuSOLVER"; ··· 49 49 sourceRoot = "cuSOLVER/gesv"; 50 50 }); 51 51 52 - cutensor = stdenv.mkDerivation (commonAttrs // { 52 + cutensor = backendStdenv.mkDerivation (commonAttrs // { 53 53 pname = "cuda-library-samples-cutensor"; 54 54 55 55 src = "${src}/cuTENSOR";