summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarijn Besseling <njirambem@gmail.com>2026-03-18 15:10:02 +0100
committerMarijn Besseling <njirambem@gmail.com>2026-03-18 15:10:02 +0100
commitf4911a77f4c94faf344a1dd46ed7a8011cac2c48 (patch)
treecc6d73eebdf526a99b62c7e29f538e44e7174c1d
launch launch
-rw-r--r--.gitignore2
-rw-r--r--build.zig138
-rw-r--r--build.zig.zon81
-rw-r--r--src/main.zig35
4 files changed, 256 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7c046b6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
1.zig-cache
2zig-out \ No newline at end of file
diff --git a/build.zig b/build.zig
new file mode 100644
index 0000000..593ccee
--- /dev/null
+++ b/build.zig
@@ -0,0 +1,138 @@
1const std = @import("std");
2
3// Although this function looks imperative, it does not perform the build
4// directly and instead it mutates the build graph (`b`) that will be then
5// executed by an external runner. The functions in `std.Build` implement a DSL
6// for defining build steps and express dependencies between them, allowing the
7// build runner to parallelize the build automatically (and the cache system to
8// know when a step doesn't need to be re-run).
9pub fn build(b: *std.Build) void {
10 const exe_name = b.option([]const u8, "exe-name", "Name of the resulting executable");
11
12 // Standard target options allow the person running `zig build` to choose
13 // what target to build for. Here we do not override the defaults, which
14 // means any target is allowed, and the default is native. Other options
15 // for restricting supported target set are available.
16 const target = b.standardTargetOptions(.{});
17 // Standard optimization options allow the person running `zig build` to select
18 // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
19 // set a preferred release mode, allowing the user to decide how to optimize.
20 const optimize = b.standardOptimizeOption(.{});
21 // It's also possible to define more custom flags to toggle optional features
22 // of this build script using `b.option()`. All defined flags (including
23 // target and optimize options) will be listed when running `zig build --help`
24 // in this directory.
25
26 // Here we define an executable. An executable needs to have a root module
27 // which needs to expose a `main` function. While we could add a main function
28 // to the module defined above, it's sometimes preferable to split business
29 // logic and the CLI into two separate modules.
30 //
31 // If your goal is to create a Zig library for others to use, consider if
32 // it might benefit from also exposing a CLI tool. A parser library for a
33 // data serialization format could also bundle a CLI syntax checker, for example.
34 //
35 // If instead your goal is to create an executable, consider if users might
36 // be interested in also being able to embed the core functionality of your
37 // program in their own executable in order to avoid the overhead involved in
38 // subprocessing your CLI tool.
39 //
40 // If neither case applies to you, feel free to delete the declaration you
41 // don't need and to put everything under a single module.
42 const exe = b.addExecutable(.{
43 .name = if (exe_name) |name| name else "launch",
44 .root_module = b.createModule(.{
45 // b.createModule defines a new module just like b.addModule but,
46 // unlike b.addModule, it does not expose the module to consumers of
47 // this package, which is why in this case we don't have to give it a name.
48 .root_source_file = b.path("src/main.zig"),
49 // Target and optimization levels must be explicitly wired in when
50 // defining an executable or library (in the root module), and you
51 // can also hardcode a specific target for an executable or library
52 // definition if desireable (e.g. firmware for embedded devices).
53 .target = target,
54 .optimize = optimize,
55 // List of modules available for import in source files part of the
56 // root module.
57 .imports = &.{
58 // Here "launch" is the name you will use in your source code to
59 // import this module (e.g. `@import("launch")`). The name is
60 // repeated because you are allowed to rename your imports, which
61 // can be extremely useful in case of collisions (which can happen
62 // importing modules from different packages).
63 // .{ .name = "launch", .module = mod },
64 },
65 }),
66 });
67
68 // This declares intent for the executable to be installed into the
69 // install prefix when running `zig build` (i.e. when executing the default
70 // step). By default the install prefix is `zig-out/` but can be overridden
71 // by passing `--prefix` or `-p`.
72 b.installArtifact(exe);
73
74 // This creates a top level step. Top level steps have a name and can be
75 // invoked by name when running `zig build` (e.g. `zig build run`).
76 // This will evaluate the `run` step rather than the default step.
77 // For a top level step to actually do something, it must depend on other
78 // steps (e.g. a Run step, as we will see in a moment).
79 const run_step = b.step("run", "Run the app");
80
81 // This creates a RunArtifact step in the build graph. A RunArtifact step
82 // invokes an executable compiled by Zig. Steps will only be executed by the
83 // runner if invoked directly by the user (in the case of top level steps)
84 // or if another step depends on it, so it's up to you to define when and
85 // how this Run step will be executed. In our case we want to run it when
86 // the user runs `zig build run`, so we create a dependency link.
87 const run_cmd = b.addRunArtifact(exe);
88 run_step.dependOn(&run_cmd.step);
89
90 // By making the run step depend on the default step, it will be run from the
91 // installation directory rather than directly from within the cache directory.
92 run_cmd.step.dependOn(b.getInstallStep());
93
94 // This allows the user to pass arguments to the application in the build
95 // command itself, like this: `zig build run -- arg1 arg2 etc`
96 if (b.args) |args| {
97 run_cmd.addArgs(args);
98 }
99
100 // Creates an executable that will run `test` blocks from the provided module.
101 // Here `mod` needs to define a target, which is why earlier we made sure to
102 // set the releative field.
103 // const mod_tests = b.addTest(.{
104 // .root_module = mod,
105 // });
106
107 // A run step that will run the test executable.
108 // const run_mod_tests = b.addRunArtifact(mod_tests);
109
110 // Creates an executable that will run `test` blocks from the executable's
111 // root module. Note that test executables only test one module at a time,
112 // hence why we have to create two separate ones.
113 const exe_tests = b.addTest(.{
114 .root_module = exe.root_module,
115 });
116
117 // A run step that will run the second test executable.
118 const run_exe_tests = b.addRunArtifact(exe_tests);
119
120 // A top level step for running all tests. dependOn can be called multiple
121 // times and since the two run steps do not depend on one another, this will
122 // make the two of them run in parallel.
123 const test_step = b.step("test", "Run tests");
124 // test_step.dependOn(&run_mod_tests.step);
125 test_step.dependOn(&run_exe_tests.step);
126
127 // Just like flags, top level steps are also listed in the `--help` menu.
128 //
129 // The Zig build system is entirely implemented in userland, which means
130 // that it cannot hook into private compiler APIs. All compilation work
131 // orchestrated by the build system will result in other Zig compiler
132 // subcommands being invoked with the right flags defined. You can observe
133 // these invocations when one fails (or you pass a flag to increase
134 // verbosity) to validate assumptions and diagnose problems.
135 //
136 // Lastly, the Zig build system is relatively simple and self-contained,
137 // and reading its source code will allow you to master it.
138}
diff --git a/build.zig.zon b/build.zig.zon
new file mode 100644
index 0000000..d6927c3
--- /dev/null
+++ b/build.zig.zon
@@ -0,0 +1,81 @@
1.{
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.
9 .name = .launch,
10 // This is a [Semantic Version](https://semver.org/).
11 // In a future version of Zig it will be used for package deduplication.
12 .version = "0.0.0",
13 // Together with name, this represents a globally unique package
14 // identifier. This field is generated by the Zig toolchain when the
15 // package is first created, and then *never changes*. This allows
16 // unambiguous detection of one package being an updated version of
17 // another.
18 //
19 // When forking a Zig project, this id should be regenerated (delete the
20 // field and run `zig build`) if the upstream project is still maintained.
21 // Otherwise, the fork is *hostile*, attempting to take control over the
22 // original project's identity. Thus it is recommended to leave the comment
23 // on the following line intact, so that it shows up in code reviews that
24 // modify the field.
25 .fingerprint = 0x79b757f596682a9a, // Changing this has security and trust implications.
26 // Tracks the earliest Zig version that the package considers to be a
27 // supported use case.
28 .minimum_zig_version = "0.16.0-dev.2905+5d71e3051",
29 // This field is optional.
30 // Each dependency must either provide a `url` and `hash`, or a `path`.
31 // `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
32 // Once all dependencies are fetched, `zig build` no longer requires
33 // internet connectivity.
34 .dependencies = .{
35 // See `zig fetch --save <url>` for a command-line interface for adding dependencies.
36 //.example = .{
37 // // When updating this field to a new URL, be sure to delete the corresponding
38 // // `hash`, otherwise you are communicating that you expect to find the old hash at
39 // // the new URL. If the contents of a URL change this will result in a hash mismatch
40 // // which will prevent zig from using it.
41 // .url = "https://example.com/foo.tar.gz",
42 //
43 // // This is computed from the file contents of the directory of files that is
44 // // obtained after fetching `url` and applying the inclusion rules given by
45 // // `paths`.
46 // //
47 // // This field is the source of truth; packages do not come from a `url`; they
48 // // come from a `hash`. `url` is just one of many possible mirrors for how to
49 // // obtain a package matching this `hash`.
50 // //
51 // // Uses the [multihash](https://multiformats.io/multihash/) format.
52 // .hash = "...",
53 //
54 // // When this is provided, the package is found in a directory relative to the
55 // // build root. In this case the package's hash is irrelevant and therefore not
56 // // computed. This field and `url` are mutually exclusive.
57 // .path = "foo",
58 //
59 // // When this is set to `true`, a package is declared to be lazily
60 // // fetched. This makes the dependency only get fetched if it is
61 // // actually used.
62 // .lazy = false,
63 //},
64 },
65 // Specifies the set of files and directories that are included in this package.
66 // Only files and directories listed here are included in the `hash` that
67 // is computed for this package. Only files listed here will remain on disk
68 // when using the zig package manager. As a rule of thumb, one should list
69 // files required for compilation plus any license(s).
70 // Paths are relative to the build root. Use the empty string (`""`) to refer to
71 // the build root itself.
72 // A directory listed here means that all files within, recursively, are included.
73 .paths = .{
74 "build.zig",
75 "build.zig.zon",
76 "src",
77 // For example...
78 //"LICENSE",
79 //"README.md",
80 },
81}
diff --git a/src/main.zig b/src/main.zig
new file mode 100644
index 0000000..1b3b689
--- /dev/null
+++ b/src/main.zig
@@ -0,0 +1,35 @@
1const std = @import("std");
2const Io = std.Io;
3
4pub fn main(init: std.process.Init) !void {
5 // This is appropriate for anything that lives as long as the process.
6 const arena: std.mem.Allocator = init.arena.allocator();
7
8 // Accessing command line arguments:
9 const args = try init.minimal.args.toSlice(arena);
10 const filepath = args[0];
11 const filename = std.fs.path.basename(filepath);
12
13 std.log.debug("executable name: {s}", .{filename});
14
15 const io = init.io;
16 var words = try tokenizeIntoArraylist(arena, filename);
17
18 const command = try words.toOwnedSlice(arena);
19
20 return std.process.replace(io, .{
21 .argv = command,
22 });
23}
24
25fn tokenizeIntoArraylist(gpa: std.mem.Allocator, buffer: []const u8) !std.ArrayList([]const u8) {
26 var it = std.mem.tokenizeScalar(u8, buffer, ' ');
27
28 var words = std.ArrayList([]const u8).empty;
29
30 while (it.next()) |word| {
31 try words.append(gpa, word);
32 }
33
34 return words;
35}