-
-
Notifications
You must be signed in to change notification settings - Fork 46
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 target_os = "none"
#70
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! I was thinking of suggesting something along these lines in #66.
I don't know that a feature
is appropriate for this. Features are required to be additive i.e. some crate not enabling the feature must be indifferent to any other crate enabling the feature.
Force-init-array-section needs to be a choice made by the top-level build, rather than any particular dependency edge on inventory
. Can you do this using --cfg=force_init_array_section
?
src/lib.rs
Outdated
any(target_os = "macos", target_os = "ios"), | ||
link_section = "__DATA,__mod_init_func" | ||
)] | ||
#[cfg_attr(windows, link_section = ".CRT$XCU")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the intended behavior if force-init-array-section
is enabled when the target OS is one of the recognized ones such as Windows or macOS? Is it better to only apply to target_os = "none"
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that the behavior of this first attempt isn't quite what we're after.
I just pushed a new attempt where the feature is renamed to default-to-init-array-section
. The new behavior is that the feature just causes the crate to default to using .init_array
.
This approach has the advantage of not deviating from the current behavior on supported platforms, while also not being limited to just those unsupported platforms where target_os = "none"
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am confused / interested to hear more about the use case you envision for default-to-init-array-section
on target_os
values other than "none"
. Does there exist any target-os on which .init_array
sometimes works and sometimes not, such that a feature to choose whether .init_array
is used makes sense?
If not, the person with an unsupported target-os should just make a PR adding the new target_os
to inventory, rather than working around with a feature that modifies default behavior.
If yes, this PR doesn't seem any better than adding the target_os
to inventory anyway to make it unconditionally use .init_array
, because the case where .init_array
doesn't work is not handled either way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment of yours has made me realize that perhaps what I should really be proposing here is just that target_os = "none"
be added to the link_section = ".init_array"
list.
In the seL4 userspace case, because seL4 is a microkernel with minimal features, an OS is implemented using userspace components. So, these userspace components run at a higher-level than baremetal, but are really target_os = "none"
. Folks building sophisticated systems compose a bunch of these low-level components to eventually provide a higher-level environment for other userspace components which have the luxury of target_os = "my-special-sel4-based-os"
.
Before looking at the Clang source, I would have considered target_os = "none"
implying link_section = ".init_array"
to be too much of a leap, but, as far as I know, target_os = "none"
will basically always mean non-legacy ELF (rather than MACH-O or COFF), which, according to Clang's policy (which I'm viewing as informative rather than informative), means .init_array
.
Does there exist any target-os on which .init_array sometimes works and sometimes not, such that a feature to choose whether .init_array is used makes sense?
To answer your question, I think not. So yes, it would make sense to limit the scope of this PR to target_os = "none"
.
bc8bb7a
to
df8cd24
Compare
I agree. I've taken a look at how Clang chooses which section to assign constructors to [1]. Predictably, Clang makes its decision based on information about the target (mostly based on the target object format, and notably not based on the target OS), that a crate like
This certainly wouldn't be the most elegant use of Cargo features. My new attempt (df8cd24, just force pushed) goes some ways towards addressing your point about the fact that the feature should be additive, perhaps even resolving it. As mentioned in my comment in the review thread above, in this new attempt, the However, regardless of the additivity question, another issue with implementing this option as a feature is that it is not a natural fit for cases where a crate which is not necessarily aware of its top-level purpose, target platform, or link-time environment depends on the While this isn't ideal, it may be the best option, provided that it's deemed just a usability issue rather than an appropriate usage of features issue.
The top-level build could inject For a concrete example of what I mean by cluttering the top-level build, I'll use my use-case for the [1] https://github.com/llvm/llvm-project/blob/main/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp |
Thank you for the explanation of the seL4 userspace component use case! I see the motivation for this approach. I looked through https://docs.rust-embedded.org/embedonomicon/custom-target.html + https://doc.rust-lang.org/1.75.0/nightly-rustc/rustc_target/spec/struct.TargetOptions.html and discovered one other option that could be worth evaluating:
Something like |
Reading that Clang source file warmed me up to another approach, which is to just default to The Clang source [1] just categorizes targets into ELF|MACH-O|COFF. I think it is reasonable to think that this crate could use So, concretely, I'm proposing: #[cfg_attr(windows, link_section = ".CRT$XCU")]
#[cfg_attr(any(target_os = "macos", target_os = "ios"), link_section = "__DATA,__mod_init_func")]
#[cfg_attr(target_os = "netbsd", link_section = ".ctors")]
#[cfg_attr(not(any(windows, target_os = "macos", target_os = "ios", target_os = "netbsd")), link_section = ".init_array")]
static __CTOR: unsafe extern "C" fn() = __ctor; [1] https://github.com/llvm/llvm-project/blob/main/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp |
Or, better, as mentioned in #70 (comment), just adding |
👍 I am on board with either or both of:
|
Yeah, I think this the direction of an ideal solution; crates having structured access to the target information required to make a robust and complete decision about which section to assign these constructors to. However, because rustc doesn't really support or deal with Even without this information being baked into the rustc target spec, the target spec still feels like a nice way to convey less formal target information to crates. I'm thinking specifically about how using the JSON target spec would be much more convenient than having to include some kind of The [1] https://doc.rust-lang.org/beta/nightly-rustc/rustc_target/spec/struct.TargetOptions.html |
To me, this feels like a safer approach for now. I'll modify this PR to implement it, but happy to explore option #2 further and switch to that one if you decide you prefer it. |
df8cd24
to
b273ebc
Compare
https://doc.rust-lang.org/1.75.0/reference/conditional-compilation.html#target_family defines It isn't a stretch to extrapolate this to family of the operating systems or architectures or executable formats. The existing definition already indicates that the use of this field is open-ended, with OS and architecture family just being 2 example use cases, and the fact that only I will consider sending a compiler PR or MCP to fill in |
.init_array
sectiontarget_os = "none"
Similar PR in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!
I appreciated your expertise and research, patient explanations, and thoughtful suggestions.
Published in 0.3.15. |
This is a great idea. You're correct, this would simplify lots of similar PRs across the ecosystem. I'll link it here as soon as I get around to it (if I get around to it before you do) to avoid duplicated efforts. Thank you for this crate, along with the countless others! |
Alternative take on #66.
Adds a feature called
force-init-array-section
to force__do_submit!
to assignstatic __CTOR
to the.init_array
section, regardless of the platform. This enables support for arbitrary platforms that support.init_array
constructors.Unlike #66, this is an intrinsic feature of the
inventory
crate.