ziglang / zig

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

Get pacman.zig on the Package Manager #16711

Open floooh opened 1 year ago

floooh commented 1 year 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 10 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 6 months 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.