Skip to content

Commit 8cc368e

Browse files
authored
Build Addons for Windows (CPU) (#771)
* Update bazel build to compile with MSVC * Update custom ops to use C++ standard * Remove Windows ParseTime until TF core exports symbols * Fix resource loader on windows * Disable parse time on windows * Fix packaging * Finalize windows build
1 parent a5034b9 commit 8cc368e

21 files changed

+230
-52
lines changed

.travis.yml

+26-5
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,6 @@ git:
77
services:
88
- docker
99

10-
install:
11-
- curl https://bootstrap.pypa.io/get-pip.py | sudo -H python
12-
- sudo -H python -m pip install -q -U twine --ignore-installed six
13-
- twine --version
14-
1510
stages:
1611
- test
1712
- build
@@ -31,6 +26,7 @@ jobs:
3126
# Build GPU kernels without runtime=nvidia as there are no GPUs/Drivers
3227
- docker run -e TF_NEED_CUDA=1 -v ${PWD}:/addons -w /addons gcr.io/tensorflow-testing/nosla-cuda10.1-cudnn7-ubuntu16.04-manylinux2010 tools/ci_build/builds/release_linux.sh
3328
after_success:
29+
- python -m pip install -q -U twine --ignore-installed six
3430
- twine upload -u $PYPI_USER -p $PYPI_PW wheelhouse/*.whl
3531

3632
# MacOS Builds
@@ -41,8 +37,33 @@ jobs:
4137
script:
4238
- bash -x -e tools/ci_build/builds/release_macos.sh
4339
after_success:
40+
- python -m pip install -q -U twine --ignore-installed six
4441
- twine upload -u $PYPI_USER -p $PYPI_PW wheelhouse/*.whl
4542

43+
# Windows nightlies for TensorFlow are not available
44+
# Windows Builds
45+
# - stage: build
46+
# name: "Build on Windows for Python 2.7 3.5 3.6 3.7"
47+
# os: windows
48+
# language: shell
49+
# before_install:
50+
# - choco install python --version 2.7.11
51+
# - choco install python --version 3.5.4
52+
# - choco install python --version 3.6.8
53+
# - choco install python --version 3.7.5
54+
# script:
55+
# - export PATH=/c/tools/python:/c/tools/python/Scripts:$PATH
56+
# - bash -x -e tools/ci_build/builds/release_windows.sh
57+
# - export PATH=/c/Python35:/c/Python35/Scripts:$PATH
58+
# - bash -x -e tools/ci_build/builds/release_windows.sh
59+
# - export PATH=/c/Python36:/c/Python36/Scripts:$PATH
60+
# - bash -x -e tools/ci_build/builds/release_windows.sh
61+
# - export PATH=/c/Python37:/c/Python37/Scripts:$PATH
62+
# - bash -x -e tools/ci_build/builds/release_windows.sh
63+
# after_success:
64+
# - python -m pip install -q -U twine --ignore-installed six
65+
# - twine upload -u $PYPI_USER -p $PYPI_PW artifacts/*.whl
66+
4667
notifications:
4768
email:
4869
recipients:

MANIFEST.in

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
recursive-include tensorflow_addons/ *.so
1+
recursive-include tensorflow_addons *.so
22
include docs/*

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export CUDNN_INSTALL_PATH="/path/to/cudnn" (default: /usr/lib/x86_64-linux-gnu)
8888
# This script links project with TensorFlow dependency
8989
./configure.sh
9090
91-
bazel build build_pip_pkg
91+
bazel build --enable_runfiles build_pip_pkg
9292
bazel-bin/build_pip_pkg artifacts --nightly
9393
9494
pip install artifacts/tensorflow_addons-*.whl

WORKSPACE

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
workspace(name = "tensorflow_addons")
2-
31
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
42
load("//build_deps/tf_dependency:tf_configure.bzl", "tf_configure")
53
load("//build_deps/toolchains/gpu:cuda_configure.bzl", "cuda_configure")

build_deps/requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
# TensorFlow greater than this date is manylinux2010 compliant
2-
tf-nightly>=2.1.0.dev20191004
2+
tf-nightly>=2.1.0.dev20191004

build_deps/tf_dependency/tf_configure.bzl

+21-6
Original file line numberDiff line numberDiff line change
@@ -133,33 +133,45 @@ def _symlink_genrule_for_dir(
133133
dest_dir,
134134
genrule_name,
135135
src_files = [],
136-
dest_files = []):
137-
"""Returns a genrule to symlink(or copy if on Windows) a set of files.
136+
dest_files = [],
137+
tf_pip_dir_rename_pair = []):
138138

139+
"""Returns a genrule to symlink(or copy if on Windows) a set of files.
139140
If src_dir is passed, files will be read from the given directory; otherwise
140141
we assume files are in src_files and dest_files.
141-
142142
Args:
143143
repository_ctx: the repository_ctx object.
144144
src_dir: source directory.
145145
dest_dir: directory to create symlink in.
146146
genrule_name: genrule name.
147147
src_files: list of source files instead of src_dir.
148148
dest_files: list of corresonding destination files.
149-
149+
tf_pip_dir_rename_pair: list of the pair of tf pip parent directory to
150+
replace. For example, in TF pip package, the source code is under
151+
"tensorflow_core", and we might want to replace it with
152+
"tensorflow" to match the header includes.
150153
Returns:
151154
genrule target that creates the symlinks.
152155
"""
156+
# Check that tf_pip_dir_rename_pair has the right length
157+
tf_pip_dir_rename_pair_len = len(tf_pip_dir_rename_pair)
158+
if tf_pip_dir_rename_pair_len != 0 and tf_pip_dir_rename_pair_len !=2:
159+
_fail("The size of argument tf_pip_dir_rename_pair should be either 0 or 2, but %d is given." % tf_pip_dir_rename_pair_len)
160+
153161
if src_dir != None:
154162
src_dir = _norm_path(src_dir)
155163
dest_dir = _norm_path(dest_dir)
156164
files = "\n".join(sorted(_read_dir(repository_ctx, src_dir).splitlines()))
157165

158166
# Create a list with the src_dir stripped to use for outputs.
159-
dest_files = files.replace(src_dir, "").splitlines()
167+
if tf_pip_dir_rename_pair_len:
168+
dest_files = files.replace(src_dir, "").replace(tf_pip_dir_rename_pair[0], tf_pip_dir_rename_pair[1]).splitlines()
169+
else:
170+
dest_files = files.replace(src_dir, "").splitlines()
160171
src_files = files.splitlines()
161172
command = []
162173
outs = []
174+
163175
for i in range(len(dest_files)):
164176
if dest_files[i] != "":
165177
# If we have only one file to link we do not want to use the dest_dir, as
@@ -168,8 +180,9 @@ def _symlink_genrule_for_dir(
168180

169181
# Copy the headers to create a sandboxable setup.
170182
cmd = "cp -f"
171-
command.append(cmd + ' "%s" "%s" | true' % (src_files[i], dest))
183+
command.append(cmd + ' "%s" "%s"' % (src_files[i], dest))
172184
outs.append(' "' + dest_dir + dest_files[i] + '",')
185+
173186
genrule = _genrule(
174187
genrule_name,
175188
" && ".join(command),
@@ -184,13 +197,15 @@ def _tf_pip_impl(repository_ctx):
184197
tf_header_dir,
185198
"include",
186199
"tf_header_include",
200+
tf_pip_dir_rename_pair = ["tensorflow_core", "tensorflow"]
187201
)
188202

189203
tf_shared_library_dir = repository_ctx.os.environ[_TF_SHARED_LIBRARY_DIR]
190204
tf_shared_library_name = repository_ctx.os.environ[_TF_SHARED_LIBRARY_NAME]
191205
tf_shared_library_path = "%s/%s" % (tf_shared_library_dir, tf_shared_library_name)
192206
tf_cx11_abi = "-D_GLIBCXX_USE_CXX11_ABI=%s" % (repository_ctx.os.environ[_TF_CXX11_ABI_FLAG])
193207

208+
194209
tf_shared_library_rule = _symlink_genrule_for_dir(
195210
repository_ctx,
196211
None,

build_deps/toolchains/gpu/cuda_configure.bzl

+1-1
Original file line numberDiff line numberDiff line change
@@ -1031,7 +1031,7 @@ def find_cuda_config(repository_ctx, cuda_libraries):
10311031
"""Returns CUDA config dictionary from running find_cuda_config.py"""
10321032
exec_result = repository_ctx.execute([
10331033
_get_python_bin(repository_ctx),
1034-
repository_ctx.path(Label("@tensorflow_addons//build_deps/toolchains/gpu:find_cuda_config.py")),
1034+
repository_ctx.path(Label("//build_deps/toolchains/gpu:find_cuda_config.py")),
10351035
] + cuda_libraries)
10361036
if exec_result.return_code:
10371037
auto_configure_fail("Failed to run find_cuda_config.py: %s" % exec_result.stderr)

build_pip_pkg.sh

+24-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,18 @@
1616
set -e
1717
set -x
1818

19-
PIP_FILE_PREFIX="bazel-bin/build_pip_pkg.runfiles/tensorflow_addons/"
19+
PLATFORM="$(uname -s | tr 'A-Z' 'a-z')"
20+
21+
function is_windows() {
22+
# On windows, the shell script is actually running in msys
23+
[[ "${PLATFORM}" =~ msys_nt*|mingw*|cygwin*|uwin* ]]
24+
}
25+
26+
if is_windows; then
27+
PIP_FILE_PREFIX="bazel-bin/build_pip_pkg.exe.runfiles/__main__/"
28+
else
29+
PIP_FILE_PREFIX="bazel-bin/build_pip_pkg.runfiles/__main__/"
30+
fi
2031

2132
function abspath() {
2233
cd "$(dirname $1)"
@@ -45,15 +56,24 @@ function main() {
4556
cp ${PIP_FILE_PREFIX}MANIFEST.in "${TMPDIR}"
4657
cp ${PIP_FILE_PREFIX}LICENSE "${TMPDIR}"
4758
touch ${TMPDIR}/stub.cc
48-
rsync -avm -L --exclude='*_test.py' ${PIP_FILE_PREFIX}tensorflow_addons "${TMPDIR}"
59+
60+
if is_windows; then
61+
from=$(cygpath -w ${PIP_FILE_PREFIX}tensorflow_addons)
62+
to=$(cygpath -w "${TMPDIR}"/tensorflow_addons)
63+
start robocopy //S "${from}" "${to}" //xf *_test.py
64+
sleep 5
65+
else
66+
rsync -avm -L --exclude='*_test.py' ${PIP_FILE_PREFIX}tensorflow_addons "${TMPDIR}"
67+
fi
4968

5069
pushd ${TMPDIR}
5170
echo $(date) : "=== Building wheel"
5271

5372
if [[ -z ${BUILD_FLAG} ]]; then
54-
${PYTHON_VERSION:=python} setup.py bdist_wheel > /dev/null
73+
# Windows has issues with locking library files for deletion so do not fail here
74+
${PYTHON_VERSION:=python} setup.py bdist_wheel || true
5575
else
56-
${PYTHON_VERSION:=python} setup.py bdist_wheel "${2}" > /dev/null
76+
${PYTHON_VERSION:=python} setup.py bdist_wheel "${2}" || true
5777
fi
5878

5979
cp dist/*.whl "${DEST}"

configure.sh

+42-6
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
# --quiet Give less output.
2020

2121

22+
PLATFORM="$(uname -s | tr 'A-Z' 'a-z')"
23+
24+
2225
# Writes variables to bazelrc file
2326
function write_to_bazelrc() {
2427
echo "$1" >> .bazelrc
@@ -28,11 +31,30 @@ function write_action_env_to_bazelrc() {
2831
write_to_bazelrc "build --action_env $1=\"$2\""
2932
}
3033

34+
function is_linux() {
35+
[[ "${PLATFORM}" == "linux" ]]
36+
}
37+
38+
function is_macos() {
39+
[[ "${PLATFORM}" == "darwin" ]]
40+
}
41+
42+
function is_windows() {
43+
# On windows, the shell script is actually running in msys
44+
[[ "${PLATFORM}" =~ msys_nt*|mingw*|cygwin*|uwin* ]]
45+
}
46+
47+
function is_ppc64le() {
48+
[[ "$(uname -m)" == "ppc64le" ]]
49+
}
50+
3151
# Converts the linkflag namespec to the full shared library name
3252
function generate_shared_lib_name() {
33-
if [[ $(uname) == "Darwin" ]]; then
53+
if is_macos; then
3454
local namespec="$1"
3555
echo "lib"${namespec:2}".dylib"
56+
elif is_windows; then
57+
echo "_pywrap_tensorflow_internal.lib"
3658
else
3759
local namespec="$1"
3860
echo ${namespec:3}
@@ -65,14 +87,31 @@ TF_CFLAGS=( $(${PYTHON_VERSION} -c 'import tensorflow as tf; print(" ".join(tf.s
6587
TF_LFLAGS=( $(${PYTHON_VERSION} -c 'import tensorflow as tf; print(" ".join(tf.sysconfig.get_link_flags()))') )
6688
TF_CXX11_ABI_FLAG=( $(${PYTHON_VERSION} -c 'import tensorflow as tf; print(tf.sysconfig.CXX11_ABI_FLAG)') )
6789

68-
TF_SHARED_LIBRARY_DIR=${TF_LFLAGS[0]:2}
90+
if is_windows; then
91+
# Use pywrap_tensorflow instead of tensorflow_framework on Windows
92+
TF_SHARED_LIBRARY_DIR=${TF_CFLAGS:2:-7}"python"
93+
else
94+
TF_SHARED_LIBRARY_DIR=${TF_LFLAGS[0]:2}
95+
fi
96+
6997
TF_SHARED_LIBRARY_NAME=$(generate_shared_lib_name ${TF_LFLAGS[1]})
98+
TF_HEADER_DIR=${TF_CFLAGS:2}
99+
100+
if is_windows; then
101+
TF_SHARED_LIBRARY_DIR=${TF_SHARED_LIBRARY_DIR//\\//}
102+
TF_SHARED_LIBRARY_NAME=${TF_SHARED_LIBRARY_NAME//\\//}
103+
TF_HEADER_DIR=${TF_HEADER_DIR//\\//}
104+
fi
70105

71-
write_action_env_to_bazelrc "TF_HEADER_DIR" ${TF_CFLAGS:2}
106+
write_action_env_to_bazelrc "TF_HEADER_DIR" ${TF_HEADER_DIR}
72107
write_action_env_to_bazelrc "TF_SHARED_LIBRARY_DIR" ${TF_SHARED_LIBRARY_DIR}
73108
write_action_env_to_bazelrc "TF_SHARED_LIBRARY_NAME" ${TF_SHARED_LIBRARY_NAME}
74109
write_action_env_to_bazelrc "TF_CXX11_ABI_FLAG" ${TF_CXX11_ABI_FLAG}
75110

111+
write_to_bazelrc "build:cuda --define=using_cuda=true --define=using_cuda_nvcc=true"
112+
write_to_bazelrc "build --spawn_strategy=standalone"
113+
write_to_bazelrc "build --strategy=Genrule=standalone"
114+
write_to_bazelrc "build -c opt"
76115

77116
if [[ "$TF_NEED_CUDA" == "1" ]]; then
78117
write_action_env_to_bazelrc "TF_NEED_CUDA" ${TF_NEED_CUDA}
@@ -83,8 +122,5 @@ if [[ "$TF_NEED_CUDA" == "1" ]]; then
83122

84123
write_to_bazelrc "test --config=cuda"
85124
write_to_bazelrc "build --config=cuda"
86-
write_to_bazelrc "build --spawn_strategy=local"
87-
write_to_bazelrc "build --strategy=Genrule=local"
88-
write_to_bazelrc "build:cuda --define=using_cuda=true --define=using_cuda_nvcc=true"
89125
write_to_bazelrc "build:cuda --crosstool_top=@local_config_cuda//crosstool:toolchain"
90126
fi

except.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
_test.py

setup.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@
7070
elif project_name == TFA_NIGHTLY:
7171
REQUIRED_PACKAGES.append('tf-nightly')
7272

73+
# Manylinux2010 requires a patch for platlib
74+
if sys.platform.startswith('linux'):
75+
ext_modules = [Extension('_foo', ['stub.cc'])]
76+
else:
77+
ext_modules = []
78+
7379

7480
class BinaryDistribution(Distribution):
7581
"""This class is needed in order to create OS specific wheels."""
@@ -86,7 +92,7 @@ def has_ext_modules(self):
8692
author='Google Inc.',
8793
author_email='[email protected]',
8894
packages=find_packages(),
89-
ext_modules=[Extension('_foo', ['stub.cc'])],
95+
ext_modules=ext_modules,
9096
install_requires=REQUIRED_PACKAGES,
9197
include_package_data=True,
9298
zip_safe=False,

tensorflow_addons/BUILD

+5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ licenses(["notice"]) # Apache 2.0
22

33
package(default_visibility = ["//visibility:public"])
44

5+
config_setting(
6+
name = "windows",
7+
constraint_values = ["@bazel_tools//platforms:windows"],
8+
)
9+
510
py_library(
611
name = "tensorflow_addons",
712
data = [

tensorflow_addons/custom_ops/activations/cc/kernels/gelu_op.h

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ limitations under the License.
1717
#define TENSORFLOW_ADDONS_ACTIVATIONS_KERNELS_GELU_OP_H_
1818

1919
#define EIGEN_USE_THREADS
20+
#define _USE_MATH_DEFINES
21+
#include <cmath>
2022

2123
#include "tensorflow/core/framework/numeric_op.h"
2224
#include "tensorflow/core/framework/op_kernel.h"

tensorflow_addons/custom_ops/activations/cc/kernels/rrelu_op.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ struct Rrelu {
3838
typename TTypes<T>::Tensor alpha,
3939
typename random::SimplePhilox& random) {
4040
if (training) {
41-
T storage[alpha.size()];
41+
T* storage = new T[alpha.size()];
4242
typename TTypes<T>::Tensor alpha_tensor(storage, alpha.size());
4343
for (int i = 0; i < alpha_tensor.size(); i++) {
4444
alpha_tensor(i) =

tensorflow_addons/tensorflow_addons.bzl

+13-5
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,25 @@ def custom_op_library(
3636
)
3737
deps = deps + if_cuda_is_configured([":" + basename + "_gpu"])
3838

39-
copts = copts + [
40-
"-pthread",
41-
"-std=c++11",
42-
D_GLIBCXX_USE_CXX11_ABI,
43-
]
39+
copts = copts + select({
40+
"//tensorflow_addons:windows": ["/DEIGEN_STRONG_INLINE=inline",
41+
"-DTENSORFLOW_MONOLITHIC_BUILD",
42+
"/DPLATFORM_WINDOWS", "/DEIGEN_HAS_C99_MATH",
43+
"/DTENSORFLOW_USE_EIGEN_THREADPOOL", "/DEIGEN_AVOID_STL_ARRAY",
44+
"/Iexternal/gemmlowp", "/wd4018", "/wd4577", "/DNOGDI",
45+
"/UTF_COMPILE_LIBRARY"],
46+
"//conditions:default": ["-pthread", "-std=c++11", D_GLIBCXX_USE_CXX11_ABI],
47+
})
4448

4549
native.cc_binary(
4650
name = name,
4751
srcs = srcs,
4852
copts = copts,
4953
linkshared = 1,
54+
features = select({
55+
"//tensorflow_addons:windows": ["windows_export_all_symbols"],
56+
"//conditions:default": [],
57+
}),
5058
deps = deps,
5159
**kwargs
5260
)

0 commit comments

Comments
 (0)