I wrote the following angry rant a while ago after getting apoplectic at how stupid this whole song-and-dance is. I've cut the screenshots (because I'd have to upload them somewhere and they've SVG and just urgh). It's not entirely waterproof, but if nothing else helps, this might do it.
Also: I tested these instructions on a brand new, totally fresh Windows 10 install in 64-bit.
[cut rambling about installing Rust; short version: this doesn't work with the msvc
compilers.]
Installing MSYS2
This is a little more involved. First, you will need to get the MSYS2 installer.
[blah blah blah, SourceForge evil, blah, blah, blah]
You can get the appropriate downloader from the MSYS2 installer website.
Note: You should select whatever "bitness" your version of Windows is. Whatever you select has no bearing whatsoever on the bitness of the binaries you intend to produce. msys2-i686-*.exe
is for 32-bit Windows, msys2-x86_64-*.exe
is for 64-bit Windows. I am not aware of any actual problems with using 32-bit MSYS2 on 64-bit Windows.
When installing MSYS2, you will most likely want to install to a location that does not contain spaces. As noted above, UNIX tools are notoriously bad at dealing with spaces in path names, and MSYS is full of them; it only takes one to ruin your day.
You should now follow the rest of the installation instructions on the installer website. You can get an appropriate MSYS2 shell using the creatively named "MSYS2 Shell" shortcut the installer added to the start menu under the "MSYS2 32bit" or "MSYS2 64bit" group (as appropriate).
[cut image]
MSYS2 and MinGW-w64
And now I have to explain this mess.
When you install MSYS2, it actually adds three Start Menu entries, each of which does something slightly different.
[cut image]
-
MSYS2 Shell: just drops you into a regular MSYS2 bash shell.
-
MinGW-w64 Win32 Shell: drops you into a MSYS2 bash shell configured to use the MinGW-w64 32-bit toolchain.
-
MinGW-w64 Win64 Shell: drops you into a MSYS2 bash shell configured to use the MinGW-w64 64-bit toolchain.
Now, despite the name, MinGW-w64 is not specific to 64-bit versions of Windows, nor does it only create 64-bit executables. Really, "MinGW-w64" is a brand name, more than anything technically meaningful. It's terribly named, but there's really nothing we can do about that.
For the purposes of building Rust software, you need to pick either "MinGW-w64 Win32 Shell" or "MinGW-w64 Win64 Shell", based on which bitness your Rust compiler is. 32-bit Rust, use "Win32"; 64-bit Rust, use "Win64".
If you get this wrong, system library crates will not link properly!
Now, open a MSYS2 shell (preferably of the kind you will use with Rust).
MSYS2 has its a package manager for taking care of installing libraries and tools, as well as their dependencies. Unfortunately, it's the package manager from Arch Linux, which means almost all of the documentation and instructions you'll find for it apply to Arch Linux and not necessarily MSYS2. You can use man pacman
from a MSYS2 shell to get the manual page, or pacman -h
for brief usage instructions.
Since we're going to want a full GCC install for compiling *-sys
crates, let's find out what the appropriate package is called. You can do this by running pacman -Ss 'gcc$'
from the shell. [^pacman-ss-gcc]
[cut image]
If you look carefully, you'll note that there are actually three versions of GCC in this list:
mingw32/mingw-w64-i686-gcc
mingw64/mingw-w64-x86_64-gcc
msys/gcc
You want exactly one of these. If you are using 32-bit Rust, you want mingw32/mingw-w64-i686-gcc
. If you are using 64-bit Rust, you want mingw64/mingw-w64-x86_64-gcc
.
You do not want msys/gcc
, because that is for compiling software that is meant to be used with MSYS2. We want to build software that is targetting a particular bitness of Windows, using a compiler built for MSYS2.
So, install the appropriate package now with pacman -S
followed by the package's name. This will also install all of its dependencies.
At this point, you should be able to use gcc --version
to verify that GCC is, indeed, installed.
OpenSSL
For this part, we'll need an example crate. The easiest one is probably the "Hello, World" example for Iron, a Rust HTTP server framework.
Drop into a shell or command prompt and execute:
cargo new --bin iron-test
This will create a new directory called iron-test
for us to put our code in. Drop in and edit Cargo.toml
to read as follows:
[package]
name = "iron-test"
version = "0.1.0"
authors = ["your name will be here"]
[dependencies]
iron = "*"
Then, edit src/main.rs
to the following:
extern crate iron;
use iron::prelude::*;
use iron::status;
fn main() {
Iron::new(|_: &mut Request| {
Ok(Response::with((status::Ok, "Hello world!")))
}).http("localhost:3000").unwrap();
}
From the appropriate MinGW-w64 MSYS2 shell, run cargo build
from anywhere in the package directory. The build will first update the crates.io
registry, then download packages, then start compiling.
At some point after you see Compiling openssl-sys v0.6.2
(or whatever version), the build should fail.
[cut image]
The openssl/hmac.h: No such file or directory
implies that the problem is missing headers. Let's fix that. First, look for an OpenSSL package with pacman -Ss 'openssl'
.
[cut image]
Again, there is more than one plausible option. Again, you want the one under either mingw32/
or mingw64/
, not the one under msys/
. Specifically, for 32-bit Rust you want mingw32/mingw-w64-i686-openssl
; for 64-bit you want mingw64/mingw-w64-x86_64-openssl
.
Again, install with pacman -S PACKAGE_NAME
.
[cut image]
Re-running cargo build
should give us a new and excitingly different error message:
[cut image: error in question is explained below]
If you got an error about missing headers, you probably installed the wrong OpenSSL package; just go back and install the right one.
Note the ld: cannot find -leay32
and ld: cannot find -lssl32
lines near the bottom. This is because the linker Rust is using cannot find the OpenSSL libraries.
Note: The gcc
and ld
that Rust uses are different to the ones you installed. Rust comes with its own, private copies, since it uses gcc
as the linker on Windows. Yes, this can be confusing as hell if you're not aware of it.
The solution is to put the OpenSSL libraries where Rust can find them. First, the libraries you want are libeay32.dll
and ssleay32.dll
from MSYS2\mingw32\bin
or MSYS2\mingw64\bin
.
You may have noticed that the names don't match. Of course they don't, because we're using Windows and software from a UNIX background always manages to throw a spanner in the works. [^damn-unix]
The official way to solve this is to write a build script, but build scripts tend to be written on the assumption that libraries are all installed system-wide, which doesn't help us, and forking an entire project just to make the build script work gets old fast. As such, we can abuse the fact that when you build a Cargo package from the same directory as the Cargo.toml
is in (i.e. not in a subdirectory), rustc
will coincidentally search the following folders for libraries:
- For 32-bit Rust:
iron-test\bin\i686-pc-windows-gnu
.
- For 64-bit Rust:
iron-test\bin\x86_64-pc-windows-gnu
.
You will almost certainly have to create these directories. Don't make a typo!
At this point, you can rename the libraries.
-
libeay32.dll
→ eay32.dll
-
ssleay32.dll
→ ssl32.dll
Now, finally, you can re-run cargo build
. It should build cleanly. You can start the server using cargo run
and point your browser at http://localhost:3000/ to see the result. Do note that you should not try killing the server using Ctrl+C
from within MSYS2: this has a habit of leaving the server running invisibly in the background, requiring it to be killed from the Task Manager or similar.
That's (finally) it. Have fun with Rust.
Optional: Freeing Yourself From MSYS2
If you're comfortable with doing so, you can free yourself from the need to build some Rust *-sys
packages from the MSYS2 shell by adding GCC to the system PATH. Specifically, you want to add MSYS2\mingw32\bin
or MSYS2\mingw64\bin
, depending on which you installed.
Note that this will not help in the presence of crates that, say, use a Makefile
to build a dependency. In these cases, you will still need to drop into an MSYS2 shell in order to get make
and the other UNIX tools, or just fork and modify the crate to not need a Makefile in the first place.
Footnotes, because Markdown is a toy and they don't work on the forum:
[^pacman-ss-gcc]: The -S
tells pacman
to look at the remote package repository (as opposed to working with what's locally available), then to search (s
) for a package matching the regex gcc$
. This was used to eliminate the mountain of related-to GCC packages.
[^damn-unix]: UNIX advocates will insist that this is Window's fault for not being a UNIX system. This is textbook victim-blaming and bullying, and such people should be ruthlessly shamed on social media for their regressive and oppressive views. Especially if they use a Mac. Damn hipsters.