xref: /aosp_15_r20/external/bazelbuild-rules_cc/cc/system_library.bzl (revision eed53cd41c5909d05eedc7ad9720bb158fd93452)
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