Factoring out a structure into a file of its own

In zigclc I had a struct Releases in main.zig which had grown to the point where I wanted to factor it out, including its sub types, to a separate file. The following steps document what I did (for Releases, replace that name everywhere with the object of your refactoring), and might help you if you are in the same situation, especially the first time around. There are likely other ways to go about this and steps that can be combined, but this worked for me.

The zigclc project is build with build.zig and zig build. If you use zig build-exe you can still factor out a file and use the first few steps, but you will have to stop as indicated below.

Running zig build --watch --error-style verbose_clear or zig build test --watch --error-style verbose_clear helps continously checking on compilability (mind the underscore in verbose_clear)

  • start with compiling and working code

  • make sure you can roll back any changes: check your code into your VCS and/or use an editor that can revert changes from before saving a file

  • clean up the internal dependencies within main.zig. If some function or other struct is referenced both from Releases’ functions as well as from other parts of main.zig, you may want to factor those out first, if they are not going to reside in the new file along with Releases.

  • decide on the new file name, keeping in mind the recommended file naming conventions:

    If the file (implicitly a struct) has top level fields, it should be named like any other struct with fields using TitleCase

    since I am factoring out a struct Releases, the filename should be Releases.zig

  • cut the code for the Releases struct, including any other code (structs, fns, etc) it depends on from main.zig

  • paste the cut code in Releases.zig and save

  • insert const Releases = @import("Releases.zig").Releases; into your main.zig

  • save, and if you get errors, because of stuff missing from Releases.zig like missing const std = @import("std"); and derivatives such as const Io = std.Io; add those to Releases.zig

  • add pub to anything in Releases.zig the compiler complains about: if missing, add it to const Releases = struct itself, and any functions (init(), deinit(), etc.) used from main.zig

  • add other lines like const SomeStruct = @import("Releases.zig").SomeStruct;, and const some_fun = @import("Releases.zig").some_fun;, to main.zig, if appropriate, to get everything to compile again

  • when things compile (and test and run) as expected, commit the changes

  • in Releases.zig at the top of the file add const Releases = @This(); and an empty line following it (so it stands out), remove the line const Releases = struct { and the line with the corresponding closing }; (leave the lines in between as is even if they are indented.); save the file

  • in main.zig remove the .Releases from const Releases = @import("Releases.zig").Releases; (i.e. make it const Releases = @import("Releases.zig");). Save main.zigand everything should compile again.

  • If you have additional imports from Releases.zig in main.zig you can change them, e.g. from const SomeStruct = @import("Releases.zig").SomeStruct; to const SomeStruct = Releases.SomeStruct;

  • Things should compile (again), so commit.

This is as far as you can go when you use zig build-exe, if you use zig build you can make
Releases.zig into a separately compiled module:

  • In main.zig change const Releases = @import("Releases.zig"); to const Releases = @import("Releases"); and save. This will get you a no module named 'Releases' error.
  • In build.zig to the fn build() body:
  const Releases = b.addModule("Releases", .{
      .root_source_file = b.path("src/Releases.zig"),
  });

and to .imports in b.createModule(.{ })

              .{ .name = "Releases", .module = Releases },

( the name after const and .module have to be the same, but don’t necessarily have to be Releases).

  • Save build.zig, and if you are running zig build --watchrestart it, as it doesn't do so onbuild.zig` changes.
  • Everything should compile again, commit.
2 Likes