kythe.io@v0.0.68-0.20240422202219-7225dbc01741/tools/build_rules/lexyacc/lexyacc.bzl (about)

     1  load("@bazel_skylib//lib:versions.bzl", "versions")
     2  
     3  def genlex(name, src, out, includes = []):
     4      """Generate a C++ lexer from a lex file using Flex.
     5  
     6      Args:
     7        name: The name of the rule.
     8        src: The .lex source file.
     9        out: The generated source file.
    10        includes: A list of headers included by the .lex file.
    11      """
    12      cmd = "$(LEX) -o $(@D)/%s $(location %s)" % (out, src)
    13      native.genrule(
    14          name = name,
    15          outs = [out],
    16          srcs = [src] + includes,
    17          cmd = cmd,
    18          toolchains = ["@io_kythe//tools/build_rules/lexyacc:current_lexyacc_toolchain"],
    19          tools = ["@io_kythe//tools/build_rules/lexyacc:current_lexyacc_toolchain"],
    20      )
    21  
    22  def genyacc(name, src, header_out, source_out, extra_outs = []):
    23      """Generate a C++ parser from a Yacc file using Bison.
    24  
    25      Args:
    26        name: The name of the rule.
    27        src: The input grammar file.
    28        header_out: The generated header file.
    29        source_out: The generated source file.
    30        extra_outs: Additional generated outputs.
    31      """
    32      cmd = "$(YACC) -o $(@D)/%s $(location %s)" % (source_out, src)
    33      native.genrule(
    34          name = name,
    35          outs = [source_out, header_out] + extra_outs,
    36          srcs = [src],
    37          cmd = cmd,
    38          toolchains = ["@io_kythe//tools/build_rules/lexyacc:current_lexyacc_toolchain"],
    39          tools = ["@io_kythe//tools/build_rules/lexyacc:current_lexyacc_toolchain"],
    40      )
    41  
    42  LexYaccInfo = provider(
    43      doc = "Paths to lex and yacc binaries.",
    44      fields = ["lex", "yacc", "runfiles"],
    45  )
    46  
    47  def _lexyacc_variables(ctx):
    48      lyinfo = ctx.toolchains["@io_kythe//tools/build_rules/lexyacc:toolchain_type"].lexyaccinfo
    49      return [
    50          DefaultInfo(runfiles = lyinfo.runfiles, files = lyinfo.runfiles.files),
    51          platform_common.TemplateVariableInfo({
    52              "LEX": lyinfo.lex,
    53              "YACC": lyinfo.yacc,
    54          }),
    55      ]
    56  
    57  lexyacc_variables = rule(
    58      implementation = _lexyacc_variables,
    59      toolchains = ["@io_kythe//tools/build_rules/lexyacc:toolchain_type"],
    60  )
    61  
    62  def _lexyacc_toolchain_impl(ctx):
    63      runfiles = ctx.runfiles()
    64      if bool(ctx.attr.lex) == bool(ctx.attr.lex_path):
    65          fail("Exactly one of lex and lex_path is required")
    66  
    67      if ctx.attr.lex:
    68          runfiles = runfiles.merge(ctx.attr.lex[DefaultInfo].default_runfiles)
    69  
    70      if bool(ctx.attr.yacc) == bool(ctx.attr.yacc_path):
    71          fail("Exactly one of yacc and yacc_path is required")
    72  
    73      if ctx.attr.yacc:
    74          runfiles = runfiles.merge(ctx.attr.yacc[DefaultInfo].default_runfiles)
    75  
    76      return [
    77          platform_common.ToolchainInfo(
    78              lexyaccinfo = LexYaccInfo(
    79                  lex = ctx.attr.lex_path or ctx.executable.lex.path,
    80                  yacc = ctx.attr.yacc_path or ctx.executable.yacc.path,
    81                  runfiles = runfiles,
    82              ),
    83          ),
    84      ]
    85  
    86  _lexyacc_toolchain = rule(
    87      implementation = _lexyacc_toolchain_impl,
    88      attrs = {
    89          "lex_path": attr.string(),
    90          "yacc_path": attr.string(),
    91          "lex": attr.label(
    92              executable = True,
    93              cfg = "exec",
    94          ),
    95          "yacc": attr.label(
    96              executable = True,
    97              cfg = "exec",
    98          ),
    99      },
   100      provides = [
   101          platform_common.ToolchainInfo,
   102      ],
   103  )
   104  
   105  def lexyacc_toolchain(name, **kwargs):
   106      _lexyacc_toolchain(name = name, **kwargs)
   107      native.toolchain(
   108          name = name + "_toolchain",
   109          toolchain = ":" + name,
   110          toolchain_type = "@io_kythe//tools/build_rules/lexyacc:toolchain_type",
   111      )
   112  
   113  def _check_flex_version(repository_ctx, min_version):
   114      flex = repository_ctx.os.environ.get("FLEX", repository_ctx.which("flex"))
   115      if flex == None:
   116          fail("Unable to find flex binary")
   117      flex_result = repository_ctx.execute([flex, "--version"])
   118      if flex_result.return_code:
   119          fail("Unable to determine flex version: " + flex_result.stderr)
   120      flex_version = flex_result.stdout.split(" ")
   121      if len(flex_version) < 2:
   122          fail("Too few components in flex version: " + flex_result.stdout)
   123      if not versions.is_at_least(min_version, flex_version[1]):
   124          fail("Flex too old (%s < %s)" % (flex_version[1], min_version))
   125      return flex
   126  
   127  def _local_lexyacc(repository_ctx):
   128      if repository_ctx.os.environ.get("KYTHE_DO_NOT_DETECT_BAZEL_TOOLCHAINS", "0") == "1":
   129          repository_ctx.file("BUILD.bazel", "# Toolchain detection disabled by KYTHE_DO_NOT_DETECT_BAZEL_TOOLCHAINS")
   130          return
   131      flex = _check_flex_version(repository_ctx, "2.6")
   132      bison = repository_ctx.os.environ.get("BISON", repository_ctx.which("bison"))
   133      if not bison:
   134          fail("Unable to find bison binary")
   135      repository_ctx.file(
   136          "WORKSPACE",
   137          content = "workspace(name=\"%s\")" % (repository_ctx.name,),
   138          executable = False,
   139      )
   140      repository_ctx.file(
   141          "BUILD.bazel",
   142          content = "\n".join([
   143              "load(\"@io_kythe//tools/build_rules/lexyacc:lexyacc.bzl\", \"lexyacc_toolchain\")",
   144              "package(default_visibility=[\"//visibility:public\"])",
   145              "lexyacc_toolchain(",
   146              "  name = \"lexyacc_local\",",
   147              "  lex_path = \"%s\"," % flex,
   148              "  yacc_path = \"%s\"," % bison,
   149              ")",
   150          ]),
   151      )
   152  
   153  local_lexyacc_repository = repository_rule(
   154      implementation = _local_lexyacc,
   155      local = True,
   156      environ = [
   157          "KYTHE_DO_NOT_DETECT_BAZEL_TOOCHAINS",
   158          "PATH",
   159          "BISON",
   160          "FLEX",
   161      ],
   162  )
   163  
   164  def lexyacc_configure():
   165      local_lexyacc_repository(name = "local_config_lexyacc")
   166      native.register_toolchains("@local_config_lexyacc//:all")