Skip to content

Commit 51af405

Browse files
committed
feat(build): use blst packaged for zig using zig build system
Packaged `blst` for use by zig projects in this [repo](https://github.com/chainsafe/blst.zig), inspired by projects in [allyourcodebase](https://github.com/allyourcodebase). This also decouples managing `blst` options into that that repo's `build.zig`.
1 parent 5f9a7b0 commit 51af405

File tree

2 files changed

+27
-251
lines changed

2 files changed

+27
-251
lines changed

build.zig

Lines changed: 24 additions & 178 deletions
Original file line numberDiff line numberDiff line change
@@ -3,114 +3,40 @@ const Compile = std.Build.Step.Compile;
33
const ResolvedTarget = std.Build.ResolvedTarget;
44
const OptimizeMode = std.builtin.OptimizeMode;
55

6-
// Although this function looks imperative, note that its job is to
7-
// declaratively construct a build graph that will be executed by an external
8-
// runner.
96
pub fn build(b: *std.Build) !void {
10-
// Standard target options allows the person running `zig build` to choose
11-
// what target to build for. Here we do not override the defaults, which
12-
// means any target is allowed, and the default is native. Other options
13-
// for restricting supported target set are available.
147
const target = b.standardTargetOptions(.{});
15-
16-
// Standard optimization options allow the person running `zig build` to select
17-
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
18-
// set a preferred release mode, allowing the user to decide how to optimize.
198
const optimize = b.standardOptimizeOption(.{});
209

21-
const blst_dep = b.dependency("blst", .{ .target = target, .optimize = optimize });
22-
23-
// passed by "zig build -Dportable=true"
24-
const portable = b.option(bool, "portable", "Enable portable implementation") orelse false;
25-
// passed by "zig build -Dforce-adx=true"
26-
const force_adx = b.option(bool, "force-adx", "Enable ADX optimizations") orelse false;
10+
const blst_c = b.dependency("blst_zig", .{});
2711

28-
// build blst-z static library
29-
const staticLib = b.addStaticLibrary(.{
30-
.name = "blst-z",
31-
// In this case the main source file is merely a path, however, in more
32-
// complicated build scripts, this could be a generated file.
12+
const lib_blst_c = blst_c.artifact("blst");
13+
// blst module (for downstream zig consumers)
14+
const blst_mod = b.addModule("blst", .{
3315
.root_source_file = b.path("src/root.zig"),
3416
.target = target,
3517
.optimize = optimize,
3618
});
3719

38-
const module_blst_min_pk = b.createModule(.{
39-
.root_source_file = b.path("src/root_min_pk.zig"),
40-
.target = target,
41-
.optimize = optimize,
42-
});
43-
try withBlst(blst_dep, module_blst_min_pk, target, false, portable, force_adx);
44-
45-
b.modules.put(b.dupe("blst_min_pk"), module_blst_min_pk) catch @panic("OOM");
46-
47-
const module_blst_min_sig = b.createModule(.{
48-
.root_source_file = b.path("src/root_min_sig.zig"),
49-
.target = target,
50-
.optimize = optimize,
51-
});
52-
try withBlst(blst_dep, module_blst_min_sig, target, false, portable, force_adx);
53-
b.modules.put(b.dupe("blst_min_sig"), module_blst_min_sig) catch @panic("OOM");
54-
55-
// blst does not need libc, however we need to link it to enable threading
56-
// see https://github.com/ChainSafe/blst-bun/issues/4
57-
staticLib.linkLibC();
58-
// the folder where blst.h is located
59-
try withBlst(blst_dep, staticLib.root_module, target, false, portable, force_adx);
60-
61-
// This declares intent for the library to be installed into the standard
62-
// location when the user invokes the "install" step (the default step when
63-
// running `zig build`).
64-
b.installArtifact(staticLib);
65-
66-
// build blst-z shared library
67-
const sharedLib = b.addSharedLibrary(.{
68-
.name = "blst_min_pk",
69-
.root_source_file = b.path("src/root_c_abi_min_pk.zig"),
70-
.target = target,
71-
.optimize = optimize,
72-
});
73-
74-
// blst does not need libc, however we need to link it to enable threading
75-
// see https://github.com/ChainSafe/blst-bun/issues/4
76-
sharedLib.linkLibC();
77-
try withBlst(blst_dep, sharedLib.root_module, target, true, portable, force_adx);
78-
b.installArtifact(sharedLib);
79-
80-
const exe = b.addExecutable(.{
81-
.name = "blst-z",
82-
.root_source_file = b.path("src/main.zig"),
83-
.target = target,
84-
.optimize = optimize,
20+
blst_mod.linkLibrary(lib_blst_c);
21+
blst_mod.addIncludePath(blst_c.path("include"));
22+
23+
// blst dynamic library (for bun consumers)
24+
const blst_dylib = b.addLibrary(.{
25+
.root_module = b.createModule(.{
26+
.root_source_file = b.path("src/root_c_abi_min_pk.zig"),
27+
.target = target,
28+
.optimize = optimize,
29+
// blst does not need libc, however we need to link it to enable threading
30+
// see https://github.com/ChainSafe/blst-bun/issues/4
31+
.link_libc = true,
32+
.pic = true,
33+
}),
34+
.name = "eth_blst",
35+
.linkage = .dynamic,
8536
});
37+
blst_dylib.linkLibrary(lib_blst_c);
8638

87-
// This declares intent for the executable to be installed into the
88-
// standard location when the user invokes the "install" step (the default
89-
// step when running `zig build`).
90-
b.installArtifact(exe);
91-
92-
// This *creates* a Run step in the build graph, to be executed when another
93-
// step is evaluated that depends on it. The next line below will establish
94-
// such a dependency.
95-
const run_cmd = b.addRunArtifact(exe);
96-
97-
// By making the run step depend on the install step, it will be run from the
98-
// installation directory rather than directly from within the cache directory.
99-
// This is not necessary, however, if the application depends on other installed
100-
// files, this ensures they will be present and in the expected location.
101-
run_cmd.step.dependOn(b.getInstallStep());
102-
103-
// This allows the user to pass arguments to the application in the build
104-
// command itself, like this: `zig build run -- arg1 arg2 etc`
105-
if (b.args) |args| {
106-
run_cmd.addArgs(args);
107-
}
108-
109-
// This creates a build step. It will be visible in the `zig build --help` menu,
110-
// and can be selected like this: `zig build run`
111-
// This will evaluate the `run` step rather than the default, which is "install".
112-
const run_step = b.step("run", "Run the app");
113-
run_step.dependOn(&run_cmd.step);
39+
b.installArtifact(blst_dylib);
11440

11541
// Creates a step for unit testing. This only builds the test executable
11642
// but does not run it.
@@ -120,8 +46,7 @@ pub fn build(b: *std.Build) !void {
12046
.optimize = optimize,
12147
});
12248

123-
try withBlst(blst_dep, lib_unit_tests.root_module, target, true, portable, force_adx);
124-
49+
lib_unit_tests.linkLibrary(lib_blst_c);
12550
const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);
12651

12752
const exe_unit_tests = b.addTest(.{
@@ -130,89 +55,10 @@ pub fn build(b: *std.Build) !void {
13055
.optimize = optimize,
13156
});
13257

58+
exe_unit_tests.linkLibrary(lib_blst_c);
13359
const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
13460

135-
// Similar to creating the run step earlier, this exposes a `test` step to
136-
// the `zig build --help` menu, providing a way for the user to request
137-
// running the unit tests.
13861
const test_step = b.step("test", "Run unit tests");
13962
test_step.dependOn(&run_lib_unit_tests.step);
14063
test_step.dependOn(&run_exe_unit_tests.step);
14164
}
142-
143-
/// instead of treating blst as a dependency lib, build and link it, we add its resource to our libs
144-
/// and zig will handle a mixture of C, assembly and Zig code
145-
/// reference to https://github.com/supranational/blst/blob/v0.3.13/bindings/rust/build.rs
146-
/// TODO: port all missing flows from the Rust build script
147-
fn withBlst(blst_dep: *std.Build.Dependency, module: *std.Build.Module, target: ResolvedTarget, is_shared_lib: bool, portable: bool, force_adx: bool) !void {
148-
module.addIncludePath(blst_dep.path("bindings"));
149-
// add later, once we have cflags
150-
const arch = target.result.cpu.arch;
151-
152-
// TODO: how to get target_env?
153-
// TODO: may have a separate build version for adx
154-
// then at Bun side, it has to detect if the target is x86_64 and has adx or not
155-
if (portable == true and force_adx == false) {
156-
// TODO: panic if target_env is sgx
157-
// use this instead
158-
module.addCMacro("__BLST_PORTABLE__", "");
159-
} else if (portable == false and force_adx == true) {
160-
if (arch == .x86_64) {
161-
module.addCMacro("__ADX__", "");
162-
} else {
163-
std.debug.print("`force-adx` is ignored for non-x86_64 targets \n", .{});
164-
}
165-
} else if (portable == false and force_adx == false) {
166-
// TODO: how to detect adx like this Rust call
167-
// if std::is_x86_feature_detected!("adx") {
168-
if (arch == .x86_64) {
169-
std.debug.print("ADX is turned on by default for x86_64 targets \n", .{});
170-
module.addCMacro("__ADX__", "");
171-
}
172-
// otherwise get: "undefined symbol redcx_mont_256" when run tests in Linux
173-
} else {
174-
// both are true
175-
@panic("Cannot set both `portable` and `force-adx` to true");
176-
}
177-
178-
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
179-
const allocator = gpa.allocator();
180-
181-
defer _ = gpa.deinit();
182-
183-
var cflags = std.ArrayList([]const u8).init(allocator);
184-
defer cflags.deinit();
185-
186-
// get this error in Mac arm: unsupported option '-mno-avx' for target 'aarch64-unknown-macosx15.1.0-unknown'
187-
if (arch == .x86_64) {
188-
try cflags.append("-mno-avx"); // avoid costly transitions
189-
}
190-
// the no_builtin should help, set here just to make sure
191-
try cflags.append("-fno-builtin");
192-
try cflags.append("-Wno-unused-function");
193-
try cflags.append("-Wno-unused-command-line-argument");
194-
195-
if (is_shared_lib) {
196-
try cflags.append("-fPIC");
197-
}
198-
199-
module.addCSourceFile(.{ .file = blst_dep.path("src/server.c"), .flags = cflags.items });
200-
module.addCSourceFile(.{ .file = blst_dep.path("build/assembly.S"), .flags = cflags.items });
201-
202-
// TODO: we may not need this since we linkLibC() above
203-
const os = target.result.os;
204-
// fix this error on Linux: 'stdlib.h' file not found
205-
// otherwise blst-bun cannot load the shared library on Linux
206-
// with error "Failed to open library. This is usually caused by a missing library or an invalid library path"
207-
if (os.tag == .linux) {
208-
// since "zig cc" works fine, we just follow it
209-
// zig cc -E -Wp,-v -
210-
module.addIncludePath(.{ .cwd_relative = "/usr/local/include" });
211-
module.addIncludePath(.{ .cwd_relative = "/usr/include" });
212-
if (arch == .x86_64) {
213-
module.addIncludePath(.{ .cwd_relative = "/usr/include/x86_64-linux-gnu" });
214-
} else if (arch == .aarch64) {
215-
module.addIncludePath(.{ .cwd_relative = "/usr/include/aarch64-linux-gnu" });
216-
}
217-
}
218-
}

build.zig.zon

Lines changed: 3 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,21 @@
11
.{
2-
// This is the default name used by packages depending on this one. For
3-
// example, when a user runs `zig fetch --save <url>`, this field is used
4-
// as the key in the `dependencies` table. Although the user can choose a
5-
// different name, most users will stick with this provided value.
6-
//
7-
// It is redundant to include "zig" in this name because it is already
8-
// within the Zig package namespace.
92
.name = .blst_z,
103

11-
// This is a [Semantic Version](https://semver.org/).
12-
// In a future version of Zig it will be used for package deduplication.
134
.version = "0.0.0",
145

15-
// Together with name, this represents a globally unique package
16-
// identifier. This field is generated by the Zig toolchain when the
17-
// package is first created, and then *never changes*. This allows
18-
// unambiguous detection of one package being an updated version of
19-
// another.
20-
//
21-
// When forking a Zig project, this id should be regenerated (delete the
22-
// field and run `zig build`) if the upstream project is still maintained.
23-
// Otherwise, the fork is *hostile*, attempting to take control over the
24-
// original project's identity. Thus it is recommended to leave the comment
25-
// on the following line intact, so that it shows up in code reviews that
26-
// modify the field.
276
.fingerprint = 0xfbd83f934c5ddb5, // Changing this has security and trust implications.
287

29-
// Tracks the earliest Zig version that the package considers to be a
30-
// supported use case.
318
.minimum_zig_version = "0.14.0",
329

33-
// This field is optional.
34-
// Each dependency must either provide a `url` and `hash`, or a `path`.
35-
// `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
36-
// Once all dependencies are fetched, `zig build` no longer requires
37-
// internet connectivity.
3810
.dependencies = .{
39-
// See `zig fetch --save <url>` for a command-line interface for adding dependencies.
40-
//.example = .{
41-
// // When updating this field to a new URL, be sure to delete the corresponding
42-
// // `hash`, otherwise you are communicating that you expect to find the old hash at
43-
// // the new URL. If the contents of a URL change this will result in a hash mismatch
44-
// // which will prevent zig from using it.
45-
// .url = "https://example.com/foo.tar.gz",
46-
//
47-
// // This is computed from the file contents of the directory of files that is
48-
// // obtained after fetching `url` and applying the inclusion rules given by
49-
// // `paths`.
50-
// //
51-
// // This field is the source of truth; packages do not come from a `url`; they
52-
// // come from a `hash`. `url` is just one of many possible mirrors for how to
53-
// // obtain a package matching this `hash`.
54-
// //
55-
// // Uses the [multihash](https://multiformats.io/multihash/) format.
56-
// .hash = "...",
57-
//
58-
// // When this is provided, the package is found in a directory relative to the
59-
// // build root. In this case the package's hash is irrelevant and therefore not
60-
// // computed. This field and `url` are mutually exclusive.
61-
// .path = "foo",
62-
//
63-
// // When this is set to `true`, a package is declared to be lazily
64-
// // fetched. This makes the dependency only get fetched if it is
65-
// // actually used.
66-
// .lazy = false,
67-
//},
68-
// zig fetch https://github.com/supranational/blst/archive/refs/tags/v0.3.13.tar.gz
69-
.blst = .{
70-
.url = "https://github.com/supranational/blst/archive/refs/tags/v0.3.13.tar.gz",
71-
.hash = "N-V-__8AAHB4OgByNs3JJNXs9f2gxmbJBYqM7HBRHfmwZa-e",
11+
.blst_zig = .{
12+
.url = "git+https://github.com/ChainSafe/blst.zig.git#0c7d233d9910c0fe851c9a7a0addbe6202ff6aac",
13+
.hash = "blst_zig-0.0.0-cnAxzogIAAB8nH6TSAGbUtZ6scv2F64aVlcuJabg5HWi",
7214
},
7315
},
74-
75-
// Specifies the set of files and directories that are included in this package.
76-
// Only files and directories listed here are included in the `hash` that
77-
// is computed for this package. Only files listed here will remain on disk
78-
// when using the zig package manager. As a rule of thumb, one should list
79-
// files required for compilation plus any license(s).
80-
// Paths are relative to the build root. Use the empty string (`""`) to refer to
81-
// the build root itself.
82-
// A directory listed here means that all files within, recursively, are included.
8316
.paths = .{
8417
"build.zig",
8518
"build.zig.zon",
8619
"src",
87-
// For example...
88-
//"LICENSE",
89-
//"README.md",
9020
},
9121
}

0 commit comments

Comments
 (0)