• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# -*- bazel-starlark -*-
2# Copyright 2024 The Chromium Authors
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5"""Siso configuration for ar."""
6
7load("@builtin//path.star", "path")
8load("@builtin//struct.star", "module")
9
10# https://en.wikipedia.org/wiki/Ar_(Unix)
11
12def __file_header(fname, size):
13    fid = fname + " " * 16
14    header = fid[:16]
15    if fname == "//":
16        header += " " * 12  # file modification timestamp
17        header += " " * 6  # owner id
18        header += " " * 6  # group id
19        header += " " * 8  # file mode
20    else:
21        header += "0" + " " * 11  # file modification timestamp
22        header += "0" + " " * 5  # owner id
23        header += "0" + " " * 5  # group id
24        header += "644" + " " * 5  # file mode
25    s = ("%d" % size) + " " * 10
26    header += s[:10]  # file size
27    header += "\x60\n"  # header trailer string
28    return header
29
30def __ref_fname(offset, fname):
31    i = offset[fname]
32    return "/%d" % i
33
34def __padding(data):
35    if len(data) % 2 == 0:
36        return data
37    return data + "\n"
38
39def __ar_create(ctx, wd, ins):
40    """Creates a thin archive without a symbol table."""
41    data = "!<thin>\n"
42    offset = {}
43    content = ""
44    for fname in ins:
45        offset[fname] = len(content)
46        content += path.rel(wd, fname) + "/\n"
47    content = __padding(content)
48    data += __file_header("//", len(content))
49    data += content
50    for fname in ins:
51        size = ctx.fs.size(fname)
52        if size:
53            data += __file_header(__ref_fname(offset, fname), size)
54    return bytes(data)
55
56def __ar_entries(ctx, fname, build_dir):
57    """Read entries from a thin archive. """
58
59    # TODO: It may take long time to read an entire archive.
60    # Is it better to read only the first X bytes?
61    lines = str(ctx.fs.read(fname)).splitlines()
62    lib_dir = path.rel(build_dir, path.dir(fname))
63    ents = []
64    if not len(lines):
65        print("warning: empty archive. `%s`" % fname)
66        return []
67    if not lines[0].startswith("!<thin>"):
68        print("not thin archive. `%s`" % fname)
69        return []
70    for l in lines:
71        l.strip()
72        if l.endswith(".obj/") or l.endswith(".o/"):
73            ents.append(path.join(lib_dir, l.removesuffix("/")))
74        if l.endswith(".lib/") or l.endswith(".a/"):
75            fail("nested archive is not supported, yet. found `%s` in `%s`" % (l, fname))
76    return ents
77
78ar = module(
79    "ar",
80    create = __ar_create,
81    entries = __ar_entries,
82)
83