chromium/third_party/mediapipe/src/third_party/org_tensorflow_system_python.diff

diff --git a/tensorflow/lite/c/BUILD b/tensorflow/lite/c/BUILD
index 19cdd37ed4f..b4253b49a61 100644
--- a/tensorflow/lite/c/BUILD
+++ b/tensorflow/lite/c/BUILD
@@ -119,10 +119,7 @@ cc_library_with_tflite_with_c_headers_test(
     tflite_deps = [
         ":c_api",
     ],
-    deps = [
-        "//tensorflow/lite/core/c:c_api_experimental",
-        "//tensorflow/lite/core/c:c_api_opaque",
-    ],
+    deps = ["//tensorflow/lite/core/c:c_api_experimental"],
 )
 
 # Same as ":c_api_experimental", but without linking in the default CreateOpResolver implementation.
@@ -143,10 +140,7 @@ cc_library_with_tflite_with_c_headers_test(
     tflite_deps = [
         ":c_api_without_op_resolver",
     ],
-    deps = [
-        "//tensorflow/lite/core/c:c_api_experimental_without_op_resolver",
-        "//tensorflow/lite/core/c:c_api_opaque_without_op_resolver",
-    ],
+    deps = ["//tensorflow/lite/core/c:c_api_experimental_without_op_resolver"],
 )
 
 # Same as ":c_api_experimental", but without linking in the default CreateOpResolver implementation,
@@ -183,6 +177,7 @@ cc_library_with_tflite_with_c_headers_test(
     copts = tflite_copts() + tflite_copts_warnings(),
     generate_opaque_delegate_target = True,
     tflite_deps = [":c_api"],
+    linkstatic = 1,
     deps = ["//tensorflow/lite/core/c:c_api_opaque"],
 )
 
@@ -209,7 +204,7 @@ cc_library_with_tflite_with_c_headers_test(
     tflite_deps = [
         ":c_api_without_op_resolver_without_alwayslink",
     ],
-    deps = ["//tensorflow/lite/core/c:c_api_opaque_without_op_resolver_without_alwayslink"],
+    deps = ["//tensorflow/lite/core/c:c_api_experimental_without_op_resolver_without_alwayslink"],
 )
 
 cc_library_with_tflite_with_c_headers_test(
@@ -457,7 +452,6 @@ cc_test(
         ":c_api_experimental",
         "//tensorflow/lite/core/c:c_api",
         "//tensorflow/lite/core/c:c_api_experimental",
-        "//tensorflow/lite/core/c:c_api_opaque",
         "//tensorflow/lite/core/c:c_api_types",
         "//tensorflow/lite/core/c:common",
     ],
diff --git a/tensorflow/lite/core/c/BUILD b/tensorflow/lite/core/c/BUILD
index 018b6e1004c..cf355612386 100644
--- a/tensorflow/lite/core/c/BUILD
+++ b/tensorflow/lite/core/c/BUILD
@@ -378,7 +378,6 @@ tflite_cc_library_with_c_headers_test(
     deps = [
         ":c_api",
         ":c_api_experimental_without_op_resolver",
-        ":c_api_opaque",
         ":c_api_types",
         ":common",
         ":operator",
@@ -399,6 +398,7 @@ tflite_cc_library_with_c_headers_test(
     name = "c_api_experimental_without_op_resolver",
     srcs = [
         "c_api_experimental.cc",
+        "c_api_opaque.cc",
     ],
     hdrs = [
         "c_api_experimental.h",
@@ -413,7 +413,6 @@ tflite_cc_library_with_c_headers_test(
     copts = tflite_copts(),
     tags = ["allow_undefined_symbols"],  # For tflite::CreateOpResolver().
     deps = [
-        ":c_api_opaque_without_op_resolver",
         ":c_api_types",
         ":c_api_without_op_resolver",
         ":common",
@@ -451,6 +450,7 @@ tflite_cc_library_with_c_headers_test(
     name = "c_api_experimental_without_op_resolver_without_alwayslink",
     srcs = [
         "c_api_experimental.cc",
+        "c_api_opaque.cc",
     ],
     hdrs = [
         "c_api_experimental.h",
@@ -467,7 +467,6 @@ tflite_cc_library_with_c_headers_test(
     copts = tflite_copts(),
     tags = ["allow_undefined_symbols"],  # For tflite::CreateOpResolver().
     deps = [
-        ":c_api_opaque_without_op_resolver_without_alwayslink",
         ":c_api_types",
         ":c_api_without_op_resolver_without_alwayslink",
         ":common",
diff --git a/tensorflow/tools/toolchains/cpus/aarch64/aarch64_compiler_configure.bzl b/tensorflow/tools/toolchains/cpus/aarch64/aarch64_compiler_configure.bzl
index 00cd6983ca3..d9c5ef16f9b 100644
--- a/tensorflow/tools/toolchains/cpus/aarch64/aarch64_compiler_configure.bzl
+++ b/tensorflow/tools/toolchains/cpus/aarch64/aarch64_compiler_configure.bzl
@@ -1,7 +1,7 @@
 """Configurations of AARCH64 builds used with Docker container."""
 
 load("//tensorflow/tools/toolchains:cpus/aarch64/aarch64.bzl", "remote_aarch64_configure")
-load("//third_party/py:python_configure.bzl", "remote_python_configure")
+load("//third_party/py/non_hermetic:python_configure.bzl", "remote_python_configure")
 load("//third_party/remote_config:remote_platform_configure.bzl", "remote_platform_configure")
 
 def ml2014_tf_aarch64_configs(name_container_map, env):
diff --git a/tensorflow/tools/toolchains/remote_config/rbe_config.bzl b/tensorflow/tools/toolchains/remote_config/rbe_config.bzl
index ae776c2a2fd..108e79edbd7 100644
--- a/tensorflow/tools/toolchains/remote_config/rbe_config.bzl
+++ b/tensorflow/tools/toolchains/remote_config/rbe_config.bzl
@@ -4,7 +4,7 @@ load("//tensorflow/tools/toolchains/remote_config:containers.bzl", "containers")
 load("//third_party/gpus:cuda_configure.bzl", "remote_cuda_configure")
 load("//third_party/gpus:rocm_configure.bzl", "remote_rocm_configure")
 load("//third_party/nccl:nccl_configure.bzl", "remote_nccl_configure")
-load("//third_party/py:python_configure.bzl", "local_python_configure", "remote_python_configure")
+load("//third_party/py/non_hermetic:python_configure.bzl", "local_python_configure", "remote_python_configure")
 load("//third_party/remote_config:remote_platform_configure.bzl", "remote_platform_configure")
 load("//third_party/tensorrt:tensorrt_configure.bzl", "remote_tensorrt_configure")
 
diff --git a/tensorflow/workspace2.bzl b/tensorflow/workspace2.bzl
index 380a1a93585..3f3e12a0617 100644
--- a/tensorflow/workspace2.bzl
+++ b/tensorflow/workspace2.bzl
@@ -44,7 +44,7 @@ load("//third_party/nasm:workspace.bzl", nasm = "repo")
 load("//third_party/nccl:nccl_configure.bzl", "nccl_configure")
 load("//third_party/opencl_headers:workspace.bzl", opencl_headers = "repo")
 load("//third_party/pasta:workspace.bzl", pasta = "repo")
-load("//third_party/py:python_configure.bzl", "python_configure")
+load("//third_party/py/non_hermetic:python_configure.bzl", "python_configure")
 load("//third_party/py/ml_dtypes:workspace.bzl", ml_dtypes = "repo")
 load("//third_party/pybind11_abseil:workspace.bzl", pybind11_abseil = "repo")
 load("//third_party/pybind11_bazel:workspace.bzl", pybind11_bazel = "repo")
diff --git a/third_party/py/non_hermetic/BUILD b/third_party/py/non_hermetic/BUILD
new file mode 100644
index 00000000000..d14731cafcd
--- /dev/null
+++ b/third_party/py/non_hermetic/BUILD
@@ -0,0 +1,2 @@
+# Empty BUILD file
+
diff --git a/third_party/py/non_hermetic/BUILD.tpl b/third_party/py/non_hermetic/BUILD.tpl
new file mode 100644
index 00000000000..0d2d06da29a
--- /dev/null
+++ b/third_party/py/non_hermetic/BUILD.tpl
@@ -0,0 +1,80 @@
+licenses(["restricted"])
+
+package(default_visibility = ["//visibility:public"])
+
+# Point both runtimes to the same python binary to ensure we always
+# use the python binary specified by ./configure.py script.
+load("@bazel_tools//tools/python:toolchain.bzl", "py_runtime_pair")
+
+py_runtime(
+    name = "py2_runtime",
+    interpreter_path = "%{PYTHON_BIN_PATH}",
+    python_version = "PY2",
+)
+
+py_runtime(
+    name = "py3_runtime",
+    interpreter_path = "%{PYTHON_BIN_PATH}",
+    python_version = "PY3",
+)
+
+py_runtime_pair(
+    name = "py_runtime_pair",
+    py2_runtime = ":py2_runtime",
+    py3_runtime = ":py3_runtime",
+)
+
+toolchain(
+    name = "py_toolchain",
+    toolchain = ":py_runtime_pair",
+    toolchain_type = "@bazel_tools//tools/python:toolchain_type",
+    target_compatible_with = [%{PLATFORM_CONSTRAINT}],
+    exec_compatible_with = [%{PLATFORM_CONSTRAINT}],
+)
+
+# To build Python C/C++ extension on Windows, we need to link to python import library pythonXY.lib
+# See https://docs.python.org/3/extending/windows.html
+cc_import(
+    name = "python_lib",
+    interface_library = select({
+        ":windows": ":python_import_lib",
+        # A placeholder for Unix platforms which makes --no_build happy.
+        "//conditions:default": "not-existing.lib",
+    }),
+    system_provided = 1,
+)
+
+cc_library(
+    name = "python_headers",
+    hdrs = [":python_include"],
+    deps = select({
+        ":windows": [":python_lib"],
+        "//conditions:default": [],
+    }),
+    includes = ["python_include"],
+)
+
+# This alias is exists for the use of targets in the @llvm-project dependency,
+# which expect a python_headers target called @python_runtime//:headers. We use
+# a repo_mapping to alias python_runtime to this package, and an alias to create
+# the correct target.
+alias(
+    name = "headers",
+    actual = ":python_headers",
+)
+
+cc_library(
+    name = "numpy_headers",
+    hdrs = [":numpy_include"],
+    includes = ["numpy_include"],
+)
+
+config_setting(
+    name = "windows",
+    values = {"cpu": "x64_windows"},
+    visibility = ["//visibility:public"],
+)
+
+%{PYTHON_INCLUDE_GENRULE}
+%{NUMPY_INCLUDE_GENRULE}
+%{PYTHON_IMPORT_LIB_GENRULE}
diff --git a/third_party/py/non_hermetic/python_configure.bzl b/third_party/py/non_hermetic/python_configure.bzl
new file mode 100644
index 00000000000..e6eeb02641a
--- /dev/null
+++ b/third_party/py/non_hermetic/python_configure.bzl
@@ -0,0 +1,313 @@
+"""Repository rule for Python autoconfiguration.
+
+`python_configure` depends on the following environment variables:
+
+  * `PYTHON_BIN_PATH`: location of python binary.
+  * `PYTHON_LIB_PATH`: Location of python libraries.
+"""
+
+load(
+    "//third_party/remote_config:common.bzl",
+    "BAZEL_SH",
+    "PYTHON_BIN_PATH",
+    "PYTHON_LIB_PATH",
+    "TF_PYTHON_CONFIG_REPO",
+    "auto_config_fail",
+    "config_repo_label",
+    "execute",
+    "get_bash_bin",
+    "get_host_environ",
+    "get_python_bin",
+    "is_windows",
+    "raw_exec",
+    "read_dir",
+)
+
+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    ],\n" +
+        '    cmd = """\n' +
+        command +
+        '\n   """,\n' +
+        ")\n"
+    )
+
+def _norm_path(path):
+    """Returns a path with '/' and remove the trailing slash."""
+    path = path.replace("\\", "/")
+    if path[-1] == "/":
+        path = path[:-1]
+    return path
+
+def _symlink_genrule_for_dir(
+        repository_ctx,
+        src_dir,
+        dest_dir,
+        genrule_name,
+        src_files = [],
+        dest_files = []):
+    """Returns a genrule to symlink(or copy if on Windows) a set of files.
+
+    If src_dir is passed, files will be read from the given directory; otherwise
+    we assume files are in src_files and dest_files
+    """
+    if src_dir != None:
+        src_dir = _norm_path(src_dir)
+        dest_dir = _norm_path(dest_dir)
+        files = "\n".join(read_dir(repository_ctx, src_dir))
+
+        # Create a list with the src_dir stripped to use for outputs.
+        dest_files = files.replace(src_dir, "").splitlines()
+        src_files = files.splitlines()
+    command = []
+    outs = []
+    for i in range(len(dest_files)):
+        if dest_files[i] != "":
+            # If we have only one file to link we do not want to use the dest_dir, as
+            # $(@D) will include the full path to the file.
+            dest = "$(@D)/" + dest_dir + dest_files[i] if len(dest_files) != 1 else "$(@D)/" + dest_files[i]
+
+            # Copy the headers to create a sandboxable setup.
+            cmd = "cp -f"
+            command.append(cmd + ' "%s" "%s"' % (src_files[i], dest))
+            outs.append('        "' + dest_dir + dest_files[i] + '",')
+    genrule = _genrule(
+        src_dir,
+        genrule_name,
+        " && ".join(command),
+        "\n".join(outs),
+    )
+    return genrule
+
+def _get_python_lib(repository_ctx, python_bin):
+    """Gets the python lib path."""
+    python_lib = get_host_environ(repository_ctx, PYTHON_LIB_PATH)
+    if python_lib != None:
+        return python_lib
+
+    # The interesting program to execute.
+    print_lib = [
+        "from __future__ import print_function",
+        "import site",
+        "import os",
+        "python_paths = []",
+        "if os.getenv('PYTHONPATH') is not None:",
+        "  python_paths = os.getenv('PYTHONPATH').split(':')",
+        "try:",
+        "  library_paths = site.getsitepackages()",
+        "except AttributeError:",
+        "  from distutils.sysconfig import get_python_lib",
+        "  library_paths = [get_python_lib()]",
+        "all_paths = set(python_paths + library_paths)",
+        "paths = []",
+        "for path in all_paths:",
+        "  if os.path.isdir(path):",
+        "    paths.append(path)",
+        "if len(paths) >=1:",
+        "  print(paths[0])",
+    ]
+
+    # The below script writes the above program to a file
+    # and executes it. This is to work around the limitation
+    # of not being able to upload files as part of execute.
+    cmd = "from os import linesep;"
+    cmd += "f = open('script.py', 'w');"
+    for line in print_lib:
+        cmd += "f.write(\"%s\" + linesep);" % line
+    cmd += "f.close();"
+    cmd += "from subprocess import call;"
+    cmd += "call([\"%s\", \"script.py\"]);" % python_bin
+
+    result = execute(repository_ctx, [python_bin, "-c", cmd])
+    return result.stdout.strip()
+
+def _check_python_lib(repository_ctx, python_lib):
+    """Checks the python lib path."""
+    cmd = 'test -d "%s" -a -x "%s"' % (python_lib, python_lib)
+    result = raw_exec(repository_ctx, [get_bash_bin(repository_ctx), "-c", cmd])
+    if result.return_code == 1:
+        auto_config_fail("Invalid python library path: %s" % python_lib)
+
+def _check_python_bin(repository_ctx, python_bin):
+    """Checks the python bin path."""
+    cmd = '[[ -x "%s" ]] && [[ ! -d "%s" ]]' % (python_bin, python_bin)
+    result = raw_exec(repository_ctx, [get_bash_bin(repository_ctx), "-c", cmd])
+    if result.return_code == 1:
+        auto_config_fail("--define %s='%s' is not executable. Is it the python binary?" % (
+            PYTHON_BIN_PATH,
+            python_bin,
+        ))
+
+def _get_python_include(repository_ctx, python_bin):
+    """Gets the python include path."""
+    result = execute(
+        repository_ctx,
+        [
+            python_bin,
+            "-Wignore",
+            "-c",
+            "import sysconfig; " +
+            "print(sysconfig.get_path('include'))",
+        ],
+        error_msg = "Problem getting python include path.",
+        error_details = ("Is the Python binary path set up right? " +
+                         "(See ./configure or " + PYTHON_BIN_PATH + ".) " +
+                         "Is distutils installed?"),
+    )
+    return result.stdout.splitlines()[0]
+
+def _get_python_import_lib_name(repository_ctx, python_bin):
+    """Get Python import library name (pythonXY.lib) on Windows."""
+    result = execute(
+        repository_ctx,
+        [
+            python_bin,
+            "-c",
+            "import sys;" +
+            'print("python" + str(sys.version_info[0]) + ' +
+            '      str(sys.version_info[1]) + ".lib")',
+        ],
+        error_msg = "Problem getting python import library.",
+        error_details = ("Is the Python binary path set up right? " +
+                         "(See ./configure or " + PYTHON_BIN_PATH + ".) "),
+    )
+    return result.stdout.splitlines()[0]
+
+def _get_numpy_include(repository_ctx, python_bin):
+    """Gets the numpy include path."""
+    return execute(
+        repository_ctx,
+        [
+            python_bin,
+            "-c",
+            "from __future__ import print_function;" +
+            "import numpy;" +
+            " print(numpy.get_include());",
+        ],
+        error_msg = "Problem getting numpy include path.",
+        error_details = "Is numpy installed?",
+    ).stdout.splitlines()[0]
+
+def _create_local_python_repository(repository_ctx):
+    """Creates the repository containing files set up to build with Python."""
+
+    # Resolve all labels before doing any real work. Resolving causes the
+    # function to be restarted with all previous state being lost. This
+    # can easily lead to a O(n^2) runtime in the number of labels.
+    build_tpl = repository_ctx.path(Label("//third_party/py/non_hermetic:BUILD.tpl"))
+
+    python_bin = get_python_bin(repository_ctx)
+    _check_python_bin(repository_ctx, python_bin)
+    python_lib = _get_python_lib(repository_ctx, python_bin)
+    _check_python_lib(repository_ctx, python_lib)
+    python_include = _get_python_include(repository_ctx, python_bin)
+    numpy_include = _get_numpy_include(repository_ctx, python_bin) + "/numpy"
+    python_include_rule = _symlink_genrule_for_dir(
+        repository_ctx,
+        python_include,
+        "python_include",
+        "python_include",
+    )
+    python_import_lib_genrule = ""
+
+    # To build Python C/C++ extension on Windows, we need to link to python import library pythonXY.lib
+    # See https://docs.python.org/3/extending/windows.html
+    if is_windows(repository_ctx):
+        python_bin = python_bin.replace("\\", "/")
+        python_include = _norm_path(python_include)
+        python_import_lib_name = _get_python_import_lib_name(repository_ctx, python_bin)
+        python_import_lib_src = python_include.rsplit("/", 1)[0] + "/libs/" + python_import_lib_name
+        python_import_lib_genrule = _symlink_genrule_for_dir(
+            repository_ctx,
+            None,
+            "",
+            "python_import_lib",
+            [python_import_lib_src],
+            [python_import_lib_name],
+        )
+    numpy_include_rule = _symlink_genrule_for_dir(
+        repository_ctx,
+        numpy_include,
+        "numpy_include/numpy",
+        "numpy_include",
+    )
+
+    platform_constraint = ""
+    if repository_ctx.attr.platform_constraint:
+        platform_constraint = "\"%s\"" % repository_ctx.attr.platform_constraint
+    repository_ctx.template("BUILD", build_tpl, {
+        "%{PYTHON_BIN_PATH}": python_bin,
+        "%{PYTHON_INCLUDE_GENRULE}": python_include_rule,
+        "%{PYTHON_IMPORT_LIB_GENRULE}": python_import_lib_genrule,
+        "%{NUMPY_INCLUDE_GENRULE}": numpy_include_rule,
+        "%{PLATFORM_CONSTRAINT}": platform_constraint,
+    })
+
+def _create_remote_python_repository(repository_ctx, remote_config_repo):
+    """Creates pointers to a remotely configured repo set up to build with Python.
+    """
+    repository_ctx.template("BUILD", config_repo_label(remote_config_repo, ":BUILD"), {})
+
+def _python_autoconf_impl(repository_ctx):
+    """Implementation of the python_autoconf repository rule."""
+    if get_host_environ(repository_ctx, TF_PYTHON_CONFIG_REPO) != None:
+        _create_remote_python_repository(
+            repository_ctx,
+            get_host_environ(repository_ctx, TF_PYTHON_CONFIG_REPO),
+        )
+    else:
+        _create_local_python_repository(repository_ctx)
+
+_ENVIRONS = [
+    BAZEL_SH,
+    PYTHON_BIN_PATH,
+    PYTHON_LIB_PATH,
+]
+
+local_python_configure = repository_rule(
+    implementation = _create_local_python_repository,
+    environ = _ENVIRONS,
+    attrs = {
+        "environ": attr.string_dict(),
+        "platform_constraint": attr.string(),
+    },
+)
+
+remote_python_configure = repository_rule(
+    implementation = _create_local_python_repository,
+    environ = _ENVIRONS,
+    remotable = True,
+    attrs = {
+        "environ": attr.string_dict(),
+        "platform_constraint": attr.string(),
+    },
+)
+
+python_configure = repository_rule(
+    implementation = _python_autoconf_impl,
+    environ = _ENVIRONS + [TF_PYTHON_CONFIG_REPO],
+    attrs = {
+        "platform_constraint": attr.string(),
+    },
+)
+"""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.
+"""
+