1# Copyright 2014 The Bazel Authors. All rights reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15go_exts = [ 16 ".go", 17] 18 19asm_exts = [ 20 ".s", 21 ".S", 22 ".h", # may be included by .s 23] 24 25# be consistent to cc_library. 26hdr_exts = [ 27 ".h", 28 ".hh", 29 ".hpp", 30 ".hxx", 31 ".inc", 32] 33 34c_exts = [ 35 ".c", 36 ".h", 37] 38 39cxx_exts = [ 40 ".cc", 41 ".cxx", 42 ".cpp", 43 ".h", 44 ".hh", 45 ".hpp", 46 ".hxx", 47] 48 49objc_exts = [ 50 ".m", 51 ".mm", 52 ".h", 53 ".hh", 54 ".hpp", 55 ".hxx", 56] 57 58cgo_exts = [ 59 ".c", 60 ".cc", 61 ".cpp", 62 ".cxx", 63 ".h", 64 ".hh", 65 ".hpp", 66 ".hxx", 67 ".inc", 68 ".m", 69 ".mm", 70] 71 72def split_srcs(srcs): 73 """Returns a struct of sources, divided by extension.""" 74 sources = struct( 75 go = [], 76 asm = [], 77 headers = [], 78 c = [], 79 cxx = [], 80 objc = [], 81 ) 82 ext_pairs = ( 83 (sources.go, go_exts), 84 (sources.headers, hdr_exts), 85 (sources.asm, asm_exts), 86 (sources.c, c_exts), 87 (sources.cxx, cxx_exts), 88 (sources.objc, objc_exts), 89 ) 90 extmap = {} 91 for outs, exts in ext_pairs: 92 for ext in exts: 93 ext = ext[1:] # strip the dot 94 if ext in extmap: 95 break 96 extmap[ext] = outs 97 for src in as_iterable(srcs): 98 extouts = extmap.get(src.extension) 99 if extouts == None: 100 fail("Unknown source type {0}".format(src.basename)) 101 extouts.append(src) 102 return sources 103 104def join_srcs(source): 105 """Combines source from a split_srcs struct into a single list.""" 106 return source.go + source.headers + source.asm + source.c + source.cxx + source.objc 107 108def os_path(ctx, path): 109 path = str(path) # maybe convert from path type 110 if ctx.os.name.startswith("windows"): 111 path = path.replace("/", "\\") 112 return path 113 114def executable_path(ctx, path): 115 path = os_path(ctx, path) 116 if ctx.os.name.startswith("windows"): 117 path += ".exe" 118 return path 119 120def executable_extension(ctx): 121 extension = "" 122 if ctx.os.name.startswith("windows"): 123 extension = ".exe" 124 return extension 125 126def goos_to_extension(goos): 127 if goos == "windows": 128 return ".exe" 129 return "" 130 131ARCHIVE_EXTENSION = ".a" 132 133SHARED_LIB_EXTENSIONS = [".dll", ".dylib", ".so"] 134 135def goos_to_shared_extension(goos): 136 return { 137 "windows": ".dll", 138 "darwin": ".dylib", 139 }.get(goos, ".so") 140 141def has_shared_lib_extension(path): 142 """ 143 Matches filenames of shared libraries, with or without a version number extension. 144 """ 145 return (has_simple_shared_lib_extension(path) or 146 get_versioned_shared_lib_extension(path)) 147 148def has_simple_shared_lib_extension(path): 149 """ 150 Matches filenames of shared libraries, without a version number extension. 151 """ 152 return any([path.endswith(ext) for ext in SHARED_LIB_EXTENSIONS]) 153 154def get_versioned_shared_lib_extension(path): 155 """If appears to be an versioned .so or .dylib file, return the extension; otherwise empty""" 156 parts = path.split("/")[-1].split(".") 157 if not parts[-1].isdigit(): 158 return "" 159 160 # only iterating to 1 because parts[0] has to be the lib name 161 for i in range(len(parts) - 1, 0, -1): 162 if not parts[i].isdigit(): 163 if parts[i] == "dylib" or parts[i] == "so": 164 return ".".join(parts[i:]) 165 166 # something like foo.bar.1.2 or dylib.1.2 167 return "" 168 169 # something like 1.2.3, or so.1.2, or dylib.1.2, or foo.1.2 170 return "" 171 172MINIMUM_BAZEL_VERSION = "5.4.0" 173 174def as_list(v): 175 """Returns a list, tuple, or depset as a list.""" 176 if type(v) == "list": 177 return v 178 if type(v) == "tuple": 179 return list(v) 180 if type(v) == "depset": 181 return v.to_list() 182 fail("as_list failed on {}".format(v)) 183 184def as_iterable(v): 185 """Returns a list, tuple, or depset as something iterable.""" 186 if type(v) == "list": 187 return v 188 if type(v) == "tuple": 189 return v 190 if type(v) == "depset": 191 return v.to_list() 192 fail("as_iterator failed on {}".format(v)) 193 194def as_tuple(v): 195 """Returns a list, tuple, or depset as a tuple.""" 196 if type(v) == "tuple": 197 return v 198 if type(v) == "list": 199 return tuple(v) 200 if type(v) == "depset": 201 return tuple(v.to_list()) 202 fail("as_tuple failed on {}".format(v)) 203 204def as_set(v): 205 """Returns a list, tuple, or depset as a depset.""" 206 if type(v) == "depset": 207 return v 208 if type(v) == "list": 209 return depset(v) 210 if type(v) == "tuple": 211 return depset(v) 212 fail("as_tuple failed on {}".format(v)) 213 214_STRUCT_TYPE = type(struct()) 215 216def is_struct(v): 217 """Returns true if v is a struct.""" 218 return type(v) == _STRUCT_TYPE 219 220def count_group_matches(v, prefix, suffix): 221 """Counts reluctant substring matches between prefix and suffix. 222 223 Equivalent to the number of regular expression matches "prefix.+?suffix" 224 in the string v. 225 """ 226 227 count = 0 228 idx = 0 229 for i in range(0, len(v)): 230 if idx > i: 231 continue 232 233 idx = v.find(prefix, idx) 234 if idx == -1: 235 break 236 237 # If there is another prefix before the next suffix, the previous prefix is discarded. 238 # This is OK; it does not affect our count. 239 idx = v.find(suffix, idx) 240 if idx == -1: 241 break 242 243 count = count + 1 244 245 return count 246 247# C/C++ compiler and linker options related to coverage instrumentation. 248COVERAGE_OPTIONS_DENYLIST = { 249 "--coverage": None, 250 "-ftest-coverage": None, 251 "-fprofile-arcs": None, 252 "-fprofile-instr-generate": None, 253 "-fcoverage-mapping": None, 254} 255