Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: remove per-module targets #22285

Open
mlugg opened this issue Dec 21, 2024 · 2 comments
Open

Proposal: remove per-module targets #22285

mlugg opened this issue Dec 21, 2024 · 2 comments
Labels
breaking Implementing this issue could cause existing code to no longer compile or have different behavior. proposal This issue suggests modifications. If it also has the "accepted" label then it is planned. zig build system std.Build, the build runner, `zig build` subcommand, package management
Milestone

Comments

@mlugg
Copy link
Member

mlugg commented Dec 21, 2024

#18160 was responsible for expanding Zig modules to include lots of state, such as link libraries, C source files, and optimization mode. One such property which can now be set on a per-module basis is the target.

Clearly, targets with (for instance) different object formats cannot be combined into a single output executable; it is also unclear whether there is a sane way to combine, for instance, different CPU architectures in one executable. The real stated use case in #18160 for this feature is to allow modules to be compiled with different CPU feature sets.

Presumably, the idea here is that a piece of source code can be compiled N times with N different CPU feature sets, allowing a single binary to run correctly and optimally across a variety of CPU models. However, the problem with this is that Zig does not allow a single file to exist in multiple modules. As such, this use case immediately breaks down: you cannot compile the same code N times for different CPU feature sets using modules alone.

Meanwhile, modules having different targets introduces other complexities. Clearly, this is difficult to support in the compiler; indeed, it doesn't really work today at all. Additionally, it introduces the problem that the standard library either cannot be shared, or needs to be compiled for the "least feature set" of all targets. Aside from code bloat, non-sharing of the standard library leads to the same usability issues as the ability to have one file in multiple modules would; namely, that std.ArrayListUnmanaged(u8) from module A is not necessarily the same type as std.ArrayListUnmanaged(u8) from module B. This leads to another issue with modules having different targets: it is unclear how these modules are actually allowed to interact. Can datastructures be exchanged between them?

Given that this feature fails to solve the problem it sets out to solve, and introduces many more issues and complexities along the way, I propose to remove this feature. The target should become a global option; for the build system, it should be set on std.Build.Step.Compile rather than on std.Build.Module.

Notes

  • The use case of having one binary which supports multiple CPU feature sets can be satisfied by compiling your application's hot path as an object file N separate times, and having your main application link all of those object files, calling the hot path over a well-defined API boundary.
  • This proposal does not suggest removing per-module optimization modes. While this feature is still not solved -- for instance, it is unclear what optimization mode the standard library should have -- it has clear utility, unlike per-module targets, and is strictly less problematic.
@mlugg mlugg added breaking Implementing this issue could cause existing code to no longer compile or have different behavior. proposal This issue suggests modifications. If it also has the "accepted" label then it is planned. zig build system std.Build, the build runner, `zig build` subcommand, package management labels Dec 21, 2024
@mlugg mlugg added this to the 0.15.0 milestone Dec 21, 2024
@aqrit
Copy link

aqrit commented Dec 21, 2024

compile/link object file N separate times

Note for dynamic dispatch, if anybody else is wondering how this might work:
I assume this requires custom name mangling via @export and std.fmt.comptimePrint().

@GalaxyShard
Copy link

Clearly, targets with (for instance) different object formats cannot be combined into a single output executable; it is also unclear whether there is a sane way to combine, for instance, different CPU architectures in one executable. The real stated use case in #18160 for this feature is to allow modules to be compiled with different CPU feature sets.

What about executables with a mix of arm and thumb? I think this could be important for embedded development, or in my case, homebrew for the Nintendo DS. I haven't actually tried any code that does mix arm and thumb, so I'm not sure what the current behavior is, but intuitively I would think to just use different targets in different modules to switch between the two architectures.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking Implementing this issue could cause existing code to no longer compile or have different behavior. proposal This issue suggests modifications. If it also has the "accepted" label then it is planned. zig build system std.Build, the build runner, `zig build` subcommand, package management
Projects
None yet
Development

No branches or pull requests

3 participants