Skip to content

Commit a263af2

Browse files
committed
Preserve symlinks in archives
1 parent e0774b9 commit a263af2

File tree

7 files changed

+138
-104
lines changed

7 files changed

+138
-104
lines changed

toolchain/gcc/BUILD

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
load("@aspect_bazel_lib//lib:copy_to_directory.bzl", "copy_to_directory")
2-
load("//:tar.bzl", "tar_package")
32
load("//:config.bzl", "LINUX_TARGETS")
43

54
package(default_visibility = ["//visibility:public"])
65

76
[
87
# Files built by make + crosstool-ng
9-
copy_to_directory(
10-
name = target,
11-
srcs = glob(["targets/{}/toolchain/**/*".format(target)]),
12-
root_paths = ["**/toolchain"],
8+
(
9+
filegroup(
10+
name = target + "-srcs",
11+
srcs = glob(["targets/{}/toolchain/**/*".format(target)]),
12+
),
13+
copy_to_directory(
14+
name = target,
15+
srcs = [target + "-srcs"],
16+
root_paths = ["**/toolchain"],
17+
),
1318
)
1419
for target in LINUX_TARGETS
1520
]

toolchain/linux/BUILD

Lines changed: 26 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
load("@aspect_bazel_lib//lib:copy_to_directory.bzl", "copy_to_directory")
21
load("@aspect_bazel_lib//lib:expand_template.bzl", "expand_template")
32
load("@llvm_version//:llvm_version.bzl", "LLVM_VERSION")
43
load("//:cmake.bzl", "cmake")
54
load("//:config.bzl", "LINUX_TARGETS")
65
load("//:host.bzl", "HOST_TARGET")
7-
load("//:tar.bzl", "tar_package")
6+
load("//util:tar.bzl", "tar_package")
87

98
package(default_visibility = ["//visibility:public"])
109

@@ -46,35 +45,21 @@ package(default_visibility = ["//visibility:public"])
4645
working_directory = "compiler-rt",
4746
),
4847

