mio: Linking fails with x86_64-pc-windows-gnu toolchain

Mio defines NtCancelIoFileEx as follows:

#[link(name = "ntdll")]
extern "system" {
    /// See <https://processhacker.sourceforge.io/doc/ntioapi_8h.html#a0d4d550cad4d62d75b76961e25f6550c>
    ///
    /// This is an undocumented API and as such not part of <https://github.com/microsoft/win32metadata>
    /// from which `windows-sys` is generated, and also unlikely to be added, so
    /// we manually declare it here
    fn NtCancelIoFileEx(
        FileHandle: HANDLE,
        IoRequestToCancel: *mut IO_STATUS_BLOCK,
        IoStatusBlock: *mut IO_STATUS_BLOCK,
    ) -> NTSTATUS;
}

If I add fn main(){} and build with cargo build I get the following linker error:

error: linking with `x86_64-w64-mingw32-gcc` failed: exit code: 1
  |
  = note: "x86_64-w64-mingw32-gcc" "-fno-use-linker-plugin" "-Wl,--dynamicbase" "-Wl,--disable-auto-image-base" "-m64" "-Wl,--high-entropy-va" "C:\\Users\\eiderdaus\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\self-contained\\crt2.o" "C:\\Users\\eiderdaus\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\rsbegin.o" "C:\\Users\\eiderdaus\\AppData\\Local\\Temp\\rustcJSg3zJ\\symbols.o" "C:\\foo\\target\\debug\\deps\\foo-cb89f6e868929cf3.1bc41oyhwfcqyo6z.rcgu.o" "C:\\foo\\target\\debug\\deps\\foo-cb89f6e868929cf3.2e77gpka6erk4c1x.rcgu.o" "C:\\foo\\target\\debug\\deps\\foo-cb89f6e868929cf3.3wy12xbuznp9hor0.rcgu.o" "C:\\foo\\target\\debug\\deps\\foo-cb89f6e868929cf3.4f95o7n55leh2ke1.rcgu.o" "C:\\foo\\target\\debug\\deps\\foo-cb89f6e868929cf3.4rbije3ghxyb129a.rcgu.o" "C:\\foo\\target\\debug\\deps\\foo-cb89f6e868929cf3.53992k6tesbub9hu.rcgu.o" "-L" "C:\\foo\\target\\debug\\deps" "-L" "C:\\Users\\eiderdaus\\.cargo\\registry\\src\\github.com-1ecc6299db9ec823\\windows_x86_64_gnu-0.42.0\\lib" "-L" "C:\\Users\\eiderdaus\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib" "-lntdll" "-Wl,-Bstatic" "C:\\foo\\target\\debug\\deps\\libwindows_sys-87741728b4e67991.rlib" "C:\\Users\\eiderdaus\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\libstd-583b0c1a8d918e48.rlib" "C:\\Users\\eiderdaus\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\libpanic_unwind-32bbe0f97d4b5e74.rlib" "C:\\Users\\eiderdaus\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\libobject-b4abf79acd3cfd5f.rlib" "C:\\Users\\eiderdaus\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\libmemchr-01a39e8be25b0a33.rlib" "C:\\Users\\eiderdaus\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\libaddr2line-4741964b98a78b52.rlib" "C:\\Users\\eiderdaus\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\libgimli-ca9aa9ad07d84224.rlib" "C:\\Users\\eiderdaus\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\librustc_demangle-77da45e82831415d.rlib" "C:\\Users\\eiderdaus\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\libstd_detect-6b504ee3232db397.rlib" "C:\\Users\\eiderdaus\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\libhashbrown-f23e5590b13d2ba1.rlib" "C:\\Users\\eiderdaus\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\libminiz_oxide-707623ebc84f4938.rlib" "C:\\Users\\eiderdaus\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\libadler-6c1f623f129f8c4e.rlib" "C:\\Users\\eiderdaus\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\librustc_std_workspace_alloc-b83298f4db169fa7.rlib" "C:\\Users\\eiderdaus\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\libunwind-24a266989a087673.rlib" "C:\\Users\\eiderdaus\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\libcfg_if-451066e352fc52df.rlib" "C:\\Users\\eiderdaus\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\liblibc-f0b9b386ac2b1f89.rlib" "C:\\Users\\eiderdaus\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\liballoc-aecd3bcc2854e359.rlib" "C:\\Users\\eiderdaus\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\librustc_std_workspace_core-295042be5ab55e2d.rlib" "C:\\Users\\eiderdaus\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\libcore-427c90bb0249ec1c.rlib" "C:\\Users\\eiderdaus\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\libcompiler_builtins-efeda5f809566e63.rlib" "-Wl,-Bdynamic" "-lwindows" "-lkernel32" "-ladvapi32" "-luserenv" "-lkernel32" "-lws2_32" "-lbcrypt" "-lgcc_eh" "-l:libpthread.a" "-lmsvcrt" "-lmingwex" "-lmingw32" "-lgcc" "-lmsvcrt" "-luser32" "-lkernel32" "-Wl,--nxcompat" "-nostartfiles" "-L" "C:\\Users\\eiderdaus\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib" "-L" "C:\\Users\\eiderdaus\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\self-contained" "-o" "C:\\foo\\target\\debug\\deps\\foo-cb89f6e868929cf3.exe" "-Wl,--gc-sections" "-no-pie" "-nodefaultlibs" "C:\\Users\\eiderdaus\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\rsend.o"
  = note: ld: cannot find -lntdll


