aboutsummarylogtreecommitdiffstats
path: root/PKGBUILD
blob: 02d8dbf8eff14040553a7efcf0febbd985f87245 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
# Maintainer: Mark Peschel <mpeschel10@gmail.com>
# Contributor: anakano <azusanakan0 at outlook dot com>
# Contributor: wuxxin <wuxxin@gmail.com>
# Contributor: acxz <akashpatel2008 at yahoo dot com>
# Contributor: Sven-Hendrik Haase <svenstaro@archlinux.org>
# Contributor: Konstantin Gizdov (kgizdov) <arch@kge.pw>
# Contributor: Adria Arrufat (archdria) <adria.arrufat+AUR@protonmail.ch>
# Contributor: Thibault Lorrain (fredszaq) <fredszaq@gmail.com>

pkgbase=tensorflow-amd-git
pkgname=(tensorflow-amd-git python-tensorflow-amd-git tensorflow-opt-amd-git python-tensorflow-opt-amd-git)
pkgver=2.12.0
_known_good_commit=de8086e14ae3152906e1137c212d2f7bb8ea463a
# You can find the latest probably successful official build at:
# http://ml-ci.amd.com:21096/job/tensorflow/job/release-rocmfork-r212-rocm-enhanced/job/release-build-whl/lastSuccessfulBuild/
# Specifically, the revision for the "ROCmSoftwarePlatform/tensorflow-upstream" repository.
pkgrel=6
pkgdesc="Library for scalable machine learning (with ROCm)"
url="https://www.tensorflow.org/"
license=('APACHE')
arch=('x86_64')

depends=('c-ares' 'pybind11' 'openssl' 'lmdb' 'libpng' 'curl' 'giflib' 'icu' 'libjpeg-turbo' 'openmp' \
         'rocrand' 'rccl' 'miopen-hip' 'hipfft' \
         'lib32-icu' 'zlib' 'glibc' 'gcc-libs' 'hsa-rocr' 'hip-runtime-amd' )
         # lib32-icu etc. were discovered with namcap.
makedepends=('python-numpy' 'git' 'python-wheel' \
             'python-installer' 'python-setuptools' 'python-h5py' 'python-keras-applications' \
             'python-keras-preprocessing' 'cython' 'patchelf' 'python-requests' \
             'java-environment=11' 'coreutils' 'base-devel' \
             'rocm-core' 'roctracer' 'hipsparse' 'hipsolver' 'hipblas' 'hipcub' )
             # bazel: Don't need bazel since this PKGBUILD downloads and installs bazel 5.4.0 locally
             #  java-environment=11: outdated bazel needs jdk 11
             # coreutils: df, for our check if there's enough space on /tmp. 
             # base-devel: fakeroot and some other things
             # rocm-core: /opt/rocm/.info/version, which the official docker image seems to need.
optdepends=('tensorboard: Tensorflow visualization toolkit')
source=('tensorflow-upstream-rocm::git+https://github.com/ROCmSoftwarePlatform/tensorflow-upstream#branch=r2.12-rocm-enhanced'
        tensorflow-2.10-sparse-transpose-op2.patch
        https://github.com/bazelbuild/bazel/releases/download/5.4.0/bazel_nojdk-5.4.0-linux-x86_64
        fix-c++17-compat.patch
        fix-cstdint-tsllibio-cache.patch
        remove-log-spam.patch)
sha512sums=( SKIP
            '45325ef3130aa95d48121d8c39bb4e683bdb5faa936ff29af953a2c359edb441a29e2dc0cae53ec6c08eee0432c0eeeaa7a40fbd063467b7f3c250d0f7f8ffed'
            'e2adb747cd1fe3c90686831703618af3f8bc8197a96d9e1e90e66db38dbc4e7a94d88dac755b25e288002983a87fcffbfb0d7c2e356d979d4635301c3daf9281'
            'f682368bb47b2b022a51aa77345dfa30f3b0d7911c56515d428b8326ee3751242f375f4e715a37bb723ef20a86916dad9871c3c81b1b58da85e1ca202bc4901e'
            '78bffffdb6fa58dfcfae37b4458c198a644605b9e9136ceef079d4d5002fad6f2ae39dee15e77e35c198267574860554a69e98674882164fad4b63e9ab68fb05'
            'fde73feeb2bbb814ba229c2b879e5e5944fd658e9810937753a25f2650f57c49f8a435924b47a1a54eb2852f9713b19a15d42b307593e26a74ad65aeee22c36a')

