|
| 1 | +# Build Time Tooling |
| 2 | + |
| 3 | +This section covers "build-time" tooling, or code that is run prior to compiling a crate's source code. |
| 4 | +Conventionally, build-time code lives in a `build.rs` file and is commonly referred to as a "build script". |
| 5 | +Common use cases include `rust` code generation and compilation of bundled `C/C++/asm` code. |
| 6 | +See `crates.io`'s [documentation on the matter][build-script-docs] for more information. |
| 7 | + |
| 8 | + |
| 9 | +| Recipe | Crates | Categories | |
| 10 | +|--------|--------|------------| |
| 11 | +| [Compile and link statically to a bundled C library][ex-cc-static-bundled] | [![cc-badge]][cc] | [![cat-development-tools-badge]][cat-development-tools] [![cat-rust-patterns-badge]][cat-rust-patterns] [![cat-external-ffi-bindings-badge]][cat-external-ffi-bindings] | |
| 12 | + |
| 13 | + |
| 14 | +[ex-cc-static-bundled]: #ex-cc-static-bundled |
| 15 | +<a name="ex-cc-static-bundled"></a> |
| 16 | +## Compile and link statically to a bundled C library |
| 17 | + |
| 18 | +[![cc-badge]][cc] [![cat-development-tools-badge]][cat-development-tools] [![cat-rust-patterns-badge]][cat-rust-patterns] [![cat-external-ffi-bindings-badge]][cat-external-ffi-bindings] |
| 19 | + |
| 20 | +To accommodate scenarios where additional `C`, `C++`, or `assembly` is required in a project, the [`cc`][cc] crate |
| 21 | +offers a simple api for compiling bundled `C/C++/asm` code into static libraries (`.a`) that can be statically linked to by `rustc`. |
| 22 | + |
| 23 | +The following example has some bundled `C` code (`src/hello.c`) that will be used from `rust`. |
| 24 | +Before compiling our `rust` source code, the `build` file (`build.rs`) specified in `Cargo.toml` will run. |
| 25 | +Using the [`cc`][cc] crate, a static library file will be produced (in this case, `libhello.a`, see |
| 26 | +[`compile` docs][cc-build-compile]) which can then be used from `rust` by declaring the external function signatures in an `extern` block. |
| 27 | + |
| 28 | +Since the bundled `C` is very simple, only a single source file needs to be passed to [`cc::Build`][cc-build]. |
| 29 | +For more complex build requirements, [`cc::Build`][cc-build] offers a full suite of builder methods for specifying |
| 30 | +[`include`][cc-build-include] paths and extra compiler [`flag`][cc-build-flag]s. |
| 31 | + |
| 32 | +### `Cargo.toml` |
| 33 | + |
| 34 | +```toml |
| 35 | +[package] |
| 36 | +... |
| 37 | +build = "build.rs" |
| 38 | + |
| 39 | +[build-dependencies] |
| 40 | +cc = "1" |
| 41 | + |
| 42 | +[dependencies] |
| 43 | +error-chain = "0.11" |
| 44 | +``` |
| 45 | + |
| 46 | +### `build.rs` |
| 47 | + |
| 48 | +```rust,no_run |
| 49 | +extern crate cc; |
| 50 | +
|
| 51 | +fn main() { |
| 52 | + cc::Build::new() |
| 53 | + .file("src/hello.c") |
| 54 | + .compile("hello"); // outputs `libhello.a` |
| 55 | +} |
| 56 | +``` |
| 57 | + |
| 58 | +### `src/hello.c` |
| 59 | + |
| 60 | +```c |
| 61 | +#include <stdio.h> |
| 62 | + |
| 63 | + |
| 64 | +void hello() { |
| 65 | + printf("Hello from C!\n"); |
| 66 | +} |
| 67 | + |
| 68 | +void greet(const char* name) { |
| 69 | + printf("Hello, %s!\n", name); |
| 70 | +} |
| 71 | +``` |
| 72 | +
|
| 73 | +### `src/main.rs` |
| 74 | +
|
| 75 | +```rust,no_run |
| 76 | +# #[macro_use] extern crate error_chain; |
| 77 | +use std::ffi::CString; |
| 78 | +use std::os::raw::c_char; |
| 79 | +
|
| 80 | +# |
| 81 | +# error_chain! { |
| 82 | +# foreign_links { |
| 83 | +# NulError(::std::ffi::NulError); |
| 84 | +# Io(::std::io::Error); |
| 85 | +# } |
| 86 | +# } |
| 87 | +# |
| 88 | +# |
| 89 | +# fn prompt(s: &str) -> Result<String> { |
| 90 | +# use std::io::Write; |
| 91 | +# print!("{}", s); |
| 92 | +# std::io::stdout().flush()?; |
| 93 | +# let mut input = String::new(); |
| 94 | +# std::io::stdin().read_line(&mut input)?; |
| 95 | +# Ok(input.trim().to_string()) |
| 96 | +# } |
| 97 | +# |
| 98 | +
|
| 99 | +extern { |
| 100 | + fn hello(); |
| 101 | + fn greet(name: *const c_char); |
| 102 | +} |
| 103 | +
|
| 104 | +
|
| 105 | +fn run() -> Result<()> { |
| 106 | + unsafe { hello() } |
| 107 | + let name = prompt("What's your name? ")?; |
| 108 | + let c_name = CString::new(name)?; |
| 109 | + unsafe { greet(c_name.as_ptr()) } |
| 110 | + Ok(()) |
| 111 | +} |
| 112 | +
|
| 113 | +# |
| 114 | +# quick_main!(run); |
| 115 | +``` |
| 116 | + |
| 117 | + |
| 118 | +{{#include links.md}} |
| 119 | + |
| 120 | +<!-- Other Reference --> |
| 121 | + |
| 122 | +[build-script-docs]: http://doc.crates.io/build-script.html |
| 123 | +[playground]: https://play.rust-lang.org |
| 124 | +[cc-build]: https://docs.rs/cc/1.0.0/cc/struct.Build.html |
| 125 | +[cc-build-include]: https://docs.rs/cc/1.0.0/cc/struct.Build.html#method.include |
| 126 | +[cc-build-flag]: https://docs.rs/cc/1.0.0/cc/struct.Build.html#method.flag |
| 127 | +[cc-build-compile]: https://docs.rs/cc/1.0.0/cc/struct.Build.html#method.compile |
| 128 | + |
0 commit comments