Referencing crate data types and functions from build script

Viewed 36

I have a rust binary crate (well, it also has a lib.rs file for tests), and am trying to write a build script. This build script needs to generate a JSON file from a static rust object (custom struct crate::datatypes::ErrorMarkup) using serde, which gets imported by the binary crate. I know I could just reference the static object in the binary crate, but the binary crate must import a JSON file that may eventually come from some other source or may be modified between the build and run phases (i.e. the intent is to ship the built file and the JSON file).

How do I reference crate data types and functions from a build script?

Project structure:

- cargo.lock
- cargo.toml
- markup.json (target file)
- build.rs
- src
    - main.rs
    - lib.rs (exports)
    - datatypes.rs
- tests
    - verify.rs

I have tried both use pump_log_tool (my crate) and use crate::src and a billion other variations.

I understand this may be an issue due to build dependencies and runtime dependencies. Is there an obviously better way to achieve this goal?

1 Answers

A build script can't depend on the crate it builds

Cargo compiles build.rs into its own crate with its own dependencies. By making your build script depend on the crate it's building, you create a circular dependency that Cargo can't resolve.

Move the needed types to a different crate

The typical solution is to move the items that are (presumably) defined in datatypes.rs to their own, separate crate, which does not require a build script. (This is also a common pattern with procedural macros.) Your new project structure might look like

/
|- Cargo.toml
|- build.rs
|- src/
|  |- lib.rs
|  \- main.rs
|- pump_log_tool_types/
|  |- Cargo.toml
|  \- src/lib.rs

Then, in /Cargo.toml, create a workspace section and add the new crate:

[workspace]
# This is a path relative to the workspace root.
members = ["pump_log_tool_types"]

In pump_log_tool/Cargo.toml, add the pump_log_tool_types crate as both a normal dependency and a build dependency:

[dependencies]
pump_log_tool_types = { path = "pump_log_tool_types" }

[build-dependencies]
pump_log_tool_types = { path = "pump_log_tool_types" }

Now when you build pump_log_tool, the pump_log_tool_types crate will be built once and shared between the build script and the crate itself.

Related