Skip to content

Commit

Permalink
Merge pull request #165 from aherrmann/dyndeps
Browse files Browse the repository at this point in the history
feat: Support linking against shared libraries
  • Loading branch information
aherrmann authored Dec 30, 2023
2 parents 4d41d5f + 481c01a commit 06734ec
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 5 deletions.
4 changes: 2 additions & 2 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import %workspace%/.bazelrc.remote
# To update these lines, execute
# `bazel run @rules_bazel_integration_test//tools:update_deleted_packages`
# docs: https://bazel.build/reference/command-line-reference#flag--deleted_packages
build --deleted_packages=e2e/workspace,e2e/workspace/c-sources,e2e/workspace/configure-mode,e2e/workspace/configure-target,e2e/workspace/configure-threaded,e2e/workspace/data-dependencies,e2e/workspace/embed-file,e2e/workspace/include-dependencies,e2e/workspace/include-dependencies/zig-include,e2e/workspace/include-dependencies/zig-include-define,e2e/workspace/include-dependencies/zig-include-isystem,e2e/workspace/include-dependencies/zig-std-include,e2e/workspace/link-dependencies,e2e/workspace/link-dependencies/static-library,e2e/workspace/linker-script,e2e/workspace/multiple-sources-and-packages-test,e2e/workspace/multiple-sources-binary,e2e/workspace/simple-binary,e2e/workspace/simple-library,e2e/workspace/simple-shared-library,e2e/workspace/simple-test,e2e/workspace/transitive-zig-packages-binary,e2e/workspace/transitive-zig-packages-binary/hello-world,e2e/workspace/transitive-zig-packages-binary/hello-world/data,e2e/workspace/transitive-zig-packages-binary/hello-world/data/hello,e2e/workspace/transitive-zig-packages-binary/hello-world/data/world,e2e/workspace/transitive-zig-packages-binary/hello-world/io,e2e/workspace/zig-package-binary,e2e/workspace/zig-package-binary/data,e2e/workspace/zig-package-binary/io,zig/tests/integration_tests/workspace,zig/tests/integration_tests/workspace/custom_interpreter
query --deleted_packages=e2e/workspace,e2e/workspace/c-sources,e2e/workspace/configure-mode,e2e/workspace/configure-target,e2e/workspace/configure-threaded,e2e/workspace/data-dependencies,e2e/workspace/embed-file,e2e/workspace/include-dependencies,e2e/workspace/include-dependencies/zig-include,e2e/workspace/include-dependencies/zig-include-define,e2e/workspace/include-dependencies/zig-include-isystem,e2e/workspace/include-dependencies/zig-std-include,e2e/workspace/link-dependencies,e2e/workspace/link-dependencies/static-library,e2e/workspace/linker-script,e2e/workspace/multiple-sources-and-packages-test,e2e/workspace/multiple-sources-binary,e2e/workspace/simple-binary,e2e/workspace/simple-library,e2e/workspace/simple-shared-library,e2e/workspace/simple-test,e2e/workspace/transitive-zig-packages-binary,e2e/workspace/transitive-zig-packages-binary/hello-world,e2e/workspace/transitive-zig-packages-binary/hello-world/data,e2e/workspace/transitive-zig-packages-binary/hello-world/data/hello,e2e/workspace/transitive-zig-packages-binary/hello-world/data/world,e2e/workspace/transitive-zig-packages-binary/hello-world/io,e2e/workspace/zig-package-binary,e2e/workspace/zig-package-binary/data,e2e/workspace/zig-package-binary/io,zig/tests/integration_tests/workspace,zig/tests/integration_tests/workspace/custom_interpreter
build --deleted_packages=e2e/workspace,e2e/workspace/c-sources,e2e/workspace/configure-mode,e2e/workspace/configure-target,e2e/workspace/configure-threaded,e2e/workspace/data-dependencies,e2e/workspace/embed-file,e2e/workspace/include-dependencies,e2e/workspace/include-dependencies/zig-include,e2e/workspace/include-dependencies/zig-include-define,e2e/workspace/include-dependencies/zig-include-isystem,e2e/workspace/include-dependencies/zig-std-include,e2e/workspace/link-dependencies,e2e/workspace/link-dependencies/shared-library,e2e/workspace/link-dependencies/static-library,e2e/workspace/linker-script,e2e/workspace/multiple-sources-and-packages-test,e2e/workspace/multiple-sources-binary,e2e/workspace/simple-binary,e2e/workspace/simple-library,e2e/workspace/simple-shared-library,e2e/workspace/simple-test,e2e/workspace/transitive-zig-packages-binary,e2e/workspace/transitive-zig-packages-binary/hello-world,e2e/workspace/transitive-zig-packages-binary/hello-world/data,e2e/workspace/transitive-zig-packages-binary/hello-world/data/hello,e2e/workspace/transitive-zig-packages-binary/hello-world/data/world,e2e/workspace/transitive-zig-packages-binary/hello-world/io,e2e/workspace/zig-package-binary,e2e/workspace/zig-package-binary/data,e2e/workspace/zig-package-binary/io,zig/tests/integration_tests/workspace,zig/tests/integration_tests/workspace/custom_interpreter
query --deleted_packages=e2e/workspace,e2e/workspace/c-sources,e2e/workspace/configure-mode,e2e/workspace/configure-target,e2e/workspace/configure-threaded,e2e/workspace/data-dependencies,e2e/workspace/embed-file,e2e/workspace/include-dependencies,e2e/workspace/include-dependencies/zig-include,e2e/workspace/include-dependencies/zig-include-define,e2e/workspace/include-dependencies/zig-include-isystem,e2e/workspace/include-dependencies/zig-std-include,e2e/workspace/link-dependencies,e2e/workspace/link-dependencies/shared-library,e2e/workspace/link-dependencies/static-library,e2e/workspace/linker-script,e2e/workspace/multiple-sources-and-packages-test,e2e/workspace/multiple-sources-binary,e2e/workspace/simple-binary,e2e/workspace/simple-library,e2e/workspace/simple-shared-library,e2e/workspace/simple-test,e2e/workspace/transitive-zig-packages-binary,e2e/workspace/transitive-zig-packages-binary/hello-world,e2e/workspace/transitive-zig-packages-binary/hello-world/data,e2e/workspace/transitive-zig-packages-binary/hello-world/data/hello,e2e/workspace/transitive-zig-packages-binary/hello-world/data/world,e2e/workspace/transitive-zig-packages-binary/hello-world/io,e2e/workspace/zig-package-binary,e2e/workspace/zig-package-binary/data,e2e/workspace/zig-package-binary/io,zig/tests/integration_tests/workspace,zig/tests/integration_tests/workspace/custom_interpreter