49-
# Arrange components into a sysroot
50-
copy_to_directory(
51-
name = "sysroot-{}".format(target),
52-
srcs = [
53-
"//gcc:{}".format(target),
54-
"openmp-{}".format(target),
55-
"targets/{}.cfg".format(target),
56-
],
57-
exclude_srcs_patterns = [
48+
# Package the sysroot into a tar
49+
tar_package(
50+
name = "sysroot-package-{}".format(target),
51+
srcs = {
52+
"//gcc:{}-srcs".format(target): "targets/{}/toolchain:.".format(target), # don't use copy_to_directory here, because it erases symlinks
53+
"openmp-{}".format(target): "openmp-{}:{}/sysroot/usr".format(target, target),
54+
"targets/{}.cfg".format(target): "targets:.",
55+
},
56+
exclude = [
5857
"build.log.bz2",
5958
"bin/**",
6059
"libexec/**",
6160
"{}/bin/**".format(target),
6261
],
63-
replace_prefixes = {
64-
"**/openmp-*": "{}/sysroot/usr".format(target),
65-
},
66-
root_paths = [
67-
"gcc/{}".format(target),
68-
"linux/targets",
69-
".",
70-
],
71-
),
72-
73-
# Package the sysroot into a tar
74-
tar_package(
75-
"sysroot-package-{}".format(target),
76-
"sysroot-{}".format(target),
77-
"sysroot-{}".format(target),
62+
output = "sysroot-" + target,
7863
),
7964

8065
# toolchain.cmake files for building with the GCC and LLVM cross-compilers
@@ -113,41 +98,26 @@ cmake(
11398
lib_source = "@zlib",
11499
)
115100

116-
ALL_COMPILER_RT_SRCS = ["compiler-rt-{}".format(target) for target in LINUX_TARGETS]
117-
118-
COMPILER_RT_PREFIX = {
119-
"**/compiler-rt-*": "lib/clang/" + LLVM_VERSION.split(".")[0],
101+
COMPILER_RT_SRCS = {
102+
"compiler-rt-" + target: "compiler-rt-{}:lib/clang/{}".format(
103+
target,
104+
LLVM_VERSION.split(".")[0],
105+
)
106+
for target in LINUX_TARGETS
120107
}
121108

122-
# Add compiler-rt to LLVM installation
123-
copy_to_directory(
124-
name = "llvm",
125-
srcs = ["//:llvm"] + ALL_COMPILER_RT_SRCS,
126-
allow_overwrites = True,
127-
replace_prefixes = COMPILER_RT_PREFIX,
128-
root_paths = [
129-
"llvm",
130-
".",
131-
],
132-
)
133-
134-
# Make standalone compiler-rt for macOS hosts
135-
copy_to_directory(
136-
name = "compiler-rt",
137-
srcs = ALL_COMPILER_RT_SRCS,
138-
allow_overwrites = True,
139-
replace_prefixes = COMPILER_RT_PREFIX,
140-
)
141-
142109
# Package the compiler into a tar
143110
tar_package(
144-
"llvm-package",
145-
"llvm-{}".format(HOST_TARGET),
146-
"llvm",
111+
name = "llvm-package",
112+
srcs = {
113+
"//:llvm": "llvm:.",
114+
} | COMPILER_RT_SRCS,
115+
output = "llvm-{}".format(HOST_TARGET),
147116
)
148117

118+
# Make standalone compiler-rt for macOS hosts
149119
tar_package(
150-
"compiler-rt-package",
151-
"compiler-rt-linux",
152-
"compiler-rt",
120+
name = "compiler-rt-package",
121+
srcs = COMPILER_RT_SRCS,
122+
output = "compiler-rt-linux",
153123
)

toolchain/macos/BUILD

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,12 @@
1-
load("@aspect_bazel_lib//lib:copy_to_directory.bzl", "copy_to_directory")
21
load("//:host.bzl", "HOST_TARGET")
3-
load("//:tar.bzl", "tar_package")
2+
load("//util:tar.bzl", "tar_package")
43

54
package(default_visibility = ["//visibility:public"])
65

7-
# Assemble LLVM package
8-
copy_to_directory(
9-
name = "llvm",
10-
srcs = ["//:llvm"],
11-
root_paths = [
12-
"llvm",
13-
".",
14-
],
15-
)
16-
17-
# Package the compiler into a tar
186
tar_package(
19-
"llvm-package",
20-
"llvm-{}".format(HOST_TARGET),
21-
"llvm",
7+
name = "llvm-package",
8+
srcs = {
9+
"//:llvm": "llvm:.",
10+
},
11+
output = "llvm-" + HOST_TARGET,
2212
)

toolchain/tar.bzl

Lines changed: 0 additions & 27 deletions
This file was deleted.

toolchain/util/BUILD

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
py_binary(
2+
name = "tar",
3+
srcs = ["tar.py"],
4+
)

toolchain/util/tar.bzl

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
load("@aspect_bazel_lib//lib:tar.bzl", "mtree_mutate", "mtree_spec", "tar")
2+
3+
def _tar_package(ctx):
4+
files = {}
5+
for target, pattern in ctx.attr.srcs.items():
6+
[strip, destination] = pattern.split(":")
7+
if target.label.package != "":
8+
strip = target.label.package + "/" + strip
9+
for file in target[DefaultInfo].files.to_list():
10+
if not file.short_path.startswith(strip):
11+
fail("Could not remove prefix `{}` from `{}`".format(strip, file.short_path))
12+
file_destination = destination + "/" + file.short_path.removeprefix(strip).removeprefix("/")
13+
files[file.path] = file_destination.removeprefix("./")
14+
15+
spec = ctx.actions.declare_file(ctx.attr.output + ".json")
16+
ctx.actions.write(spec, json.encode_indent({
17+
"files": files,
18+
"exclude": ctx.attr.exclude,
19+
"output": ctx.attr.output,
20+
}))
21+
22+
archive = ctx.actions.declare_file(ctx.attr.output + ".tar.xz")
23+
24+
inputs = [spec]
25+
for src in ctx.attr.srcs.keys():
26+
inputs += src.files.to_list()
27+
28+
ctx.actions.run(
29+
outputs = [archive],
30+
inputs = inputs,
31+
executable = ctx.executable._tool,
32+
arguments = [spec.path, archive.path],
33+
)
34+
35+
return DefaultInfo(files = depset([archive]))
36+
37+
tar_package = rule(
38+
implementation = _tar_package,
39+
attrs = {
40+
"srcs": attr.label_keyed_string_dict(allow_files = True),
41+
"exclude": attr.string_list(default = []),
42+
"output": attr.string(),
43+
"_tool": attr.label(default = "//util:tar", executable = True, cfg = "exec"),
44+
},
45+
)

toolchain/util/tar.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import fnmatch
2+
import json
3+
import sys
4+
import tarfile
5+
from pathlib import Path
6+
7+
spec = sys.argv[1]
8+
output = sys.argv[2]
9+
10+
with open(spec) as f:
11+
spec = json.load(f)
12+
13+
files = spec["files"]
14+
exclude = spec["exclude"]
15+
16+
def erase_metadata(tarinfo):
17+
tarinfo.mtime = 946684800
18+
tarinfo.uid = 0
19+
tarinfo.gid = 0
20+
tarinfo.uname = ""
21+
tarinfo.gname = ""
22+
tarinfo.mode = 0o755
23+
return tarinfo
24+
25+
def insert(archive, path, destination):
26+
if any(fnmatch.fnmatchcase(str(destination), p) for p in exclude):
27+
return None
28+
29+
# remove absolute symlinks created by bazel, but keep relative symlinks
30+
while path.is_symlink() and path.readlink().is_absolute():
31+
path = path.readlink()
32+
33+
f.add(path, arcname=destination, filter=erase_metadata)
34+
35+
with tarfile.open(output, 'x:xz') as f:
36+
for path, destination in sorted(files.items(), key=lambda v: v[1]):
37+
38+
path = Path(path)
39+
destination = Path(destination)
40+
41+
if path.is_dir():
42+
for p in sorted(path.glob('**/*')):
43+
if p.is_dir():
44+
continue
45+
insert(f, p, destination / p.relative_to(path))
46+
else:
47+
insert(f, path, destination)

0 commit comments

Comments
 (0)