nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
1{ stdenv, bazel_4, buildBazelPackage, isPy3k, lib, fetchFromGitHub, symlinkJoin
2, addOpenGLRunpath, fetchpatch, patchelfUnstable
3# Python deps
4, buildPythonPackage, pythonOlder, python
5# Python libraries
6, numpy, tensorboard, absl-py
7, setuptools, wheel, keras, keras-preprocessing, google-pasta
8, opt-einsum, astunparse, h5py
9, termcolor, grpcio, six, wrapt, protobuf-python, tensorflow-estimator
10, dill, flatbuffers-python, portpicker, tblib, typing-extensions
11# Common deps
12, git, pybind11, which, binutils, glibcLocales, cython, perl
13# Common libraries
14, jemalloc, mpi, gast, grpc, sqlite, boringssl, jsoncpp, nsync
15, curl, snappy, flatbuffers-core, lmdb-core, icu, double-conversion, libpng, libjpeg_turbo, giflib, protobuf-core
16# Upstream by default includes cuda support since tensorflow 1.15. We could do
17# that in nix as well. It would make some things easier and less confusing, but
18# it would also make the default tensorflow package unfree. See
19# https://groups.google.com/a/tensorflow.org/forum/#!topic/developers/iRCt5m4qUz0
20, cudaSupport ? false, cudaPackages ? {}
21, mklSupport ? false, mkl ? null
22, tensorboardSupport ? true
23# XLA without CUDA is broken
24, xlaSupport ? cudaSupport
25# Default from ./configure script
26, cudaCapabilities ? [ "sm_35" "sm_50" "sm_60" "sm_70" "sm_75" "compute_80" ]
27, sse42Support ? stdenv.hostPlatform.sse4_2Support
28, avx2Support ? stdenv.hostPlatform.avx2Support
29, fmaSupport ? stdenv.hostPlatform.fmaSupport
30# Darwin deps
31, Foundation, Security, cctools, llvmPackages_11
32}:
33
34let
35 inherit (cudaPackages) cudatoolkit cudnn nccl;
36in
37
38assert cudaSupport -> cudatoolkit != null
39 && cudnn != null;
40
41# unsupported combination
42assert ! (stdenv.isDarwin && cudaSupport);
43
44assert mklSupport -> mkl != null;
45
46let
47 withTensorboard = (pythonOlder "3.6") || tensorboardSupport;
48
49 cudatoolkit_joined = symlinkJoin {
50 name = "${cudatoolkit.name}-merged";
51 paths = [
52 cudatoolkit.lib
53 cudatoolkit.out
54 ] ++ lib.optionals (lib.versionOlder cudatoolkit.version "11") [
55 # for some reason some of the required libs are in the targets/x86_64-linux
56 # directory; not sure why but this works around it
57 "${cudatoolkit}/targets/${stdenv.system}"
58 ];
59 };
60
61 cudatoolkit_cc_joined = symlinkJoin {
62 name = "${cudatoolkit.cc.name}-merged";
63 paths = [
64 cudatoolkit.cc
65 binutils.bintools # for ar, dwp, nm, objcopy, objdump, strip
66 ];
67 };
68
69 # Needed for _some_ system libraries, grep INCLUDEDIR.
70 includes_joined = symlinkJoin {
71 name = "tensorflow-deps-merged";
72 paths = [
73 jsoncpp
74 ];
75 };
76
77 tfFeature = x: if x then "1" else "0";
78
79 version = "2.8.0";
80 variant = if cudaSupport then "-gpu" else "";
81 pname = "tensorflow${variant}";
82
83 pythonEnv = python.withPackages (_:
84 [ # python deps needed during wheel build time (not runtime, see the buildPythonPackage part for that)
85 # This list can likely be shortened, but each trial takes multiple hours so won't bother for now.
86 absl-py
87 astunparse
88 dill
89 flatbuffers-python
90 gast
91 google-pasta
92 grpcio
93 h5py
94 keras-preprocessing
95 numpy
96 opt-einsum
97 protobuf-python
98 setuptools
99 six
100 tblib
101 tensorboard
102 tensorflow-estimator
103 termcolor
104 typing-extensions
105 wheel
106 wrapt
107 ]);
108
109 rules_cc_darwin_patched = stdenv.mkDerivation {
110 name = "rules_cc-${pname}-${version}";
111
112 src = _bazel-build.deps;
113
114 prePatch = "pushd rules_cc";
115 patches = [
116 # https://github.com/bazelbuild/rules_cc/issues/122
117 (fetchpatch {
118 name = "tensorflow-rules_cc-libtool-path.patch";
119 url = "https://github.com/bazelbuild/rules_cc/commit/8c427ab30bf213630dc3bce9d2e9a0e29d1787db.diff";
120 sha256 = "sha256-C4v6HY5+jm0ACUZ58gBPVejCYCZfuzYKlHZ0m2qDHCk=";
121 })
122
123 # https://github.com/bazelbuild/rules_cc/pull/124
124 (fetchpatch {
125 name = "tensorflow-rules_cc-install_name_tool-path.patch";
126 url = "https://github.com/bazelbuild/rules_cc/commit/156497dc89100db8a3f57b23c63724759d431d05.diff";
127 sha256 = "sha256-NES1KeQmMiUJQVoV6dS4YGRxxkZEjOpFSCyOq9HZYO0=";
128 })
129 ];
130 postPatch = "popd";
131
132 dontConfigure = true;
133 dontBuild = true;
134
135 installPhase = ''
136 runHook preInstall
137
138 mv rules_cc/ "$out"
139
140 runHook postInstall
141 '';
142 };
143 llvm-raw_darwin_patched = stdenv.mkDerivation {
144 name = "llvm-raw-${pname}-${version}";
145
146 src = _bazel-build.deps;
147
148 prePatch = "pushd llvm-raw";
149 patches = [
150 # Fix a vendored config.h that requires the 10.13 SDK
151 ./llvm_bazel_fix_macos_10_12_sdk.patch
152 ];
153 postPatch = ''
154 touch {BUILD,WORKSPACE}
155 popd
156 '';
157
158 dontConfigure = true;
159 dontBuild = true;
160
161 installPhase = ''
162 runHook preInstall
163
164 mv llvm-raw/ "$out"
165
166 runHook postInstall
167 '';
168 };
169 bazel-build = if stdenv.isDarwin then _bazel-build.overrideAttrs (prev: {
170 bazelBuildFlags = prev.bazelBuildFlags ++ [
171 "--override_repository=rules_cc=${rules_cc_darwin_patched}"
172 "--override_repository=llvm-raw=${llvm-raw_darwin_patched}"
173 ];
174 preBuild = ''
175 export AR="${cctools}/bin/libtool"
176 '';
177 }) else _bazel-build;
178
179 _bazel-build = (buildBazelPackage.override (lib.optionalAttrs stdenv.isDarwin {
180 # clang 7 fails to emit a symbol for
181 # __ZN4llvm11SmallPtrSetIPKNS_10AllocaInstELj8EED1Ev in any of the
182 # translation units, so the build fails at link time
183 stdenv = llvmPackages_11.stdenv;
184 })) {
185 name = "${pname}-${version}";
186 bazel = bazel_4;
187
188 src = fetchFromGitHub {
189 owner = "tensorflow";
190 repo = "tensorflow";
191 rev = "v${version}";
192 hash = "sha256-w78ehpsnXElIyYftgZEq3b/+TSrRN1gyWVUVlSZpGFM=";
193 };
194
195 # On update, it can be useful to steal the changes from gentoo
196 # https://gitweb.gentoo.org/repo/gentoo.git/tree/sci-libs/tensorflow
197
198 nativeBuildInputs = [
199 which pythonEnv cython perl protobuf-core
200 ] ++ lib.optional cudaSupport addOpenGLRunpath;
201
202 buildInputs = [
203 jemalloc
204 mpi
205 glibcLocales
206 git
207
208 # libs taken from system through the TF_SYS_LIBS mechanism
209 boringssl
210 curl
211 double-conversion
212 flatbuffers-core
213 giflib
214 grpc
215 icu
216 jsoncpp
217 libjpeg_turbo
218 libpng
219 lmdb-core
220 pybind11
221 snappy
222 sqlite
223 ] ++ lib.optionals cudaSupport [
224 cudatoolkit
225 cudnn
226 ] ++ lib.optionals mklSupport [
227 mkl
228 ] ++ lib.optionals stdenv.isDarwin [
229 Foundation
230 Security
231 ] ++ lib.optionals (!stdenv.isDarwin) [
232 nsync
233 ];
234
235 # arbitrarily set to the current latest bazel version, overly careful
236 TF_IGNORE_MAX_BAZEL_VERSION = true;
237
238 # Take as many libraries from the system as possible. Keep in sync with
239 # list of valid syslibs in
240 # https://github.com/tensorflow/tensorflow/blob/master/third_party/systemlibs/syslibs_configure.bzl
241 TF_SYSTEM_LIBS = lib.concatStringsSep "," ([
242 "absl_py"
243 "astor_archive"
244 "astunparse_archive"
245 "boringssl"
246 # Not packaged in nixpkgs
247 # "com_github_googleapis_googleapis"
248 # "com_github_googlecloudplatform_google_cloud_cpp"
249 "com_github_grpc_grpc"
250 "com_google_protobuf"
251 # Fails with the error: external/org_tensorflow/tensorflow/core/profiler/utils/tf_op_utils.cc:46:49: error: no matching function for call to 're2::RE2::FullMatch(absl::lts_2020_02_25::string_view&, re2::RE2&)'
252 # "com_googlesource_code_re2"
253 "curl"
254 "cython"
255 "dill_archive"
256 "double_conversion"
257 "flatbuffers"
258 "functools32_archive"
259 "gast_archive"
260 "gif"
261 "hwloc"
262 "icu"
263 "jsoncpp_git"
264 "libjpeg_turbo"
265 "lmdb"
266 "nasm"
267 "opt_einsum_archive"
268 "org_sqlite"
269 "pasta"
270 "png"
271 "pybind11"
272 "six_archive"
273 "snappy"
274 "tblib_archive"
275 "termcolor_archive"
276 "typing_extensions_archive"
277 "wrapt"
278 "zlib"
279 ] ++ lib.optionals (!stdenv.isDarwin) [
280 "nsync" # fails to build on darwin
281 ]);
282
283 INCLUDEDIR = "${includes_joined}/include";
284
285 # This is needed for the Nix-provided protobuf dependency to work,
286 # as otherwise the rule `link_proto_files` tries to create the links
287 # to `/usr/include/...` which results in build failures.
288 PROTOBUF_INCLUDE_PATH = "${protobuf-core}/include";
289
290 PYTHON_BIN_PATH = pythonEnv.interpreter;
291
292 TF_NEED_GCP = true;
293 TF_NEED_HDFS = true;
294 TF_ENABLE_XLA = tfFeature xlaSupport;
295
296 CC_OPT_FLAGS = " ";
297
298 # https://github.com/tensorflow/tensorflow/issues/14454
299 TF_NEED_MPI = tfFeature cudaSupport;
300
301 TF_NEED_CUDA = tfFeature cudaSupport;
302 TF_CUDA_PATHS = lib.optionalString cudaSupport "${cudatoolkit_joined},${cudnn},${nccl}";
303 GCC_HOST_COMPILER_PREFIX = lib.optionalString cudaSupport "${cudatoolkit_cc_joined}/bin";
304 GCC_HOST_COMPILER_PATH = lib.optionalString cudaSupport "${cudatoolkit_cc_joined}/bin/gcc";
305 TF_CUDA_COMPUTE_CAPABILITIES = lib.concatStringsSep "," cudaCapabilities;
306
307 postPatch = ''
308 # bazel 3.3 should work just as well as bazel 3.1
309 rm -f .bazelversion
310 '' + lib.optionalString (!withTensorboard) ''
311 # Tensorboard pulls in a bunch of dependencies, some of which may
312 # include security vulnerabilities. So we make it optional.
313 # https://github.com/tensorflow/tensorflow/issues/20280#issuecomment-400230560
314 sed -i '/tensorboard ~=/d' tensorflow/tools/pip_package/setup.py
315 '';
316
317 # https://github.com/tensorflow/tensorflow/pull/39470
318 NIX_CFLAGS_COMPILE = [ "-Wno-stringop-truncation" ];
319
320 preConfigure = let
321 opt_flags = []
322 ++ lib.optionals sse42Support ["-msse4.2"]
323 ++ lib.optionals avx2Support ["-mavx2"]
324 ++ lib.optionals fmaSupport ["-mfma"];
325 in ''
326 patchShebangs configure
327
328 # dummy ldconfig
329 mkdir dummy-ldconfig
330 echo "#!${stdenv.shell}" > dummy-ldconfig/ldconfig
331 chmod +x dummy-ldconfig/ldconfig
332 export PATH="$PWD/dummy-ldconfig:$PATH"
333
334 export PYTHON_LIB_PATH="$NIX_BUILD_TOP/site-packages"
335 export CC_OPT_FLAGS="${lib.concatStringsSep " " opt_flags}"
336 mkdir -p "$PYTHON_LIB_PATH"
337
338 # To avoid mixing Python 2 and Python 3
339 unset PYTHONPATH
340 '';
341
342 configurePhase = ''
343 runHook preConfigure
344 ./configure
345 runHook postConfigure
346 '';
347
348 hardeningDisable = [ "format" ];
349
350 bazelBuildFlags = [
351 "--config=opt" # optimize using the flags set in the configure phase
352 ]
353 ++ lib.optionals stdenv.cc.isClang [ "--cxxopt=-x" "--cxxopt=c++" "--host_cxxopt=-x" "--host_cxxopt=c++" ]
354 ++ lib.optionals (mklSupport) [ "--config=mkl" ];
355
356 bazelTarget = "//tensorflow/tools/pip_package:build_pip_package //tensorflow/tools/lib_package:libtensorflow";
357
358 removeRulesCC = false;
359 # Without this Bazel complaints about sandbox violations.
360 dontAddBazelOpts = true;
361
362 fetchAttrs = {
363 # cudaSupport causes fetch of ncclArchive, resulting in different hashes
364 sha256 = if cudaSupport then
365 "sha256-dQEyfueuQPcGvbhuh8Al45np3nRLDw2PCfC2lEqAH50="
366 else
367 if stdenv.isDarwin then
368 "sha256-yfnZVtKWqNQGvlfq2owXhem0LmzDYriVfYgf1ZRlaDo="
369 else
370 "sha256:12i1ix2xwq77f3h8qr4h57g0aazrdsjjqa536cpwx3n1mvl5p6qi";
371 };
372
373 buildAttrs = {
374 outputs = [ "out" "python" ];
375
376 preBuild = ''
377 patchShebangs .
378 '';
379
380 installPhase = ''
381 mkdir -p "$out"
382 tar -xf bazel-bin/tensorflow/tools/lib_package/libtensorflow.tar.gz -C "$out"
383 # Write pkgconfig file.
384 mkdir "$out/lib/pkgconfig"
385 cat > "$out/lib/pkgconfig/tensorflow.pc" << EOF
386 Name: TensorFlow
387 Version: ${version}
388 Description: Library for computation using data flow graphs for scalable machine learning
389 Requires:
390 Libs: -L$out/lib -ltensorflow
391 Cflags: -I$out/include/tensorflow
392 EOF
393
394 # build the source code, then copy it to $python (build_pip_package
395 # actually builds a symlink farm so we must dereference them).
396 bazel-bin/tensorflow/tools/pip_package/build_pip_package --src "$PWD/dist"
397 cp -Lr "$PWD/dist" "$python"
398 '';
399
400 postFixup = lib.optionalString cudaSupport ''
401 find $out -type f \( -name '*.so' -or -name '*.so.*' \) | while read lib; do
402 addOpenGLRunpath "$lib"
403 done
404 '';
405
406 requiredSystemFeatures = [
407 "big-parallel"
408 ];
409 };
410
411 meta = with lib; {
412 description = "Computation using data flow graphs for scalable machine learning";
413 homepage = "http://tensorflow.org";
414 license = licenses.asl20;
415 maintainers = with maintainers; [ jyp abbradar ];
416 platforms = with platforms; linux ++ darwin;
417 broken = !(xlaSupport -> cudaSupport);
418 } // lib.optionalAttrs stdenv.isDarwin {
419 timeout = 86400; # 24 hours
420 maxSilent = 14400; # 4h, double the default of 7200s
421 };
422 };
423
424in buildPythonPackage {
425 inherit version pname;
426 disabled = !isPy3k;
427
428 src = bazel-build.python;
429
430 # Adjust dependency requirements:
431 # - Relax gast version requirement that doesn't match what we have packaged
432 # - Relax tf-estimator, that would require a nightly version
433 # - The purpose of python3Packages.libclang is not clear at the moment and we don't have it packaged yet
434 # - keras and tensorlow-io-gcs-filesystem will be considered as optional for now.
435 postPatch = ''
436 sed -i setup.py \
437 -e "s/'gast[^']*',/'gast',/" \
438 -e "s/'tf-estimator-nightly[^']*',/'tensorflow-estimator',/" \
439 -e "/'libclang[^']*',/d" \
440 -e "/'keras[^']*',/d" \
441 -e "/'tensorflow-io-gcs-filesystem[^']*',/d"
442 '';
443
444 # Upstream has a pip hack that results in bin/tensorboard being in both tensorflow
445 # and the propagated input tensorboard, which causes environment collisions.
446 # Another possibility would be to have tensorboard only in the buildInputs
447 # https://github.com/tensorflow/tensorflow/blob/v1.7.1/tensorflow/tools/pip_package/setup.py#L79
448 postInstall = ''
449 rm $out/bin/tensorboard
450 '';
451
452 setupPyGlobalFlags = [ "--project_name ${pname}" ];
453
454 # tensorflow/tools/pip_package/setup.py
455 propagatedBuildInputs = [
456 absl-py
457 astunparse
458 flatbuffers-python
459 gast
460 google-pasta
461 grpcio
462 h5py
463 keras-preprocessing
464 numpy
465 opt-einsum
466 protobuf-python
467 six
468 tensorflow-estimator
469 termcolor
470 typing-extensions
471 wrapt
472 ] ++ lib.optionals withTensorboard [
473 tensorboard
474 ];
475
476 # remove patchelfUnstable once patchelf 0.14 with https://github.com/NixOS/patchelf/pull/256 becomes the default
477 nativeBuildInputs = lib.optional cudaSupport [ addOpenGLRunpath patchelfUnstable ];
478
479 postFixup = lib.optionalString cudaSupport ''
480 find $out -type f \( -name '*.so' -or -name '*.so.*' \) | while read lib; do
481 addOpenGLRunpath "$lib"
482
483 patchelf --set-rpath "${cudatoolkit}/lib:${cudatoolkit.lib}/lib:${cudnn}/lib:${nccl}/lib:$(patchelf --print-rpath "$lib")" "$lib"
484 done
485 '';
486
487 # Actual tests are slow and impure.
488 # TODO try to run them anyway
489 # TODO better test (files in tensorflow/tools/ci_build/builds/*test)
490 # TEST_PACKAGES in tensorflow/tools/pip_package/setup.py
491 checkInputs = [
492 dill
493 keras
494 portpicker
495 tblib
496 ];
497 checkPhase = ''
498 ${python.interpreter} <<EOF
499 # A simple "Hello world"
500 import tensorflow as tf
501 hello = tf.constant("Hello, world!")
502 tf.print(hello)
503
504 # Fit a simple model to random data
505 import numpy as np
506 np.random.seed(0)
507 tf.random.set_seed(0)
508 model = tf.keras.models.Sequential([
509 tf.keras.layers.Dense(1, activation="linear")
510 ])
511 model.compile(optimizer="sgd", loss="mse")
512
513 x = np.random.uniform(size=(1,1))
514 y = np.random.uniform(size=(1,))
515 model.fit(x, y, epochs=1)
516 EOF
517 '';
518 # Regression test for #77626 removed because not more `tensorflow.contrib`.
519
520 passthru = {
521 inherit cudaPackages;
522 deps = bazel-build.deps;
523 libtensorflow = bazel-build.out;
524 };
525
526 inherit (bazel-build) meta;
527}