# Load any settings specific to the current user.
# .bazelrc.user should appear in .gitignore so that settings are not shared with team members
Expand Down
71 changes: 71 additions & 0 deletions e2e/workspace/link-dependencies/shared-library/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
load("@bazel_skylib//rules:build_test.bzl", "build_test")
load("@bazel_skylib//rules:diff_test.bzl", "diff_test")
load("@rules_zig//zig:defs.bzl", "zig_binary", "zig_library", "zig_test")

cc_binary(
name = "add",
srcs = ["add.c"],
linkopts = select({
"@platforms//os:linux": ["-Wl,-soname,libadd.so"],
"@platforms//os:macos": ["-Wl,-install_name,@rpath/libadd.dylib"],
"//conditions:default": [],
}),
linkshared = True,
)

cc_library(
name = "add_shared",
srcs = [":add"],
)

zig_binary(
name = "binary",
cdeps = [
":add_shared",
"@rules_zig//zig/lib:libc",
],
main = "main.zig",
)

zig_library(
name = "library",
cdeps = [
":add_shared",
"@rules_zig//zig/lib:libc",
],
main = "main.zig",
)

zig_test(
name = "test",
size = "small",
cdeps = [
":add_shared",
"@rules_zig//zig/lib:libc",
],
main = "main.zig",
)

build_test(
name = "build",
size = "small",
targets = [
":binary",
":library",
":test",
],
)

genrule(
name = "output",
outs = ["output.actual"],
cmd = "$(execpath :binary) > $(OUTS)",
tools = [":binary"],
)

diff_test(
name = "output_test",
size = "small",
file1 = ":output.expected",
file2 = ":output.actual",
)
3 changes: 3 additions & 0 deletions e2e/workspace/link-dependencies/shared-library/add.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
char add(char a, char b) {
return a + b;
}
12 changes: 12 additions & 0 deletions e2e/workspace/link-dependencies/shared-library/main.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const std = @import("std");

extern fn add(u8, u8) u8;

pub fn main() !void {
const three = add(1, 2);
try std.io.getStdOut().writer().print("{d}\n", .{three});
}

