From 4eac9bad1ca784d90ef0b78be60c4953b0769d9b Mon Sep 17 00:00:00 2001 From: Finn Behrens Date: Sat, 28 Nov 2020 02:11:24 +0100 Subject: [PATCH] Use bindgen as a program rather than as a library This allows us to remove the `kernel` `build.rs` script and simplifies the build. `Cargo.lock` is tiny now. The shlex dependency also goes away. Note that this commit does *not* use the list of included functions/types/vars etc., so it is not equivalent. Signed-off-by: Finn Behrens Signed-off-by: Miguel Ojeda --- .github/workflows/ci.yaml | 1 + Cargo.lock | 353 ----------------------------- Cargo.toml | 1 - Documentation/rust/quick-start.rst | 47 +++- Makefile | 3 +- rust/kernel/Cargo.toml | 4 - rust/kernel/build.rs | 135 ----------- rust/kernel/src/.gitignore | 3 - rust/kernel/src/bindings.rs | 2 +- rust/shlex/Cargo.toml | 11 - rust/shlex/src/lib.rs | 231 ------------------- rustfmt.toml | 2 - scripts/Makefile.build | 15 +- 13 files changed, 60 insertions(+), 748 deletions(-) delete mode 100644 rust/kernel/build.rs delete mode 100644 rust/kernel/src/.gitignore delete mode 100644 rust/shlex/Cargo.toml delete mode 100644 rust/shlex/src/lib.rs delete mode 100644 rustfmt.toml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index d50cfa62df5335..f75671b1b9a739 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -16,6 +16,7 @@ jobs: - run: sudo apt update - run: sudo apt install libelf-dev qemu-system-x86 busybox-static - run: rustup default nightly-2020-08-27 + - run: rustup component add rustfmt - run: rustup component add rust-src # Build diff --git a/Cargo.lock b/Cargo.lock index c358a6a4fbdca9..1238e5fbdc531f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,379 +1,26 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -[[package]] -name = "aho-corasick" -version = "0.7.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86" -dependencies = [ - "memchr", -] - -[[package]] -name = "ansi_term" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -dependencies = [ - "winapi", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - -[[package]] -name = "bindgen" -version = "0.54.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66c0bb6167449588ff70803f4127f0684f9063097eca5016f37eb52b92c2cf36" -dependencies = [ - "bitflags", - "cexpr", - "cfg-if", - "clang-sys", - "clap", - "env_logger", - "lazy_static", - "lazycell", - "log", - "peeking_take_while", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "which", -] - [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -[[package]] -name = "cc" -version = "1.0.59" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66120af515773fb005778dc07c261bd201ec8ce50bd6e7144c927753fe013381" - -[[package]] -name = "cexpr" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" -dependencies = [ - "nom", -] - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "clang-sys" -version = "0.29.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe6837df1d5cba2397b835c8530f51723267e16abbf83892e9e5af4f0e5dd10a" -dependencies = [ - "glob", - "libc", - "libloading", -] - -[[package]] -name = "clap" -version = "2.33.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" -dependencies = [ - "ansi_term", - "atty", - "bitflags", - "strsim", - "textwrap", - "unicode-width", - "vec_map", -] - -[[package]] -name = "env_logger" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" -dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", -] - -[[package]] -name = "glob" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" - -[[package]] -name = "hermit-abi" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" -dependencies = [ - "libc", -] - -[[package]] -name = "humantime" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -dependencies = [ - "quick-error", -] - [[package]] name = "kernel" version = "0.1.0" dependencies = [ - "bindgen", "bitflags", "module", - "shlex 0.1.1", ] -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - -[[package]] -name = "libc" -version = "0.2.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3" - -[[package]] -name = "libloading" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" -dependencies = [ - "cc", - "winapi", -] - -[[package]] -name = "log" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "memchr" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" - [[package]] name = "module" version = "0.1.0" -[[package]] -name = "nom" -version = "5.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" -dependencies = [ - "memchr", - "version_check", -] - -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - -[[package]] -name = "proc-macro2" -version = "1.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - -[[package]] -name = "quote" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "regex" -version = "1.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", - "thread_local", -] - -[[package]] -name = "regex-syntax" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" - [[package]] name = "rust_example" version = "0.1.0" dependencies = [ "kernel", ] - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "shlex" -version = "0.1.1" - -[[package]] -name = "shlex" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" - -[[package]] -name = "strsim" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" - -[[package]] -name = "termcolor" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - -[[package]] -name = "thread_local" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "unicode-width" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" - -[[package]] -name = "unicode-xid" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" - -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - -[[package]] -name = "version_check" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" - -[[package]] -name = "which" -version = "3.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724" -dependencies = [ - "libc", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 914306648fe844..e9a9b0f15d6293 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,6 @@ # TODO: generate automatically [workspace] members = [ - "rust/shlex", "rust/module", "rust/kernel", "drivers/char/rust_example", diff --git a/Documentation/rust/quick-start.rst b/Documentation/rust/quick-start.rst index d012869fcd71f6..5444cb0a7cbd2e 100644 --- a/Documentation/rust/quick-start.rst +++ b/Documentation/rust/quick-start.rst @@ -9,9 +9,14 @@ This document describes how to get started with Rust kernel development. Requirements ------------ -A recent nightly Rust toolchain (at least ``rustc``, ``cargo`` and ``rustfmt``) +rustc and cargo +*************** + +A recent nightly Rust toolchain (with, at least, ``rustc`` and ``cargo``) is required, e.g. ``nightly-2020-08-27``. In the future, this restriction -will be lifted. If you are using ``rustup``, run:: +will be lifted. + +If you are using ``rustup``, run:: rustup toolchain install nightly @@ -19,8 +24,14 @@ Otherwise, fetch a standalone installer from: https://www.rust-lang.org -The sources for the compiler are required to be available. If you are using -``rustup``, run:: + +rustc sources +************* + +The sources for the compiler are required to be available because the standard +library (``core`` and ``alloc``) is cross-compiled. + +If you are using ``rustup``, run:: rustup component add rust-src @@ -32,6 +43,34 @@ your nightly toolchain:: ln -s rust .../rust-nightly/lib/rustlib/src +bindgen +******* + +The bindings to the C side of the kernel are generated at build time using +``bindgen``. Currently we assume the latest version available, but that +may change in the future. + +Install it via:: + + cargo install bindgen + + +rustfmt +******* + +Optionally, if you install ``rustfmt``, then you will get the generated +C bindings automatically formatted. It is also useful to have the tool +to format your own code, too. + +If you are using ``rustup``, its ``default`` profile already installs it, +so you should be good to go. If you are using another one, you can also +install the component:: + + rustup component add rustfmt + +The standalone installers also come with ``rustfmt``. + + Testing a simple driver ----------------------- diff --git a/Makefile b/Makefile index f6dac695721c97..f65738a24d04d5 100644 --- a/Makefile +++ b/Makefile @@ -450,6 +450,7 @@ STRIP = $(CROSS_COMPILE)strip endif RUSTC = rustc CARGO = cargo +BINDGEN = bindgen PAHOLE = pahole RESOLVE_BTFIDS = $(objtree)/tools/bpf/resolve_btfids/resolve_btfids LEX = flex @@ -526,7 +527,7 @@ export KBUILD_LDS_MODULE := $(srctree)/scripts/module-common.lds KBUILD_LDFLAGS := CLANG_FLAGS := -export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC RUSTC CARGO +export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC RUSTC CARGO BINDGEN export CPP AR NM STRIP OBJCOPY OBJDUMP OBJSIZE READELF PAHOLE RESOLVE_BTFIDS LEX YACC AWK INSTALLKERNEL export PERL PYTHON PYTHON3 CHECK CHECKFLAGS MAKE UTS_MACHINE HOSTCXX export KGZIP KBZIP2 KLZOP LZMA LZ4 XZ ZSTD diff --git a/rust/kernel/Cargo.toml b/rust/kernel/Cargo.toml index fca60a4635ca14..bd116a6fc7db48 100644 --- a/rust/kernel/Cargo.toml +++ b/rust/kernel/Cargo.toml @@ -11,7 +11,3 @@ publish = false bitflags = "1" module = { path = "../module" } -[build-dependencies] -bindgen = "0.54" -shlex = { path = "../shlex" } - diff --git a/rust/kernel/build.rs b/rust/kernel/build.rs deleted file mode 100644 index a63ecf17c6d957..00000000000000 --- a/rust/kernel/build.rs +++ /dev/null @@ -1,135 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -use std::env; -use std::path::PathBuf; - -const INCLUDED_TYPES: &[&str] = &["file_system_type", "mode_t", "umode_t", "ctl_table"]; -const INCLUDED_FUNCTIONS: &[&str] = &[ - "cdev_add", - "cdev_init", - "cdev_del", - "register_filesystem", - "unregister_filesystem", - "krealloc", - "kfree", - "mount_nodev", - "kill_litter_super", - "register_sysctl", - "unregister_sysctl_table", - "access_ok", - "_copy_to_user", - "_copy_from_user", - "alloc_chrdev_region", - "unregister_chrdev_region", - "wait_for_random_bytes", - "get_random_bytes", - "rng_is_initialized", - "printk", - "add_device_randomness", -]; -const INCLUDED_VARS: &[&str] = &[ - "EINVAL", - "ENOMEM", - "ESPIPE", - "EFAULT", - "EAGAIN", - "__this_module", - "FS_REQUIRES_DEV", - "FS_BINARY_MOUNTDATA", - "FS_HAS_SUBTYPE", - "FS_USERNS_MOUNT", - "FS_RENAME_DOES_D_MOVE", - "BINDINGS_GFP_KERNEL", - "KERN_INFO", - "VERIFY_WRITE", - "LINUX_VERSION_CODE", - "SEEK_SET", - "SEEK_CUR", - "SEEK_END", - "O_NONBLOCK", - "param_ops_bool", - "param_ops_int", -]; -const OPAQUE_TYPES: &[&str] = &[ - // These need to be opaque because they're both packed and aligned, which rustc - // doesn't support yet. See https://github.com/rust-lang/rust/issues/59154 - // and https://github.com/rust-lang/rust-bindgen/issues/1538 - "desc_struct", - "xregs_state", -]; - -// Takes the CFLAGS from the kernel Makefile and changes all the include paths to be absolute -// instead of relative. -fn prepare_cflags(cflags: &str, kernel_dir: &str) -> Vec { - let cflag_parts = shlex::split(&cflags).unwrap(); - let mut cflag_iter = cflag_parts.iter(); - let mut kernel_args = vec![]; - while let Some(arg) = cflag_iter.next() { - // TODO: bindgen complains - if arg.starts_with("-Wp,-MMD") { - continue; - } - - if arg.starts_with("-I") && !arg.starts_with("-I/") { - kernel_args.push(format!("-I{}/{}", kernel_dir, &arg[2..])); - } else if arg == "-include" { - kernel_args.push(arg.to_string()); - let include_path = cflag_iter.next().unwrap(); - if include_path.starts_with('/') { - kernel_args.push(include_path.to_string()); - } else { - kernel_args.push(format!("{}/{}", kernel_dir, include_path)); - } - } else { - kernel_args.push(arg.to_string()); - } - } - kernel_args -} - -fn main() { - println!("cargo:rerun-if-env-changed=CC"); - println!("cargo:rerun-if-env-changed=RUST_BINDGEN_CFLAGS"); - - let kernel_dir = "../../"; - let cflags = env::var("RUST_BINDGEN_CFLAGS").expect("Must be invoked from kernel makefile"); - - let kernel_args = prepare_cflags(&cflags, &kernel_dir); - - // TODO: pass the proper triple to bindgen - let target = "x86_64-linux-kernel"; - - let mut builder = bindgen::Builder::default() - .use_core() - .ctypes_prefix("c_types") - .derive_default(true) - .size_t_is_usize(true) - .rustfmt_bindings(true); - - builder = builder.clang_arg(format!("--target={}", target)); - for arg in kernel_args.iter() { - builder = builder.clang_arg(arg.clone()); - } - - println!("cargo:rerun-if-changed=src/bindings_helper.h"); - builder = builder.header("src/bindings_helper.h"); - - for t in INCLUDED_TYPES { - builder = builder.whitelist_type(t); - } - for f in INCLUDED_FUNCTIONS { - builder = builder.whitelist_function(f); - } - for v in INCLUDED_VARS { - builder = builder.whitelist_var(v); - } - for t in OPAQUE_TYPES { - builder = builder.opaque_type(t); - } - let bindings = builder.generate().expect("Unable to generate bindings"); - - let out_path = PathBuf::from("src/bindings_gen.rs"); - bindings - .write_to_file(out_path) - .expect("Couldn't write bindings!"); -} diff --git a/rust/kernel/src/.gitignore b/rust/kernel/src/.gitignore deleted file mode 100644 index 61552b03b12d41..00000000000000 --- a/rust/kernel/src/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -bindings_gen.rs diff --git a/rust/kernel/src/bindings.rs b/rust/kernel/src/bindings.rs index cfb004a6d7861c..f0c31a36dc7600 100644 --- a/rust/kernel/src/bindings.rs +++ b/rust/kernel/src/bindings.rs @@ -9,7 +9,7 @@ )] mod bindings_raw { use crate::c_types; - include!("bindings_gen.rs"); + include!(env!("RUST_BINDINGS_FILE")); } pub use bindings_raw::*; diff --git a/rust/shlex/Cargo.toml b/rust/shlex/Cargo.toml deleted file mode 100644 index 54e984fa2bf13a..00000000000000 --- a/rust/shlex/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: MIT OR Apache-2.0 - -[package] -name = "shlex" -version = "0.1.1" -authors = ["comex "] -license = "MIT/Apache-2.0" -repository = "https://github.com/comex/rust-shlex" -description = """ -Split a string into shell words, like Python's shlex. -""" diff --git a/rust/shlex/src/lib.rs b/rust/shlex/src/lib.rs deleted file mode 100644 index 0b4a824fe4db33..00000000000000 --- a/rust/shlex/src/lib.rs +++ /dev/null @@ -1,231 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 - -// Copyright 2015 Nicholas Allegra (comex). -// Licensed under the Apache License, Version 2.0 or -// the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -//! Same idea as (but implementation not directly based on) the Python shlex module. However, this -//! implementation does not support any of the Python module's customization because it makes -//! parsing slower and is fairly useless. You only get the default settings of shlex.split, which -//! mimic the POSIX shell: -//! http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html -//! -//! This implementation also deviates from the Python version in not treating \r specially, which I -//! believe is more compliant. -//! -//! The algorithms in this crate are oblivious to UTF-8 high bytes, so they iterate over the bytes -//! directly as a micro-optimization. - -use std::borrow::Cow; - -/// An iterator that takes an input string and splits it into the words using the same syntax as -/// the POSIX shell. -pub struct Shlex<'a> { - in_iter: std::str::Bytes<'a>, - /// The number of newlines read so far, plus one. - pub line_no: usize, - /// An input string is erroneous if it ends while inside a quotation or right after an - /// unescaped backslash. Since Iterator does not have a mechanism to return an error, if that - /// happens, Shlex just throws out the last token, ends the iteration, and sets 'had_error' to - /// true; best to check it after you're done iterating. - pub had_error: bool, -} - -impl<'a> Shlex<'a> { - pub fn new(in_str: &'a str) -> Self { - Shlex { - in_iter: in_str.bytes(), - line_no: 1, - had_error: false, - } - } - - fn parse_word(&mut self, mut ch: u8) -> Option { - let mut result: Vec = Vec::new(); - loop { - match ch as char { - '"' => if let Err(()) = self.parse_double(&mut result) { - self.had_error = true; - return None; - }, - '\'' => if let Err(()) = self.parse_single(&mut result) { - self.had_error = true; - return None; - }, - '\\' => if let Some(ch2) = self.next_char() { - if ch2 != '\n' as u8 { result.push(ch2); } - } else { - self.had_error = true; - return None; - }, - ' ' | '\t' | '\n' => { break; }, - _ => { result.push(ch as u8); }, - } - if let Some(ch2) = self.next_char() { ch = ch2; } else { break; } - } - unsafe { Some(String::from_utf8_unchecked(result)) } - } - - fn parse_double(&mut self, result: &mut Vec) -> Result<(), ()> { - loop { - if let Some(ch2) = self.next_char() { - match ch2 as char { - '\\' => { - if let Some(ch3) = self.next_char() { - match ch3 as char { - // \$ => $ - '$' | '`' | '"' | '\\' => { result.push(ch3); }, - // \ => nothing - '\n' => {}, - // \x => =x - _ => { result.push('\\' as u8); result.push(ch3); } - } - } else { - return Err(()); - } - }, - '"' => { return Ok(()); }, - _ => { result.push(ch2); }, - } - } else { - return Err(()); - } - } - } - - fn parse_single(&mut self, result: &mut Vec) -> Result<(), ()> { - loop { - if let Some(ch2) = self.next_char() { - match ch2 as char { - '\\' => { - if let Some(ch3) = self.next_char() { - match ch3 as char { - // for single quotes, only these can be escaped - '\'' | '\\' => { result.push(ch3); }, - _ => { result.push('\\' as u8); result.push(ch3); } - } - } else { - return Err(()); - } - }, - '\'' => { return Ok(()); }, - _ => { result.push(ch2); }, - } - } else { - return Err(()); - } - } - } - - fn next_char(&mut self) -> Option { - let res = self.in_iter.next(); - if res == Some('\n' as u8) { self.line_no += 1; } - res - } -} - -impl<'a> Iterator for Shlex<'a> { - type Item = String; - fn next(&mut self) -> Option { - if let Some(mut ch) = self.next_char() { - // skip initial whitespace - loop { - match ch as char { - ' ' | '\t' | '\n' => {}, - '#' => { - while let Some(ch2) = self.next_char() { - if ch2 as char == '\n' { break; } - } - }, - _ => { break; } - } - if let Some(ch2) = self.next_char() { ch = ch2; } else { return None; } - } - self.parse_word(ch) - } else { // no initial character - None - } - } - -} - -/// Convenience function that consumes the whole string at once. Returns None if the input was -/// erroneous. -pub fn split(in_str: &str) -> Option> { - let mut shl = Shlex::new(in_str); - let res = shl.by_ref().collect(); - if shl.had_error { None } else { Some(res) } -} - -/// Given a single word, return a string suitable to encode it as a shell argument. -pub fn quote(in_str: &str) -> Cow { - if in_str.len() == 0 { - "\"\"".into() - } else if in_str.bytes().any(|c| match c as char { - '|' | '&' | ';' | '<' | '>' | '(' | ')' | '$' | '`' | '\\' | '"' | '\'' | ' ' | '\t' | - '\r' | '\n' | '*' | '?' | '[' | '#' | '~' | '=' | '%' => true, - _ => false - }) { - let mut out: Vec = Vec::new(); - out.push('"' as u8); - for c in in_str.bytes() { - match c as char { - '$' | '`' | '"' | '\\' => out.push('\\' as u8), - _ => () - } - out.push(c); - } - out.push('"' as u8); - unsafe { String::from_utf8_unchecked(out) }.into() - } else { - in_str.into() - } -} - -#[cfg(test)] -static SPLIT_TEST_ITEMS: &'static [(&'static str, Option<&'static [&'static str]>)] = &[ - ("foo$baz", Some(&["foo$baz"])), - ("foo baz", Some(&["foo", "baz"])), - ("foo\"bar\"baz", Some(&["foobarbaz"])), - ("foo \"bar\"baz", Some(&["foo", "barbaz"])), - (" foo \nbar", Some(&["foo", "bar"])), - ("foo\\\nbar", Some(&["foobar"])), - ("\"foo\\\nbar\"", Some(&["foobar"])), - ("'baz\\$b'", Some(&["baz\\$b"])), - ("'baz\\\''", Some(&["baz\'"])), - ("\\", None), - ("\"\\", None), - ("'\\", None), - ("\"", None), - ("'", None), - ("foo #bar\nbaz", Some(&["foo", "baz"])), - ("foo #bar", Some(&["foo"])), - ("foo#bar", Some(&["foo#bar"])), - ("foo\"#bar", None), -]; - -#[test] -fn test_split() { - for &(input, output) in SPLIT_TEST_ITEMS { - assert_eq!(split(input), output.map(|o| o.iter().map(|&x| x.to_owned()).collect())); - } -} - -#[test] -fn test_lineno() { - let mut sh = Shlex::new("\nfoo\nbar"); - while let Some(word) = sh.next() { - if word == "bar" { - assert_eq!(sh.line_no, 3); - } - } -} - -#[test] -fn test_quote() { - assert_eq!(quote("foobar"), "foobar"); - assert_eq!(quote("foo bar"), "\"foo bar\""); - assert_eq!(quote("\""), "\"\\\"\""); - assert_eq!(quote(""), "\"\""); -} diff --git a/rustfmt.toml b/rustfmt.toml deleted file mode 100644 index 25cc4a14bf2099..00000000000000 --- a/rustfmt.toml +++ /dev/null @@ -1,2 +0,0 @@ -ignore = [ "rust/shlex" ] - diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 9b50f2e0202608..2618c5f84aa8d0 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -307,14 +307,25 @@ $(obj)/%.lst: $(src)/%.c FORCE # --------------------------------------------------------------------------- quiet_cmd_cargo = CARGO $(quiet_modtag) $@ - cmd_cargo = cd $(src) && $(CARGO) build $(cargo_flags) + cmd_cargo = export RUST_BINDINGS_FILE=$(shell readlink -f $(srctree)/include/generated/rust_bindings.rs) && cd $(src) && $(CARGO) build $(cargo_flags) + +$(srctree)/include/generated/rust_bindings.rs: FORCE + $(Q)$(BINDGEN) $(srctree)/rust/kernel/src/bindings_helper.h \ + --opaque-type xregs_state \ + --opaque-type desc_struct \ + --use-core \ + --with-derive-default \ + --ctypes-prefix c_types \ + --size_t-is-usize \ + -o $(srctree)/include/generated/rust_bindings.rs \ + -- $(c_flags) # The .o from the Rust staticlib $(obj)/%.o: $(src)/out/lib%.a $(Q)$(LD) -r -o $@ --whole-archive $< # The Rust staticlib from cargo -$(obj)/out/lib%.a: FORCE +$(obj)/out/lib%.a: $(srctree)/include/generated/rust_bindings.rs FORCE $(call cmd,cargo) # Compile assembler sources (.S)