diff --git a/docs/rules.md b/docs/rules.md
index afb0a076..b698e3b0 100644
--- a/docs/rules.md
+++ b/docs/rules.md
@@ -23,6 +23,27 @@ zig_binary(name, deps<
| srcs | Other source files required to build the target. | List of labels | optional | [] |
+
+
+## zig_library
+
+
+zig_library(name, deps, main, srcs) ++ + + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| deps | Packages or libraries required to build the target. | List of labels | optional |
[] |
+| main | The main source file. | Label | required | |
+| srcs | Other source files required to build the target. | List of labels | optional | [] |
+
+
## zig_package
diff --git a/e2e/workspace/simple-library/BUILD.bazel b/e2e/workspace/simple-library/BUILD.bazel
new file mode 100644
index 00000000..3f162224
--- /dev/null
+++ b/e2e/workspace/simple-library/BUILD.bazel
@@ -0,0 +1,23 @@
+load("@bazel_skylib//rules:build_test.bzl", "build_test")
+load("@rules_zig//zig:defs.bzl", "zig_library")
+
+zig_library(
+ name = "library",
+ main = "main.zig",
+)
+
+genrule(
+ name = "library-symbol",
+ srcs = [":library"],
+ outs = ["library-symbol.txt"],
+ cmd = "$(NM) -j --defined-only $(SRCS) | grep sayHello > $(OUTS)",
+ toolchains = ["@bazel_tools//tools/cpp:current_cc_toolchain"],
+)
+
+build_test(
+ name = "library_build_test",
+ targets = [
+ ":library",
+ ":library-symbol",
+ ],
+)
diff --git a/e2e/workspace/simple-library/main.zig b/e2e/workspace/simple-library/main.zig
new file mode 100644
index 00000000..c215a20e
--- /dev/null
+++ b/e2e/workspace/simple-library/main.zig
@@ -0,0 +1,7 @@
+const std = @import("std");
+
+export fn sayHello() void {
+ std.io.getStdOut().writeAll(
+ "Hello World!\n",
+ ) catch unreachable;
+}
diff --git a/zig/BUILD.bazel b/zig/BUILD.bazel
index af6f2d61..5b3f2a0b 100644
--- a/zig/BUILD.bazel
+++ b/zig/BUILD.bazel
@@ -29,6 +29,7 @@ bzl_library(
visibility = ["//visibility:public"],
deps = [
"//zig/private:zig_binary",
+ "//zig/private:zig_library",
"//zig/private:zig_package",
],
)
diff --git a/zig/defs.bzl b/zig/defs.bzl
index a10850b7..8104f184 100644
--- a/zig/defs.bzl
+++ b/zig/defs.bzl
@@ -1,7 +1,9 @@
"Public API re-exports"
load("//zig/private:zig_binary.bzl", _zig_binary = "zig_binary")
+load("//zig/private:zig_library.bzl", _zig_library = "zig_library")
load("//zig/private:zig_package.bzl", _zig_package = "zig_package")
zig_binary = _zig_binary
+zig_library = _zig_library
zig_package = _zig_package
diff --git a/zig/private/BUILD.bazel b/zig/private/BUILD.bazel
index 17a658d0..0fac081b 100644
--- a/zig/private/BUILD.bazel
+++ b/zig/private/BUILD.bazel
@@ -1,39 +1,45 @@
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
bzl_library(
- name = "toolchains_repo",
- srcs = ["toolchains_repo.bzl"],
+ name = "zig_binary",
+ srcs = ["zig_binary.bzl"],
visibility = ["//zig:__subpackages__"],
+ deps = [
+ "//zig/private/common:filetypes",
+ "//zig/private/common:zig_cache",
+ "//zig/private/providers:zig_package_info",
+ ],
)
bzl_library(
- name = "versions",
- srcs = ["versions.bzl"],
+ name = "zig_package",
+ srcs = ["zig_package.bzl"],
visibility = ["//zig:__subpackages__"],
+ deps = [
+ "//zig/private/common:filetypes",
+ "//zig/private/providers:zig_package_info",
+ ],
)
bzl_library(
- name = "zig_binary",
- srcs = ["zig_binary.bzl"],
+ name = "zig_library",
+ srcs = ["zig_library.bzl"],
visibility = ["//zig:__subpackages__"],
deps = [
- ":filetypes",
- "@bazel_skylib//lib:paths",
+ "//zig/private/common:filetypes",
+ "//zig/private/common:zig_cache",
+ "//zig/private/providers:zig_package_info",
],
)
bzl_library(
- name = "zig_package",
- srcs = ["zig_package.bzl"],
+ name = "toolchains_repo",
+ srcs = ["toolchains_repo.bzl"],
visibility = ["//zig:__subpackages__"],
- deps = [
- ":filetypes",
- "//zig/private/providers:zig_package_info",
- ],
)
bzl_library(
- name = "filetypes",
- srcs = ["filetypes.bzl"],
+ name = "versions",
+ srcs = ["versions.bzl"],
visibility = ["//zig:__subpackages__"],
)
diff --git a/zig/private/common/BUILD.bazel b/zig/private/common/BUILD.bazel
new file mode 100644
index 00000000..d9b63d5e
--- /dev/null
+++ b/zig/private/common/BUILD.bazel
@@ -0,0 +1,14 @@
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
+
+bzl_library(
+ name = "zig_cache",
+ srcs = ["zig_cache.bzl"],
+ visibility = ["//zig:__subpackages__"],
+ deps = ["@bazel_skylib//lib:paths"],
+)
+
+bzl_library(
+ name = "filetypes",
+ srcs = ["filetypes.bzl"],
+ visibility = ["//zig:__subpackages__"],
+)
diff --git a/zig/private/filetypes.bzl b/zig/private/common/filetypes.bzl
similarity index 100%
rename from zig/private/filetypes.bzl
rename to zig/private/common/filetypes.bzl
diff --git a/zig/private/common/zig_cache.bzl b/zig/private/common/zig_cache.bzl
new file mode 100644
index 00000000..44cbdced
--- /dev/null
+++ b/zig/private/common/zig_cache.bzl
@@ -0,0 +1,26 @@
+"""Defines utilities to handle the Zig compiler cache."""
+
+load("@bazel_skylib//lib:paths.bzl", "paths")
+
+def zig_cache_output(*, actions, name, outputs, args):
+ """Handle the Zig compiler cache.
+
+ Declares directory outputs for the local and global Zig compiler cache.
+ Appends both to the given outputs list, and arguments object.
+
+ Args:
+ actions: `ctx.actions`.
+ name: String, A unique name to distinguish this cache from others.
+ outputs: List; mutable, Append the declared outputs to this list.
+ args: Args; mutable, Append the Zig cache flags to this object.
+ """
+
+ # TODO[AH] Persist or share at least the global cache somehow.
+ local_cache = actions.declare_directory(paths.join(".zig-cache", "local", name))
+ global_cache = actions.declare_directory(paths.join(".zig-cache", "global", name))
+
+ outputs.append(local_cache)
+ outputs.append(global_cache)
+
+ args.add_all(["--cache-dir", local_cache.path])
+ args.add_all(["--global-cache-dir", global_cache.path])
diff --git a/zig/private/providers/zig_package_info.bzl b/zig/private/providers/zig_package_info.bzl
index 486e946f..605fe019 100644
--- a/zig/private/providers/zig_package_info.bzl
+++ b/zig/private/providers/zig_package_info.bzl
@@ -16,18 +16,17 @@ ZigPackageInfo = provider(
doc = DOC,
)
-def add_package_flags(args, package):
- """Generate the Zig compiler flags to depend on the given package.
-
- Generates `--pkg-begin` and `--pkg-end` flags required to build a target
- that depends on this package.
+def zig_package_dependencies(*, deps, inputs, args):
+ """Collect inputs and flags for Zig package dependencies.
Args:
- args: The Args object to extend with the required flags.
- package: The package to generate flags for.
+ deps: List of Target, Considers the targets that have a ZigPackageInfo provider.
+ inputs: List of depset of File; mutable, Append the needed inputs to this list.
+ args: Args; mutable, Append the needed Zig compiler flags to this object.
"""
- args.add_all(package.flags)
-
-def get_package_files(package):
- """Generate a `depset` of the files required to depend on the package."""
- return package.all_srcs
+ for dep in deps:
+ if not ZigPackageInfo in dep:
+ continue
+ package = dep[ZigPackageInfo]
+ inputs.append(package.all_srcs)
+ args.add_all(package.flags)
diff --git a/zig/private/zig_binary.bzl b/zig/private/zig_binary.bzl
index d30abd89..276c118c 100644
--- a/zig/private/zig_binary.bzl
+++ b/zig/private/zig_binary.bzl
@@ -1,12 +1,11 @@
"""Implementation of the zig_binary rule."""
-load("@bazel_skylib//lib:paths.bzl", "paths")
-load("//zig/private:filetypes.bzl", "ZIG_SOURCE_EXTENSIONS")
+load("//zig/private/common:filetypes.bzl", "ZIG_SOURCE_EXTENSIONS")
+load("//zig/private/common:zig_cache.bzl", "zig_cache_output")
load(
"//zig/private/providers:zig_package_info.bzl",
"ZigPackageInfo",
- "add_package_flags",
- "get_package_files",
+ "zig_package_dependencies",
)
DOC = """\
@@ -33,33 +32,38 @@ ATTRS = {
def _zig_binary_impl(ctx):
ziginfo = ctx.toolchains["//zig:toolchain_type"].ziginfo
- # TODO[AH] Append `.exe` extension on Windows.
- output = ctx.actions.declare_file(ctx.label.name)
+ outputs = []
- local_cache = ctx.actions.declare_directory(paths.join(".zig-cache", "local", ctx.label.name))
- global_cache = ctx.actions.declare_directory(paths.join(".zig-cache", "global", ctx.label.name))
-
- direct_inputs = [ctx.file.main] + ctx.files.srcs
+ direct_inputs = []
transitive_inputs = []
args = ctx.actions.args()
args.use_param_file("@%s")
+ # TODO[AH] Append `.exe` extension on Windows.
+ output = ctx.actions.declare_file(ctx.label.name)
+ outputs.append(output)
args.add(output, format = "-femit-bin=%s")
+
+ direct_inputs.append(ctx.file.main)
+ direct_inputs.extend(ctx.files.srcs)
args.add(ctx.file.main)
- for dep in ctx.attr.deps:
- if ZigPackageInfo in dep:
- package = dep[ZigPackageInfo]
- transitive_inputs.append(get_package_files(package))
- add_package_flags(args, package)
+ zig_package_dependencies(
+ deps = ctx.attr.deps,
+ inputs = transitive_inputs,
+ args = args,
+ )
- # TODO[AH] Persist or share at least the global cache somehow.
- args.add_all(["--cache-dir", local_cache.path])
- args.add_all(["--global-cache-dir", global_cache.path])
+ zig_cache_output(
+ actions = ctx.actions,
+ name = ctx.label.name,
+ outputs = outputs,
+ args = args,
+ )
ctx.actions.run(
- outputs = [output, local_cache, global_cache],
+ outputs = outputs,
inputs = depset(direct = direct_inputs, transitive = transitive_inputs),
executable = ziginfo.target_tool_path,
tools = ziginfo.tool_files,
diff --git a/zig/private/zig_library.bzl b/zig/private/zig_library.bzl
new file mode 100644
index 00000000..51cef3dc
--- /dev/null
+++ b/zig/private/zig_library.bzl
@@ -0,0 +1,88 @@
+"""Implementation of the zig_library rule."""
+
+load("//zig/private/common:filetypes.bzl", "ZIG_SOURCE_EXTENSIONS")
+load("//zig/private/common:zig_cache.bzl", "zig_cache_output")
+load(
+ "//zig/private/providers:zig_package_info.bzl",
+ "ZigPackageInfo",
+ "zig_package_dependencies",
+)
+
+DOC = """\
+"""
+
+ATTRS = {
+ "main": attr.label(
+ allow_single_file = ZIG_SOURCE_EXTENSIONS,
+ doc = "The main source file.",
+ mandatory = True,
+ ),
+ "srcs": attr.label_list(
+ allow_files = ZIG_SOURCE_EXTENSIONS,
+ doc = "Other source files required to build the target.",
+ mandatory = False,
+ ),
+ "deps": attr.label_list(
+ doc = "Packages or libraries required to build the target.",
+ mandatory = False,
+ providers = [ZigPackageInfo],
+ ),
+}
+
+def _zig_library_impl(ctx):
+ ziginfo = ctx.toolchains["//zig:toolchain_type"].ziginfo
+
+ outputs = []
+
+ direct_inputs = []
+ transitive_inputs = []
+
+ args = ctx.actions.args()
+ args.use_param_file("@%s")
+
+ # TODO[AH] Set `.lib` extension on Windows.
+ static = ctx.actions.declare_file(ctx.label.name + ".a")
+ outputs.append(static)
+ args.add(static, format = "-femit-bin=%s")
+ # TODO[AH] Support dynamic library output.
+
+ direct_inputs.append(ctx.file.main)
+ direct_inputs.extend(ctx.files.srcs)
+ args.add(ctx.file.main)
+
+ zig_package_dependencies(
+ deps = ctx.attr.deps,
+ inputs = transitive_inputs,
+ args = args,
+ )
+
+ zig_cache_output(
+ actions = ctx.actions,
+ name = ctx.label.name,
+ outputs = outputs,
+ args = args,
+ )
+
+ ctx.actions.run(
+ outputs = outputs,
+ inputs = depset(direct = direct_inputs, transitive = transitive_inputs),
+ executable = ziginfo.target_tool_path,
+ tools = ziginfo.tool_files,
+ arguments = ["build-lib", args],
+ mnemonic = "ZigBuildLib",
+ progress_message = "Building %{input} as Zig library %{output}",
+ execution_requirements = {tag: "" for tag in ctx.attr.tags},
+ )
+
+ default = DefaultInfo(
+ files = depset([static]),
+ )
+
+ return [default]
+
+zig_library = rule(
+ _zig_library_impl,
+ attrs = ATTRS,
+ doc = DOC,
+ toolchains = ["//zig:toolchain_type"],
+)
diff --git a/zig/private/zig_package.bzl b/zig/private/zig_package.bzl
index 2fbe0526..f3b7c7d1 100644
--- a/zig/private/zig_package.bzl
+++ b/zig/private/zig_package.bzl
@@ -1,7 +1,7 @@
"""Implementation of the zig_package rule."""
+load("//zig/private/common:filetypes.bzl", "ZIG_SOURCE_EXTENSIONS")
load("//zig/private/providers:zig_package_info.bzl", "ZigPackageInfo")
-load("//zig/private:filetypes.bzl", "ZIG_SOURCE_EXTENSIONS")
DOC = """\
"""
diff --git a/zig/tests/package_info_test.bzl b/zig/tests/package_info_test.bzl
index df1f9779..ca9d0753 100644
--- a/zig/tests/package_info_test.bzl
+++ b/zig/tests/package_info_test.bzl
@@ -6,8 +6,7 @@ load("@bazel_skylib//lib:sets.bzl", "sets")
load(
"//zig/private/providers:zig_package_info.bzl",
"ZigPackageInfo",
- "add_package_flags",
- "get_package_files",
+ "zig_package_dependencies",
)
def _mock_args():
@@ -31,23 +30,30 @@ def _mock_args():
def _single_package_test_impl(ctx):
env = unittest.begin(ctx)
+ transitive_inputs = []
+ args = _mock_args()
+
+ zig_package_dependencies(
+ deps = [ctx.attr.pkg],
+ inputs = transitive_inputs,
+ args = args,
+ )
+
package = ctx.attr.pkg[ZigPackageInfo]
- args = _mock_args()
- add_package_flags(args, package)
asserts.equals(
env,
["--pkg-begin", package.name, package.main.path, "--pkg-end"],
args.get_args(),
- "add_package_flags should generate the expected arguments.",
+ "zig_package_dependencies should generate the expected arguments.",
)
- files = get_package_files(package)
+ inputs = depset(transitive = transitive_inputs)
asserts.set_equals(
env,
sets.make([package.main] + package.srcs),
- sets.make(files.to_list()),
- "get_package_files should capture all package files.",
+ sets.make(inputs.to_list()),
+ "zig_package_dependencies should capture all package files.",
)
return unittest.end(env)
@@ -62,13 +68,20 @@ _single_package_test = unittest.make(
def _nested_packages_test_impl(ctx):
env = unittest.begin(ctx)
+ transitive_inputs = []
+ args = _mock_args()
+
+ zig_package_dependencies(
+ deps = [dep for dep in ctx.attr.pkgs if dep.label.name == "a"],
+ inputs = transitive_inputs,
+ args = args,
+ )
+
pkgs = {
pkg.label.name: pkg[ZigPackageInfo]
for pkg in ctx.attr.pkgs
}
- args = _mock_args()
- add_package_flags(args, pkgs["a"])
asserts.equals(
env,
[
@@ -122,10 +135,10 @@ def _nested_packages_test_impl(ctx):
"--pkg-end",
],
args.get_args(),
- "add_package_flags should unfold the transitive dependency graph onto the command-line.",
+ "zig_package_dependencies should unfold the transitive dependency graph onto the command-line.",
)
- files = get_package_files(pkgs["a"])
+ inputs = depset(transitive = transitive_inputs)
asserts.set_equals(
env,
sets.make([
@@ -133,8 +146,8 @@ def _nested_packages_test_impl(ctx):
for pkg in pkgs.values()
for src in [pkg.main] + pkg.srcs
]),
- sets.make(files.to_list()),
- "get_package_files should capture all package files.",
+ sets.make(inputs.to_list()),
+ "zig_package_dependencies should capture all package files.",
)
return unittest.end(env)