test "One plus two equals three" {
try std.testing.expectEqual(@as(u8, 3), add(1, 2));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3
1 change: 1 addition & 0 deletions zig/private/common/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ bzl_library(
name = "cdeps",
srcs = ["cdeps.bzl"],
visibility = ["//zig:__subpackages__"],
deps = ["@bazel_skylib//lib:paths"],
)

bzl_library(
Expand Down
69 changes: 67 additions & 2 deletions zig/private/common/cdeps.bzl
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
"""Handle C library dependencies."""

def zig_cdeps(*, cdeps, direct_inputs, transitive_inputs, args):
load("@bazel_skylib//lib:paths.bzl", "paths")

def zig_cdeps(*, cdeps, output_dir, os, direct_inputs, transitive_inputs, args, data):
"""Handle C library dependencies.
Sets the appropriate command-line flags for the Zig compiler to expose
provided headers and link against the provided libraries.
Args:
cdeps: List of Target, Must provide `CcInfo`.
output_dir: String, The directory in which the binary or library is created. Used for RUNPATH calcuation.
os: String, The OS component of the target triple.
direct_inputs: List of File; mutable, Append the needed inputs to this list.
transitive_inputs: List of depset of File; mutable, Append the needed inputs to this list.
args: Args; mutable, Append the Zig command-line flags to this object.
data: List of File; mutable, Append the needed runtime dependencies.
"""
cc_info = cc_common.merge_cc_infos(direct_cc_infos = [cdep[CcInfo] for cdep in cdeps])
_compilation_context(
Expand All @@ -20,8 +25,11 @@ def zig_cdeps(*, cdeps, direct_inputs, transitive_inputs, args):
)
_linking_context(
linking_context = cc_info.linking_context,
output_dir = output_dir,
os = os,
inputs = direct_inputs,
args = args,
data = data,
)

def _compilation_context(*, compilation_context, inputs, args):
Expand All @@ -38,20 +46,27 @@ def _compilation_context(*, compilation_context, inputs, args):
args.add_all(compilation_context.external_includes, before_each = "-isystem")
args.add_all(compilation_context.framework_includes, format_each = "-F%s")

def _linking_context(*, linking_context, inputs, args):
def _linking_context(*, linking_context, output_dir, os, inputs, args, data):
dynamic_libraries = []
for link in linking_context.linker_inputs.to_list():
args.add_all(link.user_link_flags)
inputs.extend(link.additional_inputs)
for lib in link.libraries:
file = None
dynamic = False
if lib.static_library != None:
file = lib.static_library
elif lib.pic_static_library != None:
file = lib.pic_static_library
elif lib.interface_library != None:
file = lib.interface_library
dynamic = True
elif lib.dynamic_library != None:
file = lib.dynamic_library
dynamic = True

if dynamic and lib.dynamic_library:
dynamic_libraries.append(lib.dynamic_library)

# TODO[AH] Handle the remaining fields of LibraryToLink as needed:
# alwayslink
Expand All @@ -65,3 +80,53 @@ def _linking_context(*, linking_context, inputs, args):
if file:
inputs.append(file)
args.add(file)

data.extend(dynamic_libraries)
args.add_all(dynamic_libraries, map_each = _make_to_rpath(output_dir, os), allow_closure = True, before_each = "-rpath")

def _make_to_rpath(output_dir, os):
origin = "$ORIGIN"

# Based on `zig targets | jq .os`
if os in ["freebsd", "ios", "macos", "netbsd", "openbsd", "tvos", "watchos"]:
origin = "@loader_path"

def to_rpath(lib):
result = paths.join(origin, _relativize(lib.dirname, output_dir))
return result

return to_rpath

def _relativize(path, start):
"""Generates a path to `path` relative to `start`.
Strips any common prefix, generates up-directory references corresponding
to the depth of the remainder of `start`, and appends the remainder of
`path`.
Note, Bazel Skylib's `paths.relativize` does not generate up-directory
references.
Args:
path: String, The target path.
start: String, The starting point.
Returns:
String, A relative path.
"""
path_segments = path.split("/")
start_segments = start.split("/")

common = 0
for path_segment, start_segment in zip(path_segments, start_segments):
if path_segment != start_segment:
break

common += 1

up_count = len(start_segments) - common

result_segments = [".."] * up_count + path_segments[common:]
result = paths.join(*result_segments)

return result
6 changes: 5 additions & 1 deletion zig/private/common/zig_build.bzl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Common implementation of the zig_binary|library|test rules."""

load("@bazel_skylib//lib:paths.bzl", "paths")
load("//zig/private/common:cdeps.bzl", "zig_cdeps")
load("//zig/private/common:csrcs.bzl", "zig_csrcs")
load("//zig/private/common:data.bzl", "zig_collect_data", "zig_create_runfiles")
Expand Down Expand Up @@ -177,9 +178,12 @@ def zig_build_impl(ctx, *, kind):

zig_cdeps(
cdeps = ctx.attr.cdeps,
output_dir = paths.join(ctx.bin_dir.path, ctx.label.package),
os = zigtargetinfo.triple.os,
direct_inputs = direct_inputs,
transitive_inputs = transitive_inputs,
args = args,
data = direct_data,
)

zig_linker_script(
Expand Down Expand Up @@ -251,7 +255,7 @@ def zig_build_impl(ctx, *, kind):
files = files,
runfiles = zig_create_runfiles(
ctx_runfiles = ctx.runfiles,
direct_data = [],
direct_data = direct_data,
transitive_data = transitive_data,
transitive_runfiles = transitive_runfiles,
),
Expand Down

0 comments on commit 06734ec

Please sign in to comment.