# Swift for TensorFlow Developer Guide
## Requirements
* The latest Swift toolchain snapshot from [swift.org][swift]
Swift for TensorFlow APIs can be built with either:
* CMake 3.16 or later from [cmake.org][cmake]
* Swift Package Manager (included in the above toolchain)
## Components
Building Swift for TensorFlow APIs involves two distinct components:
1. X10
2. Swift APIs
What is X10?
> X10 provides the underlying lazy tensor implementation that is used for
> tensor computations in the Swift for TensorFlow APIs. This library builds on
> top of the TensorFlow library, using the XLA compiler to perform
> optimizations.
>
> The X10 implementation consists of two halves:
>
> 1. [XLA Client](Sources/x10/xla_client): provides an abstract interface for
> dispatching XLA computations on devices
> 2. [X10](Sources/x10/xla_tensor): Lowering rules and tracing support for
> Tensors
The two components can be built together (CMake only) or separately.
Follow the instructions below based on your preferred build tool (CMake or
SwiftPM).
## Building With CMake
With CMake, X10 and Swift APIs can be built either together or separately.
To determine the appropriate build path, first consider your platform and
whether you are modifying X10.
* If you are modifying files in any subdirectory within **Sources/CX10** or
**Sources/x10**, you are modifying X10 and must follow
[**Option 1**](#option-1-build-x10-and-swift-apis-together).
* If you are not modifying X10 and are on Windows or macOS or have previously
built X10, use [**Option 2**](#option-2-use-a-prebuilt-version-of-x10).
* Otherwise, use [**Option 1**](#option-1-build-x10-and-swift-apis-together).
> **Note:** In-tree builds are not supported.
> **Note:** To enable CUDA support, run `export TF_NEED_CUDA=1` before the
steps below.
> **Note:** If `swiftc` is not in your `PATH`, you must specify the path to it
using `-D CMAKE_Swift_COMPILER=`.
### Option 1: Build X10 and Swift APIs together
This command builds both X10 and Swift APIs in sequence. Ensure that you
do not have the X10 modules in the toolchain that you are using to develop here
(more explicitly, use a stock toolchain rather than a TensorFlow toolchain).
```shell
cmake -B out -G Ninja -S swift-apis -D CMAKE_BUILD_TYPE=Release
cmake --build out
```
### Option 2: Use a prebuilt version of X10
If you are not modifying X10 or have already built it yourself using Option 1
above, you can inform CMake where to find the build time components of the
library (SDK contents).
There are prebuilt versions of the X10 library for certain platforms. If a
prebuilt library is unavailable for your desired platform, you can build X10
from source following the instructions in [Option 1](#option-2-build-x10).
- [Windows 10 (x64)][windows10]
- [macOS (x64)][macOS]
- [Ubuntu 18.04 (x64, CPU)][ubuntu1804]
- [Ubuntu 18.04 (x64, CUDA 11)][ubuntu1804cuda11]
Note the location where you extract the prebuilt library. The path to these
libraries is not fixed and depends on your machine setup.
You should substitute the paths with the appropriate values. In the example
commands below, we assume that the library is packaged in a traditional Unix
style layout and placed in `/Library/tensorflow-2.4.0`.
Because the library name differs based on the platform, the following examples
may help identify what the flags should look like for the target that you are
building for.
macOS:
```shell
cmake -B out -G Ninja -S swift-apis -D CMAKE_BUILD_TYPE=Release \
-D X10_LIBRARY=/Library/tensorflow-2.4.0/usr/lib/libx10.dylib \
-D X10_INCLUDE_DIRS=/Library/tensorflow-2.4.0/usr/include
cmake --build out
```
Windows:
```shell
cmake -B out -G Ninja -S swift-apis -D CMAKE_BUILD_TYPE=Release \
-D X10_LIBRARY=/Library/tensorflow-2.4.0/usr/lib/x10.lib \
-D X10_INCLUDE_DIRS=/Library/tensorflow-2.4.0/usr/include
cmake --build out
```
Other Unix systems (e.g. Linux, BSD, Android, etc):
```shell
cmake -B out -G Ninja -S swift-apis -D CMAKE_BUILD_TYPE=Release \
-D X10_LIBRARY=/Library/tensorflow-2.4.0/usr/lib/libx10.so \
-D X10_INCLUDE_DIRS=/Library/tensorflow-2.4.0/usr/include
cmake --build out
```
### Running tests
To run tests:
> **Note:** To view failure output, run `export CTEST_OUTPUT_ON_FAILURE=1`
before running tests.
```shell
cmake --build out --target test
```
#### macOS
On macOS, passing `-D BUILD_TESTING=NO` is currently necessary to skip building
tests. This avoids an error: `cannot load underlying module for 'XCTest'`.
```shell
cmake -B out -G Ninja -S swift-apis -D CMAKE_BUILD_TYPE=Release \
-D BUILD_TESTING=NO
cmake --build out
```
## Building With Swift Package Manager
Building with SwiftPM involves building X10 and Swift APIs separately.
### Building X10
To determine the appropriate build path, first consider your platform and
whether you are modifying X10.
* If you are modifying files in any subdirectory within **Sources/CX10** or
**Sources/x10**, you are modifying X10 and must follow
[**Option 1**](#option-1-build-x10).
* If you are on Windows or macOS and are not modifying X10, use
[**Option 2**](#option-2-use-a-prebuilt-version-of-x10-1).
* Otherwise, use [**Option 1**](#option-1-build-x10).
#### Option 1: Build X10
Although using the prebuilt libraries is more convenient, there may be some
situations where you may need to build X10 yourself. These include:
1. You are targeting a platform where we do not have prebuilt binaries for X10
2. You are attempting to make changes to the X10 implementation itself, and must
therefore build a new version.
##### Requirements
* Bazel. This can be installed [manually][bazel] or with
[Bazelisk][bazelisk]. You will need a version supported by TensorFlow
(between `_TF_MIN_BAZEL_VERSION` and `_TF_MAX_BAZEL_VERSION` as specified in
[tensorflow/configure.py][configure.py]).
* Python3 with [numpy][numpy].
##### Building
The library is designed to be built as part of the
[tensorflow](https://github.com/tensorflow/tensorflow) build. As such, in
order to build X10, you must build tensorflow.
Currently X10 is developed against TensorFlow 2.4.0. The following build
scripts provide commands to build on common platforms. They largely replicate
the build instructions for TensorFlow. The instructions diverge in that we
must copy the additional X10 library sources into the tensorflow repository.
The following table identifies the copied locations:
| swift-apis source | tensorflow destination |
|-------------------|------------------------|
| Sources/CX10 | swift_bindings |
| Sources/x10/xla_client | tensorflow/compiler/xla/xla_client |
| Sources/x10/xla_tensor | tensorflow/compiler/tf2xla/xla_tensor |
We build two specific targets:
1. `//tensorflow:tensorflow`
2. `//tensorflow/compiler/tf2xla/xla_tensor:x10`
On Windows, we build the additional targets to allow us to link against the
libraries:
1. `//tensorflow:tensorflow_dll_import_lib`
2. `//tensorflow/compiler/tf2xla/xla_tensor:x10_dll_import_lib `
We must pass the `--nocheck_visibility` flag to bazel to accomodate the new
libraries.
Windows Build Script
*Note: This must be executed in the x64 Native Developer Command Prompt.*
*Note: You will either need to be running with elevated privilleges, have
rights to create symbolic links and junctions, or have enabled developer mode
to successfully create the directory junctions. You may alternatively copy the
sources instead of creating a junction.*
```cmd
:: clone swift-apis
git clone git://github.com/tensorflow/swift-apis
:: checkout tensorflow
git clone --depth 1 --no-tags git://github.com/tensorflow/tensorflow
git -C tensorflow checkout refs/heads/r2.4
:: Link X10 into the source tree
mklink /J %CD%\tensorflow\swift_bindings %CD%\swift-apis\Sources\CX10
mklink /J %CD%\tensorflow\tensorflow\compiler\xla\xla_client %CD%\swift-apis\Sources\x10\xla_client
mklink /J %CD%\tensorflow\tensorflow\compiler\tf2xla\xla_tensor %CD%\swift-apis\Sources\x10\xla_tensor
:: configure path - we need the Git tools in the path
path %ProgramFiles%\Git\usr\bin;%PATH%
:: ensure that python dependencies are available
python -m pip install --user numpy six
:: configure X10/TensorFlow
set TF_ENABLE_XLA=1
set TF_NEED_ROCM=0
set TF_NEED_CUDA=0
set TF_CUDA_COMPUTE_CAPABILITIES=7.5
set CC_OPT_FLAGS="/arch:AVX /D_USE_MATH_DEFINES"
set TF_OVERRIDE_EIGEN_STRONG_INLINE=1
.\tensorflow\configure.py
:: build
set BAZEL_SH=%ProgramFiles%\Git\usr\bin\bash.exe
set BAZEL_VC=%VCINSTALLDIR%
bazel --output_user_root %CD%/caches/bazel/tensorflow build -c opt --copt /D_USE_MATH_DEFINES --define framework_shared_object=false --config short_logs --nocheck_visibility //tensorflow:tensorflow //tensorflow:tensorflow_dll_import_lib //tensorflow/compiler/tf2xla/xla_tensor:x10 //tensorflow/compiler/tf2xla/xla_tensor:x10_dll_import_lib
:: terminate bazel daemon
bazel --output_user_root %CD%/caches/bazel/tensorflow shutdown
:: package
set DESTDIR=%CD%\Library\tensorflow-windows-%VSCMD_ARG_TGT_ARCH%\tensorflow-2.4.0
md %DESTDIR\usr\bin
copy tensorflow\bazel-bin\tensorflow\tensorflow.dll %DESTDIR%\usr\bin\
copy tensorflow\bazel-bin\tensorflow\compiler\tf2xla\xla_tensor\x10.dll %DESTDIR%\usr\bin\
md %DESTDIR%\usr\lib
copy tensorflow\bazel-out\%VSCMD_ARG_TGT_ARCH%_windows-opt\bin\tensorflow\tensorflow.lib %DESTDIR%\usr\lib\
copy tensorflow\bazel-out\%VSCMD_ARG_TGT_ARCH%_windows-opt\bin\tensorflow\compiler\tf2xla\xla_tensor\x10.lib %DESTDIR%\usr\lib\
md %DESTDIR%\usr\include\tensorflow\c
copy tensorflow\tensorflow\c\c_api.h %DESTDIR%\usr\include\tensorflow\c\
copy tensorflow\tensorflow\c\c_api_experimental.h %DESTDIR%\usr\include\tensorflow\c\
copy tensorflow\tensorflow\c\tf_attrtype.h %DESTDIR%\usr\include\tensorflow\c\
copy tensorflow\tensorflow\c\tf_datatype.h %DESTDIR%\usr\include\tensorflow\c\
copy tensorflow\tensorflow\c\tf_file_statistics.h %DESTDIR%\usr\include\tensorflow\c\
copy tensorflow\tensorflow\c\tf_status.h %DESTDIR%\usr\include\tensorflow\c\
copy tensorflow\tensorflow\c\tf_tensor.h %DESTDIR%\usr\include\tensorflow\c\
md %DESTDIR%\usr\include\tensorflow\c\eager
cp tensorflow\tensorflow\c\eager\c_api.h %DESTDIR%\usr\include\tensorflow\c\eager\
md %DESTDIR%\usr\include\x10
copy swift-apis\Sources\x10\swift_bindings\device_wrapper.h %DESTDIR%\usr\include\x10\
copy swift-apis\Sources\x10\swift_bindings\xla_tensor_tf_ops.h %DESTDIR%\usr\include\x10\
copy swift-apis\Sources\x10\swift_bindings\xla_tensor_wrapper.h %DESTDIR%\usr\include\x10\
md %DESTDIR%\usr\share
copy tensorflow\bazel-out\%VSCMD_ARG_TGT_ARCH%_windows-opt\bin\tensorflow\tensorflow_filtered_def_file.def %DESTDIR%\usr\share
```
macOS/Linux Build Script
> **Note:** If you are unable to run bazel on macOS due to an error about an
> unverified developer due to System Integrity Protection (SIP), you can use
> `xattr -dr com.apple.quarantine bazel` to designate it as trusted.
```bash
# clone swift-apis
git clone git://github.com/tensorflow/swift-apis
# checkout tensorflow
git clone --depth 1 --no-tags git://github.com/tensorflow/tensorflow
git -C tensorflow checkout refs/heads/r2.4
# Link X10 into the source tree
ln -sf ${PWD}/swift-apis/Sources/CX10 ${PWD}/tensorflow/swift_bindings
ln -sf ${PWD}/swift-apis/Sources/x10/xla_client ${PWD}/tensorflow/tensorflow/compiler/xla/xla_client
ln -sf ${PWD}/swift-apis/Sources/x10/xla_tensor ${PWD}/tensorflow/tensorflow/compiler/tf2xla/xla_tensor
# ensure that python dependencies are available
python3 -m pip install --user numpy six
# configure X10/TensorFlow
export PYTHON_BIN_PATH=$(which python3)
export USE_DEFAULT_PYTHON_LIB_PATH=1
export TF_NEED_OPENCL_SYCL=0
export TF_DOWNLOAD_CLANG=0
export TF_SET_ANDROID_WORKSPACE=0
export TF_CONFIGURE_IOS=0
export TF_ENABLE_XLA=1
export TF_NEED_ROCM=0
export TF_NEED_CUDA=0
export TF_CUDA_COMPUTE_CAPABILITIES=7.5
export CC_OPT_FLAGS="-march=native"
python3 ./tensorflow/configure.py
bazel --output_user_root ${PWD}/caches/bazel/tensorflow build -c opt --define framework_shared_object=false --config short_logs --nocheck_visibility //tensorflow:tensorflow //tensorflow/compiler/tf2xla/xla_tensor:x10
# terminate bazel daemon
bazel --output_user_root ${PWD}/caches/bazel/tensorflow shutdown
# package
DESTDIR=${PWD}/Library/tensorflow-$(echo $(uname -s) | tr 'A-Z' 'a-z')-$(uname -m)/tensorflow-2.4.0
mkdir -p ${DESTDIR}/usr/lib
cp tensorflow/bazel-bin/tensorflow/libtensorflow-2.4.0.(dylib|so) ${DESTDIR}/usr/lib/
cp tensorflow/bazel-bin/tensorflow/compiler/tf2xla/xla_tensor/libx10.(dylib|so) ${DESTDIR}/usr/lib/
mkdir -p ${DESTDIR}/usr/include/tensorflow/c
cp tensorflow/tensorflow/c/c_api.h ${DESTDIR}/usr/include/tensorflow/c/
cp tensorflow/tensorflow/c/c_api_experimental.h ${DESTDIR}/usr/include/tensorflow/c/
cp tensorflow/tensorflow/c/tf_attrtype.h ${DESTDIR}/usr/include/tensorflow/c/
cp tensorflow/tensorflow/c/tf_datatype.h ${DESTDIR}/usr/include/tensorflow/c/
cp tensorflow/tensorflow/c/tf_file_statistics.h ${DESTDIR}/usr/include/tensorflow/c/
cp tensorflow/tensorflow/c/tf_status.h ${DESTDIR}/usr/include/tensorflow/c/
cp tensorflow/tensorflow/c/tf_tensor.h ${DESTDIR}/usr/include/tensorflow/c/
mkdir -p ${DESTDIR}/usr/include/tensorflow/c/eager
cp tensorflow/tensorflow/c/eager/c_api.h ${DESTDIR}/usr/include/tensorflow/c/eager/
mkdir -p ${DESTDIR}/usr/include/x10
cp swift-apis/Sources/x10/swift_bindings/device_wrapper.h ${DESTDIR}/usr/include/x10/
cp swift-apis/Sources/x10/swift_bindings/xla_tensor_tf_ops.h ${DESTDIR}/usr/include/x10/
cp swift-apis/Sources/x10/swift_bindings/xla_tensor_wrapper.h ${DESTDIR}/usr/include/x10/
```
#### Option 2: Use a prebuilt version of X10
You can use a prebuilt version of the X10 library for building the Swift for
TensorFlow APIs package if you are on a supported platform and do not need to
make changes to the X10 library implementation.
There are prebuilt versions of the X10 library for certain platforms. If a
prebuilt library is unavailable for your desired platform, you can build X10
from source following the instructions in [Option 1](#option-1-build-x10).
- [Windows 10 (x64)][windows10]
- [macOS (x64)][macOS]
Note the location where you extract the prebuilt library, since it is required
for building Swift for TensorFlow APIs.
### Building Swift APIs
> **Note:** This step requires pre-built X10 binaries. Building with SwiftPM
> does not include changes to X10.
SwiftPM requires two items:
1. The location of the X10 & TensorFlow headers.
2. The location of the X10 & TensorFlow libraries.
The path to these libraries is not fixed and depends on your machine setup.
You should substitute the paths with the appropriate values. In the example
commands below, we assume that the library is packaged in a traditional Unix
style layout and placed in `/Library/tensorflow-2.4.0`.
```shell
$ swift build -Xcc -I/Library/tensorflow-2.4.0/usr/include -Xlinker -L/Library/tensorflow-2.4.0/usr/lib
```
#### macOS
On macOS, in order to select the proper toolchain, the `TOOLCHAINS` environment
variable can be used to modify the selected Xcode toolchain temporarily. The
macOS (Xcode) toolchain distributed from [swift.org][swift] has a
bundle identifier which can uniquely identify the toolchain to the system. The
following attempts to determine the latest toolchain snapshot and extract the
identifier for it.
```shell
xpath 2>/dev/null $(find /Library/Developer/Toolchains ~/Library/Developer/Toolchains -type d -depth 1 -regex '.*/swift-DEVELOPMENT-SNAPSHOT-.*.xctoolchain' | sort -u | tail -n 1)/Info.plist "/plist/dict/key[. = 'CFBundleIdentifier']/following-sibling::string[1]//text()"
```
This allows one to build the package as:
```shell
TOOLCHAINS=$(xpath 2>/dev/null $(find /Library/Developer/Toolchains ~/Library/Developer/Toolchains -type d -depth 1 -regex '.*/swift-DEVELOPMENT-SNAPSHOT-.*.xctoolchain' | sort -u | tail -n 1)/Info.plist "/plist/dict/key[. = 'CFBundleIdentifier']/following-sibling::string[1]//text()") swift build -Xswiftc -DTENSORFLOW_USE_STANDARD_TOOLCHAIN -Xcc -I/Library/tensorflow-2.4.0/usr/include -Xlinker -L/Library/tensorflow-2.4.0/usr/lib
```
### Running tests
To run tests:
```shell
$ swift test -Xcc -I/Library/tensorflow-2.4.0/usr/include -Xlinker -L/Library/tensorflow-2.4.0/usr/lib
```
[swift]: https://swift.org/download/#snapshots
[cmake]: https://www.cmake.org/download
[windows10]: https://artprodeus21.artifacts.visualstudio.com/A8fd008a0-56bc-482c-ba46-67f9425510be/3133d6ab-80a8-4996-ac4f-03df25cd3224/_apis/artifact/cGlwZWxpbmVhcnRpZmFjdDovL2NvbXBuZXJkL3Byb2plY3RJZC8zMTMzZDZhYi04MGE4LTQ5OTYtYWM0Zi0wM2RmMjVjZDMyMjQvYnVpbGRJZC80NTU3NC9hcnRpZmFjdE5hbWUvdGVuc29yZmxvdy13aW5kb3dzLXg2NA2/content?format=zip
[macOS]: https://artprodeus21.artifacts.visualstudio.com/A8fd008a0-56bc-482c-ba46-67f9425510be/3133d6ab-80a8-4996-ac4f-03df25cd3224/_apis/artifact/cGlwZWxpbmVhcnRpZmFjdDovL2NvbXBuZXJkL3Byb2plY3RJZC8zMTMzZDZhYi04MGE4LTQ5OTYtYWM0Zi0wM2RmMjVjZDMyMjQvYnVpbGRJZC80NTU3NC9hcnRpZmFjdE5hbWUvdGVuc29yZmxvdy1kYXJ3aW4teDY00/content?format=zip
[bazel]: https://docs.bazel.build/versions/master/install.html
[bazelisk]: https://github.com/bazelbuild/bazelisk
[configure.py]: https://github.com/tensorflow/tensorflow/blob/master/configure.py
[numpy]: https://numpy.org/
[ubuntu1804]: https://storage.googleapis.com/swift-tensorflow-artifacts/oneoff-builds/tensorflow-ubuntu1804-x86.zip
[ubuntu1804cuda11]: https://storage.googleapis.com/swift-tensorflow-artifacts/oneoff-builds/tensorflow-ubuntu1804-cuda11-x86.zip