warning: `foo` (bin "foo") generated 1 warning
error: could not compile `foo` due to previous error; 1 warning emitted

Compiling the example from README.md fails with the same error (only with more dependencies in the linker command) and so does my Tokio-dependent application.

The reason is obviously #[link(name = "ntdll")]. There’s no libntdll.a in my %USERPROFILE%\.rustup\toolchains\stable-x86_64-pc-windows-gnu\lib\rustlib\x86_64-pc-windows-gnu\lib\self-contained folder.

The windows-sys crate for example also provides some functions from ntdll.dll but those are annotated with link(name = “windows”) and they provide their own libwindows.a. This works flawlessly for me. winapi-rs provides libwindows_ntdll.a in addition to many other libraries but it doesn’t actually provide any functions from ntdll.dll (I think).

I am using Windows 10 and just reinstalled Rust freshly via Rustup, changing only the platform tuple to x86_64-pc-windows-gnu and leaving all other defaults alone. I am uncertain which version of Rust or mio introduced this issue. I only found out when I wanted to recompile a Tokio-dependent project which still worked a few months ago at least.

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 26 (1 by maintainers)

Most upvoted comments

since it’s now documented: https://learn.microsoft.com/en-us/windows/win32/devnotes/nt-cancel-io-file-ex

Don’t read this documentation though! It is very much incorrect, reading it will make you dumber and your program crash.

The signature spelled out in the issue description is the right one.

Why are you not using x86_64-pc-windows-msvc?

Do I really need to elaborate? Honestly your question baffles me. There are many reasons:

  • It provides a much nicer “works out of the box” experience because it’s way simpler to set up (literally asking Rustup to install x86_64-pc-windows-gnu was all I had to do, no MSVC or build tools needed).
  • It doesn’t burden my hard disk as much.
  • If my code works with x86_64-pc-windows-gnu I’ll be more likely to be able to cross-compile from Linux should I ever need to.
  • I like open source:
    • It makes me independent from a single company and
    • open source software has other advantages (figuring those out is left as an exercise for the reader).
  • I don’t really see many advantages of the MSVC toolchain:
    • Apart from this exact issue above I never had any problems at all with the GNU toolchain.
    • Because debugging C++ using MSVC is such a nice experience one time I tried to setup debugging Rust with MSVC and miserably failed. The Rust extension for MSVC was barely working at the time and has not been updated since.
  • At times I dislike MSFT.
  • It’s cheaper for companies and other entities that can’t use MSVC for free. This is especially relevant to me.

Why are you not using x86_64-pc-windows-msvc?

https://github.com/microsoft/windows-rs/pull/2573 updated the repo with the latest metadata. Please kick the tires and let me know if you experience any issues.

windows-targets 0.48.2 will include these imports.

Sure, I’ll see about getting this function included in the Win32 metadata.

Okay.

Please forgive my unfriendlyness, I regretted my wording the moment I pressed the comment button.

But you’re running Windows 10? Not judging or disagreeing mind you…

Well as you might imagine I have my reasons for that, too 😅

Does changing #[link(name = "ntdll")] to #[link(name = "windows")] work? Or windows_ntdll, which winapi seems to do?

Yes both do work. It’s winapi_ntdll for winapi-rs, I have spelled it wrongly before. I just had to figure out how to patch dependent crates for testing. Is the [patch] section in Cargo.toml the way to go? Somehow it spits out the same linker error three times in a row now if I override mio with a path dependency that refers to an unchanged Mio repository.

Alternatively we can try adding it to windows-sys since it’s now documented: https://learn.microsoft.com/en-us/windows/win32/devnotes/nt-cancel-io-file-ex (/cc @kennykerr).

That would be great. I think changing the link attribute without actually providing suitable linker import libraries makes this rather brittle as it depends on an implementation detail of windows-sys or winapi-rs.