# consolidate common dependencies to prevent mishaps
_common_py_depends=(python-termcolor python-astor python-gast03 python-numpy python-protobuf
                    absl-py python-h5py python-keras python-keras-applications python-keras-preprocessing
                    python-tensorflow-estimator python-opt_einsum python-astunparse python-pasta
                    python-flatbuffers python-typing_extensions)

get_pyver () {
  python -c 'import sys; print(str(sys.version_info[0]) + "." + str(sys.version_info[1]))'
}

check_dir() {
  # first make sure we do not break parsepkgbuild
  if ! command -v cp &> /dev/null; then
    >&2 echo "'cp' command not found. PKGBUILD is probably being checked by parsepkgbuild."
    if ! command -v install &> /dev/null; then
      >&2 echo "'install' command also not found. PKGBUILD must be getting checked by parsepkgbuild."
      >&2 echo "Cannot check if directory '${1}' exists. Ignoring."
      >&2 echo "If you are not running nacmap or parsepkgbuild, please make sure the PATH is correct and try again."
      >&2 echo "PATH should not be '/dummy': PATH=$PATH"
      return 0
    fi
  fi
  # if we are running normally, check the given path
  if [ -d "${1}" ]; then
    return 0
  else
    >&2 echo Directory "${1}" does not exist or is a file! Exiting...
    exit 1
  fi
}

prepare() {
  cd tensorflow-upstream-rocm
  git revert --no-commit "$_known_good_commit..HEAD" || :
  cd ..
  
  # Allow any bazel version
  echo "*" > tensorflow-upstream-rocm/.bazelversion

  # Since Tensorflow is currently incompatible with Bazel 6, we're going to use
  # a local Bazel 5 to fix that. Stupid problems call for stupid solutions.
  install -Dm755 "${srcdir}"/bazel_nojdk-5.4.0-linux-x86_64 bazel/bazel
  bazel --version

  # Get rid of hardcoded versions. Not like we ever cared about what upstream
  # thinks about which versions should be used anyway. ;) (FS#68772)
  sed -i -E "s/'([0-9a-z_-]+) .= [0-9].+[0-9]'/'\1'/" tensorflow-upstream-rocm/tensorflow/tools/pip_package/setup.py

  # setup.py generates ~1Mb of warnings if you don't explicitly include namespace packages.
  sed -i -E "s/find_packages/find_namespace_packages/" tensorflow-upstream-rocm/tensorflow/tools/pip_package/setup.py
  
  patch -Np1 -i "${srcdir}/tensorflow-2.10-sparse-transpose-op2.patch" -d tensorflow-upstream-rocm
  # Patch for gcc13: cstdint is no longer implicitly included in some headers, so include it explicitly.
  # See https://gcc.gnu.org/gcc-13/porting_to.html
  patch -Np1 -i "${srcdir}/fix-cstdint-tsllibio-cache.patch" -d tensorflow-upstream-rocm
  # Patch tensorflow/core/common_runtime/gpu_fusion_pass.cc to fix "ROCm Fusion is enabled." log spam.
  patch -Np1 -i "${srcdir}/remove-log-spam.patch" -d tensorflow-upstream-rocm
  
  [ -d tensorflow-upstream-opt-rocm ] && rm -rf tensorflow-upstream-opt-rocm
  # cp may not replace files if they already exist, even if contents are different.
  # Very confusing to make changes in -rocm and not have them show up in -opt-rocm...
  cp -r tensorflow-upstream-rocm tensorflow-upstream-opt-rocm
  
  if [ ! -f "/opt/rocm/bin/target.lst" ]; then
    echo WARNING: If you are building for GPUs not currently installed in your machine,
    echo \ or if you are getting random segfaults and suspect that this build is not
    echo \ properly targeting your architecture,
    echo \ you must provide a target list in /opt/rocm/bin/target.lst
    echo Something of the form:
    echo -e "gfx803\ngfx900\ngfx906\ngfx908\ngfx90a\ngfx1030\ngfx904"
    echo You can see the architectures of cards in your machine by running
    echo "pacman -S rocminfo"
    echo "/opt/rocm/bin/rocminfo | grep gfx"
  fi
}

