-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Support static constructors (ctors) #1216
Comments
Thanks for the report! It looks like there's prior art to some degree in LLVM/LLD, there's discussion threaded off https://reviews.llvm.org/D40759 and such, and notably LLD has treatment for a special @sunfishcode would you be able to help us out here? It looks like you may be familiar with the intentions of LLVM/LLD. This issue is about supporting static constructors (like C++ static constructors sorta), and I'm curious if there's an existing convention that Clang is going to use, and if so we should stick to that too! |
Assuming you're producing LLVM IR, the @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @foo, i8* null }] is LLVM IR to register "foo" as a static constructor. There's also an The linker then collects all of the static constructors and synthesizes a function named |
Ok thanks @sunfishcode! That all makes sense As a follow-up question, do you know why LLD doesn't inject a |
The wasm |
Ok cool thanks for the clarifications! We perform a few transformations already to ensure that the I believe the next items to implement this feature would be:
|
Awesome! Thanks for the quick reply and addressing this. As much as I hate to add a potential obstacle, it seems like if we're adding in support for LLVM's global constructors in rustc for WASM, it might make sense to do that further?
Since Global constructors were listed as an explicit non-goal in the design FAQ when it existed, so it might not be a great idea. But they're quite useful for coordinating separate pieces code pieces without any central list, and I don't know of anything else can do that right now. If a non-ctor-based alternative to the inventory crate doesn't come up, I imagine more projects will indirectly depend on rust-ctor despite its unrustyness. Official support could avoid splitting the ecosystem between targets supported by rust-ctor and those which aren't. I originally thought this issue would be just adding some specific support to wasm-bindgen with a wasm-bindgen-specific attribute. But if it requires modifying CC @mmastrac from rust-ctor (edit: added some remarks I completely forgot I wanted to say until 5 minutes after posting!) |
I'm happy to add support to Ideally this feature would end up in stdlib, but if we can add support for the wasm platform to |
A good question @daboross! Over time philosophies shift ever so slightly and such, but nowadays I think it'd be fine to roughly add something like this. We don't want to hide features in rustc that a platform has, and as @mmastrac has shown this is already somewhat supported on platforms today! I think, though, we probably won't be able to add a first-class feature using That's ok though! We have a long history of providing features here and there that "do their best" to work on all platforms but are clearly documented as "you shouldn't absolutely rely on this to work everywhere". Such a feature is fine to add and support. What all that boils down to is:
|
Thanks for following up on everything so quickly! I've been a bit distracted, but I'm going to try and see what I can do to move forward with this. I've looked a bit more into what LLVM does with Separate from that, I wrote up my current thoughts on the design in a pre-RFC. I've described it as a cross-platform attribute, but could easily be downgraded to WASM-only. This might not be at all useful in the long run given how little research I've done into the actual implementation - I mainly wanted to get some thoughts into nicer words before trying to do more with it. I'm planning on diving into rustc to see if I can take this any further in that direction. If nothing else, hopefully hacking If anyone else is interested in this part, though, feel free to step in. I will by no means be moving quickly. |
I was just playing with it to confirm that it would actually work on wasm lld. I was able to link some additional Unfortunately, I still had to call First, I created this IR
Then, compiled it with // build.rs
use std::env;
fn main() {
let project_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
println!("cargo:rustc-link-search={}", project_dir);
println!("cargo:rustc-cdylib-link-arg=define_ctors.o");
} Then, the following programs successfully calls both ctor functions at the beginning of main. #[no_mangle]
pub fn call_ctor() {
log("Hello, ctor!");
}
#[no_mangle]
pub fn call_ctor2() {
log("Hello, ctor2!");
}
extern "C" {
fn __wasm_call_ctors();
}
#[wasm_bindgen(start)]
pub fn main() {
unsafe { __wasm_call_ctors() };
log("Hello, world!");
} This should work just fine for ctors defined in other crates as well, as long as the Of course having to prepare ctors list manually is kinda pointless, so we need to find a way to generate that from rust directly. If generating the object files from |
Okay people. Now that this issue is silent for more than a year and we need to do platform-specific hacks in the WASM binding layer, I could not hold myself back to give my 2 satoshis. I love the generic idea in the Rust Design FAQ that static constructors and destructors are things to avoid, because they complicate lifetime guarantees otherwise checked by Rust. If you check how most libraries use the rust-ctor crate, they are implementing some kind of dependency injection with it. These techniques solve a single problem: an application crate does not need to depend on each library crate that has structs implementing a trait the application uses. (the application crate can therefore be compiled earlier than thos library crates) So if the rustc developers do not want to complicate the design with the static ctors/dtors (which decision I would completely understand and support), applications need another solution to
In that sense, the functions |
I may be wrong since I'm not an LLVM expert: according to this, LLVM uses
By searching rustc's source code, I found this: https://github.com/rust-lang/rust/blob/f8ab56bf3201b0638e44caf5a484041f22e32d65/compiler/rustc_typeck/src/check/mod.rs#L760-L774 That concern seems unnecessary at least for EDIT: I tried to bypass the check using a custom JSON target but hit this:
I have no idea what did that mean. |
My main motivation here is using typetag, which depends on rust-ctor to function.
rust-ctor uses link sections on Windows, Mac and Linux to allow functions to run
main
. Any crate can add these functions, and then they'll all be run without needing central configuration. The problem is that this depends on Windows/Mac/Linux specific link sections, and there is no equivalent for wasm32.I'm opening this issue for discussion of static constructors (also called global or module constructors) and wasm-bindgen. . My ideal resolution would be adding support for something to
wasm-bindgen
, and then rust-ctor could use that support and crates like typetag would simply work.I opened stdweb#321 earlier for the same issue, but @koute mentioned that it might be a good idea to coordinate how this is done across the ecosystem rather than having stdweb and wasm-bindgen implement separate measures.
Arbitrary discussions I've found about ctors and WASM which may or may not be relevant:
wasm-ctor-eval
pre-executes a list of functions meant as static constructors.I don't have a concrete proposal, mostly just opening this up for discussion. Also, if anyone knows any prior work on ctors+rust+wasm that could be linked, I'd greatly appreciate it!
The text was updated successfully, but these errors were encountered: