Equivalent of C's __DATE__ and __TIME__ macros?

Is there a way to get a string with a timestamp of when my executable was built, like __DATE__ and __TIME__ in C?

Use case: I’m making a tool that takes input files and generates output files. It exits early if it detects that the modification time of the output file is greater than the modification time of the input file (since the output file is up-to-date). I want to add a similar check where it knows to rebuild the output file if the tool itself was modified since the output file was generated.

I guess I could open the executable itself and get the modification time, the same way I’m getting the modification time of the output file, but that’s still not technically the same thing as the build time.

1 Like

You probably can do something inside build.zig where you add an options module, get the current time inside build.zig and copy it into the generated options module. Something along the lines of:

const build_options = b.addOptions();
build_options.addOption(
        64,
        "timestamp",
        std.time.timestamp(),
    );

your_cli.addModule("build_options", build_options.createModule());

and inside your application:

const build = @import("build_options");
const build_time = build.timestamp;

I haven’t tested this precise scenario, but I use this exact method to copy boolean flags passed to zig build into a build_options module for conditional compilation, and what is an i64 if not a more complicated boolean?

edit: Just to confirm, I just ran this code and as expected, it baked pub const timestamp: i64 = 1698679928; into the options module, so you can use it to re-implement __DATE__ and __TIME__.

5 Likes

Another solution.
At first build-time, generation dummy file in zig-cache folder. (dummy file timestamp equals build-timestamp)
At next build-time, timestamp of dummy file is compared with timestamp of input file.
if timestamp of input file is greater, input file will be rebuild and update dummy file timestamp.

Another another solution.
I’ve recommend to record hash-value calculating from input-file contents in dummy file.
At next build-time, generated hash-value is compared with hash-value from calculating input-file contents.
if hash-value changed, it will rebuild and update hash-value.
Advantage of calculating hash-value is able to avoid changing file timestamp only.

This is used for zig-lang package management.
More details, see zig/src/Package/Fetch.zig

In the zig.build file, create a dependency between the output file and the tool. The cache system will handle the rest, no need for __DATE__ and __TIME__.

// The tool you are building
const tool = builder.addExecutable(.{ 
  // options here
});

const run_cmd = builder.addRunArtifact(tool);
run_cmd.addFileArg(
  // The input file
);

run_cmd is the command that will run your program. It depends both on tool, which is the act of compiling the tool, and on the input file.

2 Likes

You seem to have read my mind and saw where I was going with this.

I’m coming from an XNA/MonoGame background, so I’m used to setting my folder structure up something like this:

root\
  content\ - contains all un-processed assets
    content.contentproj - contains instructions for building assets; references customPipelineProcessor1/processor1.csproj and customPipelineProcessor2\processor2.csproj
  game\ - contains all source for the game itself
    game.csproj
  customPipelineProcessor1\ - tool used to process a specific asset type within the "content" folder
    processor1.csproj
  customPipelineProcessor2\ - ditto
    processor2.csproj

Is there a way that I have have a build.zig file inside root/content that references exes defined in build.zig files inside root/customPipelineProcessor1 and root/customPipelineProcessor2? Or does customPipelineProcessor1 and customPipelineProcessor2 have to be a subfolder of content? Because right now I’m getting “import of file outside module path” errors.

1 Like

I see, the problem you’re having is that you split the build.zig into many build.zig. I tried this a while ago, but felt that zig was constantly pushing me toward using a single zig.build, which is what I do now. It’s been working really well for me.
I suggest moving everything to a root folder build.zig, where you build all the intermediary tools that you need. If re-architecting you program to adopt a single zig.build is inadequate for you, I suggest looking into the package manager, that uses .zon files. I don’t use it because I’ve been waiting for the system to mature a bit, but I believe it is desgned to be able to merge muitiple build.zig projects.

1 Like

Support for relative paths in the build .zon file was recently added allowing for package support in a monorepo. It’s definitely being actively developed, but if you can deal with that instability it should be good to go for this structure.

2 Likes