build() {
  # Use outdated bazel since tensorflow is configured for that,
  #  and use outdated java since bazel needs specifically java 11.
  PATH="/usr/lib/jvm/java-11-openjdk/bin:$PATH"
  export PATH="${srcdir}/bazel:$PATH"
  # bazel somehow caches the jvm,
  #  so if you pacman -R jre11-openjdk; pacman -S jre-openjdk to see if modern java also works,
  #  makepkg may still build as though java 20 is ok.
  # For a clean test, you must rm -rf ~/.cache/bazel
  
  # These environment variables influence the behavior of the configure call.
  export PYTHON_BIN_PATH=/usr/bin/python
  export USE_DEFAULT_PYTHON_LIB_PATH=1
  export TF_SET_ANDROID_WORKSPACE=0
  export TF_DOWNLOAD_CLANG=0
  
  # See https://github.com/tensorflow/tensorflow/blob/master/third_party/systemlibs/syslibs_configure.bzl
  # Important since boringssl may no longer build due to dangling pointer warning as of 2023-06-04
  export TF_SYSTEM_LIBS="boringssl,curl,cython,gif,icu,libjpeg_turbo,lmdb,nasm,png,pybind11,zlib"
  
  # Don't need --config=rocm, since it's included from .tf_configure.bazelrc
  export BAZEL_ARGS="--config=opt"

  tmp_size=`df /tmp | sed -rn "s|tmpfs +([[:digit:]]+) +.*|\1|p"`
  if [ -z "$tmp_size" ]; then
      echo Please confirm your /tmp directory is larger than 8 gigabytes\;
      echo if it isn\'t, you may run into errors during the build due to running out of space
      echo \ if you are building for multiple architectures.
      echo Find /tmp size with "df -h".
      echo You can remount it larger with "mount -o remount,size=12G /tmp"
      echo \ if it is tmpfs and you have enough RAM.
  else
      if [ "$tmp_size" -lt 8388608 ]; then
          echo WARNING: Your /tmp directory is less than 8 gigibytes.
          echo You may run into errors during the build due to /tmp running out of space
          echo \ if you are building for multiple architectures.
          echo You can remount it larger with "mount -o remount,size=12G /tmp"
          echo \ if it is tmpfs and you have enough RAM.
      fi
  fi
  
  echo "Building with rocm and without non-x86-64 optimizations"
  cd "${srcdir}"/tensorflow-upstream-rocm
  
  export CC_OPT_FLAGS="-march=x86-64"
  export TF_NEED_CUDA=0
  export TF_NEED_ROCM=1
  ./configure
  
  bazel \
    build ${BAZEL_ARGS[@]} \
      //tensorflow:libtensorflow.so \
      //tensorflow:libtensorflow_cc.so \
      //tensorflow:install_headers \
      //tensorflow/tools/pip_package:build_pip_package
  bazel-bin/tensorflow/tools/pip_package/build_pip_package "${srcdir}"/tmprocm --rocm
  
  echo "Building with rocm and non-x86-64 optimizations"
  cd "${srcdir}"/tensorflow-upstream-opt-rocm
  
  export CC_OPT_FLAGS="-march=haswell -O3"
  export TF_NEED_CUDA=0
  export TF_NEED_ROCM=1
  ./configure
  
  bazel \
    build ${BAZEL_ARGS[@]} \
      //tensorflow:libtensorflow.so \
      //tensorflow:libtensorflow_cc.so \
      //tensorflow:install_headers \
      //tensorflow/tools/pip_package:build_pip_package
  bazel-bin/tensorflow/tools/pip_package/build_pip_package "${srcdir}"/tmpoptrocm --rocm
}

