Rust + AWS Lambda + Windows Part 1

Let it be known that the existing tutorials are all poor and lack thoroughness. They’re fine if you already have experience cross-compiling Rust AND working with AWS Lambda. I intend to cover everything from zero. It seems to me that a chief reason for the poor tutorials is the ever-evolving landscape of these technologies. If this ever stops working, LET ME KNOW! Much of this information is based on the README.md at the aws-lambda-rust-runtime repo.

Windows Tools

You’ll need to install these on Windows.

Debian Tools

As the heading, implies, I’ll be using Debian. Ubuntu, Kali, and a few others will probably work exactly as described this tutorial since they’re Debian forks. Many of the following commands will require input; I’m not mentioning that part, but this isn’t an automated process as written. Fire up PowerShell and enter:

wsl --set-default-version 2
wsl --install -d Debian

Follow the prompts, and a few minutes later you should be presented with a typical Unix terminal. There are a few tools we’ll need to install. Let’s update first.

sudo apt update && sudo apt upgrade
sudo apt install curl
sudo apt install build-essential

The following is optional.

sudo apt install zip

Let’s now install and configure Rust for WSL.

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

You’ll want to restart the WSL instance at this point. I’m not sure the following is strictly necessary, but I do it just to be sure.

rustup update
rustup target add x86_64-unknown-linux-gnu

Back to Windows

Navigate to the aws-lambda-rust-runtime repo on GitHub. Download the whole thing as a Zip or use the following git command (assuming you installed git):

git clone https://github.com/awslabs/aws-lambda-rust-runtime.git

For this tutorial, I’m extracting/cloning the files into C:\aws-lambda-rust-runtime, but anywhere should do so long as spaces are not in the path name. Let’s open up C:\aws-lambda-rust-runtime\lambda-runtime\examples\basic.rs with our text editor and make a few changes to better understand the connection between the code and the AWS Lambda environment.

#[derive(Deserialize)]
struct Request {
    command: String,
}

Change this to:

#[derive(Deserialize)]
struct Request {
    test_name: String,
}

Two more edits.

let command = event.payload.command;

// prepare the response
let resp = Response {
    req_id: event.context.request_id,
    msg: format!("Command {} executed.", command),
};

Note the subtle differences:

let output_name = event.payload.test_name;

// prepare the response
let resp = Response {
    req_id: event.context.request_id,
    msg: format!("Hello {}!", output_name),
};

Save the file, of course!

Back to Debian

What’s neat about WSL is that it mounts the entire C: root in its filesystem. I’m not sure about other letters however. This means we can:

cd /mnt/c/aws-lambda-rust-runtime/

The next command may seem confusing to those new to Rust, but it should work.

cargo build -p lambda_runtime --example basic --release --target x86_64-unknown-linux-gnu

If you didn’t install build-essential in Debian, this error will appear:

ERROR:

error: linker `cc` not found
  |
  = note: No such file or directory (os error 2)

error: could not compile `futures-core` due to previous error
warning: build failed, waiting for other jobs to finish...
error: build failed

Windows or Debian

After some time, several files will be created, but we’re interested in C:\aws-lambda-rust-runtime\target\x86_64-unknown-linux-gnu\release\examples\basic (note that’s a file not a directory!) We can rename this to bootstrap (no extension) and put it in a zip file of our choosing. For the sake of this example, I stuck with the terminal command:

cp ./target/x86_64-unknown-linux-gnu/release/examples/basic ./bootstrap && zip lambda.zip bootstrap && rm bootstrap

That copied the file into C:\aws-lambda-rust-runtime\ and changed the copied file’s name to bootstrap. Finally, it zipped it into lambda.zip and deleted the copied file.

The follow-up to this tutorial regarding AWS Lambda is now live!

Notes

I have tried several different approaches to completely eliminate the need for WSL and simply cross-compiling the Rust program directly into an x86_64-unknown-linux-gnu under Windows. I think there’s an incompatibility between Visual Studio C++ Build tools and the target OS. Hunting down clues, the solution may be to set Rust’s build environment to MingW.