Skip to content

Commit

Permalink
v0.4.0: support compile time features and env vars (#3)
Browse files Browse the repository at this point in the history
* Support features and compile-time env vars

* Rename `workspace_dir` -> `WORKSPACE_DIR`

* Yes local testing for now

* Checkin changes

* Add changes to rust-bins

* Checkin updates for rust-workspaces

* Add determination of Lambda architecture

* Update docs

* Update stuff

* Remove unused imports

* Fix typo

* Add section on conditional compilation

* Fix docs

* Update docs

* Update docs

* Update docs

* Update docs

* Bump version
  • Loading branch information
cb-rnag committed Mar 8, 2022
1 parent b964cac commit 7c29e76
Show file tree
Hide file tree
Showing 27 changed files with 11,699 additions and 32,127 deletions.
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,33 @@ Possible header types:

## [Unreleased]

## v0.4.0 (2022-03-08)

### Features

- Rename `Settings` parameter `workspace_dir` -> `WORKSPACE_DIR`.
- Add support for Rust [features] and compile-time [environment variables].
- Add parameters to `Settings`:
- `FEATURES`
- `BUILD_ENVIRONMENT`
- `EXTRA_BUILD_ARGS`
- Add parameters to `RustFunctionProps`:
- `features`
- `buildEnvironment`
- `extraBuildArgs`

[features]: https://doc.rust-lang.org/cargo/reference/features.html
[environment variables]: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates

### Breaking Changes

- Updated default target from `x86_64-unknown-linux-musl` -> `x86_64-unknown-linux-gnu`; technically this is not a _breaking_ change, but it will require the target to be added via `rustup`.

### Bug Fixes

- Ensure that the Lambda architecture is correctly set based on the `target` to cross-compile to.
- Do not pass `--target` when running `cargo check`, as this can result in errors in some cases.

## v0.3.0 (2022-02-23)

### Features
Expand Down
84 changes: 71 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ The `RustFunction` construct creates a Lambda function with automatic bundling a
$ cargo install cross
```

3. Install the **x86_64-unknown-linux-musl** toolchain with Rustup by running:
3. Install the **x86_64-unknown-linux-gnu** toolchain with Rustup by running:

```shell
$ rustup target add x86_64-unknown-linux-musl
$ rustup target add x86_64-unknown-linux-gnu
```

Finally, ensure you have [Docker] installed and running, as it will be used by `cross` to compile Rust code for deployment.
Expand Down Expand Up @@ -108,7 +108,7 @@ When bundling the code, the `RustFunction` runs the following steps in order:
- First it runs `cargo check` to confirm that the Rust code can compile.
Note that this is an optional step, and [can be disabled](#settings) as mentioned below.

- Next it calls `cross build`, and passes in the `--release` and `--target` flags, so it compiles for a Lambda environment - which defaults to the **x86_64-unknown-linux-musl** target, as mentioned above.
- Next it calls `cross build`, and passes in the `--release` and `--target` flags, so it compiles for a Lambda environment - which defaults to the **x86_64-unknown-linux-gnu** target, as mentioned above.

- Finally, it copies the release app binary from the `target/` folder to a file named `bootstrap`, which the Lambda custom runtime environment looks for. It adds this new file under the _build directory_, which defaults to a `.build/` folder under the directory where `cdk` was invoked.

Expand Down Expand Up @@ -202,19 +202,74 @@ You can find a more complete project structure in the [rust-workspaces/] CDK sam
[workspaces]: https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html
[rust-workspaces/]: https://github.com/rnag/rust.aws-cdk-lambda/tree/main/cdk-examples/rust-workspaces

## Conditional Compilation

A common use case is building Rust code with enabled [features], and compile-
time environment variables that can be used with the [`env!`] macro.

For example, we might want to run different logic in our code for _development_ and _production_ environments, or call a different API endpoint depending on which environment we are deploying code to.

For a sample CDK app that demonstrate such usage, check out the [rust-bins/] example.

### Enabling Features

You can achieve conditional compilation by [introducing features](https://stackoverflow.com/a/27634313/10237506) which can later be enabled in Rust code.

In the `Cargo.toml`, create a new `features` section:

```toml
[features]
my-feature = [] # feature has no explicit dependencies
```

In your code, add the line `#[cfg(feature="my-feature")]` before a function declaration, or before a statement to execute.

In your CDK code in the `lib/` folder, add the following line:

```ts
// Enable features at compile or build time.
Settings.FEATURES = ['my-feature'];
```

### Build Environment Variables

You can also introduce environment variables which are resolved at build or compile time. These values can be used in code via the [`env!`] macro in Rust.

In your code, add a call to the `env!()` macro:

```rust
// Retrieve an environment variable set at build (compile) time.
let build_value = env!("MY_BUILD_VAR");
```

In your CDK code in the `lib/` folder, add the following line:

```ts
// Enable environment variables at compile or build time.
Settings.BUILD_ENVIRONMENT = {
MY_BUILD_VAR: 'Hello World! Testing 123.',
};
```

[features]: https://doc.rust-lang.org/cargo/reference/features.html
[`env!`]: https://doc.rust-lang.org/std/macro.env.html

## Rust Function Properties

Below lists some commonly used properties you can pass in to the `RustFunction` construct.

| Name | Description |
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `target` | Build target to cross-compile to. Defaults to the target for Linux MUSL, `x86_64-unknown-linux-musl`. |
| `directory` | Entry point where the project's main `Cargo.toml` is located. By default, the construct will use directory where `cdk` was invoked as the directory where Cargo files are located. |
| `buildDir` | Default Build directory, which defaults to a `.build` folder under the project's root directory. |
| `bin` | Executable name to pass to `--bin` |
| `package` | Workspace package name to pass to `--package` |
| `setupLogging` | Determines whether we want to set up [library logging](https://rust-lang-nursery.github.io/rust-cookbook/development_tools/debugging/config_log.html) - i.e. set the `RUST_LOG` environment variable - for the lambda function.<br><br>The format defaults to `warn,module_name=debug`, which means that the default log level is `warn`, and the executable or library's log level is `debug`. |
| |
| Name | Description |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `target` | Build target to cross-compile to. Defaults to the target for the **x86_64** architecture, `x86_64-unknown-linux-gnu`. |
| `directory` | Entry point where the project's main `Cargo.toml` is located. By default, the construct will use directory where `cdk` was invoked as the directory where Cargo files are located. |
| `buildDir` | Default Build directory, which defaults to a `.build` folder under the project's root directory. |
| `bin` | Executable name to pass to `--bin` |
| `package` | Workspace package name to pass to `--package` |
| `setupLogging` | Determines whether we want to set up [library logging](https://rust-lang-nursery.github.io/rust-cookbook/development_tools/debugging/config_log.html) - i.e. set the `RUST_LOG` environment variable - for the lambda function.<br><br>The format defaults to `warn,module_name=debug`, which means that the default log level is `warn`, and the executable or library's log level is `debug`. |
| |
| `features` | A list of features to activate when compiling Rust code. These must also be added to the `Cargo.toml` file. |
| `buildEnvironment` | Key-value pairs that are passed in at compile time, i.e. to `cargo build` or `cross build`. This differs from `environment`, which determines the environment variables which are set on the AWS Lambda function itself. |
| `extraBuildArgs` | Additional arguments that are passed in at build time to both `cargo check` and `cross build`. For example, [`--all-features`]. |

## Settings

Expand All @@ -232,4 +287,7 @@ Below are some useful _global_ defaults which can be set for all Rust Lambda Fun
| `RUN_CARGO_CHECK` | Whether to run `cargo check` to validate Rust code before building it with `cross`. Defaults to _true_. |
| `DEFAULT_LOG_LEVEL` | Log Level for non-module libraries. Note that this value is only used when `RustFunctionProps.setupLogging` is enabled. Defaults to `warn`. |
| `MODULE_LOG_LEVEL` | Log Level for a module (i.e. the executable). Note that this value is only used when `RustFunctionProps.setupLogging` is enabled. Defaults to `debug`. |
| `workspace_dir` | Sets the root workspace directory. By default, the workspace directory is assumed to be the directory where `cdk` was invoked.<br><br>This directory should contain at the minimum a `Cargo.toml` file which defines the workspace members. |
| `WORKSPACE_DIR` | Sets the root workspace directory. By default, the workspace directory is assumed to be the directory where `cdk` was invoked.<br><br>This directory should contain at the minimum a `Cargo.toml` file which defines the workspace members. |
| `FEATURES` | A list of features to activate when compiling Rust code. These must also be added to the `Cargo.toml` file. |
| `BUILD_ENVIRONMENT` | Key-value pairs that are passed in at compile time, i.e. to `cargo build` or `cross build`. This differs from `environment`, which determines the environment variables which are set on the AWS Lambda function itself. |
| `EXTRA_BUILD_ARGS` | Additional arguments that are passed in at build time to both `cargo check` and `cross build`. For example, [`--all-features`]. |
9 changes: 9 additions & 0 deletions cdk-examples/rust-bins/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,12 @@ aws-sdk-s3 = "0.6.0"
# Dependencies for `my_lambda2`
anyhow = "1.0.53"
reqwest = { version = "0.11.9", default-features=false, features = ["rustls-tls", "json", "blocking", "stream", "multipart"] }

[features]

# We could choose to enable any project dependencies marked as `optional = true`
# here, but in this case it simply serves as a config flag that we use in code.
#
# See https://stackoverflow.com/a/27634313/10237506 for more info.
my-dev-feature = []
my-prod-feature = []
17 changes: 15 additions & 2 deletions cdk-examples/rust-bins/lib/rust-bins-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,31 @@ import { Stack, StackProps } from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';
import { BlockPublicAccess } from 'aws-cdk-lib/aws-s3';
import { Construct } from 'constructs';
import { RustFunction, Settings } from 'rust.aws-cdk-lambda';
// import { RustFunction, Settings } from 'rust.aws-cdk-lambda';
// uncomment for local testing
// import { RustFunction, Settings } from '../../../lib';
import { RustFunction, Settings } from '../../../lib';

export class RustBinsStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);

// Enable optional features and env variables at build (compile) time.
Settings.FEATURES = [
'my-dev-feature',
// uncomment to see how the lambda output changes!
// 'my-prod-feature'
];
Settings.BUILD_ENVIRONMENT = {
LEARN_RUST_URL: 'https://doc.rust-lang.org',
};

// Uncomment if you want to build (e.g. cross-compile) each target, or
// binary, individually.
// Settings.BUILD_INDIVIDUALLY = true;

// Uncomment to cross-compile Rust code to a different Lambda architecture.
// Settings.TARGET = 'aarch64-unknown-linux-gnu';

const bucket = new s3.Bucket(this, 'RustBinsBucket', {
blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
publicReadAccess: false,
Expand Down
Loading

0 comments on commit 7c29e76

Please sign in to comment.