1*eed53cd4SHONG Yifan"""system_library is a repository rule for importing system libraries""" 2*eed53cd4SHONG Yifan 3*eed53cd4SHONG YifanBAZEL_LIB_ADDITIONAL_PATHS_ENV_VAR = "BAZEL_LIB_ADDITIONAL_PATHS" 4*eed53cd4SHONG YifanBAZEL_LIB_OVERRIDE_PATHS_ENV_VAR = "BAZEL_LIB_OVERRIDE_PATHS" 5*eed53cd4SHONG YifanBAZEL_INCLUDE_ADDITIONAL_PATHS_ENV_VAR = "BAZEL_INCLUDE_ADDITIONAL_PATHS" 6*eed53cd4SHONG YifanBAZEL_INCLUDE_OVERRIDE_PATHS_ENV_VAR = "BAZEL_INCLUDE_OVERRIDE_PATHS" 7*eed53cd4SHONG YifanENV_VAR_SEPARATOR = "," 8*eed53cd4SHONG YifanENV_VAR_ASSIGNMENT = "=" 9*eed53cd4SHONG Yifan 10*eed53cd4SHONG Yifandef _make_flags(flag_values, flag): 11*eed53cd4SHONG Yifan flags = [] 12*eed53cd4SHONG Yifan if flag_values: 13*eed53cd4SHONG Yifan for s in flag_values: 14*eed53cd4SHONG Yifan flags.append(flag + s) 15*eed53cd4SHONG Yifan return " ".join(flags) 16*eed53cd4SHONG Yifan 17*eed53cd4SHONG Yifandef _split_env_var(repo_ctx, var_name): 18*eed53cd4SHONG Yifan value = repo_ctx.os.environ.get(var_name) 19*eed53cd4SHONG Yifan if value: 20*eed53cd4SHONG Yifan assignments = value.split(ENV_VAR_SEPARATOR) 21*eed53cd4SHONG Yifan dict = {} 22*eed53cd4SHONG Yifan for assignment in assignments: 23*eed53cd4SHONG Yifan pair = assignment.split(ENV_VAR_ASSIGNMENT) 24*eed53cd4SHONG Yifan if len(pair) != 2: 25*eed53cd4SHONG Yifan fail( 26*eed53cd4SHONG Yifan "Assignments should have form 'name=value', " + 27*eed53cd4SHONG Yifan "but encountered {} in env variable {}" 28*eed53cd4SHONG Yifan .format(assignment, var_name), 29*eed53cd4SHONG Yifan ) 30*eed53cd4SHONG Yifan key, value = pair[0], pair[1] 31*eed53cd4SHONG Yifan if not dict.get(key): 32*eed53cd4SHONG Yifan dict[key] = [] 33*eed53cd4SHONG Yifan dict[key].append(value) 34*eed53cd4SHONG Yifan return dict 35*eed53cd4SHONG Yifan else: 36*eed53cd4SHONG Yifan return {} 37*eed53cd4SHONG Yifan 38*eed53cd4SHONG Yifandef _get_list_from_env_var(repo_ctx, var_name, key): 39*eed53cd4SHONG Yifan return _split_env_var(repo_ctx, var_name).get(key, default = []) 40*eed53cd4SHONG Yifan 41*eed53cd4SHONG Yifandef _execute_bash(repo_ctx, cmd): 42*eed53cd4SHONG Yifan return repo_ctx.execute(["/bin/bash", "-c", cmd]).stdout.strip("\n") 43*eed53cd4SHONG Yifan 44*eed53cd4SHONG Yifandef _find_linker(repo_ctx): 45*eed53cd4SHONG Yifan ld = _execute_bash(repo_ctx, "which ld") 46*eed53cd4SHONG Yifan lld = _execute_bash(repo_ctx, "which lld") 47*eed53cd4SHONG Yifan if ld: 48*eed53cd4SHONG Yifan return ld 49*eed53cd4SHONG Yifan elif lld: 50*eed53cd4SHONG Yifan return lld 51*eed53cd4SHONG Yifan else: 52*eed53cd4SHONG Yifan fail("No linker found") 53*eed53cd4SHONG Yifan 54*eed53cd4SHONG Yifandef _find_compiler(repo_ctx): 55*eed53cd4SHONG Yifan gcc = _execute_bash(repo_ctx, "which g++") 56*eed53cd4SHONG Yifan clang = _execute_bash(repo_ctx, "which clang++") 57*eed53cd4SHONG Yifan if gcc: 58*eed53cd4SHONG Yifan return gcc 59*eed53cd4SHONG Yifan elif clang: 60*eed53cd4SHONG Yifan return clang 61*eed53cd4SHONG Yifan else: 62*eed53cd4SHONG Yifan fail("No compiler found") 63*eed53cd4SHONG Yifan 64*eed53cd4SHONG Yifandef _find_lib_path(repo_ctx, lib_name, archive_names, lib_path_hints): 65*eed53cd4SHONG Yifan override_paths = _get_list_from_env_var( 66*eed53cd4SHONG Yifan repo_ctx, 67*eed53cd4SHONG Yifan BAZEL_LIB_OVERRIDE_PATHS_ENV_VAR, 68*eed53cd4SHONG Yifan lib_name, 69*eed53cd4SHONG Yifan ) 70*eed53cd4SHONG Yifan additional_paths = _get_list_from_env_var( 71*eed53cd4SHONG Yifan repo_ctx, 72*eed53cd4SHONG Yifan BAZEL_LIB_ADDITIONAL_PATHS_ENV_VAR, 73*eed53cd4SHONG Yifan lib_name, 74*eed53cd4SHONG Yifan ) 75*eed53cd4SHONG Yifan 76*eed53cd4SHONG Yifan # Directories will be searched in order 77*eed53cd4SHONG Yifan path_flags = _make_flags( 78*eed53cd4SHONG Yifan override_paths + lib_path_hints + additional_paths, 79*eed53cd4SHONG Yifan "-L", 80*eed53cd4SHONG Yifan ) 81*eed53cd4SHONG Yifan linker = _find_linker(repo_ctx) 82*eed53cd4SHONG Yifan for archive_name in archive_names: 83*eed53cd4SHONG Yifan cmd = """ 84*eed53cd4SHONG Yifan {} -verbose -l:{} {} 2>/dev/null | \\ 85*eed53cd4SHONG Yifan grep succeeded | \\ 86*eed53cd4SHONG Yifan head -1 | \\ 87*eed53cd4SHONG Yifan sed -e 's/^\\s*attempt to open //' -e 's/ succeeded\\s*$//' 88*eed53cd4SHONG Yifan """.format( 89*eed53cd4SHONG Yifan linker, 90*eed53cd4SHONG Yifan archive_name, 91*eed53cd4SHONG Yifan path_flags, 92*eed53cd4SHONG Yifan ) 93*eed53cd4SHONG Yifan path = _execute_bash(repo_ctx, cmd) 94*eed53cd4SHONG Yifan if path: 95*eed53cd4SHONG Yifan return (archive_name, path) 96*eed53cd4SHONG Yifan return (None, None) 97*eed53cd4SHONG Yifan 98*eed53cd4SHONG Yifandef _find_header_path(repo_ctx, lib_name, header_name, includes): 99*eed53cd4SHONG Yifan override_paths = _get_list_from_env_var( 100*eed53cd4SHONG Yifan repo_ctx, 101*eed53cd4SHONG Yifan BAZEL_INCLUDE_OVERRIDE_PATHS_ENV_VAR, 102*eed53cd4SHONG Yifan lib_name, 103*eed53cd4SHONG Yifan ) 104*eed53cd4SHONG Yifan additional_paths = _get_list_from_env_var( 105*eed53cd4SHONG Yifan repo_ctx, 106*eed53cd4SHONG Yifan BAZEL_INCLUDE_ADDITIONAL_PATHS_ENV_VAR, 107*eed53cd4SHONG Yifan lib_name, 108*eed53cd4SHONG Yifan ) 109*eed53cd4SHONG Yifan 110*eed53cd4SHONG Yifan compiler = _find_compiler(repo_ctx) 111*eed53cd4SHONG Yifan cmd = """ 112*eed53cd4SHONG Yifan print | \\ 113*eed53cd4SHONG Yifan {} -Wp,-v -x c++ - -fsyntax-only 2>&1 | \\ 114*eed53cd4SHONG Yifan sed -n -e '/^\\s\\+/p' | \\ 115*eed53cd4SHONG Yifan sed -e 's/^[ \t]*//' 116*eed53cd4SHONG Yifan """.format(compiler) 117*eed53cd4SHONG Yifan system_includes = _execute_bash(repo_ctx, cmd).split("\n") 118*eed53cd4SHONG Yifan all_includes = (override_paths + includes + 119*eed53cd4SHONG Yifan system_includes + additional_paths) 120*eed53cd4SHONG Yifan 121*eed53cd4SHONG Yifan for directory in all_includes: 122*eed53cd4SHONG Yifan cmd = """ 123*eed53cd4SHONG Yifan test -f "{dir}/{hdr}" && echo "{dir}/{hdr}" 124*eed53cd4SHONG Yifan """.format(dir = directory, hdr = header_name) 125*eed53cd4SHONG Yifan result = _execute_bash(repo_ctx, cmd) 126*eed53cd4SHONG Yifan if result: 127*eed53cd4SHONG Yifan return result 128*eed53cd4SHONG Yifan return None 129*eed53cd4SHONG Yifan 130*eed53cd4SHONG Yifandef _system_library_impl(repo_ctx): 131*eed53cd4SHONG Yifan repo_name = repo_ctx.attr.name 132*eed53cd4SHONG Yifan includes = repo_ctx.attr.includes 133*eed53cd4SHONG Yifan hdrs = repo_ctx.attr.hdrs 134*eed53cd4SHONG Yifan optional_hdrs = repo_ctx.attr.optional_hdrs 135*eed53cd4SHONG Yifan deps = repo_ctx.attr.deps 136*eed53cd4SHONG Yifan lib_path_hints = repo_ctx.attr.lib_path_hints 137*eed53cd4SHONG Yifan static_lib_names = repo_ctx.attr.static_lib_names 138*eed53cd4SHONG Yifan shared_lib_names = repo_ctx.attr.shared_lib_names 139*eed53cd4SHONG Yifan 140*eed53cd4SHONG Yifan static_lib_name, static_lib_path = _find_lib_path( 141*eed53cd4SHONG Yifan repo_ctx, 142*eed53cd4SHONG Yifan repo_name, 143*eed53cd4SHONG Yifan static_lib_names, 144*eed53cd4SHONG Yifan lib_path_hints, 145*eed53cd4SHONG Yifan ) 146*eed53cd4SHONG Yifan shared_lib_name, shared_lib_path = _find_lib_path( 147*eed53cd4SHONG Yifan repo_ctx, 148*eed53cd4SHONG Yifan repo_name, 149*eed53cd4SHONG Yifan shared_lib_names, 150*eed53cd4SHONG Yifan lib_path_hints, 151*eed53cd4SHONG Yifan ) 152*eed53cd4SHONG Yifan 153*eed53cd4SHONG Yifan if not static_lib_path and not shared_lib_path: 154*eed53cd4SHONG Yifan fail("Library {} could not be found".format(repo_name)) 155*eed53cd4SHONG Yifan 156*eed53cd4SHONG Yifan hdr_names = [] 157*eed53cd4SHONG Yifan hdr_paths = [] 158*eed53cd4SHONG Yifan for hdr in hdrs: 159*eed53cd4SHONG Yifan hdr_path = _find_header_path(repo_ctx, repo_name, hdr, includes) 160*eed53cd4SHONG Yifan if hdr_path: 161*eed53cd4SHONG Yifan repo_ctx.symlink(hdr_path, hdr) 162*eed53cd4SHONG Yifan hdr_names.append(hdr) 163*eed53cd4SHONG Yifan hdr_paths.append(hdr_path) 164*eed53cd4SHONG Yifan else: 165*eed53cd4SHONG Yifan fail("Could not find required header {}".format(hdr)) 166*eed53cd4SHONG Yifan 167*eed53cd4SHONG Yifan for hdr in optional_hdrs: 168*eed53cd4SHONG Yifan hdr_path = _find_header_path(repo_ctx, repo_name, hdr, includes) 169*eed53cd4SHONG Yifan if hdr_path: 170*eed53cd4SHONG Yifan repo_ctx.symlink(hdr_path, hdr) 171*eed53cd4SHONG Yifan hdr_names.append(hdr) 172*eed53cd4SHONG Yifan hdr_paths.append(hdr_path) 173*eed53cd4SHONG Yifan 174*eed53cd4SHONG Yifan hdrs_param = "hdrs = {},".format(str(hdr_names)) 175*eed53cd4SHONG Yifan 176*eed53cd4SHONG Yifan # This is needed for the case when quote-includes and system-includes 177*eed53cd4SHONG Yifan # alternate in the include chain, i.e. 178*eed53cd4SHONG Yifan # #include <SDL2/SDL.h> -> #include "SDL_main.h" 179*eed53cd4SHONG Yifan # -> #include <SDL2/_real_SDL_config.h> -> #include "SDL_platform.h" 180*eed53cd4SHONG Yifan # The problem is that the quote-includes are assumed to be 181*eed53cd4SHONG Yifan # in the same directory as the header they are included from - 182*eed53cd4SHONG Yifan # they have no subdir prefix ("SDL2/") in their paths 183*eed53cd4SHONG Yifan include_subdirs = {} 184*eed53cd4SHONG Yifan for hdr in hdr_names: 185*eed53cd4SHONG Yifan path_segments = hdr.split("/") 186*eed53cd4SHONG Yifan path_segments.pop() 187*eed53cd4SHONG Yifan current_path_segments = ["external", repo_name] 188*eed53cd4SHONG Yifan for segment in path_segments: 189*eed53cd4SHONG Yifan current_path_segments.append(segment) 190*eed53cd4SHONG Yifan current_path = "/".join(current_path_segments) 191*eed53cd4SHONG Yifan include_subdirs.update({current_path: None}) 192*eed53cd4SHONG Yifan 193*eed53cd4SHONG Yifan includes_param = "includes = {},".format(str(include_subdirs.keys())) 194*eed53cd4SHONG Yifan 195*eed53cd4SHONG Yifan deps_names = [] 196*eed53cd4SHONG Yifan for dep in deps: 197*eed53cd4SHONG Yifan dep_name = repr("@" + dep) 198*eed53cd4SHONG Yifan deps_names.append(dep_name) 199*eed53cd4SHONG Yifan deps_param = "deps = [{}],".format(",".join(deps_names)) 200*eed53cd4SHONG Yifan 201*eed53cd4SHONG Yifan link_hdrs_command = "mkdir -p $(RULEDIR)/remote \n" 202*eed53cd4SHONG Yifan remote_hdrs = [] 203*eed53cd4SHONG Yifan for path, hdr in zip(hdr_paths, hdr_names): 204*eed53cd4SHONG Yifan remote_hdr = "remote/" + hdr 205*eed53cd4SHONG Yifan remote_hdrs.append(remote_hdr) 206*eed53cd4SHONG Yifan link_hdrs_command += "cp {path} $(RULEDIR)/{hdr}\n ".format( 207*eed53cd4SHONG Yifan path = path, 208*eed53cd4SHONG Yifan hdr = remote_hdr, 209*eed53cd4SHONG Yifan ) 210*eed53cd4SHONG Yifan 211*eed53cd4SHONG Yifan link_remote_static_lib_genrule = "" 212*eed53cd4SHONG Yifan link_remote_shared_lib_genrule = "" 213*eed53cd4SHONG Yifan remote_static_library_param = "" 214*eed53cd4SHONG Yifan remote_shared_library_param = "" 215*eed53cd4SHONG Yifan static_library_param = "" 216*eed53cd4SHONG Yifan shared_library_param = "" 217*eed53cd4SHONG Yifan 218*eed53cd4SHONG Yifan if static_lib_path: 219*eed53cd4SHONG Yifan repo_ctx.symlink(static_lib_path, static_lib_name) 220*eed53cd4SHONG Yifan static_library_param = "static_library = \"{}\",".format( 221*eed53cd4SHONG Yifan static_lib_name, 222*eed53cd4SHONG Yifan ) 223*eed53cd4SHONG Yifan remote_static_library = "remote/" + static_lib_name 224*eed53cd4SHONG Yifan link_library_command = """ 225*eed53cd4SHONG Yifanmkdir -p $(RULEDIR)/remote && cp {path} $(RULEDIR)/{lib}""".format( 226*eed53cd4SHONG Yifan path = static_lib_path, 227*eed53cd4SHONG Yifan lib = remote_static_library, 228*eed53cd4SHONG Yifan ) 229*eed53cd4SHONG Yifan remote_static_library_param = """ 230*eed53cd4SHONG Yifanstatic_library = "remote_link_static_library",""" 231*eed53cd4SHONG Yifan link_remote_static_lib_genrule = """ 232*eed53cd4SHONG Yifangenrule( 233*eed53cd4SHONG Yifan name = "remote_link_static_library", 234*eed53cd4SHONG Yifan outs = ["{remote_static_library}"], 235*eed53cd4SHONG Yifan cmd = {link_library_command} 236*eed53cd4SHONG Yifan) 237*eed53cd4SHONG Yifan""".format( 238*eed53cd4SHONG Yifan link_library_command = repr(link_library_command), 239*eed53cd4SHONG Yifan remote_static_library = remote_static_library, 240*eed53cd4SHONG Yifan ) 241*eed53cd4SHONG Yifan 242*eed53cd4SHONG Yifan if shared_lib_path: 243*eed53cd4SHONG Yifan repo_ctx.symlink(shared_lib_path, shared_lib_name) 244*eed53cd4SHONG Yifan shared_library_param = "shared_library = \"{}\",".format( 245*eed53cd4SHONG Yifan shared_lib_name, 246*eed53cd4SHONG Yifan ) 247*eed53cd4SHONG Yifan remote_shared_library = "remote/" + shared_lib_name 248*eed53cd4SHONG Yifan link_library_command = """ 249*eed53cd4SHONG Yifanmkdir -p $(RULEDIR)/remote && cp {path} $(RULEDIR)/{lib}""".format( 250*eed53cd4SHONG Yifan path = shared_lib_path, 251*eed53cd4SHONG Yifan lib = remote_shared_library, 252*eed53cd4SHONG Yifan ) 253*eed53cd4SHONG Yifan remote_shared_library_param = """ 254*eed53cd4SHONG Yifanshared_library = "remote_link_shared_library",""" 255*eed53cd4SHONG Yifan link_remote_shared_lib_genrule = """ 256*eed53cd4SHONG Yifangenrule( 257*eed53cd4SHONG Yifan name = "remote_link_shared_library", 258*eed53cd4SHONG Yifan outs = ["{remote_shared_library}"], 259*eed53cd4SHONG Yifan cmd = {link_library_command} 260*eed53cd4SHONG Yifan) 261*eed53cd4SHONG Yifan""".format( 262*eed53cd4SHONG Yifan link_library_command = repr(link_library_command), 263*eed53cd4SHONG Yifan remote_shared_library = remote_shared_library, 264*eed53cd4SHONG Yifan ) 265*eed53cd4SHONG Yifan 266*eed53cd4SHONG Yifan repo_ctx.file( 267*eed53cd4SHONG Yifan "BUILD", 268*eed53cd4SHONG Yifan executable = False, 269*eed53cd4SHONG Yifan content = 270*eed53cd4SHONG Yifan """ 271*eed53cd4SHONG Yifanload("@bazel_tools//tools/build_defs/cc:cc_import.bzl", "cc_import") 272*eed53cd4SHONG Yifancc_import( 273*eed53cd4SHONG Yifan name = "local_includes", 274*eed53cd4SHONG Yifan {static_library} 275*eed53cd4SHONG Yifan {shared_library} 276*eed53cd4SHONG Yifan {hdrs} 277*eed53cd4SHONG Yifan {deps} 278*eed53cd4SHONG Yifan {includes} 279*eed53cd4SHONG Yifan) 280*eed53cd4SHONG Yifan 281*eed53cd4SHONG Yifangenrule( 282*eed53cd4SHONG Yifan name = "remote_link_headers", 283*eed53cd4SHONG Yifan outs = {remote_hdrs}, 284*eed53cd4SHONG Yifan cmd = {link_hdrs_command} 285*eed53cd4SHONG Yifan) 286*eed53cd4SHONG Yifan 287*eed53cd4SHONG Yifan{link_remote_static_lib_genrule} 288*eed53cd4SHONG Yifan 289*eed53cd4SHONG Yifan{link_remote_shared_lib_genrule} 290*eed53cd4SHONG Yifan 291*eed53cd4SHONG Yifancc_import( 292*eed53cd4SHONG Yifan name = "remote_includes", 293*eed53cd4SHONG Yifan hdrs = [":remote_link_headers"], 294*eed53cd4SHONG Yifan {remote_static_library} 295*eed53cd4SHONG Yifan {remote_shared_library} 296*eed53cd4SHONG Yifan {deps} 297*eed53cd4SHONG Yifan {includes} 298*eed53cd4SHONG Yifan) 299*eed53cd4SHONG Yifan 300*eed53cd4SHONG Yifanalias( 301*eed53cd4SHONG Yifan name = "{name}", 302*eed53cd4SHONG Yifan actual = select({{ 303*eed53cd4SHONG Yifan "@bazel_tools//src/conditions:remote": "remote_includes", 304*eed53cd4SHONG Yifan "//conditions:default": "local_includes", 305*eed53cd4SHONG Yifan }}), 306*eed53cd4SHONG Yifan visibility = ["//visibility:public"], 307*eed53cd4SHONG Yifan) 308*eed53cd4SHONG Yifan""".format( 309*eed53cd4SHONG Yifan static_library = static_library_param, 310*eed53cd4SHONG Yifan shared_library = shared_library_param, 311*eed53cd4SHONG Yifan hdrs = hdrs_param, 312*eed53cd4SHONG Yifan deps = deps_param, 313*eed53cd4SHONG Yifan hdr_names = str(hdr_names), 314*eed53cd4SHONG Yifan link_hdrs_command = repr(link_hdrs_command), 315*eed53cd4SHONG Yifan name = repo_name, 316*eed53cd4SHONG Yifan includes = includes_param, 317*eed53cd4SHONG Yifan remote_hdrs = remote_hdrs, 318*eed53cd4SHONG Yifan link_remote_static_lib_genrule = link_remote_static_lib_genrule, 319*eed53cd4SHONG Yifan link_remote_shared_lib_genrule = link_remote_shared_lib_genrule, 320*eed53cd4SHONG Yifan remote_static_library = remote_static_library_param, 321*eed53cd4SHONG Yifan remote_shared_library = remote_shared_library_param, 322*eed53cd4SHONG Yifan ), 323*eed53cd4SHONG Yifan ) 324*eed53cd4SHONG Yifan 325*eed53cd4SHONG Yifansystem_library = repository_rule( 326*eed53cd4SHONG Yifan implementation = _system_library_impl, 327*eed53cd4SHONG Yifan local = True, 328*eed53cd4SHONG Yifan remotable = True, 329*eed53cd4SHONG Yifan environ = [ 330*eed53cd4SHONG Yifan BAZEL_INCLUDE_ADDITIONAL_PATHS_ENV_VAR, 331*eed53cd4SHONG Yifan BAZEL_INCLUDE_OVERRIDE_PATHS_ENV_VAR, 332*eed53cd4SHONG Yifan BAZEL_LIB_ADDITIONAL_PATHS_ENV_VAR, 333*eed53cd4SHONG Yifan BAZEL_LIB_OVERRIDE_PATHS_ENV_VAR, 334*eed53cd4SHONG Yifan ], 335*eed53cd4SHONG Yifan attrs = { 336*eed53cd4SHONG Yifan "deps": attr.string_list(doc = """ 337*eed53cd4SHONG YifanList of names of system libraries this target depends upon. 338*eed53cd4SHONG Yifan"""), 339*eed53cd4SHONG Yifan "hdrs": attr.string_list( 340*eed53cd4SHONG Yifan mandatory = True, 341*eed53cd4SHONG Yifan allow_empty = False, 342*eed53cd4SHONG Yifan doc = """ 343*eed53cd4SHONG YifanList of the library's public headers which must be imported. 344*eed53cd4SHONG Yifan""", 345*eed53cd4SHONG Yifan ), 346*eed53cd4SHONG Yifan "includes": attr.string_list(doc = """ 347*eed53cd4SHONG YifanList of directories that should be browsed when looking for headers. 348*eed53cd4SHONG Yifan"""), 349*eed53cd4SHONG Yifan "lib_path_hints": attr.string_list(doc = """ 350*eed53cd4SHONG YifanList of directories that should be browsed when looking for library archives. 351*eed53cd4SHONG Yifan"""), 352*eed53cd4SHONG Yifan "optional_hdrs": attr.string_list(doc = """ 353*eed53cd4SHONG YifanList of library's private headers. 354*eed53cd4SHONG Yifan"""), 355*eed53cd4SHONG Yifan "shared_lib_names": attr.string_list(doc = """ 356*eed53cd4SHONG YifanList of possible shared library names in order of preference. 357*eed53cd4SHONG Yifan"""), 358*eed53cd4SHONG Yifan "static_lib_names": attr.string_list(doc = """ 359*eed53cd4SHONG YifanList of possible static library names in order of preference. 360*eed53cd4SHONG Yifan"""), 361*eed53cd4SHONG Yifan }, 362*eed53cd4SHONG Yifan doc = 363*eed53cd4SHONG Yifan """system_library is a repository rule for importing system libraries 364*eed53cd4SHONG Yifan 365*eed53cd4SHONG Yifan`system_library` is a repository rule for safely depending on system-provided 366*eed53cd4SHONG Yifanlibraries on Linux. It can be used with remote caching and remote execution. 367*eed53cd4SHONG YifanUnder the hood it uses gcc/clang for finding the library files and headers 368*eed53cd4SHONG Yifanand symlinks them into the build directory. Symlinking allows Bazel to take 369*eed53cd4SHONG Yifanthese files into account when it calculates a checksum of the project. 370*eed53cd4SHONG YifanThis prevents cache poisoning from happening. 371*eed53cd4SHONG Yifan 372*eed53cd4SHONG YifanCurrently `system_library` requires two exeperimental flags: 373*eed53cd4SHONG Yifan--experimental_starlark_cc_import 374*eed53cd4SHONG Yifan--experimental_repo_remote_exec 375*eed53cd4SHONG Yifan 376*eed53cd4SHONG YifanA typical usage looks like this: 377*eed53cd4SHONG YifanWORKSPACE 378*eed53cd4SHONG Yifan``` 379*eed53cd4SHONG Yifansystem_library( 380*eed53cd4SHONG Yifan name = "jpeg", 381*eed53cd4SHONG Yifan hdrs = ["jpeglib.h"], 382*eed53cd4SHONG Yifan shared_lib_names = ["libjpeg.so, libjpeg.so.62"], 383*eed53cd4SHONG Yifan static_lib_names = ["libjpeg.a"], 384*eed53cd4SHONG Yifan includes = ["/usr/additional_includes"], 385*eed53cd4SHONG Yifan lib_path_hints = ["/usr/additional_libs", "/usr/some/other_path"] 386*eed53cd4SHONG Yifan optional_hdrs = [ 387*eed53cd4SHONG Yifan "jconfig.h", 388*eed53cd4SHONG Yifan "jmorecfg.h", 389*eed53cd4SHONG Yifan ], 390*eed53cd4SHONG Yifan) 391*eed53cd4SHONG Yifan 392*eed53cd4SHONG Yifansystem_library( 393*eed53cd4SHONG Yifan name = "bar", 394*eed53cd4SHONG Yifan hdrs = ["bar.h"], 395*eed53cd4SHONG Yifan shared_lib_names = ["libbar.so"], 396*eed53cd4SHONG Yifan deps = ["jpeg"] 397*eed53cd4SHONG Yifan 398*eed53cd4SHONG Yifan) 399*eed53cd4SHONG Yifan``` 400*eed53cd4SHONG Yifan 401*eed53cd4SHONG YifanBUILD 402*eed53cd4SHONG Yifan``` 403*eed53cd4SHONG Yifancc_binary( 404*eed53cd4SHONG Yifan name = "foo", 405*eed53cd4SHONG Yifan srcs = ["foo.cc"], 406*eed53cd4SHONG Yifan deps = ["@bar"] 407*eed53cd4SHONG Yifan) 408*eed53cd4SHONG Yifan``` 409*eed53cd4SHONG Yifan 410*eed53cd4SHONG Yifanfoo.cc 411*eed53cd4SHONG Yifan``` 412*eed53cd4SHONG Yifan#include "jpeglib.h" 413*eed53cd4SHONG Yifan#include "bar.h" 414*eed53cd4SHONG Yifan 415*eed53cd4SHONG Yifan[code using symbols from jpeglib and bar] 416*eed53cd4SHONG Yifan``` 417*eed53cd4SHONG Yifan 418*eed53cd4SHONG Yifan`system_library` requires users to specify at least one header 419*eed53cd4SHONG Yifan(as it makes no sense to import a library without headers). 420*eed53cd4SHONG YifanPublic headers of a library (i.e. those included in the user-written code, 421*eed53cd4SHONG Yifanlike `jpeglib.h` in the example above) should be put in `hdrs` param, as they 422*eed53cd4SHONG Yifanare required for the library to work. However, some libraries may use more 423*eed53cd4SHONG Yifan"private" headers. They should be imported as well, but their names may differ 424*eed53cd4SHONG Yifanfrom system to system. They should be specified in the `optional_hdrs` param. 425*eed53cd4SHONG YifanThe build will not fail if some of them are not found, so it's safe to put a 426*eed53cd4SHONG Yifansuperset there, containing all possible combinations of names for different 427*eed53cd4SHONG Yifanversions/distributions. It's up to the user to determine which headers are 428*eed53cd4SHONG Yifanrequired for the library to work. 429*eed53cd4SHONG Yifan 430*eed53cd4SHONG YifanOne `system_library` target always imports exactly one library. 431*eed53cd4SHONG YifanUsers can specify many potential names for the library file, 432*eed53cd4SHONG Yifanas these names can differ from system to system. The order of names establishes 433*eed53cd4SHONG Yifanthe order of preference. As some libraries can be linked both statically 434*eed53cd4SHONG Yifanand dynamically, the names of files of each kind can be specified separately. 435*eed53cd4SHONG Yifan`system_library` rule will try to find library archives of both kinds, but it's 436*eed53cd4SHONG Yifanup to the top-level target (for example, `cc_binary`) to decide which kind of 437*eed53cd4SHONG Yifanlinking will be used. 438*eed53cd4SHONG Yifan 439*eed53cd4SHONG Yifan`system_library` rule depends on gcc/clang (whichever is installed) for 440*eed53cd4SHONG Yifanfinding the actual locations of library archives and headers. 441*eed53cd4SHONG YifanLibraries installed in a standard way by a package manager 442*eed53cd4SHONG Yifan(`sudo apt install libjpeg-dev`) are usually placed in one of directories 443*eed53cd4SHONG Yifansearched by the compiler/linker by default - on Ubuntu library most archives 444*eed53cd4SHONG Yifanare stored in `/usr/lib/x86_64-linux-gnu/` and their headers in 445*eed53cd4SHONG Yifan`/usr/include/`. If the maintainer of a project expects the files 446*eed53cd4SHONG Yifanto be installed in a non-standard location, they can use the `includes` 447*eed53cd4SHONG Yifanparameter to add directories to the search path for headers 448*eed53cd4SHONG Yifanand `lib_path_hints` to add directories to the search path for library 449*eed53cd4SHONG Yifanarchives. 450*eed53cd4SHONG Yifan 451*eed53cd4SHONG YifanUser building the project can override or extend these search paths by 452*eed53cd4SHONG Yifanproviding these environment variables to the build: 453*eed53cd4SHONG YifanBAZEL_INCLUDE_ADDITIONAL_PATHS, BAZEL_INCLUDE_OVERRIDE_PATHS, 454*eed53cd4SHONG YifanBAZEL_LIB_ADDITIONAL_PATHS, BAZEL_LIB_OVERRIDE_PATHS. 455*eed53cd4SHONG YifanThe syntax for setting the env variables is: 456*eed53cd4SHONG Yifan`<library>=<path>,<library>=<path2>`. 457*eed53cd4SHONG YifanUsers can provide multiple paths for one library by repeating this segment: 458*eed53cd4SHONG Yifan`<library>=<path>`. 459*eed53cd4SHONG Yifan 460*eed53cd4SHONG YifanSo in order to build the example presented above but with custom paths for the 461*eed53cd4SHONG Yifanjpeg lib, one would use the following command: 462*eed53cd4SHONG Yifan 463*eed53cd4SHONG Yifan``` 464*eed53cd4SHONG Yifanbazel build //:foo \ 465*eed53cd4SHONG Yifan --experimental_starlark_cc_import \ 466*eed53cd4SHONG Yifan --experimental_repo_remote_exec \ 467*eed53cd4SHONG Yifan --action_env=BAZEL_LIB_OVERRIDE_PATHS=jpeg=/custom/libraries/path \ 468*eed53cd4SHONG Yifan --action_env=BAZEL_INCLUDE_OVERRIDE_PATHS=jpeg=/custom/include/path,jpeg=/inc 469*eed53cd4SHONG Yifan``` 470*eed53cd4SHONG Yifan 471*eed53cd4SHONG YifanSome libraries can depend on other libraries. `system_library` rule provides 472*eed53cd4SHONG Yifana `deps` parameter for specifying such relationships. `system_library` targets 473*eed53cd4SHONG Yifancan depend only on other system libraries. 474*eed53cd4SHONG Yifan""", 475*eed53cd4SHONG Yifan) 476