mach: allow setting magical declarations used by the zig standard library #360
Labels
No labels
CI
all
basisu
blog
bug
build
contributor-friendly
core
correctness
deferred
dev
direct3d-headers
docs
driver-os-issue
duplicate
dxcompiler
editor
examples
experiment
feature-idea
feedback
flac
freetype
gamemode
gkurve
glfw
gpu
gpu-dawn
harfbuzz
help welcome
in-progress
infrastructure
invalid
libmach
linux-audio-headers
long-term
mach
mach.gfx
mach.math
mach.physics
mach.testing
model3d
needs-triage
object
opengl-headers
opus
os/linux
os/macos
os/wasm
os/windows
package-manager
priority
proposal
proposal-accepted
question
roadmap
slipped
stability
sysaudio
sysgpu
sysjs
validating-fix
vulkan-zig-generated
wayland-headers
website
wontfix
wrench
www
x11-headers
xcode-frameworks
zig-update
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
hexops/mach#360
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The discussion in #309 says that Mach won't use magical public declarations to set things such as options, however I think it makes sense to use them for (any applicable) magical public declarations that
stdlooks for. This shouldn't impose any extra cognitive overhead compared to whatstdalready does and not re-exporting them may make somethings very hard; for example at the moment if you want tostd.logwith a custom logging function or logging level you have to modifysrc/platform/{native,wasm}.zig.Grepping Zig's standard library for 'hasDecl(root' suggests that the magical declarations that might makes sense to export are:
loglog_levelscope_levelsallow_todo_in_releasepanicenable_segfault_handlerevent_loopio_modeThere are roughly in order of how clear I think it is that they be re-exported by Mach
"root"package. I would default to saying all of these should be re-exported unless Mach wants to impose its own choice (e.g. maybe Mach just has its own event loop and doesn't let you use your own withstd).The other magic decls that
stdlooks for are eitherosor ones used by startup code (e.g.main,_start,WinMainCTRStartupetc), which presumably don't need to be considered.I'm not totally sure how to handle
logfor wasm.Mach provides a log for wasm. But it cannot be that easily replaced. Providing an alternative reimplementation for the user would be complicated. Same goes for panic for wasm.
I don't see why this would be useful. Mach being a high level application framework should always provide the most sensible defaults out of the box.
Yes, I agree that custom log and panic for wasm is not straightforward - you could either not allow it, or force the user to get it right at their own risk. I definitely think that things like logging levels should be left to the user to set though.
I think it's very important we consider each of these in isolation, not all together. Merely re-exporting all of these is probably not a good idea.
It's important that we consider the use case of each, how they apply to different platforms, and consequences of supporting them.
For logging in specific
I don't know enough about Zig's logging library, I haven't read it's source yet, but the full impact of this change is not clear to me. Presumably
std.log.info,std.log.err, etc. work - but it sounds like they're not sufficient from your POV?The other thing here is, beyond WASM support (which also needs to be considered), is this:
How exactly we support this needs a lot of thought, especially defaults. Once we have an editor, for example, I can imagine it being quite useful to have logs show up in the editor. In contrast, for most release-mode applications it seems likely that you'd want logs to go to a file - because someone opening your
.exeisn't going to be storing those for you in the event something goes wrong. Crash reporting is another thing in this area.All this to say, I don't know what the right answer is here - but I'm hesitant to support a change that is native-only right now, and that we may need to break as an API in the future to support the above functionality.
I'd be very supportive of anyone interested in pitching a more clear proposal around how we could achieve such things in the future, otherwise I'll get to it later on.
Event loop, IO mode, etc.
This hasn't been considered yet, but is also another example where just exporting would be a mistake. We need to consider what the async event loop would look like in Mach applications, and likely force the evented IO mode to be always on.
Simply turning on evented IO right now, for example, wouldn't work AFAIK (Zig's builtin event loop wouldn't have a chance to run I believe?)
I can try to explain a bit more about my thoughts on logging (which is the main feature of the above I am interested in at the moment).
Logging
The current Zig standard library has logging functions that take a scope, level, format string and arguments, and then write a message using a global log function (the private decl
std.log.log). The behaviour ofstd.logcan be controlled by the above mentioned "magic" declarations of the root file (log,log_levelandlevel_scopes).I'm happy enough with
std.log.{debug,info,warn,err}andstd.log.scoped, what I think is undesirable at the moment is not being able to setlog_level,level_scopesand (to a lesser degree)log.Note that regardless of whether Mach wants to use the standard library's logging framework, it should be aware of it (and, I think, allow users to set the "magic" decls) as package dependencies may be using it.
logThe global log function is chosen by
std.logchecking for a public decllogin the compilations"root"package and falling back tostd.log.defaultLog.std.logwraps this function to filter messages based onlog_levelandlevel_scopes. Mach current sets this logging function for wasm targets, but does not do anything on native targets, meaning thatstd.log.defaultLogis used (and cannot be overridden by users) on native targets.I think there are a number of reasons a user might want to override the native logging function (I am not really familiar with wasm). The most obvious to me are
Re-exporting
logon wasm adds some complication, as the function has to be suitable for the wasm target, and I'm am not sure what this entails.This is something I expect Mach will want to do as well. If Mach uses the standard library's logging framework, it will also capture any logging that third party packages might do (assuming they use it). The way packages would use it at the moment would be to pick a scope (this could clash with other packages at the moment, but there an issue in the Zig issue tracker for this)) or use the default scope. It's quite possible that you may not want log messages for some packages showing up in your editor, in which case I think Mach should probably not use the standard logging framework (so by default it does not capture logging from external packages), but either has a comptime/build option to use it, or (for more flexibility) provides a function the user can to set
logto or use in their own customlogfunction that outputs messages to Mach's logging framework.How Mach wants to handle logging will probably affect whether
logshould be re-exported - if Mach wants to use the standard library's logging framework, than mostly likely it won't re-exportlog.log_levelandscope_levelsThere are 4 logging levels:
.debug,.info,.warn,.err. Thelog_leveldecl is an enum that sets the minimum logging level that should be output (unless overridden byscope_levels). It defaults to.debugfor Debug builds,.infofor ReleaseSafe builds and.errfor ReleaseFast and ReleaseSmall builds. Unless Mach allows you to set this, you will be stuck with these logging levels, even though you may want a ReleaseFast build that logs warnings.The
scope_levelsdecl works the same way aslog_levelbut it is scope-specific. It is an array ofstd.log.ScopeLevels, which determine a minimum logging level for an individual scope, overridinglog_level.Re-exporting both of these should not be an issue for Mach, whether Mach uses
std.logor not, and I can't see a reason to prevent people from picking thelog_levelandscope_levels. Their effect is just to remove logging calls from the program (message level and scopes are comptime parameters tostd.log.log, so if they cause a logging statement to get filtered out, it should be elided from the program at comptime).Other decls
Similar to
log_levelandscope_levels,allow_todo_in_releaseshould be safe to re-export; it just chooses whether calls tostd.debug.todo()are compile errors or panics in release builds.The other four (
panic,enable_segfault_handler,event_loopandio_mode) all would warrant consideration of how they might integrate with other aspect of Mach. But there are probably use cases for people who want to use Mach just for cross platform windowing and input, with a low-level application like was proposed in https://github.com/hexops/mach/issues/309#issuecomment-1140479760.I'm pretty sure that turning on
io_mode = .eventedwould cause the event loop to be initialised on native targets at the moment (the relevant code to look at is instd/io.zig,std/event/loop.zigandstd/start.zig). The event loop is started bystart.zigin this case - it happens beforemain()gets called. On wasm, the event loop wouldn't get started.Thanks for the detailed write-up, this makes a lot of sense. I've just merged https://github.com/hexops/mach/issues/360 and my conclusions for now are:
log_level,scope_levels, andallow_todo_in_releaseshould be re-exported for now.This was fixed in a recent version of mach-core; your
app.zighas its declarations re-exported in ourmain.zigso there is no issue.