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")