Reproducible build recipe and prebuilt release artifact for TensorFlow 2.20 on Linux x86_64 systems that do not support AVX instructions.
This project exists because the official TensorFlow 2.20 Linux wheel terminates with:
Illegal instruction (core dumped)
on older Intel CPUs such as the Xeon X7560 / Westmere generation.
The repository contains the pinned build configuration and source patches used to produce a TensorFlow CPU wheel that was successfully executed on actual non-AVX Xeon X7560 hardware.
Release:
v2.20.0-nonavx.1
TensorFlow package version:
2.20.0.dev0+selfbuilt
Wheel:
tensorflow_cpu-2.20.0.dev0+selfbuilt-cp312-cp312-linux_x86_64.whl
Python ABI:
cp312
Architecture:
linux_x86_64
SHA256:
b5c0ca166e83b67c0c038b84bca5b4f4426669da86187a047ed2b64e01dca949
Release page:
https://github.com/leg3/tensorflow-nonavx/releases/tag/v2.20.0-nonavx.1
Direct wheel download:
https://github.com/leg3/tensorflow-nonavx/releases/download/v2.20.0-nonavx.1/tensorflow_cpu-2.20.0.dev0+selfbuilt-cp312-cp312-linux_x86_64.whl
Checksum manifest:
https://github.com/leg3/tensorflow-nonavx/releases/download/v2.20.0-nonavx.1/SHA256SUMS
The validated deployment target is:
Intel Xeon X7560
Westmere
Linux x86_64
The target supports the x86-64-v2 CPU baseline, including instructions such as:
- SSSE3
- SSE4.1
- SSE4.2
- POPCNT
It does not support AVX.
The build therefore uses an explicit CPU baseline rather than optimizing for the build host.
The primary compiler flags are:
-march=x86-64-v2
-mno-avx
-mno-avx2
-mno-fma
-mno-f16c
The build intentionally does not use:
-march=native
The build host may support newer CPU instructions than the deployment target. Using -march=native could therefore silently produce a binary that works on the build machine but fails on the intended non-AVX system.
The current build pins the following versions:
TensorFlow: 2.20.0
TensorFlow SHA: 72fbba3d20f4616d7312b5e2b7f79daf6e82f2fa
Python: 3.12.9
Python ABI: cp312
Bazel: 7.4.1
Clang: 18.1.8
Architecture: x86_64
CPU baseline: x86-64-v2
TensorFlow build image:
tensorflow/build:2.20-python3.12
Pinned image digest:
sha256:9a9722d3e6d10fce276e6e6396c4faea6be96ce471d9a40de33fce0433780e99
The pinned values are stored in:
build/tensorflow-nonavx/versions.env
build/
└── tensorflow-nonavx/
├── build.sh
├── versions.env
└── patches/
├── absl-nonavx.patch
├── boringssl-nonavx.patch
├── highwayhash-nonavx.patch
├── ruy-nonavx.patch
├── tensorflow-nonavx.patch
└── xnnpack-nonavx.patch
The repository contains the build recipe and patches.
The compiled TensorFlow wheel is distributed as a GitHub Release asset rather than committed to Git history.
TensorFlow includes a large third-party dependency graph.
Several dependencies can independently enable newer CPU instructions through:
- dependency-specific compiler options;
- Bazel target configuration;
- architecture-specific assembly;
- per-function compiler attributes;
- template specialization; and
- runtime CPU dispatch.
As a result, adding -mno-avx at the top-level TensorFlow build is not sufficient by itself.
The current recipe includes targeted configuration and patches for components encountered during the TensorFlow 2.20 build.
The build disables oneDNN:
--define=disable_onednn=true
--@local_xla//xla/tsl/framework/contraction:disable_onednn_contraction_kernel=True
libjpeg-turbo SIMD assembly is disabled with:
--@libjpeg_turbo//:noasm=yes
XNNPACK AVX-family implementations are explicitly disabled through Bazel configuration in addition to the XNNPACK patch.
XNNPACK contains architecture-specific optimized microkernels and its own CPU feature configuration.
The build disables AVX-family XNNPACK variants and applies a source/build patch to prevent those implementations from entering the build graph.
BoringSSL can include architecture-specific assembly independently of TensorFlow's general compiler flags.
The non-AVX patch disables the affected assembly path and defines:
OPENSSL_NO_ASM
ruy contains target-specific compiler options that can explicitly add flags including:
-mavx
-mavx2
-mfma
The non-AVX patch prevents those AVX-family compiler-option helpers from introducing unsupported instructions.
Abseil CRC code contained a function-level AVX implementation using a compiler target attribute.
Function-level attributes can generate AVX instructions even when the surrounding project is compiled with a non-AVX baseline.
The patch disables the forced AVX implementation so a compatible fallback path is used.
HighwayHash was the most subtle source of residual AVX2 instructions during development.
Removing the obvious AVX2 Bazel dependency was not sufficient because HighwayHash runtime-dispatch code still instantiated the AVX2 implementation.
The final patch addresses both:
- the AVX2 dependency path; and
- the source-level runtime dispatch that could instantiate or advertise the AVX2 implementation.
SSE4.1 and Portable implementations remain available.
This is an important consideration for future TensorFlow versions: a clean dependency graph does not necessarily prove that template or runtime-dispatch code cannot still reference an unsupported implementation.
The build requires Docker and Git.
From the repository root:
./build/tensorflow-nonavx/build.shBy default, build work is stored under:
~/build-work/tensorflow-nonavx
The build script recreates the TensorFlow source checkout and output directory for each build while retaining the Bazel cache.
The completed wheel is copied to:
~/build-work/tensorflow-nonavx/dist/
The host-side dist/ directory is the canonical build output.
Do not rely on Docker-internal or Bazel-internal bazel-bin paths when consuming the artifact from the host.
The build retains:
~/build-work/tensorflow-nonavx/bazel-home
so subsequent builds can reuse previously compiled objects.
This significantly reduces rebuild time when only targeted dependencies or patches change.
Avoid deleting the Bazel cache unless there is evidence that the cache itself is invalid.
Download the release artifact:
curl -fLO https://github.com/leg3/tensorflow-nonavx/releases/download/v2.20.0-nonavx.1/tensorflow_cpu-2.20.0.dev0+selfbuilt-cp312-cp312-linux_x86_64.whlDownload the checksum manifest:
curl -fLO https://github.com/leg3/tensorflow-nonavx/releases/download/v2.20.0-nonavx.1/SHA256SUMSVerify the artifact before installation:
sha256sum -c SHA256SUMSExpected result:
tensorflow_cpu-2.20.0.dev0+selfbuilt-cp312-cp312-linux_x86_64.whl: OK
Install into a Python 3.12 environment:
python3.12 -m pip install \
./tensorflow_cpu-2.20.0.dev0+selfbuilt-cp312-cp312-linux_x86_64.whlThe exact released wheel was copied to and tested on an Intel Xeon X7560 system without AVX support.
It was installed into a clean Python 3.12 virtual environment and tested with:
python -c "import tensorflow as tf; print(tf.__version__); print(tf.constant([1,2,3]))"TensorFlow reported:
2.20.0-dev0+selfbuilt
and successfully returned:
tf.Tensor([1 2 3], shape=(3,), dtype=int32)
The Illegal instruction (core dumped) failure encountered with the official TensorFlow wheel did not occur.
The completed wheel was extracted and its native shared libraries were inspected for AVX-family instruction mnemonics.
The final validation scan did not identify AVX-family instruction hits.
Static inspection should be treated as supporting evidence rather than a replacement for runtime testing on actual non-AVX hardware.
Runtime execution on the target CPU remains the primary acceptance test.
The current release artifact was verified through the following chain:
build artifact
↓
SHA256 verification on build host
↓
copy to Xeon X7560 target
↓
SHA256 verification
↓
runtime TensorFlow validation
↓
GitHub Release publication
↓
unauthenticated public download using curl
↓
SHA256 verification
The final public download produced the same SHA256 as the originally validated wheel.
Published binary releases are intended to be immutable.
The current release:
v2.20.0-nonavx.1
corresponds to the exact wheel with SHA256:
b5c0ca166e83b67c0c038b84bca5b4f4426669da86187a047ed2b64e01dca949
If TensorFlow 2.20.0 is rebuilt and the resulting binary has different contents, it should receive a new release identity such as:
v2.20.0-nonavx.2
rather than replacing the existing release asset.
A future TensorFlow version would follow the same pattern, for example:
v2.21.0-nonavx.1
The current patches should be treated as an implementation reference, not as patches guaranteed to apply unchanged to future TensorFlow releases.
For a future TensorFlow upgrade:
- Pin the TensorFlow source commit and build-image digest.
- Record the required Python, Bazel, and Clang versions.
- Confirm the intended CPU baseline.
- Re-audit TensorFlow build configuration for AVX-enabling options.
- Determine the exact third-party dependency revisions used by the new release.
- Re-audit XNNPACK, BoringSSL, ruy, Abseil, HighwayHash, libjpeg-turbo, and oneDNN.
- Search source and Bazel rules for:
-mavx-mavx2-mfma- AVX-512 options
- per-function target attributes
- architecture-specific assembly
- runtime CPU dispatch.
- Validate each existing patch against the new dependency revision before applying it.
- Build and inspect suspicious individual libraries where practical.
- Build the complete wheel.
- Extract and scan its native shared libraries.
- Verify the artifact checksum.
- Install the exact artifact on actual non-AVX hardware.
- Require TensorFlow import and representative computation to complete without
SIGILL/Illegal instruction. - Publish the artifact under a new immutable release version.
This repository exists only to build and distribute the custom TensorFlow dependency.
It does not contain:
- SVRaaS;
- SVRaaS model runners;
- the SVRaaS API;
- the SVRaaS orchestrator; or
- the downstream Docker runner implementation.
Projects such as SVRaaS consume the released wheel as a pinned external dependency and should verify its SHA256 before installation.