Auto merge of #64882 - ehuss:stabilize-bare-extern, r=eddyb
Stabilize --extern flag without a path. This stabilizes the `--extern` flag without a path, implemented in #54116. This flag is used to add a crate that may be found in the search path to the extern prelude. The intent of stabilizing this now is to change Cargo to emit this flag for `proc_macro` when building a proc-macro crate. This will allow the ability to elide `extern crate proc_macro;` for proc-macros, one of the few places where it is still necessary. It is intended that Cargo may also use this flag for other cases in the future as part of the [std-aware work](https://github.com/rust-lang/wg-cargo-std-aware/). There will likely be some kind of syntax where users may declare dependencies on other crates (such as `alloc`), and Cargo will use this flag so that they may be used like any other crate. At this time there are no short-term plans to use it for anything other than proc-macro. This will not help for non-proc-macro crates that use `proc_macro`, which I believe is not too common? An alternate approach for proc-macro is to use the `meta` crate, but from my inquiries there doesn't appear to be anyone interested in pushing that forward. The `meta` crate also doesn't help with things like `alloc` or `test`. cc #57288
This commit is contained in:
commit
d2574403b3
17 changed files with 101 additions and 29 deletions
|
@ -197,7 +197,11 @@ in software.
|
||||||
## prefer-dynamic
|
## prefer-dynamic
|
||||||
|
|
||||||
By default, `rustc` prefers to statically link dependencies. This option will
|
By default, `rustc` prefers to statically link dependencies. This option will
|
||||||
make it use dynamic linking instead.
|
indicate that dynamic linking should be used if possible if both a static and
|
||||||
|
dynamic versions of a library are available. There is an internal algorithm
|
||||||
|
for determining whether or not it is possible to statically or dynamically
|
||||||
|
link with a dependency. For example, `cdylib` crate types may only use static
|
||||||
|
linkage.
|
||||||
|
|
||||||
## no-integrated-as
|
## no-integrated-as
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,7 @@ to `#[cfg(verbose)]` and `#[cfg(feature = "serde")]` respectively.
|
||||||
<a id="option-l-search-path"></a>
|
<a id="option-l-search-path"></a>
|
||||||
## `-L`: add a directory to the library search path
|
## `-L`: add a directory to the library search path
|
||||||
|
|
||||||
When looking for external crates or libraries, a directory passed to this flag
|
The `-L` flag adds a path to search for external crates and libraries.
|
||||||
will be searched.
|
|
||||||
|
|
||||||
The kind of search path can optionally be specified with the form `-L
|
The kind of search path can optionally be specified with the form `-L
|
||||||
KIND=PATH` where `KIND` may be one of:
|
KIND=PATH` where `KIND` may be one of:
|
||||||
|
@ -262,9 +261,30 @@ This flag, when combined with other flags, makes them produce extra output.
|
||||||
<a id="option-extern"></a>
|
<a id="option-extern"></a>
|
||||||
## `--extern`: specify where an external library is located
|
## `--extern`: specify where an external library is located
|
||||||
|
|
||||||
This flag allows you to pass the name and location of an external crate that
|
This flag allows you to pass the name and location for an external crate of a
|
||||||
will be linked into the crate you are building. This flag may be specified
|
direct dependency. Indirect dependencies (dependencies of dependencies) are
|
||||||
multiple times. The format of the value should be `CRATENAME=PATH`.
|
located using the [`-L` flag](#option-l-search-path). The given crate name is
|
||||||
|
added to the [extern prelude], which is the same as specifying `extern crate`
|
||||||
|
within the root module. The given crate name does not need to match the name
|
||||||
|
the library was built with.
|
||||||
|
|
||||||
|
This flag may be specified multiple times. This flag takes an argument with
|
||||||
|
either of the following formats:
|
||||||
|
|
||||||
|
* `CRATENAME=PATH` — Indicates the given crate is found at the given path.
|
||||||
|
* `CRATENAME` — Indicates the given crate may be found in the search path,
|
||||||
|
such as within the sysroot or via the `-L` flag.
|
||||||
|
|
||||||
|
The same crate name may be specified multiple times for different crate types.
|
||||||
|
If both an `rlib` and `dylib` are found, an internal algorithm is used to
|
||||||
|
decide which to use for linking. The [`-C prefer-dynamic`
|
||||||
|
flag][prefer-dynamic] may be used to influence which is used.
|
||||||
|
|
||||||
|
If the same crate name is specified with and without a path, the one with the
|
||||||
|
path is used and the pathless flag has no effect.
|
||||||
|
|
||||||
|
[extern prelude]: ../reference/items/extern-crates.html#extern-prelude
|
||||||
|
[prefer-dynamic]: codegen-options/index.md#prefer-dynamic
|
||||||
|
|
||||||
<a id="option-sysroot"></a>
|
<a id="option-sysroot"></a>
|
||||||
## `--sysroot`: Override the system root
|
## `--sysroot`: Override the system root
|
||||||
|
|
|
@ -1800,7 +1800,7 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
|
||||||
"",
|
"",
|
||||||
"extern",
|
"extern",
|
||||||
"Specify where an external rust library is located",
|
"Specify where an external rust library is located",
|
||||||
"NAME=PATH",
|
"NAME[=PATH]",
|
||||||
),
|
),
|
||||||
opt::multi_s(
|
opt::multi_s(
|
||||||
"",
|
"",
|
||||||
|
@ -2164,7 +2164,6 @@ fn collect_print_requests(
|
||||||
cg: &mut CodegenOptions,
|
cg: &mut CodegenOptions,
|
||||||
dopts: &mut DebuggingOptions,
|
dopts: &mut DebuggingOptions,
|
||||||
matches: &getopts::Matches,
|
matches: &getopts::Matches,
|
||||||
is_unstable_enabled: bool,
|
|
||||||
error_format: ErrorOutputType,
|
error_format: ErrorOutputType,
|
||||||
) -> Vec<PrintRequest> {
|
) -> Vec<PrintRequest> {
|
||||||
let mut prints = Vec::<PrintRequest>::new();
|
let mut prints = Vec::<PrintRequest>::new();
|
||||||
|
@ -2206,7 +2205,7 @@ fn collect_print_requests(
|
||||||
"tls-models" => PrintRequest::TlsModels,
|
"tls-models" => PrintRequest::TlsModels,
|
||||||
"native-static-libs" => PrintRequest::NativeStaticLibs,
|
"native-static-libs" => PrintRequest::NativeStaticLibs,
|
||||||
"target-spec-json" => {
|
"target-spec-json" => {
|
||||||
if is_unstable_enabled {
|
if dopts.unstable_options {
|
||||||
PrintRequest::TargetSpec
|
PrintRequest::TargetSpec
|
||||||
} else {
|
} else {
|
||||||
early_error(
|
early_error(
|
||||||
|
@ -2370,7 +2369,6 @@ fn parse_externs(
|
||||||
matches: &getopts::Matches,
|
matches: &getopts::Matches,
|
||||||
debugging_opts: &DebuggingOptions,
|
debugging_opts: &DebuggingOptions,
|
||||||
error_format: ErrorOutputType,
|
error_format: ErrorOutputType,
|
||||||
is_unstable_enabled: bool,
|
|
||||||
) -> Externs {
|
) -> Externs {
|
||||||
if matches.opt_present("extern-private") && !debugging_opts.unstable_options {
|
if matches.opt_present("extern-private") && !debugging_opts.unstable_options {
|
||||||
early_error(
|
early_error(
|
||||||
|
@ -2392,13 +2390,6 @@ fn parse_externs(
|
||||||
let name = parts.next().unwrap_or_else(||
|
let name = parts.next().unwrap_or_else(||
|
||||||
early_error(error_format, "--extern value must not be empty"));
|
early_error(error_format, "--extern value must not be empty"));
|
||||||
let location = parts.next().map(|s| s.to_string());
|
let location = parts.next().map(|s| s.to_string());
|
||||||
if location.is_none() && !is_unstable_enabled {
|
|
||||||
early_error(
|
|
||||||
error_format,
|
|
||||||
"the `-Z unstable-options` flag must also be passed to \
|
|
||||||
enable `--extern crate_name` without `=path`",
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
let entry = externs
|
let entry = externs
|
||||||
.entry(name.to_owned())
|
.entry(name.to_owned())
|
||||||
|
@ -2483,12 +2474,10 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let is_unstable_enabled = nightly_options::is_unstable_enabled(matches);
|
|
||||||
let prints = collect_print_requests(
|
let prints = collect_print_requests(
|
||||||
&mut cg,
|
&mut cg,
|
||||||
&mut debugging_opts,
|
&mut debugging_opts,
|
||||||
matches,
|
matches,
|
||||||
is_unstable_enabled,
|
|
||||||
error_format,
|
error_format,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -2521,7 +2510,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let externs = parse_externs(matches, &debugging_opts, error_format, is_unstable_enabled);
|
let externs = parse_externs(matches, &debugging_opts, error_format);
|
||||||
|
|
||||||
let crate_name = matches.opt_str("crate-name");
|
let crate_name = matches.opt_str("crate-name");
|
||||||
|
|
||||||
|
|
|
@ -615,10 +615,6 @@ fn parse_externs(matches: &getopts::Matches) -> Result<Externs, String> {
|
||||||
let mut parts = arg.splitn(2, '=');
|
let mut parts = arg.splitn(2, '=');
|
||||||
let name = parts.next().ok_or("--extern value must not be empty".to_string())?;
|
let name = parts.next().ok_or("--extern value must not be empty".to_string())?;
|
||||||
let location = parts.next().map(|s| s.to_string());
|
let location = parts.next().map(|s| s.to_string());
|
||||||
if location.is_none() && !nightly_options::is_unstable_enabled(matches) {
|
|
||||||
return Err("the `-Z unstable-options` flag must also be passed to \
|
|
||||||
enable `--extern crate_name` without `=path`".to_string());
|
|
||||||
}
|
|
||||||
let name = name.to_string();
|
let name = name.to_string();
|
||||||
// For Rustdoc purposes, we can treat all externs as public
|
// For Rustdoc purposes, we can treat all externs as public
|
||||||
externs.entry(name)
|
externs.entry(name)
|
||||||
|
|
|
@ -140,7 +140,7 @@ fn opts() -> Vec<RustcOptGroup> {
|
||||||
}),
|
}),
|
||||||
stable("cfg", |o| o.optmulti("", "cfg", "pass a --cfg to rustc", "")),
|
stable("cfg", |o| o.optmulti("", "cfg", "pass a --cfg to rustc", "")),
|
||||||
stable("extern", |o| {
|
stable("extern", |o| {
|
||||||
o.optmulti("", "extern", "pass an --extern to rustc", "NAME=PATH")
|
o.optmulti("", "extern", "pass an --extern to rustc", "NAME[=PATH]")
|
||||||
}),
|
}),
|
||||||
unstable("extern-html-root-url", |o| {
|
unstable("extern-html-root-url", |o| {
|
||||||
o.optmulti("", "extern-html-root-url",
|
o.optmulti("", "extern-html-root-url",
|
||||||
|
|
|
@ -4,7 +4,6 @@ all:
|
||||||
$(RUSTC) bar.rs --crate-type=rlib
|
$(RUSTC) bar.rs --crate-type=rlib
|
||||||
$(RUSTC) bar.rs --crate-type=rlib -C extra-filename=-a
|
$(RUSTC) bar.rs --crate-type=rlib -C extra-filename=-a
|
||||||
$(RUSTC) bar-alt.rs --crate-type=rlib
|
$(RUSTC) bar-alt.rs --crate-type=rlib
|
||||||
$(RUSTC) foo.rs --extern hello && exit 1 || exit 0
|
|
||||||
$(RUSTC) foo.rs --extern bar=no-exist && exit 1 || exit 0
|
$(RUSTC) foo.rs --extern bar=no-exist && exit 1 || exit 0
|
||||||
$(RUSTC) foo.rs --extern bar=foo.rs && exit 1 || exit 0
|
$(RUSTC) foo.rs --extern bar=foo.rs && exit 1 || exit 0
|
||||||
$(RUSTC) foo.rs \
|
$(RUSTC) foo.rs \
|
||||||
|
@ -15,3 +14,6 @@ all:
|
||||||
--extern bar=$(TMPDIR)/libbar.rlib \
|
--extern bar=$(TMPDIR)/libbar.rlib \
|
||||||
--extern bar=$(TMPDIR)/libbar-a.rlib
|
--extern bar=$(TMPDIR)/libbar-a.rlib
|
||||||
$(RUSTC) foo.rs --extern bar=$(TMPDIR)/libbar.rlib
|
$(RUSTC) foo.rs --extern bar=$(TMPDIR)/libbar.rlib
|
||||||
|
# Try to be sneaky and load a private crate from with a non-private name.
|
||||||
|
$(RUSTC) rustc.rs -Zforce-unstable-if-unmarked --crate-type=rlib
|
||||||
|
$(RUSTC) gated_unstable.rs --extern alloc=$(TMPDIR)/librustc.rlib 2>&1 | $(CGREP) 'rustc_private'
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
fn main() {}
|
1
src/test/run-make-fulldeps/extern-flag-fun/rustc.rs
Normal file
1
src/test/run-make-fulldeps/extern-flag-fun/rustc.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub fn foo() {}
|
18
src/test/run-make-fulldeps/extern-flag-pathless/Makefile
Normal file
18
src/test/run-make-fulldeps/extern-flag-pathless/Makefile
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
-include ../tools.mk
|
||||||
|
|
||||||
|
# Test mixing pathless --extern with paths.
|
||||||
|
|
||||||
|
all:
|
||||||
|
$(RUSTC) bar-static.rs --crate-name=bar --crate-type=rlib
|
||||||
|
$(RUSTC) bar-dynamic.rs --crate-name=bar --crate-type=dylib -C prefer-dynamic
|
||||||
|
# rlib preferred over dylib
|
||||||
|
$(RUSTC) foo.rs --extern bar
|
||||||
|
$(call RUN,foo) | $(CGREP) 'static'
|
||||||
|
$(RUSTC) foo.rs --extern bar=$(TMPDIR)/libbar.rlib --extern bar
|
||||||
|
$(call RUN,foo) | $(CGREP) 'static'
|
||||||
|
# explicit --extern overrides pathless
|
||||||
|
$(RUSTC) foo.rs --extern bar=$(call DYLIB,bar) --extern bar
|
||||||
|
$(call RUN,foo) | $(CGREP) 'dynamic'
|
||||||
|
# prefer-dynamic does what it says
|
||||||
|
$(RUSTC) foo.rs --extern bar -C prefer-dynamic
|
||||||
|
$(call RUN,foo) | $(CGREP) 'dynamic'
|
|
@ -0,0 +1,3 @@
|
||||||
|
pub fn f() {
|
||||||
|
println!("dynamic");
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
pub fn f() {
|
||||||
|
println!("static");
|
||||||
|
}
|
3
src/test/run-make-fulldeps/extern-flag-pathless/foo.rs
Normal file
3
src/test/run-make-fulldeps/extern-flag-pathless/foo.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
fn main() {
|
||||||
|
bar::f();
|
||||||
|
}
|
|
@ -1,8 +1,7 @@
|
||||||
-include ../tools.mk
|
-include ../tools.mk
|
||||||
|
|
||||||
all: extern_absolute_paths.rs krate2
|
all: extern_absolute_paths.rs krate2
|
||||||
$(RUSTC) extern_absolute_paths.rs -Zsave-analysis --edition=2018 \
|
$(RUSTC) extern_absolute_paths.rs -Zsave-analysis --edition=2018 --extern krate2
|
||||||
-Z unstable-options --extern krate2
|
|
||||||
cat $(TMPDIR)/save-analysis/extern_absolute_paths.json | "$(PYTHON)" validate_json.py
|
cat $(TMPDIR)/save-analysis/extern_absolute_paths.json | "$(PYTHON)" validate_json.py
|
||||||
|
|
||||||
krate2: krate2.rs
|
krate2: krate2.rs
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// aux-build:use_crate_2.rs
|
// aux-build:use_crate_2.rs
|
||||||
// build-aux-docs
|
// build-aux-docs
|
||||||
// edition:2018
|
// edition:2018
|
||||||
// compile-flags:--extern use_crate --extern use_crate_2 -Z unstable-options
|
// compile-flags:--extern use_crate --extern use_crate_2
|
||||||
|
|
||||||
// During the buildup to Rust 2018, rustdoc would eagerly inline `pub use some_crate;` as if it
|
// During the buildup to Rust 2018, rustdoc would eagerly inline `pub use some_crate;` as if it
|
||||||
// were a module, so we changed it to make `pub use`ing crate roots remain as a `pub use` statement
|
// were a module, so we changed it to make `pub use`ing crate roots remain as a `pub use` statement
|
||||||
|
|
10
src/test/ui-fulldeps/pathless-extern-unstable.rs
Normal file
10
src/test/ui-fulldeps/pathless-extern-unstable.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
// ignore-stage1
|
||||||
|
// edition:2018
|
||||||
|
// compile-flags:--extern rustc
|
||||||
|
|
||||||
|
// Test that `--extern rustc` fails with `rustc_private`.
|
||||||
|
|
||||||
|
pub use rustc;
|
||||||
|
//~^ ERROR use of unstable library feature 'rustc_private'
|
||||||
|
|
||||||
|
fn main() {}
|
12
src/test/ui-fulldeps/pathless-extern-unstable.stderr
Normal file
12
src/test/ui-fulldeps/pathless-extern-unstable.stderr
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead?
|
||||||
|
--> $DIR/pathless-extern-unstable.rs:7:9
|
||||||
|
|
|
||||||
|
LL | pub use rustc;
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= note: for more information, see https://github.com/rust-lang/rust/issues/27812
|
||||||
|
= help: add `#![feature(rustc_private)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
9
src/test/ui/pathless-extern-ok.rs
Normal file
9
src/test/ui/pathless-extern-ok.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
// edition:2018
|
||||||
|
// compile-flags:--extern alloc
|
||||||
|
// build-pass
|
||||||
|
|
||||||
|
// Test that `--extern alloc` will load from the sysroot without error.
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _: Vec<i32> = alloc::vec::Vec::new();
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue