Skip to content

Commit

Permalink
Auto merge of #122268 - ChrisDenton:no-libc, r=Mark-Simulacrum
Browse files Browse the repository at this point in the history
Link MSVC default lib in core

## The Problem

On Windows MSVC, Rust invokes the linker directly. This means only the objects and libraries Rust explicitly passes to the linker are used. In short, this is equivalent to passing `-nodefaultlibs`, `-nostartfiles`, etc for gnu compilers.

To compensate for this [the libc crate links to the necessary libraries](https://github.com/rust-lang/libc/blob/a0f5b4b21391252fe38b2df9310dc65e37b07d9f/src/windows/mod.rs#L258-L261). The libc crate is then linked from std, thus when you use std you get the defaults back.or integrate with C/C++.

However, this has a few problems:

- For `no_std`, users are left to manually pass the default lib to the linker
- Whereas `std` has the opposite problem, using [`/nodefaultlib`](https://learn.microsoft.com/en-us/cpp/build/reference/nodefaultlib-ignore-libraries?view=msvc-170) doesn't work as expected because Rust treats them as normal libs. This is a particular problem when you want to use e.g. the debug CRT libraries in their place or integrate with C/C++..

## The solution

This PR fixes this in two ways:

- moves linking the default lib into `core`
- passes the lib to the linker using [`/defaultlib`](https://learn.microsoft.com/en-us/cpp/build/reference/defaultlib-specify-default-library?view=msvc-170). This allows users to override it in the normal way (i.e. with [`/nodefaultlib`](https://learn.microsoft.com/en-us/cpp/build/reference/nodefaultlib-ignore-libraries?view=msvc-170)).

This is more or less equivalent to what the MSVC C compiler does. You can see what this looks like in my second commit, which I'll reproduce here for convenience:

```rust
// In library/core
#[cfg(all(windows, target_env = "msvc"))]
#[link(
    name = "/defaultlib:msvcrt",
    modifiers = "+verbatim",
    cfg(not(target_feature = "crt-static"))
)]
#[link(name = "/defaultlib:libcmt", modifiers = "+verbatim", cfg(target_feature = "crt-static"))]
extern "C" {}
```

## Alternatives

- Add the above to `unwind` and `std` but not `core`
- The status quo
- Some other kind of compiler magic maybe

This bares some discussion so I've t-libs nominated it.
  • Loading branch information
bors committed Apr 14, 2024
2 parents 78bc0a5 + 87e1dd0 commit a8a88fe
Show file tree
Hide file tree
Showing 16 changed files with 46 additions and 15 deletions.
10 changes: 10 additions & 0 deletions library/core/src/ffi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -609,3 +609,13 @@ extern "rust-intrinsic" {
#[rustc_nounwind]
fn va_arg<T: sealed_trait::VaArgSafe>(ap: &mut VaListImpl<'_>) -> T;
}

// Link the MSVC default lib
#[cfg(all(windows, target_env = "msvc"))]
#[link(
name = "/defaultlib:msvcrt",
modifiers = "+verbatim",
cfg(not(target_feature = "crt-static"))
)]
#[link(name = "/defaultlib:libcmt", modifiers = "+verbatim", cfg(target_feature = "crt-static"))]
extern "C" {}
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@
#![feature(ip_bits)]
#![feature(is_ascii_octdigit)]
#![feature(isqrt)]
#![feature(link_cfg)]
#![feature(maybe_uninit_uninit_array)]
#![feature(non_null_convenience)]
#![feature(offset_of_enum)]
Expand Down
4 changes: 3 additions & 1 deletion library/panic_abort/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,7 @@ doc = false
alloc = { path = "../alloc" }
cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
core = { path = "../core" }
libc = { version = "0.2", default-features = false }
compiler_builtins = "0.1.0"

[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
libc = { version = "0.2", default-features = false }
4 changes: 3 additions & 1 deletion library/panic_unwind/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ doc = false
[dependencies]
alloc = { path = "../alloc" }
core = { path = "../core" }
libc = { version = "0.2", default-features = false }
unwind = { path = "../unwind" }
compiler_builtins = "0.1.0"
cfg-if = "1.0"

[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
libc = { version = "0.2", default-features = false }
2 changes: 1 addition & 1 deletion library/panic_unwind/src/seh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@

use alloc::boxed::Box;
use core::any::Any;
use core::ffi::{c_int, c_uint, c_void};
use core::mem::{self, ManuallyDrop};
use core::ptr::{addr_of, addr_of_mut};
use libc::{c_int, c_uint, c_void};

// NOTE(nbdd0121): The `canary` field is part of stable ABI.
#[repr(C)]
Expand Down
7 changes: 6 additions & 1 deletion library/std/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
panic_unwind = { path = "../panic_unwind", optional = true }
panic_abort = { path = "../panic_abort" }
core = { path = "../core", public = true }
libc = { version = "0.2.153", default-features = false, features = ['rustc-dep-of-std'], public = true }
compiler_builtins = { version = "0.1.105" }
profiler_builtins = { path = "../profiler_builtins", optional = true }
unwind = { path = "../unwind" }
Expand All @@ -31,6 +30,12 @@ rustc-demangle = { version = "0.1.21", features = ['rustc-dep-of-std'] }
miniz_oxide = { version = "0.7.0", optional = true, default-features = false }
addr2line = { version = "0.21.0", optional = true, default-features = false }

[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
libc = { version = "0.2.153", default-features = false, features = ['rustc-dep-of-std'], public = true }

[target.'cfg(all(windows, target_env = "msvc"))'.dependencies]
libc = { version = "0.2.153", default-features = false }

[target.'cfg(all(not(target_os = "aix"), not(all(windows, target_env = "msvc", not(target_vendor = "uwp")))))'.dependencies]
object = { version = "0.32.0", default-features = false, optional = true, features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive'] }

Expand Down
3 changes: 3 additions & 0 deletions library/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,9 @@ extern crate test;
#[allow(unused_imports)] // macros from `alloc` are not used on all platforms
#[macro_use]
extern crate alloc as alloc_crate;

// Many compiler tests depend on libc being pulled in by std
// so include it here even if it's unused.
#[doc(masked)]
#[allow(unused_extern_crates)]
extern crate libc;
Expand Down
2 changes: 1 addition & 1 deletion library/std/src/os/unix/net/addr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{fmt, io, mem, ptr};
#[cfg(not(unix))]
#[allow(non_camel_case_types)]
mod libc {
pub use libc::c_int;
pub use core::ffi::c_int;
pub type socklen_t = u32;
pub struct sockaddr;
#[derive(Clone)]
Expand Down
2 changes: 1 addition & 1 deletion library/std/src/os/unix/net/ancillary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use crate::sys::net::Socket;
))]
#[allow(non_camel_case_types)]
mod libc {
pub use libc::c_int;
pub use core::ffi::c_int;
pub struct ucred;
pub struct cmsghdr;
pub struct sockcred2;
Expand Down
4 changes: 2 additions & 2 deletions library/std/src/os/unix/net/datagram.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use libc::MSG_NOSIGNAL;
target_os = "haiku",
target_os = "nto",
)))]
const MSG_NOSIGNAL: libc::c_int = 0x0;
const MSG_NOSIGNAL: core::ffi::c_int = 0x0;

/// A Unix datagram socket.
///
Expand Down Expand Up @@ -317,7 +317,7 @@ impl UnixDatagram {
fn recv_from_flags(
&self,
buf: &mut [u8],
flags: libc::c_int,
flags: core::ffi::c_int,
) -> io::Result<(usize, SocketAddr)> {
let mut count = 0;
let addr = SocketAddr::new(|addr, len| unsafe {
Expand Down
8 changes: 4 additions & 4 deletions library/std/src/os/unix/net/listener.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,14 @@ impl UnixListener {
target_os = "espidf",
target_os = "horizon"
))]
const backlog: libc::c_int = 128;
const backlog: core::ffi::c_int = 128;
#[cfg(any(
target_os = "linux",
target_os = "freebsd",
target_os = "openbsd",
target_os = "macos"
))]
const backlog: libc::c_int = -1;
const backlog: core::ffi::c_int = -1;
#[cfg(not(any(
target_os = "windows",
target_os = "redox",
Expand Down Expand Up @@ -138,9 +138,9 @@ impl UnixListener {
unsafe {
let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
#[cfg(target_os = "linux")]
const backlog: libc::c_int = -1;
const backlog: core::ffi::c_int = -1;
#[cfg(not(target_os = "linux"))]
const backlog: libc::c_int = 128;
const backlog: core::ffi::c_int = 128;
cvt(libc::bind(
inner.as_raw_fd(),
core::ptr::addr_of!(socket_addr.addr) as *const _,
Expand Down
2 changes: 2 additions & 0 deletions library/test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ std = { path = "../std" }
core = { path = "../core" }
panic_unwind = { path = "../panic_unwind" }
panic_abort = { path = "../panic_abort" }

[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
libc = { version = "0.2.150", default-features = false }
4 changes: 3 additions & 1 deletion library/unwind/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ doc = false

[dependencies]
core = { path = "../core" }
libc = { version = "0.2.140", features = ['rustc-dep-of-std'], default-features = false }
compiler_builtins = "0.1.0"
cfg-if = "1.0"

[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
libc = { version = "0.2.140", features = ['rustc-dep-of-std'], default-features = false }

[target.'cfg(target_os = "xous")'.dependencies]
unwinding = { version = "0.2.1", features = ['rustc-dep-of-std', 'unwinder', 'fde-custom'], default-features = false }

Expand Down
4 changes: 4 additions & 0 deletions library/unwind/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
)]
#![allow(internal_features)]

// Force libc to be included even if unused. This is required by many platforms.
#[cfg(not(all(windows, target_env = "msvc")))]
extern crate libc as _;

cfg_if::cfg_if! {
if #[cfg(target_env = "msvc")] {
// Windows MSVC no extra unwinder support needed
Expand Down
2 changes: 1 addition & 1 deletion library/unwind/src/libunwind.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![allow(nonstandard_style)]

use libc::{c_int, c_void};
use core::ffi::{c_int, c_void};

#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq)]
Expand Down
2 changes: 1 addition & 1 deletion library/unwind/src/unwinding.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![allow(nonstandard_style)]

use libc::{c_int, c_void};
use core::ffi::{c_int, c_void};

#[repr(C)]
#[derive(Copy, Clone, PartialEq)]
Expand Down

0 comments on commit a8a88fe

Please sign in to comment.