Skip to content

0.14.0 namedlazypath interface #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,21 @@ Is equivalent to this Javascript:
console.log("Hello from Zig");
```

## Generated Javascript

The generated Javascript can be retrieved through
the zig build Dependency Interface:

```zig
const js_basename = "zjb_extract.js";
const zjb = b.dependency("zjb", .{
.@"wasm-bindgen-bin" = example.getEmittedBin(),
.@"wasm-bindgen-name" = @as([]const u8, js_basename),
.@"wasm-bindgen-classname" = @as([]const u8, "Zjb"),
});
const extract_example_out = zjb.namedLazyPath(js_basename);
```

## Project Status

ZJB is fully functional and is ready to be used in other projects. However 1.0 will not be tagged until there is significant enough usage that confidence in the API not needing further changes is high.
Expand Down
44 changes: 43 additions & 1 deletion build.zig
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
const std = @import("std");
const LazyPath = std.Build.LazyPath;

pub fn build(b: *std.Build) void {
/////////////////////////////////////////////////////////////
// generate js exe
const generate_js = b.addExecutable(.{
.name = "generate_js",
.root_source_file = b.path("src/generate_js.zig"),
.target = b.host,
.target = b.graph.host,
// Reusing this will occur more often than compiling this, as
// it usually can be cached. So faster execution is worth slower
// initial build.
Expand All @@ -20,4 +21,45 @@ pub fn build(b: *std.Build) void {
_ = b.addModule("zjb", .{
.root_source_file = b.path("src/zjb.zig"),
});

// Generate JS for binary supplied through options
// usage from build.zig through the Dependency Interface:
//
// const js_basename = "zjb_extract.js";
// const zjb = b.dependency("zjb", .{
// .@"wasm-bindgen-bin" = example.getEmittedBin(),
// .@"wasm-bindgen-name" = @as([]const u8, js_basename),
// .@"wasm-bindgen-classname" = @as([]const u8, "Zjb"),
// });
// const extract_example_out = zjb.namedLazyPath(js_basename);
//
const wasm_bindgen_name = b.option(
[]const u8,
"wasm-bindgen-name",
"js Bindings Basename",
) orelse "zjb_extract.js";
const wasm_bindgen_classname = b.option(
[]const u8,
"wasm-bindgen-classname",
"js Bindings Classname",
) orelse "Zjb";
const wasm_bindgen_bin = b.option(
LazyPath,
"wasm-bindgen-bin",
"wasm Binary for Binding Generation",
);
const wasm_bindgen_module = b.option(
bool,
"wasm-bindgen-module",
"output an ES6 module export",
) orelse false;

if (wasm_bindgen_bin) |wasm_bin| {
const extract_js = b.addRunArtifact(generate_js);
const extract_js_out = extract_js.addOutputFileArg(wasm_bindgen_name);
extract_js.addArg(wasm_bindgen_classname);
extract_js.addFileArg(wasm_bin);
b.addNamedLazyPath(wasm_bindgen_name, extract_js_out);
extract_js.addArg(if (wasm_bindgen_module) "true" else "false");
}
}
2 changes: 1 addition & 1 deletion build.zig.zon
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.{
.name = "javascript-bridge",
.name = "zjb",
.version = "0.0.0",
.paths = .{
"build.zig",
Expand Down
17 changes: 10 additions & 7 deletions example/build.zig
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
const std = @import("std");
const LazyPath = std.Build.LazyPath;

pub fn build(b: *std.Build) void {
const optimize = b.standardOptimizeOption(.{});
const dir = std.Build.InstallDir.bin;

const zjb = b.dependency("zjb", .{});

const example = b.addExecutable(.{
.name = "example",
.root_source_file = b.path("src/main.zig"),
.target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }),
.optimize = optimize,
});
example.root_module.addImport("zjb", zjb.module("zjb"));
example.entry = .disabled;
example.rdynamic = true;

const extract_example = b.addRunArtifact(zjb.artifact("generate_js"));
const extract_example_out = extract_example.addOutputFileArg("zjb_extract.js");
extract_example.addArg("Zjb"); // Name of js class.
extract_example.addArtifactArg(example);
const js_basename = "zjb_extract.js";
const zjb = b.dependency("zjb", .{
.@"wasm-bindgen-bin" = example.getEmittedBin(),
.@"wasm-bindgen-name" = @as([]const u8, js_basename),
.@"wasm-bindgen-classname" = @as([]const u8, "Zjb"),
});
const extract_example_out = zjb.namedLazyPath(js_basename);

example.root_module.addImport("zjb", zjb.module("zjb"));

const example_step = b.step("example", "Build the hello Zig example");
example_step.dependOn(&b.addInstallArtifact(example, .{
Expand Down
8 changes: 4 additions & 4 deletions example/src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ export fn main() void {
}

logStr("\n============================= Exporting functions (press a key for a callback) =============================");
zjb.global("document").call("addEventListener", .{ zjb.constString("keydown"), zjb.fnHandle("keydownCallback", keydownCallback) }, void);
zjb.global("document").call("addEventListener", .{ zjb.constString("keydown"), zjb.fnHandle("keydownCallback", &keydownCallback) }, void);

logStr("\n============================= Handle vs ConstHandle =============================");
{
Expand Down Expand Up @@ -180,9 +180,9 @@ fn setTestVar() callconv(.C) f32 {
}

comptime {
zjb.exportFn("incrementAndGet", incrementAndGet);
zjb.exportFn("incrementAndGet", &incrementAndGet);

zjb.exportGlobal("test_var", &test_var);
zjb.exportFn("checkTestVar", checkTestVar);
zjb.exportFn("setTestVar", setTestVar);
zjb.exportFn("checkTestVar", &checkTestVar);
zjb.exportFn("setTestVar", &setTestVar);
}
13 changes: 6 additions & 7 deletions simple/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,21 @@ pub fn build(b: *std.Build) void {
const optimize = b.standardOptimizeOption(.{});
const dir = std.Build.InstallDir.bin;

const zjb = b.dependency("zjb", .{});

const simple = b.addExecutable(.{
.name = "simple",
.root_source_file = b.path("src/simple.zig"),
.target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }),
.optimize = optimize,
});
simple.root_module.addImport("zjb", zjb.module("zjb"));
simple.entry = .disabled;
simple.rdynamic = true;

const extract_simple = b.addRunArtifact(zjb.artifact("generate_js"));
const extract_simple_out = extract_simple.addOutputFileArg("zjb_extract.js");
extract_simple.addArg("Zjb"); // Name of js class.
extract_simple.addArtifactArg(simple);
const zjb = b.dependency("zjb", .{
.@"wasm-bindgen-bin" = simple.getEmittedBin(),
});
const extract_simple_out = zjb.namedLazyPath("zjb_extract.js");

simple.root_module.addImport("zjb", zjb.module("zjb"));

const simple_step = b.step("simple", "Build the hello Zig example");
simple_step.dependOn(&b.addInstallArtifact(simple, .{
Expand Down
16 changes: 15 additions & 1 deletion src/generate_js.zig
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,17 @@ pub fn main() !void {
const args = try std.process.argsAlloc(alloc);
defer std.process.argsFree(alloc, args);

if (args.len != 4) {
if (args.len != 5) {
return ExtractError.BadArguments;
}

const is_module = if (std.mem.eql(u8, args[4], "true"))
true
else if (std.mem.eql(u8, args[4], "false"))
false
else
return ExtractError.ExpectedBoolArgument;

var importFunctions = std.ArrayList([]const u8).init(alloc);
defer importFunctions.deinit();
var exportFunctions = std.ArrayList([]const u8).init(alloc);
Expand Down Expand Up @@ -91,6 +98,7 @@ pub fn main() !void {
defer out_file.close();
const writer = out_file.writer();

try writer.writeAll("\"use strict\";\n");
try writer.writeAll("const ");
try writer.writeAll(args[2]);
try writer.writeAll(
Expand Down Expand Up @@ -457,6 +465,11 @@ pub fn main() !void {

try writer.writeAll("};\n"); // end class

if (is_module) {
try writer.writeAll("export { ");
try writer.writeAll(args[2]);
try writer.writeAll(" };\n");
}
std.sort.insertion([]const u8, export_names.items, {}, strBefore);
if (export_names.items.len > 1) {
for (0..export_names.items.len - 1) |i| {
Expand Down Expand Up @@ -529,6 +542,7 @@ const ExtractError = error{
WasmWrongVersion,
ImportTypeNotSupported,
InvalidExportedName,
ExpectedBoolArgument,
};

fn strBefore(_: void, lhs: []const u8, rhs: []const u8) bool {
Expand Down
8 changes: 4 additions & 4 deletions src/zjb.zig
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ pub fn exportGlobal(comptime name: []const u8, comptime value: anytype) void {

pub fn exportFn(comptime name: []const u8, comptime f: anytype) void {
comptime var export_name: []const u8 = "zjb_fn_";
const type_info = @typeInfo(@TypeOf(f)).Fn;
const type_info = @typeInfo(@typeInfo(@TypeOf(f)).pointer.child).@"fn";
validateToJavascriptReturnType(type_info.return_type orelse void);
inline for (type_info.params) |param| {
validateFromJavascriptArgumentType(param.type orelse void);
Expand Down Expand Up @@ -104,7 +104,7 @@ pub fn u8ClampedArrayView(data: []const u8) Handle {

pub fn dataView(data: anytype) Handle {
switch (@typeInfo(@TypeOf(data))) {
.Pointer => |ptr| {
.pointer => |ptr| {
if (ptr.size == .One) {
return zjb.dataview(data, @sizeOf(ptr.child));
} else if (ptr.size == .Slice) {
Expand Down Expand Up @@ -227,7 +227,7 @@ pub const Handle = enum(i32) {

fn invoke(handle: Handle, args: anytype, comptime RetType: type, comptime prefix: []const u8, comptime suffix: []const u8) RetType {
validateFromJavascriptReturnType(RetType);
const fields = comptime @typeInfo(@TypeOf(args)).Struct.fields;
const fields = comptime @typeInfo(@TypeOf(args)).@"struct".fields;
comptime var call_params: [fields.len + 1]std.builtin.Type.Fn.Param = undefined;
comptime var extern_name: []const u8 = prefix;

Expand All @@ -247,7 +247,7 @@ pub const Handle = enum(i32) {
extern_name = extern_name ++ comptime shortTypeName(field.type);
}

const F = @Type(.{ .Fn = .{
const F = @Type(.{ .@"fn" = .{
.calling_convention = .C,
.is_generic = false,
.is_var_args = false,
Expand Down