|
14 | 14 |
|
15 | 15 | SUPPORTED_TARGETS = [("linux", "x86_64"), ("linux", "aarch64"), ("darwin", "x86_64")] |
16 | 16 |
|
| 17 | +host_tool_features = struct( |
| 18 | + SUPPORTS_ARG_FILE = "supports_arg_file", |
| 19 | +) |
| 20 | + |
17 | 21 | def python(rctx): |
18 | 22 | # Get path of the python interpreter. |
19 | 23 |
|
@@ -53,6 +57,107 @@ def arch(rctx): |
53 | 57 | fail("Failed to detect machine architecture: \n%s\n%s" % (exec_result.stdout, exec_result.stderr)) |
54 | 58 | return exec_result.stdout.strip() |
55 | 59 |
|
| 60 | +# Tries to figure out if a tool supports newline separated arg files (i.e. |
| 61 | +# `@file`). |
| 62 | +def _tool_supports_arg_file(rctx, tool_path): |
| 63 | + # We assume nothing other than that `tool_path` is an executable. |
| 64 | + # |
| 65 | + # First we have to find out what command line flag gets the tool to just |
| 66 | + # print out some text and exit successfully. |
| 67 | + # |
| 68 | + # Most tools support `-v` or `--version` or (for `libtool`) `-V` but some |
| 69 | + # tools don't have such an option (BSD `ranlib` and `ar`, for example). |
| 70 | + # |
| 71 | + # We just try all the options we know of until one works and if none work |
| 72 | + # we return "None" indicating an indeterminate result. |
| 73 | + opts = ( |
| 74 | + ["-v", "--version", "-version", "-V"] + |
| 75 | + ["-h", "--help", "-help", "-H"] |
| 76 | + ) |
| 77 | + |
| 78 | + no_op_opt = None |
| 79 | + for opt in opts: |
| 80 | + if rctx.execute([tool_path, opt], timeout = 2).return_code == 0: |
| 81 | + no_op_opt = opt |
| 82 | + break |
| 83 | + |
| 84 | + if no_op_opt == None: |
| 85 | + return None |
| 86 | + |
| 87 | + # Okay! Once we have an opt that we *know* does nothing but make the |
| 88 | + # executable exit successfully, we'll stick that opt in a file and try |
| 89 | + # again: |
| 90 | + tmp_file = "tmp-arg-file" |
| 91 | + rctx.file(tmp_file, content = "{}\n".format(no_op_opt), executable = False) |
| 92 | + |
| 93 | + res = rctx.execute([tool_path, "@{}".format(tmp_file)]).return_code == 0 |
| 94 | + rctx.delete(tmp_file) |
| 95 | + |
| 96 | + return res |
| 97 | + |
| 98 | +def _get_host_tool_info(rctx, tool_path, features_to_test = [], tool_key = None): |
| 99 | + if tool_key == None: |
| 100 | + tool_key = tool_path |
| 101 | + |
| 102 | + if tool_path == None or not rctx.path(tool_path).exists: |
| 103 | + return {} |
| 104 | + |
| 105 | + f = host_tool_features |
| 106 | + features = {} |
| 107 | + for feature in features_to_test: |
| 108 | + features[feature] = { |
| 109 | + f.SUPPORTS_ARG_FILE: _tool_supports_arg_file, |
| 110 | + }[feature](rctx, tool_path) |
| 111 | + |
| 112 | + return { |
| 113 | + tool_key: struct( |
| 114 | + path = tool_path, |
| 115 | + features = features, |
| 116 | + ), |
| 117 | + } |
| 118 | + |
| 119 | +def _extract_tool_path_and_features(tool_info): |
| 120 | + # Have to support structs or dicts: |
| 121 | + tool_path = tool_info.path if type(tool_info) == "struct" else tool_info["path"] |
| 122 | + tool_features = tool_info.features if type(tool_info) == "struct" else tool_info["features"] |
| 123 | + |
| 124 | + return (tool_path, tool_features) |
| 125 | + |
| 126 | +def _check_host_tool_supports(host_tool_info, tool_key, features = []): |
| 127 | + if tool_key in host_tool_info: |
| 128 | + _, tool_features = _extract_tool_path_and_features(host_tool_info[tool_key]) |
| 129 | + |
| 130 | + for f in features: |
| 131 | + if not f in tool_features or not tool_features[f]: |
| 132 | + return False |
| 133 | + |
| 134 | + return True |
| 135 | + else: |
| 136 | + return False |
| 137 | + |
| 138 | +def _get_host_tool_and_assert_supports(host_tool_info, tool_key, features = []): |
| 139 | + if tool_key in host_tool_info: |
| 140 | + tool_path, tool_features = _extract_tool_path_and_features(host_tool_info[tool_key]) |
| 141 | + |
| 142 | + missing = [f for f in features if not f in tool_features or not tool_features[f]] |
| 143 | + |
| 144 | + if missing: |
| 145 | + fail("Host tool `{key}` (`{path}`) is missing these features: `{missing}`.".format( |
| 146 | + key = tool_key, |
| 147 | + path = tool_path, |
| 148 | + missing = missing, |
| 149 | + )) |
| 150 | + |
| 151 | + return tool_path |
| 152 | + else: |
| 153 | + return False |
| 154 | + |
| 155 | +host_tools = struct( |
| 156 | + get_tool_info = _get_host_tool_info, |
| 157 | + tool_supports = _check_host_tool_supports, |
| 158 | + get_and_assert = _get_host_tool_and_assert_supports, |
| 159 | +) |
| 160 | + |
56 | 161 | def os_arch_pair(os, arch): |
57 | 162 | return "{}-{}".format(os, arch) |
58 | 163 |
|
|
0 commit comments