Can you locate and copy dependency files specified in .zon files?

I have been trying to use raylib with raygui in a project, and raylib actually has a build.zig file and there is plenty of examples of this working fine as a static library or as a zig module (incorrect terminology?), but the way raygui works (its a separate repo with no build.zig file) is that in raylib if you specify the option for raygui it expects you to already have the raygui.h file in a location that zig can just find. and if you try to instead just have both repos as dependencys that you use both as c librarys that you static link, it doesn’t work because raygui itself relys on raylib and so you get a bunch of undefined issues for raygui at build time.

I would really like my project to be completely stand alone and be able to built from source and contain everything needed for raylib and raygui to work. So with that context, what i’ve been trying to do is with raygui as a dependency to the project, it downloads the repo and puts it in the .cache/zig/p/ directory, with the hash as the folder name as expected, but i need to copy the header file from the src directory and put it into the same location as where the raylib dependency gets downloaded, But i can’t find a way to get the abs path of the dependency cache, and then my next problem would be how to copy the file anyway.

So before i spend more time trying to get this to work, i’ve been trying to find resources to know if this is even possible, or if this is just really a bad idea. Going into this given how easily it is to pull in a c library into your project and static link to your zig module, i thought it would be no problem. But i guess i’ve mostly been struggling with how to handle two different c libraries that rely on each other.

Any information would be greatly appreciated. If you wish to see the code, here is the link to the repo

https://gitlab.pavocracy.dev/personal-projects/raylib-and-raygui-in-zig

1 Like

Now I have never worked with raylib or raygui, but I think I know what you can do:
In your build.zig you probably already have something like this:

const raylib = b.dependency("raylib", .{
	.target = target,
	.optimize = optimize,
});

Then you can get the path of the raylib.h file like this: raylib.path("src/raylib.h")
(Note: This requires a 0.12.0-dev version)
Now assuming that raygui gets the raylib.h file from the include path, you can just add this as an include directory:

exe_or_lib.addIncludePath(raylib.path("src"));
2 Likes

I do have that! i will try that now.

Oh right, im already doing that? line 59 of build.zig

https://gitlab.pavocracy.dev/personal-projects/raylib-and-raygui-in-zig/-/blob/main/build.zig?ref_type=heads#L59

1 Like

I took a closer look at your project and I think the way you are handling that C file is not really a good solution. Currently you are generating a new file and passing that to the addStaticLibrary command:

-    const generate_raygui_c = b.addWriteFiles();
-    const generated_file = generate_raygui_c.add("src/raygui.c", "#define RAYGUI_IMPLEMENTATION\n#define RAYGUI_STANDALONE\n#include \"raygui.h\"\n");
     // Since this repo doesn't have a build.zig, we will add it as a static library to link to the exe
     const raygui_lib = b.addStaticLibrary(.{
         .name = "raygui",
-        .root_source_file = generated_file,
         .link_libc = true,
         .optimize = optimize,
         .target = target,
     });
-    raygui_lib.step.dependOn(&generate_raygui_c.step);

But a better solution would to use addCSourceFile, passing the defines as command line arguments:

     raygui_lib.addIncludePath(raygui_package.path("src/"));
     raygui_lib.addIncludePath(raylib_package.path("src/"));
+    raygui_lib.addCSourceFile(.{ .file = raygui_package.path("src/raygui.h"), .flags = &[_][]const u8 {"-DRAYGUI_IMPLEMENTATION"}});
     raygui_lib.linkLibrary(raylib_artifact); // raygui depends on raylib

Note that I removed the RAYGUI_STANDALONE flag, which may have been the root issue.
That flag prevents raygui.h from including raylib.h which was probably the cause for the missing symbols.

Apart from that you also need to add the include path to the executable:

+    exe.addIncludePath(raygui_package.path("src/"));
+    exe.addIncludePath(raylib_package.path("src/"));

And you need to change the cImport, given that raygui automatically include raylib:

const rl = @cImport({
    @cInclude("raygui.h");
    @cInclude("raymath.h");
    @cInclude("rlgl.h");
});

Oh and you also messed up the capitalization of all raylib functions in your main.zig.

6 Likes

So first of all, just let me say thank you so much for looking at my project so deeply. You have truly gone above and beyond and i can’t state how much i appreciate that!

Secondly, i can confirm that following your code changes fixes my problems and it all works :smiley: amazing!

So now the onus is on me to properly understand what all my different problems were and how your changes fixes those issues. I guess adding the include path to the exe is the main confusing part to me. This whole project (trying to build a game in zig with a library im familiar with) was very much an exercise to learn the zig syntax, but also the zig build system. I know the package manager is new and is still changing and there is accepted proposals around those changes ect, But i think much of my confusion comes from not understanding the difference between the zig-cache in the project, and the .cache/zig/p of the package manager, and how adding dependencys works in the build file and then what those .path() calls refer to and when its all packaged together the kind of structure that is underneath it all at the end.

but all of that is just to say, that i really appreciate your help and you have absolutely solved my immediate problems, and now i will continue trying to understand everything you have fixed for me :slight_smile:

4 Likes

also just as an FYI if you were curious, there is one error spat out by the compiler (although like i said, it does build, and it does open a raylib window as expected :slight_smile: )

pavocracy@minty:~/git/personal/raylib-and-raygui-in-zig$ zig build run
zig build-exe raylib-and-raygui-example Debug native: error: warning(link): unexpected LLD stderr:
ld.lld: warning: /home/pavocracy/git/personal/raylib-and-raygui-in-zig/zig-cache/o/eadfe1c065605f630e207cdfd3c99af0/libraygui.a: archive member '/home/pavocracy/git/personal/raylib-and-raygui-in-zig/zig-cache/o/61ad4c570efaebecd69f60ea923c6a4d/raygui.o' is neither ET_REL nor LLVM bitcode

Is this because of the way you suggested handling the implementation for raygui? I don’t really understand this error, other than it seems like its compiling the generated c file to a .o output file, and then because thats in the src/ directory its getting passed to the zig compiler which doesn’t like it? am i on the right track here?

1 Like

I guess adding the include path to the exe is the main confusing part to me.

You are including raygui.h in the main.zig, which is part of your exe.
So in order for the compiler to find it, it needs to be on the include path.

there is one error spat out by the compiler

I have no idea what’s up with that. I’ve never seen it before. It only is a warning though.

1 Like

Hey, I’d be interested in this setup as well.
Thanks a lot for taking a stab at it.

I’ve cloned your repository and tried zig build run, but with neither 0.11.0 nor 0.12.dev it works for me.
With 0.11.0 it spits out an error

zig build run
warning: FileNotFound: /Users/lklein/.cache/zig/p/122005a45aa0cf025fd0e72f3f3ec9b8c738cc86c52cb32d72d334035acdcee1c726/build.zig
error: FileNotFound

And with 0.12.dev it’s:

/Users/lklein/.cache/zig/p/1220bd9c983d89fa08ecfcec29f5e35887dd023ab99b98845be6e929989f71ee661b/src/build.zig:23:11: error: member function expected 1 argument(s), found 2
    raylib.addCSourceFiles(&.{
    ~~~~~~^~~~~~~~~~~~~~~~
/Users/lklein/programs/zig-macos-aarch64-0.12.0-dev.926+3be8490d8/lib/std/Build/Step/Compile.zig:937:5: note: function declared here
pub fn addCSourceFiles(self: *Compile, options: AddCSourceFilesOptions) void {
~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
referenced by:
    build: /Users/lklein/.cache/zig/p/1220bd9c983d89fa08ecfcec29f5e35887dd023ab99b98845be6e929989f71ee661b/src/build.zig:193:17
    build: /Users/lklein/.cache/zig/p/1220bd9c983d89fa08ecfcec29f5e35887dd023ab99b98845be6e929989f71ee661b/build.zig:6:11
    remaining reference traces hidden; use '-freference-trace' to see all reference traces

As far as I can see, the second error is raylibs own build.zig. And after reading up on that, they don’t seem to use zig master and instead rely on 0.11.0.
So an incompatible syntax makes sense.

But then does that mean that using raylib locks the codebase into zig 0.11.0?

Well, regarding the first error, that’s on raygui and it seems to complain that there’s no build.zig – fair enough, since there isn’t.
Looking at your build.zig you do say that this has to be linked manually.
But it surprises me that this error message is triggered here, then.

@pavocracy If you’ve made progress on this it would be great if you could share it.

The main problem here is that 0.11 doesn’t support depending on packages without a build.zig
However the newest 0.12-dev release made some changes to the addCSourceFiles function, making raylib unusable.
Possible solutions are:
Either you can use an older 0.12-dev release, like 0.12.0-dev.706+62a0fbdae. The downloads are still up on ziglang.org, but only accessible through a direct link:
windows x86_64
linux x86_64

Or you can try to use raylib as if it had no build.zig. But that would require you to copy all the stuff from their build.zig file into your own and adjust it to use the package paths.

2 Likes

Sorry about that! I did not push up the changes IntegratedQuantum suggested that fixes the problem to the repo.

I have done that now. If you do a git fetch and git pull from the repo you should get the commit that works for me. As i put in the readme, it works for my machine using the version of zig i have installed. so YMMV still.

It looks like IntegratedQuantum has also provided feedback on your specific issue where the latest dev version of zig has changed the function signature for adding the c file. But im confident if you pull down the latest commit of my repo and fix that specific function call it should also work for you!

Please do let us know how you go.

1 Like

@pavocracy that sounds great.
Could you do zig version and post the results?

Its also in the readme FYI, but just to be explicit its: 0.12.0-dev.817+54e7f58fc

1 Like

Hm, using zig 0.12.0-dev.926+3be8490d8
gives me an error for the build.zig.zon:

/Users/lklein/Documents/programming/raylib-and-raygui-in-zig/build.zig.zon:1:2: 
error: missing top-level 'paths' field
.{

@pavocracy is it possible that this wasn’t added in the last commit?
It’s still 3 days old.

Ah sorry, somehow I overlooked the feedback that IntegratedQuantum gave:
The newest version of zig 0.12 introduces an incompatibility.
I was somehow still under the assumption that there’s two settings: 0.11 and 0.12 and one of them should work.
But your repo compiles with an older version of 0.12 than what I have on my system.

Thanks a lot for putting this together!
It’s very helpful

1 Like

The build.zig.zon error looks like the package manager has also changed in the latest dev version of zig. I will have to look into that.

In general i guess this is the risk of using the dev versions of zig, its a fast moving language! (which is great, but also hard to keep up :slight_smile: )

Hopefully the build.zig file in my repo is commented well enough to give the general idea of how to manage a c dependency with a zig dependency though. I think long term, it would be much better if raylib implements some way to enable raygui without having to provide the header file by the user (and in a specific location).

Also the community does have multiple zig bindings for raylib and there is also a zig binding for raygui, which i know currently has an issue open to supporting the package manager. And so that fact that these are options is also great.

But as i mentioned in the original post, this whole exercise for me personally was about getting this to work in a way that has zero input from the user, and everything using the package manager, and was also about learning the build system and trying to peek slightly under the hood (which is what the title refers to about understanding how to manipulate dependency file locations ect). But i suspect this example repo will be unnecessary as zig continues to move forward and as the upstream libraries also change, particularly raylib as it seems very onboard with supporting the zig build system.

1 Like

Your code has definitely been a huge help for me.
Thank you so much.

The way these puzzle pieces fit into each other wasn’t at all clear to me. And the zig build system is a bit overwhelming.

But from reading your code, I understood that the raylib build.zig actually has a mechanism for including the various add-in modules (like raygui).
And your comments made it clear what the correct path structure is.

What I ended up doing is:

  • adding raylib and raygui as submodules in git
  • use zig 0.11.0
  • rely on the raylib build.zig to set everything up

I’ve put it all in a git repo (not my code, just patching things together from various sources):

Now, this seems to work.
Zig LSP is even smart enough to provide autocomplete.

@pavocracy, @IntegratedQuantum thanks so much :slight_smile:
Now I got a raylib + raygui setup which works (well, seems to so far. I’ve created a small demo with some raylib shape drawing and a raygui checkbox).
That will be fun for tinkering and learning zig.

3 Likes

Yeah i think submodules are probably the next cleanest way to do it after the zig package manager. That makes alot of sense to do it that way when you are using the optional raygui flag as part of the raylib build.zig.

Very cool! thanks for sharing your repo too, it helps me solidify all the different pieces too and understand the different approaches to the same desired result :smiley:

1 Like