_package() {
  # install headers first
  install -d "${pkgdir}"/usr/include/tensorflow
  cp -r bazel-bin/tensorflow/include/* "${pkgdir}"/usr/include/tensorflow/

  # install python-version to get all extra headers
  WHEEL_PACKAGE=$(find "${srcdir}"/$1 -name "tensor*.whl")
  python -m installer --destdir="$pkgdir" $WHEEL_PACKAGE

  # move extra headers to correct location
  local _srch_path="${pkgdir}/usr/lib/python$(get_pyver)"/site-packages/tensorflow/include
  check_dir "${_srch_path}"  # we need to quit on broken search paths
  cp -rf "${_srch_path}"/* "${pkgdir}"/usr/include/tensorflow/

  # clean up unneeded files
  rm -rf "${pkgdir}"/usr/bin
  rm -rf "${pkgdir}"/usr/lib
  rm -rf "${pkgdir}"/usr/share

  # make sure no lib objects are outside valid paths
  local _so_srch_path="${pkgdir}/usr/include"
  check_dir "${_so_srch_path}"  # we need to quit on broken search paths
  find "${_so_srch_path}" -type f,l \( -iname "*.so" -or -iname "*.so.*" \) -print0 | while read -rd $'\0' _so_file; do
    # check if file is a dynamic executable
    ldd "${_so_file}" &>/dev/null && rm -rf "${_so_file}"
  done

  # install the rest of tensorflow
  tensorflow/c/generate-pc.sh --prefix=/usr --version=${pkgver}
  sed -e 's@/include$@/include/tensorflow@' -i tensorflow.pc -i tensorflow_cc.pc
  install -Dm644 tensorflow.pc "${pkgdir}"/usr/lib/pkgconfig/tensorflow.pc
  install -Dm644 tensorflow_cc.pc "${pkgdir}"/usr/lib/pkgconfig/tensorflow_cc.pc
  install -Dm755 bazel-bin/tensorflow/libtensorflow.so "${pkgdir}"/usr/lib/libtensorflow.so.${pkgver}
  ln -s libtensorflow.so.${pkgver} "${pkgdir}"/usr/lib/libtensorflow.so.${pkgver:0:1}
  ln -s libtensorflow.so.${pkgver:0:1} "${pkgdir}"/usr/lib/libtensorflow.so
  install -Dm755 bazel-bin/tensorflow/libtensorflow_cc.so "${pkgdir}"/usr/lib/libtensorflow_cc.so.${pkgver}
  ln -s libtensorflow_cc.so.${pkgver} "${pkgdir}"/usr/lib/libtensorflow_cc.so.${pkgver:0:1}
  ln -s libtensorflow_cc.so.${pkgver:0:1} "${pkgdir}"/usr/lib/libtensorflow_cc.so
  install -Dm755 bazel-bin/tensorflow/libtensorflow_framework.so "${pkgdir}"/usr/lib/libtensorflow_framework.so.${pkgver}
  ln -s libtensorflow_framework.so.${pkgver} "${pkgdir}"/usr/lib/libtensorflow_framework.so.${pkgver:0:1}
  ln -s libtensorflow_framework.so.${pkgver:0:1} "${pkgdir}"/usr/lib/libtensorflow_framework.so
  install -Dm644 tensorflow/c/c_api.h "${pkgdir}"/usr/include/tensorflow/tensorflow/c/c_api.h
  install -Dm644 LICENSE "${pkgdir}"/usr/share/licenses/${pkgname}/LICENSE

  # Fix interoperability of C++14 and C++17. See https://bugs.archlinux.org/task/65953
  patch -Np0 -i "${srcdir}"/fix-c++17-compat.patch -d "${pkgdir}"/usr/include/tensorflow/absl/base

}

_python_package() {
  WHEEL_PACKAGE=$(find "${srcdir}"/$1 -name "tensor*.whl")
  python -m installer --destdir="$pkgdir" $WHEEL_PACKAGE

  # create symlinks to headers
  local _srch_path="${pkgdir}/usr/lib/python$(get_pyver)"/site-packages/tensorflow/include/
  check_dir "${_srch_path}"  # we need to quit on broken search paths
  find "${_srch_path}" -maxdepth 1 -mindepth 1 -type d -print0 | while read -rd $'\0' _folder; do
    rm -rf "${_folder}"
    _smlink="$(basename "${_folder}")"
    ln -s /usr/include/tensorflow/"${_smlink}" "${_srch_path}"
  done

  # tensorboard has been separated from upstream but they still install it with
  # tensorflow. I don't know what kind of sense that makes but we have to clean
  # it out from this package.
  rm -rf "${pkgdir}"/usr/bin/tensorboard

  install -Dm644 LICENSE "${pkgdir}"/usr/share/licenses/${pkgname}/LICENSE
}

package_tensorflow-amd-git() {
  conflicts=(tensorflow)
  provides=(tensorflow)
  
  cd "${srcdir}"/tensorflow-upstream-rocm
  _package tmprocm
}

package_tensorflow-opt-amd-git() {
  pkgdesc="Library for scalable machine learning (with ROCm and non-x86 optimizations)"
  conflicts=(tensorflow)
  provides=(tensorflow)
  
  cd "${srcdir}"/tensorflow-upstream-opt-rocm
  _package tmpoptrocm
}

package_python-tensorflow-amd-git() {
  depends+=(tensorflow "${_common_py_depends[@]}")
  conflicts=(python-tensorflow)
  provides=(python-tensorflow)

  cd "${srcdir}"/tensorflow-upstream-rocm
  _python_package tmprocm
}

package_python-tensorflow-opt-amd-git() {
  pkgdesc="Library for scalable machine learning (with ROCm and non-x86 optimizations)"
  depends+=(tensorflow "${_common_py_depends[@]}")
  conflicts=(python-tensorflow)
  provides=(python-tensorflow)

  cd "${srcdir}"/tensorflow-upstream-opt-rocm
  _python_package tmpoptrocm
}

# vim:set ts=2 sw=2 et: