ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
32.16k stars 2.35k forks source link

Get pacman.zig on the Package Manager #16711

Open floooh opened 11 months ago

floooh commented 11 months ago

On @andrewrk's suggestion, I'm opening a similar ticket like https://github.com/ziglang/zig/issues/16672 to document and track the hickups I encountered when bringing https://github.com/floooh/sokol-zig as package into https://github.com/floooh/pacman.zig.

(NOTE: the package manager support is currently in branches:

It might make sense to split this issue into more detailed issues later.

Some background info:

Currently (without package manager integration) sokol-zig can be integrated in two ways:

With the package manager integration it now works like this (but this was quite a bit of trial and error):

(writing this I guess it would be nice if I could add a linker dependency to a module, so that I only need to expose the Zig module, which would have a dependency on the C library, so that a project would only need to get the Zig module from the dependency, and this would automatically add a library dependency to the top-level project - but this would currently not work with the way I'm handling the web build).

Communicating build parameters to package manager dependencies

I stumbled over two problems:

Some confusion about using dependency build.zig as import

I had a little detour when I thought that I'm stuck, and imported the dependency's build zig as module (great feature!).

But calling functions in the import also caused some confusion, but I think this just needs to be documented.

wasm32-freestanding vs wasm32-emscripten

This is a known issue: currently I can't compile the Zig part of pacman.zig with the wasm32-emscripten target because of a problem in the Zig stdlib (see here: https://github.com/ziglang/zig/issues/10836#issuecomment-1666488896), this means I need to "patch" the platform .emscripten into the CrossTarget when building the sokol-zig C library (because the C code depends on Emscripten SDK featurs). This means that the Zig parts of the project need to be built with wasm32-freestanding and the C parts as wasm32-emscripten (which works, but feels kinda weird).

Need to provide C include directory on top of Emscripten sysroot

This might be a simple bug, but I noticed that in order for the C compilation to work, I need to provide a separate header search path derived from the sysroot so that the C stdlib headers are found:

https://github.com/floooh/sokol-zig/blob/24a47f10231e45875452a110aacb78aa1a8e9648/build.zig#L110-L112

Without this, common headers like stdlib.h, string.h etc are not found in the C compile step.

Suggestion: given a sysroot path, the header and library search paths should be setup automatically for C compilation.

Suggestion: better integration of external linkers (like the Emscripten linker)

As I described above, the C code of sokol-zig depends on Emscripten platform features (embedding Javascript code into C source files, and using Emscripten specific headers). For the compilation part this works fine with the Zig compiler by using the wasm32-emscripten target, and providing a sysroot which points into the Emscripten SDK, but in the end I need to use the Emscripten linker to get a runnable web build (.html + .js + .wasm files).

Currently I create a system command build step to invoke the Emscripten linker like this: https://github.com/floooh/pacman.zig/blob/b26f4f258ee0aa9889098973edc40df04471d9fc/build.zig#L106-L130

It took a while to figure this out, and it's a bit awkward mainly because I need to make all build outputs available as installed artifacts before the Emscripten linker is called, and I need to make sure that all dependencies are setup correctly.

Maybe it makes sense to provide a ExternalLinkerStep wrapper for "gcc toolchain compatible linkers" which at least takes care of the dependency setup, and adds the build outputs as -l....

Emscripten Integration Wishlist

The following are some ideas for the future, and with the package manager infrastructure I think this doesn't need to be part of the Zig core project:

...ideally this would be coordinated with other "SDK/toolchain packages", like:

build.zig.zon wishlist

It would be nice if I could directly use a git-url and git-ref to provide the package content (.tar.gz for any git commit works via "github magic", but it looks a bit messy):

https://github.com/floooh/pacman.zig/blob/sokol-package/build.zig.zon

This is because sokol-zig doesn't have "semver release tags" so far, they are updated automatically on each commit to the main sokol repository, and a single semver version number also doesn't really make sense, because it's actually a collection of libraries (and technically each library would need its own semver version number).

This is also why I hope that the version number in the build.zig.zon file is just "decorative" and won't be used to check if any caches are uptodate.

floooh commented 5 months ago

Hey, quick update on the current state:

Here are some example build.zig scripts how it looks now (there are still 2 separate code paths for 'native vs web':

...and this is what the sokol-zig build.zig currently looks like, which also currently contains a lot of Emscripten SDK specific code (this is the one point which could be vastly improved in the future -> move out into a separate emsdk-zig package, and turn the Emscripten linker step into a proper custom build step, instead of a cobbled together run-step:

Overall, the amount of hacks and workarounds for the wasm32-emscripten build could be drastically reduced (for instance it's no longer necessary to provide a separate entry.c file with a C main() function).

Right now I'm happy :)

...ok, apart from a few minor cosmetical/style issues in the "new" build system API, like this:

pacman.root_module.addImport("sokol", dep_sokol.module("sokol"));

...could at least be shorted to this:

pacman.addImport("sokol", dep_sokol.module("sokol"));

It feels a bit less like poking around in the guts of the build system ;)

peterino2 commented 1 month ago

I wanted to ask how did you solve this problem?

First, I was confused that the CrossTarget and OptimizeMode are not communicated automatically to the dependency builder object, instead I need to pass those in the args: anytype parameter of the std.Build.dependency() function. I think it would be better if all -D options are "inherited" automatically, and the parameter would only be used for overriding or adding build options.

It seems like to me that if one package generates a build flag there's no way to effectively use that build flag in a nested system without leaking that flag to all future potential dependencies.