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