Skip to content

Instantly share code, notes, and snippets.

@fperezgamonal
Created September 17, 2021 10:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fperezgamonal/c6df3df9cd7dbcadb0c63ae9aed99470 to your computer and use it in GitHub Desktop.
Save fperezgamonal/c6df3df9cd7dbcadb0c63ae9aed99470 to your computer and use it in GitHub Desktop.
Script to build from source and extract DLL, lib and includes for TF 1.15.3 and 2.6.0 (Windows)
#
# Auxiliary script that simply calls the 2 main scripts above: one builds TF, the other extracts the lib, DLL and includes.
# TF version should be in the format v.X.Y.Z, for instance: v2.6.0.
#
# Usage:
# .\build_and_extract_TF_source.ps1 -TFVersion v2.6.0
#
param (
[Parameter(Mandatory = $true)]
[string]$TFVersion
)
# Parameters for GPU build (check https://www.tensorflow.org/install/source_windows for more options)
$BazelBuildParameters = "--config=opt --config=cuda --define=no_tensorflow_py_deps=true --copt=-nvcc_options=disable-warnings //tensorflow:tensorflow_cc.dll --verbose_failures --local_ram_resources=2048"
Write-Output "Building target TF version '$TFVersion'..."
.\build_TF_source.ps1 -BazelBuildParameters $BazelBuildParameters -buildVersion $TFVersion
# Ensure we return to the scripts folder (the above script navigates through some folders)
cd $PSScriptRoot
Write-Output "Extracting lib, DLL and include(s) to bin folder..."
.\extract-build-tensorflow-cpp-api.ps1 -TFVersion $TFVersion
Write-Output "All done, exitting script!"
# Requires -RunAsAdministrator
# This script needs to be run with administrator rights.
# --------------------------------------- Credits and assumptions --------------------------------------------------
# Based off: https://github.com/guikarist/tensorflow-windows-build-script (required for building TF 1.X)
# TF 2.6.0 does NOT depend on the above code and instead merges all the steps in https://www.tensorflow.org/install/source_windows
# in a semi-automatised way.
#
# Please, note that we assumed you have already installed:
# - Python 3.9.6 (although if you have not it will be installed IN A NON-DEFAULT DIRECTORY [line 140])
# - CUDA 11.2 (TF 2.6.0) + cuDNN 8.1 (TF 2.6.0). For TF 1.15.3: CUDA 10.2, cuDNN 7.6.5.
# - MSVC 2019 build tools (https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2019)
# - MSYS2 (version 20210725 a.k.a. v6.0.0): we need some of the tools it installs (https://www.msys2.org/)
#
# Usage:
# .\build_TF_source.ps1 -BazelBuildParameters $BazelBuildParameters -buildVersion $TFVersion
# E.g.:
# $BazelBuildParameters = "--config=opt --config=cuda --define=no_tensorflow_py_deps=true --copt=-nvcc_options=disable-warnings //tensorflow:tensorflow_cc.dll --verbose_failures --local_ram_resources=2048"
# $TFVersion = "v2.6.0"
# .\build_TF_source.ps1 -BazelBuildParameters $BazelBuildParameters -buildVersion $TFVersion
# Limiting local RAM resources was critical to avoid "compiler run out of heap space"-like errors (may be Windows specific since I had no problems in Linux)
#
# Last updated: added support for TF 2.6.0
# Feel free to contact me for doubts at fperez.gamonal@gmail.com
# Extraction script is identical that the one used for TF 1.15.3 (same paths if your source repository was extracted to a folder
# with the same name (i.e.: 'bazel-$folderName') [same gist]
# ------------------------------------------------------------------------------------------------------------------
param (
[Parameter(Mandatory = $true)]
[string]$BazelBuildParameters,
[Parameter(Mandatory = $true)]
[string]$buildVersion,
[switch]$BuildCppAPI = $false,
[switch]$ReserveSource = $false,
[switch]$ReserveVenv = $false,
[switch]$IgnoreDepsVersionIssues = $false,
[switch]$InstallDefaultDeps = $false,
[switch]$UseForkedVersion = $false
)
# Set parameters for execution.
Set-StrictMode -Version latest
$ErrorActionPreference = "Stop"
# Cleaning work
if (Test-Path tensorflow) {
Remove-Item tensorflow -Force -Recurse
}
if (!$ReserveVenv -and (Test-Path venv)) {
Remove-Item venv -Force -Recurse
}
if (!$ReserveSource -and (Test-Path source)) {
Remove-Item source -Force -Recurse
}
# Functions used in installation of dependencies
function CheckInstalled {
param (
[string]$ExeName,
[Parameter(Mandatory = $false)]
[string]$RequiredVersion
)
$installed = Get-Command $ExeName -ErrorAction SilentlyContinue
if ($null -eq $installed) {
Write-Host "Unable to find $ExeName." -ForegroundColor Red
return $false
} else {
Write-Host "Found $ExeName installed." -ForegroundColor Green
if ([string]::Empty -ne $RequiredVersion -and $true -ne $IgnoreDepsVersionIssues) {
Write-Host $("Make sure you have installed same version of $ExeName $RequiredVersion.") -ForegroundColor Yellow
$confirmation = Read-Host "Are you sure you want to PROCEED? [y/n]"
while ($confirmation -ne "y") {
if ($confirmation -eq "n") {exit}
$confirmation = Read-Host "Are you sure you want to PROCEED? [y/n]"
}
}
return $true
}
}
function askForVersion {
param (
[Parameter(Mandatory = $true)]
[string]$DefaultVersion
)
if ($InstallDefaultDeps) {
return $DefaultVersion
}
$version = Read-Host "Which version would you like to install? [Default version: $DefaultVersion]"
if ($version -eq "") {
return $DefaultVersion
}
return $version
}
# Assign correct versions of dependencies.
Write-Host "Checking dependencies versions and making sure they match targets..."
if ($buildVersion -eq "v1.11.0" -or $buildVersion -eq "v1.12.0") {
$bazelVersion = "0.15.0"
} elseif ($buildVersion -eq "v1.13.1") {
$bazelVersion = "0.20.0"
} elseif ($buildVersion -eq "v1.15.3") {
$bazelVersion = "0.26.0" # chocolatey does not have subversions, only 0.26.0 or 0.27.0, staying with 0.26.0
} elseif ($buildVersion -eq "v2.6.0") {
$bazelVersion = "3.7.2"
}
# Installation of dependencies
if (!(CheckInstalled chocolatey)) {
Write-Host "Installing Chocolatey package manager."
Set-ExecutionPolicy Bypass -Scope Process -Force
# Invoke-Expression ((New-Object System.Net.WebClient).DownloadString("https://chocolatey.org/install.ps1"))
# Updated powershell command from chocolatey website
Set-ExecutionPolicy Bypass -Scope Process -Force
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
}
choco feature enable -n allowGlobalConfirmation | Out-Null # Enable global confirmation for chocolatey package installation.
if (!(CheckInstalled pacman)) {
if ($buildVersion -eq "v1.15.3") {
$version = askForVersion "20200602.0.0"
} elseif ($buildVersion -eq "v2.6.0") {
$version = askForVersion "20210725" # not sure if we should add '.0.0' at the end or not (correct this if it fails!)
}
else {
$version = askForVersion "20180531.0.0"
}
choco install msys2 --version $version --params "/NoUpdate /InstallDir:C:\msys64"
}
$ENV:Path += ";C:\msys64\usr\bin"
$ENV:BAZEL_SH = "C:\msys64\usr\bin\bash.exe"
if (!(CheckInstalled patch)) {
pacman -S --noconfirm patch
}
if (!(CheckInstalled unzip)) {
pacman -S --noconfirm unzip
}
if (!(CheckInstalled bazel $bazelVersion)) {
$version = askForVersion $bazelVersion
# Bazel will also install msys2, but with an incorrect version, so we will ignore the dependencies.
choco install bazel --version $version --ignore-dependencies
}
if (!(CheckInstalled git)) {
choco install git
}
if ($buildVersion -eq "v2.6.0") {
if (!(CheckInstalled python "3.9.6")) {
$version = askForVersion "3.9.6"
choco install python --version $version --params "'TARGETDIR:C:/Python39'"
}
}
else {
if (!(CheckInstalled python "3.6.7")) {
$version = askForVersion "3.6.7"
choco install python --version $version --params "'TARGETDIR:C:/Python36'"
}
}
# Get the source code of Tensorflow and checkout to the specific version.
Write-Host "Cloning TF repo and checking out target branch/tag..."
if ($buildVersion -eq "v2.6.0")
{
Set-Location tf2-6_from_source
git clone https://github.com/tensorflow/tensorflow.git
Set-Location tensorflow
git fetch
git checkout r2.6
}
else {
if ($UseForkedVersion) { # TODO: if this is the case, do not apply the patch?
Set-Location source # simply change to source, leave the code as is!
if ($buildVersion -eq "v1.15.3") {
git checkout r1.15 # to add any new changes vs 1.15.3 (maybe there are none)
}
else {
git checkout -f tags/$buildVersion
}
}
else {
if (!$ReserveSource) {
git clone https://github.com/tensorflow/tensorflow.git
Rename-Item tensorflow source
Set-Location source
} else {
Set-Location source
git fetch
git reset --hard origin/master
git checkout -f master
git pull
}
git checkout -f tags/$buildVersion
git clean -fx
}
}
# Apply patches to source.
if ($buildVersion -eq "v1.11.0") {
# Eigen Patch for v1.11.0
git apply --ignore-space-change --ignore-white "tf_from_source\tensorflow-windows-build-script\patches\eigen.1.11.0.patch"
Copy-Item tf_from_source\tensorflow-windows-build-script\patches\eigen_half.patch third_party\
} elseif ($buildVersion -eq "v1.12.0") {
# Eigen Patch for v1.12.0
git apply --ignore-space-change --ignore-white "tf_from_source\tensorflow-windows-build-script\patches\eigen.1.12.0.patch"
Copy-Item tf_from_source\tensorflow-windows-build-script\patches\eigen_half.patch third_party\
} elseif ($buildVersion -eq "v1.13.1") {
git apply --ignore-space-change --ignore-white 'tf_from_source\tensorflow-windows-build-script\patches\vs_2017.1.13.1.patch'
}
# In TF.VERSION >=1.15.3 the 'vs_2017.1.13.1.patch' has already been integrated into the code.
if ($BuildCppAPI) {
Write-Host "Applying symbols patch..."
if ($buildVersion -eq "v1.11.0") {
# C++ Symbol Patch for v1.11.0
git apply --ignore-space-change --ignore-white "tf_from_source\tensorflow-windows-build-script\patches\cpp_symbol.1.11.0.patch"
Copy-Item tf_from_source\tensorflow-windows-build-script\patches\tf_exported_symbols_msvc.lds tf_from_source\tensorflow-windows-build-script\source\tensorflow\
} elseif ($buildVersion -eq "v1.12.0") {
# C++ Symbol Patch for v1.12.0
git apply --ignore-space-change --ignore-white "tf_from_source\tensorflow-windows-build-script\patches\cpp_symbol.1.12.0.patch"
Copy-Item tf_from_source\tensorflow-windows-build-script\patches\tf_exported_symbols_msvc.lds tf_from_source\tensorflow-windows-build-script\source\tensorflow\
} elseif ($buildVersion -eq "v1.13.1") {
# C++ Symbol Patch for v1.13.1
git apply --ignore-space-change --ignore-white "tf_from_source\tensorflow-windows-build-script\patches\cpp_symbol.1.13.1.patch"
Copy-Item tf_from_source\tensorflow-windows-build-script\patches\tf_exported_symbols_msvc.lds tf_from_source\tensorflow-windows-build-script\source\tensorflow\
} elseif ($buildVersion -eq "v1.15.3") {
# Copy user-defined list of symbols from 'def_file_filter.py.tpl' equivalent to 'tf_exported_symbols_msvc.lds' in TF 1.15
Copy-Item tf_from_source\tensorflow-windows-build-script\patches\def_file_filter.py.tpl tf_from_source\tensorflow-windows-build-script\source\tensorflow\tools\def_file_filter\ -Force
} elseif ($buildVersion -eq "v2.6.0") {
# Works exactly like TF 1.15
Copy-Item tf2-6_from_source\patches\def_file_filter.py.tpl tf2-6_from_source\tensorflow\tensorflow\tools\def_file_filter\ -Force
}
}
Set-Location ..
# Setup folder structure.
$rootDir = $pwd
if ($buildVersion -eq "v2.6.0") {
$sourceDir = "$rootDir\tensorflow"
} else {
$sourceDir = "$rootDir\source"
}
$venvDir = "$rootDir\venv"
# Create python environment.
Write-Host "Creating python environment if we are not already in one..."
# For TF 2.6.0, we use an already created environment!
if ($buildVersion -ne "v2.6.0") {
if (!$ReserveVenv) {
mkdir $venvDir | Out-Null
py -3 -m venv venv
.\venv\Scripts\Activate.ps1
pip3 install six numpy wheel
if ($buildVersion -eq "v1.15.3" -or $buildVersion -eq "v2.6.0") {
pip3 install keras_applications==1.0.6 --no-deps
pip3 install keras_preprocessing==1.0.5 --no-deps
} else {
pip3 install keras_applications==1.0.5 --no-deps
pip3 install keras_preprocessing==1.0.3 --no-deps
}
} else {
.\venv\Scripts\Activate.ps1
}
}
Set-Location $sourceDir
if ($ReserveSource) {
# Clean Bazel files.
bazel clean --expunge
}
# Configure
if ($buildVersion -ne "v2.6.0") {
$ENV:PYTHON_BIN_PATH = "$VenvDir/Scripts/python.exe" -replace "[\\]", "/"
$ENV:PYTHON_LIB_PATH = "$VenvDir/lib/site-packages" -replace "[\\]", "/"
}
Write-Host "Configurating TF build..."
python configure.py
# Build
Write-Host "============================== TF BUILD STARTED =============================="
Invoke-Expression ("bazel build " + $BazelBuildParameters)
# Shutdown Bazel
bazel shutdown
Write-Host "============================== TF BUILD ENDED =============================="
Set-Location $rootDir
Write-Host "All tasks done. Next, we will extract libraries, DLLs and includes to 'bin'..."
# Based off @guikarist' gist: https://gist.github.com/guikarist/e10dff3a4e777856cf40e44713fc2cb7
# This script should be executed on the parent folder of the repository 'tensorflow-windows-build-script' (be it a fork or @guikarist original repo)
# Updated according to new .so filenames in 1.15
# Changes: added compatibility for 1.15 (name changes, etc.) + copy several other needed headers from core/ and cc/
# Update according to new filenames in 2.6.0 (added compatibility)
# Reminder to self: piping a command with verbose to Out-Null avoids printing to stdout!
#
# Usage:
# .\extract-build-tensorflow-cpp-api.ps1 -TFVersion $TFVersion # where $TFVersion in ('v2.6.0', 'v1.15.3' or 'v1.13.1')
# Feel free to contact me for doubts at fperez.gamonal@gmail.com
param (
[Parameter(Mandatory = $true)]
[string]$TFVersion
)
# $TFVersion = Read-Host "Enter built tensorflow version (> 1.13 => 'v1.15.3', <=1.13 ==> 'v1.13.1', 2.6.0 => 'v2.6.0')"
if ($TFVersion -eq "v1.15.3") {
Write-Output "--------------- TF version 1.15.3 ---------------"
} elseif ($TFVersion -eq "v2.6.0") {
Write-Output "--------------- TF version 2.6.0 ---------------"
}
else {
Write-Output "--------------- TF version 1.13.1 ---------------"
}
Set-StrictMode -Version latest
$ErrorActionPreference = "Stop"
Remove-Item bin -ErrorAction SilentlyContinue -Force -Recurse
# =================== Change bin and source dir to accomodate your needs ===================
if ($TFVersion -eq "v2.6.0")
{
$tensorFlowBinDir = "$pwd\tf2-6_from_source\bin"
}
else
{
$tensorFlowBinDir = "$pwd\tf_from_source\bin"
}
mkdir $tensorFlowBinDir | Out-Null
if ($TFVersion -eq "v2.6.0")
{
$tensorFlowSourceDir = "$pwd\tf2-6_from_source\tensorflow"
}
else
{
$tensorFlowSourceDir = "$pwd\tf_from_source\tensorflow-windows-build-script\source"
}
# =================== Tensorflow lib and includes ===================
mkdir "$tensorFlowBinDir/tensorflow/lib" | Out-Null
Write-Output "Copying tensorflow_cc.lib and tensorflow_cc.dll..."
if ($TFVersion -eq "v1.15.3") {
# Note: if you run bazel build ... tensorflow_cc.lib, the second copy instruction may be not correct, as you will already have a .lib, if so change this as needed!
Copy-Item $tensorFlowSourceDir\bazel-bin\tensorflow\tensorflow_cc.dll $tensorFlowBinDir\tensorflow\lib\tensorflow_cc.dll
Copy-Item $tensorFlowSourceDir\bazel-bin\tensorflow\libtensorflow_cc.dll.ifso $tensorFlowBinDir\tensorflow\lib\tensorflow_cc.lib
} elseif ($TFVersion -eq "v2.6.0")
{
Copy-Item $tensorFlowSourceDir\bazel-bin\tensorflow\tensorflow_cc.dll $tensorFlowBinDir\tensorflow\lib\tensorflow_cc.dll
Copy-Item $tensorFlowSourceDir\bazel-bin\tensorflow\tensorflow_cc.dll.if.lib $tensorFlowBinDir\tensorflow\lib\tensorflow_cc.lib
} else {
Copy-Item $tensorFlowSourceDir\bazel-bin\tensorflow\libtensorflow_cc.so $tensorFlowBinDir\tensorflow\lib\tensorflow_cc.dll
Copy-Item $tensorFlowSourceDir\bazel-bin\tensorflow\libtensorflow_cc.so.if.so $tensorFlowBinDir\tensorflow\lib\tensorflow_cc.lib
}
# =================== 1. Copy cc/ and core/ headers ===================
Write-Output "Copying cc/ and core/ headers..."
Robocopy $tensorFlowSourceDir\tensorflow\core $tensorFlowBinDir\tensorflow\include\tensorflow\core "*.h" /S | Out-Null
Robocopy $tensorFlowSourceDir\tensorflow\cc $tensorFlowBinDir\tensorflow\include\tensorflow\cc "*.h" /S | Out-Null
# =================== 2. Copy external and third party dependencies properly resolving with a deep copy the symlinks ===================
Write-Output "Copying external and third_party dependencies..."
# NOTE: bazel-source gets the name from the folder from which is called (parent), so for TF 2.6.0 is simply 'tensorflow' => bazel-tensorflow
# external/eigen:
if ($TFVersion -eq "v2.6.0")
{
Robocopy $tensorFlowSourceDir\bazel-tensorflow\external\eigen_archive $tensorFlowBinDir\tensorflow\include\external\eigen_archive /S | Out-Null
}
else {
Robocopy $tensorFlowSourceDir\bazel-source\external\eigen_archive $tensorFlowBinDir\tensorflow\include\external\eigen_archive /S | Out-Null
}
# absl (in earlier versions than 1.13 this package may be outside 'com_google' with the name 'absl' or similar)
if ($TFVersion -eq "v2.6.0")
{
Robocopy $tensorFlowSourceDir\bazel-tensorflow\external\com_google_absl $tensorFlowBinDir\tensorflow\include\external\com_google_absl /S | Out-Null
} else {
Robocopy $tensorFlowSourceDir\bazel-source\external\com_google_absl $tensorFlowBinDir\tensorflow\include\external\com_google_absl /S | Out-Null
}
# nsync
if ($TFVersion -eq "v2.6.0")
{
Robocopy $tensorFlowSourceDir\bazel-tensorflow\external\nsync $tensorFlowBinDir\tensorflow\include\external\nsync /S | Out-Null
} else {
Robocopy $tensorFlowSourceDir\bazel-source\external\nsync $tensorFlowBinDir\tensorflow\include\external\nsync /S | Out-Null
}
# protobuf (at least in 1.15, is under com_google_protobuf. We do not know if this change is present in 1.14, check it.)
if ($TFVersion -eq "v2.6.0")
{
Robocopy $tensorFlowSourceDir\bazel-tensorflow\external\com_google_protobuf $tensorFlowBinDir\tensorflow\include\external\com_google_protobuf /S | Out-Null
} elseif ($TFVersion -eq "v1.15.3") {
Robocopy $tensorFlowSourceDir\bazel-source\external\com_google_protobuf $tensorFlowBinDir\tensorflow\include\external\com_google_protobuf /S | Out-Null
} else {
Robocopy $tensorFlowSourceDir\bazel-source\external\protobuf_archive $tensorFlowBinDir\tensorflow\include\external\protobuf_archive /S | Out-Null
}
# snappy
if ($TFVersion -eq "v2.6.0")
{
Robocopy $tensorFlowSourceDir\bazel-tensorflow\external\snappy $tensorFlowBinDir\tensorflow\include\external\snappy /S | Out-Null
} else {
Robocopy $tensorFlowSourceDir\bazel-source\external\snappy $tensorFlowBinDir\tensorflow\include\external\snappy /S | Out-Null
}
# third_party/eigen3
if ($TFVersion -eq "v2.6.0")
{
Robocopy $tensorFlowSourceDir\bazel-tensorflow\third_party\eigen3 $tensorFlowBinDir\tensorflow\include\third_party\eigen3 /S | Out-Null
} else {
Robocopy $tensorFlowSourceDir\bazel-source\third_party\eigen3 $tensorFlowBinDir\tensorflow\include\third_party\eigen3 /S | Out-Null
}
# =================== 3. Copy more headers (.pb.h and .h) ===================
Write-Output "Copying more .pb.h headers (protobuf, framework, lib/core)..."
# .pb.h from core/framework:
if ($TFVersion -eq "v2.6.0")
{
Robocopy $tensorFlowSourceDir\bazel-bin\tensorflow\core\framework $tensorFlowBinDir\tensorflow\include\tensorflow\core\framework "*.pb.h" /S | Out-Null
} else {
Robocopy $tensorFlowSourceDir\bazel-genfiles\tensorflow\core\framework $tensorFlowBinDir\tensorflow\include\tensorflow\core\framework "*.pb.h" /S | Out-Null
}
# .pb.h from core/protobuf:
if ($TFVersion -eq "v2.6.0")
{
Robocopy $tensorFlowSourceDir\bazel-bin\tensorflow\core\protobuf $tensorFlowBinDir\tensorflow\include\tensorflow\core\protobuf "*.pb.h" /S | Out-Null
} else {
Robocopy $tensorFlowSourceDir\bazel-genfiles\tensorflow\core\protobuf $tensorFlowBinDir\tensorflow\include\tensorflow\core\protobuf "*.pb.h" /S | Out-Null
}
# .pb.h from core\lib\core:
if ($TFVersion -eq "v2.6.0")
{
Robocopy $tensorFlowSourceDir\bazel-bin\tensorflow\core\lib\core $tensorFlowBinDir\tensorflow\include\tensorflow\core\lib\core "*.pb.h" /S | Out-Null
} else {
Robocopy $tensorFlowSourceDir\bazel-genfiles\tensorflow\core\lib\core $tensorFlowBinDir\tensorflow\include\tensorflow\core\lib\core "*.pb.h" /S | Out-Null
}
# .h from cc\ops:
if ($TFVersion -eq "v2.6.0")
{
Robocopy $tensorFlowSourceDir\bazel-bin\tensorflow\cc\ops $tensorFlowBinDir\tensorflow\include\tensorflow\cc\ops "*.h" /S | Out-Null
} else {
Robocopy $tensorFlowSourceDir\bazel-genfiles\tensorflow\cc\ops $tensorFlowBinDir\tensorflow\include\tensorflow\cc\ops "*.h" /S | Out-Null
}
Write-Output "Everything copied to '$tensorFlowBinDir', exitting script!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment