From 8e0d6f12efec0aeef16a64c6422aa3e90bbf4058 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Fri, 21 Apr 2017 06:35:18 -0800 Subject: Automated rollback of change 153736477 Change: 153825726 --- third_party/py/BUILD | 0 third_party/py/BUILD.tpl | 53 ++++++++++ third_party/py/numpy/BUILD | 6 +- third_party/py/python_configure.bzl | 206 ++++++++++++++++++++++++++++++++++++ 4 files changed, 261 insertions(+), 4 deletions(-) create mode 100644 third_party/py/BUILD create mode 100644 third_party/py/BUILD.tpl create mode 100644 third_party/py/python_configure.bzl (limited to 'third_party/py') diff --git a/third_party/py/BUILD b/third_party/py/BUILD new file mode 100644 index 0000000000..e69de29bb2 diff --git a/third_party/py/BUILD.tpl b/third_party/py/BUILD.tpl new file mode 100644 index 0000000000..157834df4b --- /dev/null +++ b/third_party/py/BUILD.tpl @@ -0,0 +1,53 @@ +licenses(["restricted"]) + +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "python_headers", + hdrs = select({ + "windows" : [ + "python_include_windows", + ], + "//conditions:default" : [ + "python_include", + ], + }), + includes = select({ + "windows" : [ + "python_include_windows", + ], + "//conditions:default" : [ + "python_include", + ], + }), +) + +cc_library( + name = "numpy_headers", + hdrs = select({ + "windows" : [ + "numpy_include_windows", + ], + "//conditions:default" : [ + "numpy_include", + ], + }), + includes = select({ + "windows" : [ + "numpy_include_windows", + ], + "//conditions:default" : [ + "numpy_include", + ], + }), +) + +config_setting( + name = "windows", + values = {"cpu": "x64_windows"}, + visibility = ["//visibility:public"], +) + +%{PYTHON_INCLUDE_GENRULE} + +%{NUMPY_INCLUDE_GENRULE} diff --git a/third_party/py/numpy/BUILD b/third_party/py/numpy/BUILD index 1d461505a6..be8332572b 100644 --- a/third_party/py/numpy/BUILD +++ b/third_party/py/numpy/BUILD @@ -8,11 +8,9 @@ py_library( srcs_version = "PY2AND3", ) -cc_library( +alias( name = "headers", - hdrs = glob(["numpy_include/**/*.h"]), - data = ["//util/python:python_checked"], - includes = ["numpy_include"], + actual = "@local_config_python//:numpy_headers", ) genrule( diff --git a/third_party/py/python_configure.bzl b/third_party/py/python_configure.bzl new file mode 100644 index 0000000000..d49d4c1781 --- /dev/null +++ b/third_party/py/python_configure.bzl @@ -0,0 +1,206 @@ +# -*- Python -*- +"""Repository rule for Python autoconfiguration. + +`python_configure` depends on the following environment variables: + + * `NUMPY_INCLUDE_PATH`: Location of Numpy libraries. + * `PYTHON_BIN_PATH`: location of python binary. + * `PYTHON_INCLUDE_PATH`: Location of python binaries. +""" + +_NUMPY_INCLUDE_PATH = "NUMPY_INCLUDE_PATH" +_PYTHON_BIN_PATH = "PYTHON_BIN_PATH" +_PYTHON_INCLUDE_PATH = "PYTHON_INCLUDE_PATH" + + +def _tpl(repository_ctx, tpl, substitutions={}, out=None): + if not out: + out = tpl + repository_ctx.template( + out, + Label("//third_party/py:%s.tpl" % tpl), + substitutions) + + +def _python_configure_warning(msg): + """Output warning message during auto configuration.""" + yellow = "\033[1;33m" + no_color = "\033[0m" + print("\n%sPython Configuration Warning:%s %s\n" % (yellow, no_color, msg)) + + +def _python_configure_fail(msg): + """Output failure message when auto configuration fails.""" + red = "\033[0;31m" + no_color = "\033[0m" + fail("\n%sPython Configuration Error:%s %s\n" % (red, no_color, msg)) + + +def _get_env_var(repository_ctx, name, default = None, enable_warning = True): + """Find an environment variable in system path.""" + if name in repository_ctx.os.environ: + return repository_ctx.os.environ[name] + if default != None: + if enable_warning: + _python_configure_warning( + "'%s' environment variable is not set, using '%s' as default" % (name, default)) + return default + _python_configure_fail("'%s' environment variable is not set" % name) + + +def _is_windows(repository_ctx): + """Returns true if the host operating system is windows.""" + os_name = repository_ctx.os.name.lower() + if os_name.find("windows") != -1: + return True + return False + + +def _symlink_genrule_for_dir(repository_ctx, src_dir, dest_dir, genrule_name): + """returns a genrule to symlink all files in a directory.""" + # Get the list of files under this directory + find_result = None + if _is_windows(repository_ctx): + find_result = repository_ctx.execute([ + "dir", src_dir, "/b", "/s", "/a-d", + ]) + else: + find_result = repository_ctx.execute([ + "find", src_dir, "-follow", "-type", "f", + ]) + # Create a list with the src_dir stripped to use for outputs. + dest_files = find_result.stdout.replace(src_dir, '').splitlines() + src_files = find_result.stdout.splitlines() + command = [] + command_windows = [] + outs = [] + outs_windows = [] + for i in range(len(dest_files)): + if dest_files[i] != "": + command.append('ln -s ' + src_files[i] + ' $(@D)/' + + dest_dir + dest_files[i]) + # ln -sf is actually implemented as copying in msys since creating + # symbolic links is privileged on Windows. But copying is too slow, so + # invoke mklink to create junctions on Windows. + command_windows.append('mklink /J ' + src_files[i] + ' $(@D)/' + + dest_dir + dest_files[i]) + outs.append(' "' + dest_dir + dest_files[i] + '",') + outs_windows.append(' "' + dest_dir + '_windows' + + dest_files[i] + '",') + genrule = _genrule(src_dir, genrule_name, ' && '.join(command), + '\n'.join(outs)) + genrule_windows = _genrule(src_dir, genrule_name + '_windows', + "cmd /c \"" + ' && '.join(command_windows) + "\"", + '\n'.join(outs_windows)) + return genrule + '\n' + genrule_windows + + +def _genrule(src_dir, genrule_name, command, outs): + """Returns a string with a genrule. + + Genrule executes the given command and produces the given outputs. + """ + return ( + 'genrule(\n' + + ' name = "' + + genrule_name + '",\n' + + ' outs = [\n' + + outs + + ' ],\n' + + ' cmd = """\n' + + command + + ' """,\n' + + ')\n' + ) + + +def _check_python_bin(repository_ctx, python_bin): + """Checks the python bin path.""" + cmd = '[[ -x "%s" ]] && [[ ! -d "%s" ]]' % (python_bin, python_bin) + result = repository_ctx.execute(["bash", "-c", cmd]) + if result.return_code == 1: + _python_configure_fail( + "PYTHON_BIN_PATH is not executable. Is it the python binary?") + + +def _get_python_include(repository_ctx, python_bin): + """Gets the python include path.""" + result = repository_ctx.execute([python_bin, "-c", + 'from __future__ import print_function;' + + 'from distutils import sysconfig;' + + 'print(sysconfig.get_python_inc())']) + if result == "": + _python_configure_fail( + "Problem getting python include path. Is distutils installed?") + return result.stdout.splitlines()[0] + + +def _get_numpy_include(repository_ctx, python_bin): + """Gets the numpy include path.""" + result = repository_ctx.execute([python_bin, "-c", + 'from __future__ import print_function;' + + 'import numpy;' + + ' print(numpy.get_include());']) + if result == "": + _python_configure_fail( + "Problem getting numpy include path. Is numpy installed?") + return result.stdout.splitlines()[0] + + +def _create_python_repository(repository_ctx): + """Creates the repository containing files set up to build with Python.""" + python_include = None + numpy_include = None + # If local checks were requested, the python and numpy include will be auto + # detected on the host config (using _PYTHON_BIN_PATH). + if repository_ctx.attr.local_checks: + python_bin = _get_env_var(repository_ctx, _PYTHON_BIN_PATH) + _check_python_bin(repository_ctx, python_bin) + python_include = _get_python_include(repository_ctx, python_bin) + numpy_include = _get_numpy_include(repository_ctx, python_bin) + '/numpy' + else: + # Otherwise, we assume user provides all paths (via ENV or attrs) + python_include = _get_env_var(repository_ctx, _PYTHON_INCLUDE_PATH, + repository_ctx.attr.python_include) + numpy_include = _get_env_var(repository_ctx, _NUMPY_INCLUDE_PATH, + repository_ctx.attr.numpy_include) + '/numpy' + + python_include_rule = _symlink_genrule_for_dir( + repository_ctx, python_include, 'python_include', 'python_include') + numpy_include_rule = _symlink_genrule_for_dir( + repository_ctx, numpy_include, 'numpy_include/numpy', 'numpy_include') + _tpl(repository_ctx, "BUILD", { + "%{PYTHON_INCLUDE_GENRULE}": python_include_rule, + "%{NUMPY_INCLUDE_GENRULE}": numpy_include_rule, + }) + + +def _python_autoconf_impl(repository_ctx): + """Implementation of the python_autoconf repository rule.""" + _create_python_repository(repository_ctx) + + +python_configure = repository_rule( + implementation = _python_autoconf_impl, + attrs = { + "local_checks": attr.bool(mandatory = False, default = True), + "python_include": attr.string(mandatory = False), + "numpy_include": attr.string(mandatory = False), + }, + environ = [ + _PYTHON_BIN_PATH, + _PYTHON_INCLUDE_PATH, + _NUMPY_INCLUDE_PATH, + ], +) +"""Detects and configures the local Python. + +Add the following to your WORKSPACE FILE: + +```python +python_configure(name = "local_config_python") +``` + +Args: + name: A unique name for this workspace rule. +""" -- cgit v1.2.3