Tracking issue for internal feature no_core
The no_core feature allows you to avoid linking to libcore.
Perhaps it would be better to give this a 'positive' name, like
[freestanding]?Ahmed Charles at 2015-11-09 23:20:52
no_coreis basically useless on its own at the moment; you needlang_itemsto actually implement enough of the core traits to allow compiling anything non-trivial.eefriedman at 2015-11-10 04:14:28
Traige: no change
Steve Klabnik at 2017-03-08 19:40:03
no_core is basically useless on its own at the moment; you need lang_items to actually implement enough of the core traits to allow compiling anything non-trivial.
#[no_core]is super useful: some crates do not use any lang items and compile just fine (e.g.cfg-if), and if these crates aren't#[no_core]then we can't use them as dependencies oflibcore, which means we have to duplicate them. For example, we currently duplicatecfg-ifin libcore, libstd, stdsimd, and in libc (EDIT: and probably in hashbrown as well, that's 5 times that this macro is duplicated).If we make
cfg-if#[no_core]we can just add it as a normal cargo dependency to all those crates, and everything "just works". But we can't make it#[no_core]because it is not stable.gnzlbg at 2019-03-07 19:18:48
@gnzlbg makes a great point.
Additionally I'd like it if it was renamed to not mention the name of any create. If we get core depending on more crates, core might not seem so
core-y. Something likeno_dependenciesis more future proof.On the other hand, maybe we'll someday want to make primitives like
floatonly available from come crate, removing them from the ambient prelude. That would mean the current name is more forward compatible after all.John Ericson at 2019-03-08 01:40:54
This idea seems fishy and impractical for me, let me quote @Ericson2314 to elaborate why:
If we get core depending on more crates, core might not seem so
core-y.If
corerequires a certain crate for its convenience features and that crate is small enough to be used bycoreand to not depend oncoreat all, then why wouldn'tcorejust include that crate into itself as an RFC to the language as a whole? Ifcoredepends on such a crate, therefore all of its members are linked tocoreand take the disk space in the final executable, meaning that not there's totally no reason to avoid using such a crate even if it's used only briefly in a very specific place where it's not that necessary which is why people rewrite a subset functionality from existing crates themselves for their specific use case.This is not true for procedural macros, which are loaded into the compiler when
coreitself is compiled but are completely transparent to the final application, but either way there's the problem with the "standard" part in "standard library". The point of it is to provide utilities and core language features which are useful in a wide range of programs. Now, admittedly,cfg_ifperforms conditional compilation which is typically only used in abstractions over platform-specific code and that is supposed to implemented by a few crates and then reused by many other crates, meaning that the total amount of code which usescfg_ifis relatively low. But since it's such a small thing which was found useful incore, maybe it can become part of its public API, solving the duplication problem, providing access to its (unchanging!) interface for all Rust programs and promoting the use of it in a wider range of crates, improving readability.no_corewould only promote hiding useful macros as private dependencies ofcoreinstead of promoting those macros becoming a part of Rust.kotauskas at 2020-07-08 19:15:12
If we make
cfg-if#[no_core]we can just add it as a normal cargo dependency to all those crates, and everything "just works".Please don't make
coredepend on anything unless there is a very good reason for it, much less on external repositories or on a particular build system.Miguel Ojeda at 2021-01-14 10:54:19
Marking as "needs-summary", because we need a closer look at the use cases for
#[no_core], and why it is that core can't "compile to nothing" to serve some of those use cases (macro-only crates aside).Josh Triplett at 2021-12-08 18:54:39
no_coreimplies so many things -- noAdd, noFn, etc -- that it doesn't seem like the right way to expose whatever the goals here are. To me,no_coreis perma-unstable, as it's there for internal reasons so will stick around but won't be stable.That's not to say that there couldn't be other things that would make sense to have on stable, like a "please don't use simd" kind of flag/attribute or "I wish LTO worked better to remove parts I don't need" or ..., but those wouldn't be this issue.
scottmcm at 2021-12-08 19:05:12
In a recent embedded project, I needed to calculate CRC. I knew there is the
crccrate which is quite minimal and meets every requirements.The project is written mostly in C, so in order to save time, I exported a simple interface:
#[no_mangle] unsafe extern "C" fn calculate_crc(data: *const u8, len: usize) -> u32 { ... }... and turned that into an object file with
$ cargo rustc --release -- --emit=objand simply linked it to the rest.This had no dependency on
core. Initially I declared the whole thing as#![no_core]but faced the mentioned missing lang items.Does this count in any way?
min at 2021-12-12 19:26:26
no_corewould defiintelly open up possibility of alternate core implementations. How useful would that be in current rust ecosystem - hard to tell. I could see this used in projects that require formal verification - eg.Adalimits it's stdlib forSPARK. But there may be better ways to achieve this.luke-biel at 2022-02-11 01:43:27
Should I be opening bug reports related to my use of
no_core? I've seen confusing diagnostic messages and ICEs.Gheorghe Anghelescu at 2022-04-25 15:45:04
@gheoan ICEs need to be reported and fixed in most cases, even in
no_core.As for diagnostics, I don't think we should do anything for
no_core-specific diagnostics, unless it's zero cost in terms of code added to rustc.Vadim Petrochenkov at 2022-04-25 15:52:26
ICEs need to be reported and fixed in most cases, even in
no_core.Contradicts https://github.com/rust-lang/rust/issues/92495#issuecomment-1006193883:
Personally, I don't think ICEs with
#![no_core]are worth addressing. It's a perma-unstable feature, and lang items are effectively internal compiler code that happens to be written in a crate. We don't try to prevent ICEs in the face of modifications to the compiler itself (in fact, many internal compiler APIs will deliberately ICE when they are used incorrectly).The only correct way to use
#![no_core]is to copy-paste all of the lang items, types, and impls that you're using (and even then, leaving out "unused" ones is pretty dubious).eggyal at 2022-06-12 04:12:08
I think getting ICEs in
no_corefor not providing all the things is absolutely to be expected, and not something that needs to be fixed. For example,u32isCopy, and if you don't include that and thus get an ICE, too bad. We should not expend any effort at all to improve that situation.scottmcm at 2022-06-12 04:32:02
I could see this used in projects that require formal verification - eg. Ada limits it's stdlib for SPARK. But there may be better ways to achieve this.
Imho, I think that it would be good to give Rust some hooks that would allow for use in safety-critical systems that could potentially eliminate the need for a separate core (for at least the basic SIL levels) - which would probably have benefits to the language as a whole. Some things I've considered that would help that -
#![no_panic]being used to classify a any potential panics as UB. This would be pretty useful as a sanity check too throughout the language,#[no_panic]tags could be added to a lot of core/std functions for the compiler to verify (this would be useful in kernel space too)- Some way to disallow unchecked casts and arithmetic
- Some sort of way to programatically tie
unsafeblocks to the code that makes them safe. I'm stealing a bit from Ada contracts here where you can have a syntax likewith Pre => Name'Length > 0for a function definition, indicating a precondition to make that function valid. It would be pretty awesome if you could do that sort of thing for anyunsafe fn, indicate a precondition and make the caller indicate the lines where they check that brecondition to be true.
The first two things are basically clippy lints, but they would need to be applied recursively to everything linked. Stack size analysis is another thing, but this is already sort of coming via
stack_sizes. It would be interesting to reach out to Ferrous Systems and see what the people there have to say on the subject.Regarding the cfg-if thing, is there any reasons the implementations aren't just exported from core?
Trevor Gross at 2022-09-13 01:49:34
@kotauskas
If core requires a certain crate for its convenience features and that crate is small enough to be used by core and to not depend on core at all, then why wouldn't core just include that crate into itself as an RFC to the language as a whole? If core depends on such a crate, therefore all of its members are linked to core and take the disk space in the final executable, meaning that not there's totally no reason to avoid using such a crate even if it's used only briefly in a very specific place where it's not that necessary which is why people rewrite a subset functionality from existing crates themselves for their specific use case.
IIUC you might want to have core depend on an external crate for its implementation without exposing that crate's API in core's API. E.g., per @gnzlbg, "we currently duplicate
cfg-ifin libcore, libstd, stdsimd, and in libc" - even if we don't intend to exposecfg-if's API anywhere in the standard library, it would still be a boon to allow libcore, libstd, stdsimd, and libc to depend on a single crate rather than duplicating code across their implementations.Joshua Liebow-Feeser at 2022-10-02 14:20:51
it would still be a boon to allow libcore, libstd, stdsimd, and libc to depend on a single crate rather than duplicating code across their implementations.
If I understand the argument correctly, it is essentially "except
core, they all already depend on a single crate, namelycoreitself".Cerber-Ursi at 2023-01-19 02:02:01
I really don't understand why you would use this. A lot of people have given issues and said that "this isn't useful." But nobody has asked why you would even want not to use core. Is there a reason that I haven't realized? Why would I want to get rid of core, which has so many amazing features that do not depend on the operating system.
Goren Barak at 2023-11-28 19:04:34
just writing here to throw in my $0.02. I’d like to avoid libcore in some places where I’d rather not be obligated to follow the license of the libcore code for some particular binary (this seems to indicate its licensed under MIT/Apache2).
Now in 99% of cases this is a complete non-issue, but surely it should at least be possible to write a (non-trivial) rust program without needing to do so? It’s not even really documented anywhere that an empty rust program with
no_stdstill has a dependency on an MIT/Apache2 library, which might surprise some people, I’d say.Aside from that (little bit of pedantry) though, I figure it’s at least worth having for completeness’s sake, as crates like
cfg-ifhave shown might be useful. If some crate doesn’t depend on libcore, it should be able to express that. Keeping it as a permanently unstable feature might be wise, but it could be just as wise to stabilize it and epoch-bump whenever the feature is broken, seeing as it’s unlikely that would happen too often.Either way, I think this is a good thing assuming it wouldn’t be a stability nightmare or anything.
Ayman El Didi at 2024-04-03 17:43:23
Well, if we talk about licenses... are the compiler intrinsics distributed under MIT/Apache too?
Cerber-Ursi at 2024-04-04 02:29:16
LLVM has a specific exception for these
---- LLVM Exceptions to the Apache 2.0 License ---- As an exception, if, as a result of your compiling your source code, portions of this Software are embedded into an Object form of such source code, you may redistribute such embedded portions in such Object form without complying with the conditions of Sections 4(a), 4(b) and 4(d) of the License. In addition, if you combine or link compiled forms of this Software with software that is licensed under the GPLv2 ("Combined Software") and if a court of competent jurisdiction determines that the patent provision (Section 3), the indemnity provision (Section 9) or other Section of the License conflicts with the conditions of the GPLv2, you may retroactively and prospectively choose to deem waived or otherwise exclude such Section(s) of the License, but only in their entirety and only with respect to the Combined Software.(From LICENSE.txt in LLVM). Does Rust have some equivalent that I wasn't aware of? I couldn't find any such thing but that would make the licensing thing a non-issue.
Ayman El Didi at 2024-04-04 08:03:07
LLVM is only distributed under the Apache 2.0 license, and excluded sections 4(a), 4(b) and 4(d) exempt the parts about needing to provide the license upon redistribution and giving attribution. Rust is dual licensed under either Apache or MIT at your choice https://github.com/rust-lang/rust/blob/43f4f2a3b1a3d3fb3dbbbe4fde33fb97c780ee98/COPYRIGHT#L16-L19. So de facto selecting to use
coreunder the MIT license already means you don't have to worry about these attribution things, nor the GPL / patent provision / indemnity provision waiver.It’s not even really documented anywhere that an empty rust program with
no_stdstill has a dependency on an MIT/Apache2 library, which might surprise some people, I’d say.Under what specific circumstances would this be surprising? Having the MIT license allows the source and software to be distributed liberally. Having no license is less free, unlicensed software cannot be distributed at all. LLVM intrinsics are still under the Apache2 license, just with some exceptions. Using Rust's
coreunder MIT gets you roughly the same permissions as the modified Apache.Trevor Gross at 2024-04-04 08:21:22
So de facto selecting to use core under the MIT license already means you don't have to worry about these attribution things
This isn't correct. The MIT license definitely requires attribution and including a copy of the license with distribution.
Under what specific circumstances would this be surprising?
Under the circumstances that both gcc and clang both have exceptions so that this isn't the case. The norm for people coming from C/C++ is that "compiling without the standard library means you don't have to worry about licenses", and it's surprising that rust differs in this way.
Having no license is less free, unlicensed software cannot be distributed at all. LLVM intrinsics are still under the Apache2 license, just with some exceptions. Using Rust's core under MIT gets you roughly the same permissions as the modified Apache.
Again: the differences granted by the exception are what I'm after here. Whether or not something is licensed under Apache 2 or MIT, the point is whether or not the user has some hidden obligation to give a copy of the license and give attribution when it's not obvious. With both gcc and clang, these exceptions mean that someone compiling with
-nostdlibdoesn't have to worry about producing any licenses or giving attribution at all, which I was trying to say would be nice to have in rust, since It's a little odd that withoutno_coreevery rust program requires giving attribution and a copy of some license.The proposed solution here isn't "no license is better", just that having
no_coreor introducing some linking exception for libcore would be nice.Ayman El Didi at 2024-04-04 17:49:10
This isn't correct. The MIT license definitely requires attribution and including a copy of the license with distribution.
I am not a lawyer, but I believe the clause
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Softwareis usually interpreted as "Software" referring to the library itself (i.e. Rust as a whole), but anything built with it is not considered a "copy" or "substantial portion".Whether this is the correct way to interpret it or not I do not know. The question really isn't related to
no_core, so could you bring this up on Zulip?Trevor Gross at 2024-04-04 18:06:33
I agree that the specific issue on what the MIT license requires in binary distribution is off topic, I'll continue that discussion elsewhere.
Ayman El Didi at 2024-04-04 18:35:12
I think I have a use-case for this. I want to specify a logical data model using Rust's syntax and type system so that implementations can map in and out (a la serde). It is important to keep it zero-sized to maintain maximum flexibility for both the people mapping in and out as well as the end users relying on those crates.
I want to mark my definition crate as
#[no_core]so the compiler automatically guarantees I don't accidentally depend on a specific storage implementation detail such as u64.I can achieve my overhead and compatibility goals by sticking to
const, but a) there's no guarantee that const happens at compile time and b) even if it was guaranteed to run at compile time, there is not something like#[const_only]to have the compiler make it so I don't inadvertently introduce something non-const wrapping the const in the future.Christian Legnitto at 2024-04-21 02:32:06
I want to mark my definition crate as
#[no_core]so the compiler automatically guarantees I don't accidentally depend on a specific storage implementation detail such as u64.u64is a magic primitive, not something from core, so it'll still be there even inno_core. (And the correct way to do type restrictions is with traits, not trying to remove them from existence.)scottmcm at 2024-04-21 02:37:17
u64is a magic primitive, not something from core, so it'll still be there even inno_core. (And the correct way to do type restrictions is with traits, not trying to remove them from existence.)Right, but if I make a
NoCoretrait I can't tell the compiler to enforce that I am not using anything from core either in the trait or for my items that impl it.One could informally not use std and have the same observable effects (minus linked std which might be stripped), but the existence of an optional
#[no_std]is a strictly better alternative as invariants are enforced by the compiler. I don't see how core is different, other than the fact that there are fewer uses of#[no_core].Christian Legnitto at 2024-04-21 03:54:13