xref: /aosp_15_r20/external/grpc-grpc/third_party/py/python_configure.bzl (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1*cc02d7e2SAndroid Build Coastguard Worker# Adapted with modifications from tensorflow/third_party/py/
2*cc02d7e2SAndroid Build Coastguard Worker"""Repository rule for Python autoconfiguration.
3*cc02d7e2SAndroid Build Coastguard Worker
4*cc02d7e2SAndroid Build Coastguard Worker`python_configure` depends on the following environment variables:
5*cc02d7e2SAndroid Build Coastguard Worker
6*cc02d7e2SAndroid Build Coastguard Worker  * `PYTHON3_BIN_PATH`: location of python binary.
7*cc02d7e2SAndroid Build Coastguard Worker  * `PYTHON3_LIB_PATH`: Location of python libraries.
8*cc02d7e2SAndroid Build Coastguard Worker"""
9*cc02d7e2SAndroid Build Coastguard Worker
10*cc02d7e2SAndroid Build Coastguard Worker_BAZEL_SH = "BAZEL_SH"
11*cc02d7e2SAndroid Build Coastguard Worker_PYTHON3_BIN_PATH = "PYTHON3_BIN_PATH"
12*cc02d7e2SAndroid Build Coastguard Worker_PYTHON3_LIB_PATH = "PYTHON3_LIB_PATH"
13*cc02d7e2SAndroid Build Coastguard Worker
14*cc02d7e2SAndroid Build Coastguard Worker_HEADERS_HELP = (
15*cc02d7e2SAndroid Build Coastguard Worker    "Are Python headers installed? Try installing " +
16*cc02d7e2SAndroid Build Coastguard Worker    "python3-dev on Debian-based systems. Try python3-devel " +
17*cc02d7e2SAndroid Build Coastguard Worker    "on Redhat-based systems."
18*cc02d7e2SAndroid Build Coastguard Worker)
19*cc02d7e2SAndroid Build Coastguard Worker
20*cc02d7e2SAndroid Build Coastguard Workerdef _tpl(repository_ctx, tpl, substitutions = {}, out = None):
21*cc02d7e2SAndroid Build Coastguard Worker    if not out:
22*cc02d7e2SAndroid Build Coastguard Worker        out = tpl
23*cc02d7e2SAndroid Build Coastguard Worker    repository_ctx.template(
24*cc02d7e2SAndroid Build Coastguard Worker        out,
25*cc02d7e2SAndroid Build Coastguard Worker        Label("//third_party/py:%s.tpl" % tpl),
26*cc02d7e2SAndroid Build Coastguard Worker        substitutions,
27*cc02d7e2SAndroid Build Coastguard Worker    )
28*cc02d7e2SAndroid Build Coastguard Worker
29*cc02d7e2SAndroid Build Coastguard Workerdef _fail(msg):
30*cc02d7e2SAndroid Build Coastguard Worker    """Output failure message when auto configuration fails."""
31*cc02d7e2SAndroid Build Coastguard Worker    red = "\033[0;31m"
32*cc02d7e2SAndroid Build Coastguard Worker    no_color = "\033[0m"
33*cc02d7e2SAndroid Build Coastguard Worker    fail("%sPython Configuration Error:%s %s\n" % (red, no_color, msg))
34*cc02d7e2SAndroid Build Coastguard Worker
35*cc02d7e2SAndroid Build Coastguard Workerdef _is_windows(repository_ctx):
36*cc02d7e2SAndroid Build Coastguard Worker    """Returns true if the host operating system is windows."""
37*cc02d7e2SAndroid Build Coastguard Worker    os_name = repository_ctx.os.name.lower()
38*cc02d7e2SAndroid Build Coastguard Worker    return os_name.find("windows") != -1
39*cc02d7e2SAndroid Build Coastguard Worker
40*cc02d7e2SAndroid Build Coastguard Workerdef _execute(
41*cc02d7e2SAndroid Build Coastguard Worker        repository_ctx,
42*cc02d7e2SAndroid Build Coastguard Worker        cmdline,
43*cc02d7e2SAndroid Build Coastguard Worker        error_msg = None,
44*cc02d7e2SAndroid Build Coastguard Worker        error_details = None,
45*cc02d7e2SAndroid Build Coastguard Worker        empty_stdout_fine = False):
46*cc02d7e2SAndroid Build Coastguard Worker    """Executes an arbitrary shell command.
47*cc02d7e2SAndroid Build Coastguard Worker
48*cc02d7e2SAndroid Build Coastguard Worker    Args:
49*cc02d7e2SAndroid Build Coastguard Worker        repository_ctx: the repository_ctx object
50*cc02d7e2SAndroid Build Coastguard Worker        cmdline: list of strings, the command to execute
51*cc02d7e2SAndroid Build Coastguard Worker        error_msg: string, a summary of the error if the command fails
52*cc02d7e2SAndroid Build Coastguard Worker        error_details: string, details about the error or steps to fix it
53*cc02d7e2SAndroid Build Coastguard Worker        empty_stdout_fine: bool, if True, an empty stdout result is fine, otherwise
54*cc02d7e2SAndroid Build Coastguard Worker        it's an error
55*cc02d7e2SAndroid Build Coastguard Worker    Return:
56*cc02d7e2SAndroid Build Coastguard Worker        the result of repository_ctx.execute(cmdline)
57*cc02d7e2SAndroid Build Coastguard Worker  """
58*cc02d7e2SAndroid Build Coastguard Worker    result = repository_ctx.execute(cmdline)
59*cc02d7e2SAndroid Build Coastguard Worker    if result.stderr or not (empty_stdout_fine or result.stdout):
60*cc02d7e2SAndroid Build Coastguard Worker        _fail("\n".join([
61*cc02d7e2SAndroid Build Coastguard Worker            error_msg.strip() if error_msg else "Repository command failed",
62*cc02d7e2SAndroid Build Coastguard Worker            result.stderr.strip(),
63*cc02d7e2SAndroid Build Coastguard Worker            error_details if error_details else "",
64*cc02d7e2SAndroid Build Coastguard Worker        ]))
65*cc02d7e2SAndroid Build Coastguard Worker    else:
66*cc02d7e2SAndroid Build Coastguard Worker        return result
67*cc02d7e2SAndroid Build Coastguard Worker
68*cc02d7e2SAndroid Build Coastguard Workerdef _read_dir(repository_ctx, src_dir):
69*cc02d7e2SAndroid Build Coastguard Worker    """Returns a string with all files in a directory.
70*cc02d7e2SAndroid Build Coastguard Worker
71*cc02d7e2SAndroid Build Coastguard Worker  Finds all files inside a directory, traversing subfolders and following
72*cc02d7e2SAndroid Build Coastguard Worker  symlinks. The returned string contains the full path of all files
73*cc02d7e2SAndroid Build Coastguard Worker  separated by line breaks.
74*cc02d7e2SAndroid Build Coastguard Worker  """
75*cc02d7e2SAndroid Build Coastguard Worker    if _is_windows(repository_ctx):
76*cc02d7e2SAndroid Build Coastguard Worker        src_dir = src_dir.replace("/", "\\")
77*cc02d7e2SAndroid Build Coastguard Worker        find_result = _execute(
78*cc02d7e2SAndroid Build Coastguard Worker            repository_ctx,
79*cc02d7e2SAndroid Build Coastguard Worker            ["cmd.exe", "/c", "dir", src_dir, "/b", "/s", "/a-d"],
80*cc02d7e2SAndroid Build Coastguard Worker            empty_stdout_fine = True,
81*cc02d7e2SAndroid Build Coastguard Worker        )
82*cc02d7e2SAndroid Build Coastguard Worker
83*cc02d7e2SAndroid Build Coastguard Worker        # src_files will be used in genrule.outs where the paths must
84*cc02d7e2SAndroid Build Coastguard Worker        # use forward slashes.
85*cc02d7e2SAndroid Build Coastguard Worker        return find_result.stdout.replace("\\", "/")
86*cc02d7e2SAndroid Build Coastguard Worker    else:
87*cc02d7e2SAndroid Build Coastguard Worker        find_result = _execute(
88*cc02d7e2SAndroid Build Coastguard Worker            repository_ctx,
89*cc02d7e2SAndroid Build Coastguard Worker            ["find", src_dir, "-follow", "-type", "f"],
90*cc02d7e2SAndroid Build Coastguard Worker            empty_stdout_fine = True,
91*cc02d7e2SAndroid Build Coastguard Worker        )
92*cc02d7e2SAndroid Build Coastguard Worker        return find_result.stdout
93*cc02d7e2SAndroid Build Coastguard Worker
94*cc02d7e2SAndroid Build Coastguard Workerdef _genrule(src_dir, genrule_name, command, outs):
95*cc02d7e2SAndroid Build Coastguard Worker    """Returns a string with a genrule.
96*cc02d7e2SAndroid Build Coastguard Worker
97*cc02d7e2SAndroid Build Coastguard Worker  Genrule executes the given command and produces the given outputs.
98*cc02d7e2SAndroid Build Coastguard Worker  """
99*cc02d7e2SAndroid Build Coastguard Worker    return ("genrule(\n" + '    name = "' + genrule_name + '",\n' +
100*cc02d7e2SAndroid Build Coastguard Worker            "    outs = [\n" + outs + "\n    ],\n" + '    cmd = """\n' +
101*cc02d7e2SAndroid Build Coastguard Worker            command + '\n   """,\n' + ")\n")
102*cc02d7e2SAndroid Build Coastguard Worker
103*cc02d7e2SAndroid Build Coastguard Workerdef _normalize_path(path):
104*cc02d7e2SAndroid Build Coastguard Worker    """Returns a path with '/' and remove the trailing slash."""
105*cc02d7e2SAndroid Build Coastguard Worker    path = path.replace("\\", "/")
106*cc02d7e2SAndroid Build Coastguard Worker    if path[-1] == "/":
107*cc02d7e2SAndroid Build Coastguard Worker        path = path[:-1]
108*cc02d7e2SAndroid Build Coastguard Worker    return path
109*cc02d7e2SAndroid Build Coastguard Worker
110*cc02d7e2SAndroid Build Coastguard Workerdef _symlink_genrule_for_dir(
111*cc02d7e2SAndroid Build Coastguard Worker        repository_ctx,
112*cc02d7e2SAndroid Build Coastguard Worker        src_dir,
113*cc02d7e2SAndroid Build Coastguard Worker        dest_dir,
114*cc02d7e2SAndroid Build Coastguard Worker        genrule_name,
115*cc02d7e2SAndroid Build Coastguard Worker        src_files = [],
116*cc02d7e2SAndroid Build Coastguard Worker        dest_files = []):
117*cc02d7e2SAndroid Build Coastguard Worker    """Returns a genrule to symlink(or copy if on Windows) a set of files.
118*cc02d7e2SAndroid Build Coastguard Worker
119*cc02d7e2SAndroid Build Coastguard Worker  If src_dir is passed, files will be read from the given directory; otherwise
120*cc02d7e2SAndroid Build Coastguard Worker  we assume files are in src_files and dest_files
121*cc02d7e2SAndroid Build Coastguard Worker  """
122*cc02d7e2SAndroid Build Coastguard Worker    if src_dir != None:
123*cc02d7e2SAndroid Build Coastguard Worker        src_dir = _normalize_path(src_dir)
124*cc02d7e2SAndroid Build Coastguard Worker        dest_dir = _normalize_path(dest_dir)
125*cc02d7e2SAndroid Build Coastguard Worker        files = "\n".join(
126*cc02d7e2SAndroid Build Coastguard Worker            sorted(_read_dir(repository_ctx, src_dir).splitlines()),
127*cc02d7e2SAndroid Build Coastguard Worker        )
128*cc02d7e2SAndroid Build Coastguard Worker
129*cc02d7e2SAndroid Build Coastguard Worker        # Create a list with the src_dir stripped to use for outputs.
130*cc02d7e2SAndroid Build Coastguard Worker        dest_files = files.replace(src_dir, "").splitlines()
131*cc02d7e2SAndroid Build Coastguard Worker        src_files = files.splitlines()
132*cc02d7e2SAndroid Build Coastguard Worker    command = []
133*cc02d7e2SAndroid Build Coastguard Worker    outs = []
134*cc02d7e2SAndroid Build Coastguard Worker    for i in range(len(dest_files)):
135*cc02d7e2SAndroid Build Coastguard Worker        if dest_files[i] != "":
136*cc02d7e2SAndroid Build Coastguard Worker            # If we have only one file to link we do not want to use the dest_dir, as
137*cc02d7e2SAndroid Build Coastguard Worker            # $(@D) will include the full path to the file.
138*cc02d7e2SAndroid Build Coastguard Worker            dest = "$(@D)/" + dest_dir + dest_files[i] if len(
139*cc02d7e2SAndroid Build Coastguard Worker                dest_files,
140*cc02d7e2SAndroid Build Coastguard Worker            ) != 1 else "$(@D)/" + dest_files[i]
141*cc02d7e2SAndroid Build Coastguard Worker
142*cc02d7e2SAndroid Build Coastguard Worker            # On Windows, symlink is not supported, so we just copy all the files.
143*cc02d7e2SAndroid Build Coastguard Worker            cmd = "cp -f" if _is_windows(repository_ctx) else "ln -s"
144*cc02d7e2SAndroid Build Coastguard Worker            command.append(cmd + ' "%s" "%s"' % (src_files[i], dest))
145*cc02d7e2SAndroid Build Coastguard Worker            outs.append('        "' + dest_dir + dest_files[i] + '",')
146*cc02d7e2SAndroid Build Coastguard Worker    return _genrule(
147*cc02d7e2SAndroid Build Coastguard Worker        src_dir,
148*cc02d7e2SAndroid Build Coastguard Worker        genrule_name,
149*cc02d7e2SAndroid Build Coastguard Worker        " && ".join(command),
150*cc02d7e2SAndroid Build Coastguard Worker        "\n".join(outs),
151*cc02d7e2SAndroid Build Coastguard Worker    )
152*cc02d7e2SAndroid Build Coastguard Worker
153*cc02d7e2SAndroid Build Coastguard Workerdef _get_python_bin(repository_ctx, bin_path_key, default_bin_path, allow_absent):
154*cc02d7e2SAndroid Build Coastguard Worker    """Gets the python bin path."""
155*cc02d7e2SAndroid Build Coastguard Worker    python_bin = repository_ctx.os.environ.get(bin_path_key, default_bin_path)
156*cc02d7e2SAndroid Build Coastguard Worker    if not repository_ctx.path(python_bin).exists:
157*cc02d7e2SAndroid Build Coastguard Worker        # It's a command, use 'which' to find its path.
158*cc02d7e2SAndroid Build Coastguard Worker        python_bin_path = repository_ctx.which(python_bin)
159*cc02d7e2SAndroid Build Coastguard Worker    else:
160*cc02d7e2SAndroid Build Coastguard Worker        # It's a path, use it as it is.
161*cc02d7e2SAndroid Build Coastguard Worker        python_bin_path = python_bin
162*cc02d7e2SAndroid Build Coastguard Worker    if python_bin_path != None:
163*cc02d7e2SAndroid Build Coastguard Worker        return str(python_bin_path)
164*cc02d7e2SAndroid Build Coastguard Worker    if not allow_absent:
165*cc02d7e2SAndroid Build Coastguard Worker        _fail("Cannot find python in PATH, please make sure " +
166*cc02d7e2SAndroid Build Coastguard Worker              "python is installed and add its directory in PATH, or --define " +
167*cc02d7e2SAndroid Build Coastguard Worker              "%s='/something/else'.\nPATH=%s" %
168*cc02d7e2SAndroid Build Coastguard Worker              (bin_path_key, repository_ctx.os.environ.get("PATH", "")))
169*cc02d7e2SAndroid Build Coastguard Worker    else:
170*cc02d7e2SAndroid Build Coastguard Worker        return None
171*cc02d7e2SAndroid Build Coastguard Worker
172*cc02d7e2SAndroid Build Coastguard Workerdef _get_bash_bin(repository_ctx):
173*cc02d7e2SAndroid Build Coastguard Worker    """Gets the bash bin path."""
174*cc02d7e2SAndroid Build Coastguard Worker    bash_bin = repository_ctx.os.environ.get(_BAZEL_SH)
175*cc02d7e2SAndroid Build Coastguard Worker    if bash_bin != None:
176*cc02d7e2SAndroid Build Coastguard Worker        return bash_bin
177*cc02d7e2SAndroid Build Coastguard Worker    else:
178*cc02d7e2SAndroid Build Coastguard Worker        bash_bin_path = repository_ctx.which("bash")
179*cc02d7e2SAndroid Build Coastguard Worker        if bash_bin_path != None:
180*cc02d7e2SAndroid Build Coastguard Worker            return str(bash_bin_path)
181*cc02d7e2SAndroid Build Coastguard Worker        else:
182*cc02d7e2SAndroid Build Coastguard Worker            _fail(
183*cc02d7e2SAndroid Build Coastguard Worker                "Cannot find bash in PATH, please make sure " +
184*cc02d7e2SAndroid Build Coastguard Worker                "bash is installed and add its directory in PATH, or --define " +
185*cc02d7e2SAndroid Build Coastguard Worker                "%s='/path/to/bash'.\nPATH=%s" %
186*cc02d7e2SAndroid Build Coastguard Worker                (_BAZEL_SH, repository_ctx.os.environ.get("PATH", "")),
187*cc02d7e2SAndroid Build Coastguard Worker            )
188*cc02d7e2SAndroid Build Coastguard Worker
189*cc02d7e2SAndroid Build Coastguard Workerdef _get_python_lib(repository_ctx, python_bin, lib_path_key):
190*cc02d7e2SAndroid Build Coastguard Worker    """Gets the python lib path."""
191*cc02d7e2SAndroid Build Coastguard Worker    python_lib = repository_ctx.os.environ.get(lib_path_key)
192*cc02d7e2SAndroid Build Coastguard Worker    if python_lib != None:
193*cc02d7e2SAndroid Build Coastguard Worker        return python_lib
194*cc02d7e2SAndroid Build Coastguard Worker    print_lib = (
195*cc02d7e2SAndroid Build Coastguard Worker        "<<END\n" + "from __future__ import print_function\n" +
196*cc02d7e2SAndroid Build Coastguard Worker        "import site\n" + "import os\n" + "\n" + "try:\n" +
197*cc02d7e2SAndroid Build Coastguard Worker        "  input = raw_input\n" + "except NameError:\n" + "  pass\n" + "\n" +
198*cc02d7e2SAndroid Build Coastguard Worker        "python_paths = []\n" + "if os.getenv('PYTHONPATH') is not None:\n" +
199*cc02d7e2SAndroid Build Coastguard Worker        "  python_paths = os.getenv('PYTHONPATH').split(':')\n" + "try:\n" +
200*cc02d7e2SAndroid Build Coastguard Worker        "  library_paths = site.getsitepackages()\n" +
201*cc02d7e2SAndroid Build Coastguard Worker        "except AttributeError:\n" +
202*cc02d7e2SAndroid Build Coastguard Worker        " import sysconfig\n" +
203*cc02d7e2SAndroid Build Coastguard Worker        " library_paths = [sysconfig.get_path('purelib')]\n" +
204*cc02d7e2SAndroid Build Coastguard Worker        "all_paths = set(python_paths + library_paths)\n" + "paths = []\n" +
205*cc02d7e2SAndroid Build Coastguard Worker        "for path in all_paths:\n" + "  if os.path.isdir(path):\n" +
206*cc02d7e2SAndroid Build Coastguard Worker        "    paths.append(path)\n" + "if len(paths) >=1:\n" +
207*cc02d7e2SAndroid Build Coastguard Worker        "  print(paths[0])\n" + "END"
208*cc02d7e2SAndroid Build Coastguard Worker    )
209*cc02d7e2SAndroid Build Coastguard Worker    cmd = '"%s" - %s' % (python_bin, print_lib)
210*cc02d7e2SAndroid Build Coastguard Worker    result = repository_ctx.execute([_get_bash_bin(repository_ctx), "-c", cmd])
211*cc02d7e2SAndroid Build Coastguard Worker    return result.stdout.strip("\n")
212*cc02d7e2SAndroid Build Coastguard Worker
213*cc02d7e2SAndroid Build Coastguard Workerdef _check_python_lib(repository_ctx, python_lib):
214*cc02d7e2SAndroid Build Coastguard Worker    """Checks the python lib path."""
215*cc02d7e2SAndroid Build Coastguard Worker    cmd = 'test -d "%s" -a -x "%s"' % (python_lib, python_lib)
216*cc02d7e2SAndroid Build Coastguard Worker    result = repository_ctx.execute([_get_bash_bin(repository_ctx), "-c", cmd])
217*cc02d7e2SAndroid Build Coastguard Worker    if result.return_code == 1:
218*cc02d7e2SAndroid Build Coastguard Worker        _fail("Invalid python library path: %s" % python_lib)
219*cc02d7e2SAndroid Build Coastguard Worker
220*cc02d7e2SAndroid Build Coastguard Workerdef _check_python_bin(repository_ctx, python_bin, bin_path_key, allow_absent):
221*cc02d7e2SAndroid Build Coastguard Worker    """Checks the python bin path."""
222*cc02d7e2SAndroid Build Coastguard Worker    cmd = '[[ -x "%s" ]] && [[ ! -d "%s" ]]' % (python_bin, python_bin)
223*cc02d7e2SAndroid Build Coastguard Worker    result = repository_ctx.execute([_get_bash_bin(repository_ctx), "-c", cmd])
224*cc02d7e2SAndroid Build Coastguard Worker    if result.return_code == 1:
225*cc02d7e2SAndroid Build Coastguard Worker        if not allow_absent:
226*cc02d7e2SAndroid Build Coastguard Worker            _fail("--define %s='%s' is not executable. Is it the python binary?" %
227*cc02d7e2SAndroid Build Coastguard Worker                  (bin_path_key, python_bin))
228*cc02d7e2SAndroid Build Coastguard Worker        else:
229*cc02d7e2SAndroid Build Coastguard Worker            return None
230*cc02d7e2SAndroid Build Coastguard Worker    return True
231*cc02d7e2SAndroid Build Coastguard Worker
232*cc02d7e2SAndroid Build Coastguard Workerdef _get_python_include(repository_ctx, python_bin):
233*cc02d7e2SAndroid Build Coastguard Worker    """Gets the python include path."""
234*cc02d7e2SAndroid Build Coastguard Worker    result = _execute(
235*cc02d7e2SAndroid Build Coastguard Worker        repository_ctx,
236*cc02d7e2SAndroid Build Coastguard Worker        [
237*cc02d7e2SAndroid Build Coastguard Worker            python_bin,
238*cc02d7e2SAndroid Build Coastguard Worker            "-c",
239*cc02d7e2SAndroid Build Coastguard Worker            "from __future__ import print_function;" +
240*cc02d7e2SAndroid Build Coastguard Worker            "import sysconfig;" +
241*cc02d7e2SAndroid Build Coastguard Worker            "print(sysconfig.get_path('include'))",
242*cc02d7e2SAndroid Build Coastguard Worker        ],
243*cc02d7e2SAndroid Build Coastguard Worker        error_msg = "Problem getting python include path for {}.".format(python_bin),
244*cc02d7e2SAndroid Build Coastguard Worker        error_details = (
245*cc02d7e2SAndroid Build Coastguard Worker            "Is the Python binary path set up right? " + "(See ./configure or " +
246*cc02d7e2SAndroid Build Coastguard Worker            python_bin + ".) " + _HEADERS_HELP
247*cc02d7e2SAndroid Build Coastguard Worker        ),
248*cc02d7e2SAndroid Build Coastguard Worker    )
249*cc02d7e2SAndroid Build Coastguard Worker    include_path = result.stdout.splitlines()[0]
250*cc02d7e2SAndroid Build Coastguard Worker    _execute(
251*cc02d7e2SAndroid Build Coastguard Worker        repository_ctx,
252*cc02d7e2SAndroid Build Coastguard Worker        [
253*cc02d7e2SAndroid Build Coastguard Worker            python_bin,
254*cc02d7e2SAndroid Build Coastguard Worker            "-c",
255*cc02d7e2SAndroid Build Coastguard Worker            "import os;" +
256*cc02d7e2SAndroid Build Coastguard Worker            "main_header = os.path.join(r'{}', 'Python.h');".format(include_path) +
257*cc02d7e2SAndroid Build Coastguard Worker            "assert os.path.exists(main_header), main_header + ' does not exist.'",
258*cc02d7e2SAndroid Build Coastguard Worker        ],
259*cc02d7e2SAndroid Build Coastguard Worker        error_msg = "Unable to find Python headers for {}".format(python_bin),
260*cc02d7e2SAndroid Build Coastguard Worker        error_details = _HEADERS_HELP,
261*cc02d7e2SAndroid Build Coastguard Worker        empty_stdout_fine = True,
262*cc02d7e2SAndroid Build Coastguard Worker    )
263*cc02d7e2SAndroid Build Coastguard Worker    return include_path
264*cc02d7e2SAndroid Build Coastguard Worker
265*cc02d7e2SAndroid Build Coastguard Workerdef _get_python_import_lib_name(repository_ctx, python_bin, bin_path_key):
266*cc02d7e2SAndroid Build Coastguard Worker    """Get Python import library name (pythonXY.lib) on Windows."""
267*cc02d7e2SAndroid Build Coastguard Worker    result = _execute(
268*cc02d7e2SAndroid Build Coastguard Worker        repository_ctx,
269*cc02d7e2SAndroid Build Coastguard Worker        [
270*cc02d7e2SAndroid Build Coastguard Worker            python_bin,
271*cc02d7e2SAndroid Build Coastguard Worker            "-c",
272*cc02d7e2SAndroid Build Coastguard Worker            "import sys;" + 'print("python" + str(sys.version_info[0]) + ' +
273*cc02d7e2SAndroid Build Coastguard Worker            '      str(sys.version_info[1]) + ".lib")',
274*cc02d7e2SAndroid Build Coastguard Worker        ],
275*cc02d7e2SAndroid Build Coastguard Worker        error_msg = "Problem getting python import library.",
276*cc02d7e2SAndroid Build Coastguard Worker        error_details = ("Is the Python binary path set up right? " +
277*cc02d7e2SAndroid Build Coastguard Worker                         "(See ./configure or " + bin_path_key + ".) "),
278*cc02d7e2SAndroid Build Coastguard Worker    )
279*cc02d7e2SAndroid Build Coastguard Worker    return result.stdout.splitlines()[0]
280*cc02d7e2SAndroid Build Coastguard Worker
281*cc02d7e2SAndroid Build Coastguard Workerdef _create_single_version_package(
282*cc02d7e2SAndroid Build Coastguard Worker        repository_ctx,
283*cc02d7e2SAndroid Build Coastguard Worker        variety_name,
284*cc02d7e2SAndroid Build Coastguard Worker        bin_path_key,
285*cc02d7e2SAndroid Build Coastguard Worker        default_bin_path,
286*cc02d7e2SAndroid Build Coastguard Worker        lib_path_key,
287*cc02d7e2SAndroid Build Coastguard Worker        allow_absent):
288*cc02d7e2SAndroid Build Coastguard Worker    """Creates the repository containing files set up to build with Python."""
289*cc02d7e2SAndroid Build Coastguard Worker    empty_include_rule = "filegroup(\n  name=\"{}_include\",\n  srcs=[],\n)".format(variety_name)
290*cc02d7e2SAndroid Build Coastguard Worker
291*cc02d7e2SAndroid Build Coastguard Worker    python_bin = _get_python_bin(repository_ctx, bin_path_key, default_bin_path, allow_absent)
292*cc02d7e2SAndroid Build Coastguard Worker    if (python_bin == None or
293*cc02d7e2SAndroid Build Coastguard Worker        _check_python_bin(repository_ctx,
294*cc02d7e2SAndroid Build Coastguard Worker                          python_bin,
295*cc02d7e2SAndroid Build Coastguard Worker                          bin_path_key,
296*cc02d7e2SAndroid Build Coastguard Worker                          allow_absent) == None) and allow_absent:
297*cc02d7e2SAndroid Build Coastguard Worker            python_include_rule = empty_include_rule
298*cc02d7e2SAndroid Build Coastguard Worker    else:
299*cc02d7e2SAndroid Build Coastguard Worker        python_lib = _get_python_lib(repository_ctx, python_bin, lib_path_key)
300*cc02d7e2SAndroid Build Coastguard Worker        _check_python_lib(repository_ctx, python_lib)
301*cc02d7e2SAndroid Build Coastguard Worker        python_include = _get_python_include(repository_ctx, python_bin)
302*cc02d7e2SAndroid Build Coastguard Worker        python_include_rule = _symlink_genrule_for_dir(
303*cc02d7e2SAndroid Build Coastguard Worker            repository_ctx,
304*cc02d7e2SAndroid Build Coastguard Worker            python_include,
305*cc02d7e2SAndroid Build Coastguard Worker            "{}_include".format(variety_name),
306*cc02d7e2SAndroid Build Coastguard Worker            "{}_include".format(variety_name),
307*cc02d7e2SAndroid Build Coastguard Worker        )
308*cc02d7e2SAndroid Build Coastguard Worker    python_import_lib_genrule = ""
309*cc02d7e2SAndroid Build Coastguard Worker
310*cc02d7e2SAndroid Build Coastguard Worker    # To build Python C/C++ extension on Windows, we need to link to python import library pythonXY.lib
311*cc02d7e2SAndroid Build Coastguard Worker    # See https://docs.python.org/3/extending/windows.html
312*cc02d7e2SAndroid Build Coastguard Worker    if _is_windows(repository_ctx):
313*cc02d7e2SAndroid Build Coastguard Worker        python_include = _normalize_path(python_include)
314*cc02d7e2SAndroid Build Coastguard Worker        python_import_lib_name = _get_python_import_lib_name(
315*cc02d7e2SAndroid Build Coastguard Worker            repository_ctx,
316*cc02d7e2SAndroid Build Coastguard Worker            python_bin,
317*cc02d7e2SAndroid Build Coastguard Worker            bin_path_key,
318*cc02d7e2SAndroid Build Coastguard Worker        )
319*cc02d7e2SAndroid Build Coastguard Worker        python_import_lib_src = python_include.rsplit(
320*cc02d7e2SAndroid Build Coastguard Worker            "/",
321*cc02d7e2SAndroid Build Coastguard Worker            1,
322*cc02d7e2SAndroid Build Coastguard Worker        )[0] + "/libs/" + python_import_lib_name
323*cc02d7e2SAndroid Build Coastguard Worker        python_import_lib_genrule = _symlink_genrule_for_dir(
324*cc02d7e2SAndroid Build Coastguard Worker            repository_ctx,
325*cc02d7e2SAndroid Build Coastguard Worker            None,
326*cc02d7e2SAndroid Build Coastguard Worker            "",
327*cc02d7e2SAndroid Build Coastguard Worker            "{}_import_lib".format(variety_name),
328*cc02d7e2SAndroid Build Coastguard Worker            [python_import_lib_src],
329*cc02d7e2SAndroid Build Coastguard Worker            [python_import_lib_name],
330*cc02d7e2SAndroid Build Coastguard Worker        )
331*cc02d7e2SAndroid Build Coastguard Worker    _tpl(
332*cc02d7e2SAndroid Build Coastguard Worker        repository_ctx,
333*cc02d7e2SAndroid Build Coastguard Worker        "variety",
334*cc02d7e2SAndroid Build Coastguard Worker        {
335*cc02d7e2SAndroid Build Coastguard Worker            "%{PYTHON_INCLUDE_GENRULE}": python_include_rule,
336*cc02d7e2SAndroid Build Coastguard Worker            "%{PYTHON_IMPORT_LIB_GENRULE}": python_import_lib_genrule,
337*cc02d7e2SAndroid Build Coastguard Worker            "%{VARIETY_NAME}": variety_name,
338*cc02d7e2SAndroid Build Coastguard Worker        },
339*cc02d7e2SAndroid Build Coastguard Worker        out = "{}/BUILD".format(variety_name),
340*cc02d7e2SAndroid Build Coastguard Worker    )
341*cc02d7e2SAndroid Build Coastguard Worker
342*cc02d7e2SAndroid Build Coastguard Workerdef _python_autoconf_impl(repository_ctx):
343*cc02d7e2SAndroid Build Coastguard Worker    """Implementation of the python_autoconf repository rule."""
344*cc02d7e2SAndroid Build Coastguard Worker    _create_single_version_package(
345*cc02d7e2SAndroid Build Coastguard Worker        repository_ctx,
346*cc02d7e2SAndroid Build Coastguard Worker        "_python3",
347*cc02d7e2SAndroid Build Coastguard Worker        _PYTHON3_BIN_PATH,
348*cc02d7e2SAndroid Build Coastguard Worker        "python3" if not _is_windows(repository_ctx) else "python.exe",
349*cc02d7e2SAndroid Build Coastguard Worker        _PYTHON3_LIB_PATH,
350*cc02d7e2SAndroid Build Coastguard Worker        False
351*cc02d7e2SAndroid Build Coastguard Worker    )
352*cc02d7e2SAndroid Build Coastguard Worker    _tpl(repository_ctx, "BUILD")
353*cc02d7e2SAndroid Build Coastguard Worker
354*cc02d7e2SAndroid Build Coastguard Workerpython_configure = repository_rule(
355*cc02d7e2SAndroid Build Coastguard Worker    implementation = _python_autoconf_impl,
356*cc02d7e2SAndroid Build Coastguard Worker    environ = [
357*cc02d7e2SAndroid Build Coastguard Worker        _BAZEL_SH,
358*cc02d7e2SAndroid Build Coastguard Worker        _PYTHON3_BIN_PATH,
359*cc02d7e2SAndroid Build Coastguard Worker        _PYTHON3_LIB_PATH,
360*cc02d7e2SAndroid Build Coastguard Worker    ],
361*cc02d7e2SAndroid Build Coastguard Worker    attrs = {
362*cc02d7e2SAndroid Build Coastguard Worker        "_build_tpl": attr.label(
363*cc02d7e2SAndroid Build Coastguard Worker            default = Label("//third_party/py:BUILD.tpl"),
364*cc02d7e2SAndroid Build Coastguard Worker            allow_single_file = True,
365*cc02d7e2SAndroid Build Coastguard Worker        ),
366*cc02d7e2SAndroid Build Coastguard Worker        "_variety_tpl": attr.label(
367*cc02d7e2SAndroid Build Coastguard Worker            default = Label("//third_party/py:variety.tpl"),
368*cc02d7e2SAndroid Build Coastguard Worker            allow_single_file = True,
369*cc02d7e2SAndroid Build Coastguard Worker        ),
370*cc02d7e2SAndroid Build Coastguard Worker    },
371*cc02d7e2SAndroid Build Coastguard Worker)
372*cc02d7e2SAndroid Build Coastguard Worker"""Detects and configures the local Python.
373*cc02d7e2SAndroid Build Coastguard Worker
374*cc02d7e2SAndroid Build Coastguard WorkerIt expects the system have a working Python 3 installation.
375*cc02d7e2SAndroid Build Coastguard Worker
376*cc02d7e2SAndroid Build Coastguard WorkerAdd the following to your WORKSPACE FILE:
377*cc02d7e2SAndroid Build Coastguard Worker
378*cc02d7e2SAndroid Build Coastguard Worker```python
379*cc02d7e2SAndroid Build Coastguard Workerpython_configure(name = "local_config_python")
380*cc02d7e2SAndroid Build Coastguard Worker```
381*cc02d7e2SAndroid Build Coastguard Worker
382*cc02d7e2SAndroid Build Coastguard WorkerArgs:
383*cc02d7e2SAndroid Build Coastguard Worker  name: A unique name for this workspace rule.
384*cc02d7e2SAndroid Build Coastguard Worker"""
385