From cf7582cbd2173b843b4cac5d9afa906dad58c02a Mon Sep 17 00:00:00 2001 From: Alex Lyon Date: Fri, 29 Dec 2017 22:17:54 -0800 Subject: [PATCH] stdbuf: make build more reliable and allow installation using Cargo --- Cargo.lock | 103 ++++++++++++++++++++++++++- README.md | 114 ++++++++++++++++++------------ src/stdbuf/Cargo.toml | 6 +- src/stdbuf/build.rs | 53 +++----------- src/stdbuf/libstdbuf.c | 7 -- src/stdbuf/libstdbuf.h | 6 -- src/stdbuf/libstdbuf.rs | 51 ------------- src/stdbuf/libstdbuf/Cargo.toml | 7 +- src/stdbuf/libstdbuf/build.rs | 8 +++ src/stdbuf/libstdbuf/libstdbuf.rs | 33 +++++++-- src/stdbuf/stdbuf.rs | 47 +++++------- 11 files changed, 239 insertions(+), 196 deletions(-) delete mode 100644 src/stdbuf/libstdbuf.c delete mode 100644 src/stdbuf/libstdbuf.h delete mode 100644 src/stdbuf/libstdbuf.rs create mode 100644 src/stdbuf/libstdbuf/build.rs diff --git a/Cargo.lock b/Cargo.lock index ab6a62a3d..c78b8f835 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -218,6 +218,79 @@ dependencies = [ "xattr 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cpp" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cpp_macros 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cpp_build" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cpp_common 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cpp_syn 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cpp_synmap 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cpp_synom 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cpp_common" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cpp_syn 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cpp_synom 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cpp_macros" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cpp_common 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cpp_syn 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cpp_synom 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cpp_syn" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cpp_synom 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cpp_synmap" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cpp_syn 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cpp_synom 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cpp_synom" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cut" version = "0.0.1" @@ -374,6 +447,11 @@ name = "fuchsia-zircon-sys" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "gcc" +version = "0.3.54" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "generic-array" version = "0.8.3" @@ -524,6 +602,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "libstdbuf" version = "0.0.1" dependencies = [ + "cpp 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cpp_build 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "uucore 0.0.1", ] @@ -858,6 +938,11 @@ name = "quick-error" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "quote" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rand" version = "0.3.19" @@ -1067,10 +1152,9 @@ dependencies = [ name = "stdbuf" version = "0.0.1" dependencies = [ - "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", - "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "libstdbuf 0.0.1", + "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "uucore 0.0.1", ] @@ -1301,6 +1385,11 @@ name = "unicode-width" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-xid" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unindent" version = "0.1.2" @@ -1601,6 +1690,13 @@ dependencies = [ "checksum chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c20ebe0b2b08b0aeddba49c609fe7957ba2e33449882cb186a180bc60682fa9" "checksum clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "110d43e343eb29f4f51c1db31beb879d546db27998577e5715270a54bcf41d3f" "checksum cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "56d741ea7a69e577f6d06b36b7dff4738f680593dc27a701ffa8506b73ce28bb" +"checksum cpp 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b244cf36c028e27227d6e7f9963c768dff5a1c06d5e01ff97f12ef4e05afd57c" +"checksum cpp_build 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e9aebc7c97550a8c6a1f48dbaf078b033dc546e1b5badde300767099d4cace8f" +"checksum cpp_common 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca58053cb5433ac7d3852eeee6a58314762bdbcbcd765a8f9a4f0e66bf90c72" +"checksum cpp_macros 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "569d52f48c31a5d9ecc749340d355a2d4b80de91d950164bcca7a7580bd2189b" +"checksum cpp_syn 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8cd649bf5b3804d92fe12a60c7698f5a538a6033ed8a668bf5241d4d4f1644e" +"checksum cpp_synmap 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "897e4f9cdbe2874edd3ffe53718ee5d8b89e2a970057b2c93d3214104f2e90b6" +"checksum cpp_synom 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fc8da5694233b646150c785118f77835ad0a49680c7f312a10ef30957c67b6d" "checksum data-encoding 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d867ddbf09de0b73e09ec798972fb7f870495a0893f6f736c1855448c5a56789" "checksum digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5b29bf156f3f4b3c4f610a25ff69370616ae6e0657d416de22645483e72af0a" "checksum either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740178ddf48b1a9e878e6d6509a1442a2d42fd2928aae8e7a6f8a36fb01981b3" @@ -1609,6 +1705,7 @@ dependencies = [ "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum fuchsia-zircon 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bd510087c325af53ba24f3be8f1c081b0982319adcb8b03cad764512923ccc19" "checksum fuchsia-zircon-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "08b3a6f13ad6b96572b53ce7af74543132f1a7055ccceb6d073dd36c54481859" +"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" "checksum generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fceb69994e330afed50c93524be68c42fa898c2d9fd4ee8da03bd7363acd26f2" "checksum getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "65922871abd2f101a2eb0eaebadc66668e54a87ad9c3dd82520b5f86ede5eff9" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" @@ -1635,6 +1732,7 @@ dependencies = [ "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" "checksum pretty-bytes 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "009d6edd2c1dbf2e1c0cd48a2f7766e03498d49ada7109a01c6911815c685316" "checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4" +"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "9e7944d95d25ace8f377da3ac7068ce517e4c646754c43a1b1849177bbf72e59" "checksum redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "07b8f011e3254d5a9b318fde596d409a0001c9ae4c6e7907520c2eaa4d988c99" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" @@ -1658,6 +1756,7 @@ dependencies = [ "checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520" "checksum typenum 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "13a99dc6780ef33c78780b826cf9d2a78840b72cae9474de4bcaf9051e60ebbd" "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" +"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unindent 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "10743f62eafa8863b3dbb35cd6abbb609c963dd98940142a85bc530b753e33a4" "checksum unix_socket 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6aa2700417c405c38f5e6902d699345241c28c0b7ade4abaad71e35a87eb1564" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" diff --git a/README.md b/README.md index c5ad14aea..85209b69c 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,9 @@ Requirements ------------ * Rust (`cargo`, `rustc`) -* GNU Make (an option to build on Unix and to install on every platform) -* CMake (used by Oniguruma, which is required for `expr`) +* GNU Make (required to build documentation) +* CMake (Unix; used by Oniguruma, which is required for `expr`) +* NMake (Windows; used by Oniguruma, which is required for `expr`) * [Sphinx](http://www.sphinx-doc.org/) (for documentation) * gzip (for installing documentation) @@ -84,76 +85,95 @@ $ make ``` To build all but a few of the available utilities: -``` +```bash $ make SKIP_UTILS='UTILITY_1 UTILITY_2' ``` To build only a few of the available utilities: -``` +```bash $ make UTILS='UTILITY_1 UTILITY_2' ``` Installation Instructions ------------------------- -Unfortunately, due to limitations with Cargo, uutils requires `make` to -install. +### Cargo ### + +Likewise, installing can simply be done using: +```bash +$ cargo install +``` + +This command will install uutils into Cargo's *bin* folder (*e.g.* `$HOME/.cargo/bin`). + +### GNU Make ### To install all available utilities: -``` -make install +```bash +$ make install ``` To install all but a few of the available utilities: -``` -make SKIP_UTILS='UTILITY_1 UTILITY_2' install +```bash +$ make SKIP_UTILS='UTILITY_1 UTILITY_2' install ``` To install only a few of the available utilities: -``` -make UTILS='UTILITY_1 UTILITY_2' install +```bash +$ make UTILS='UTILITY_1 UTILITY_2' install ``` To install every program with a prefix (e.g. uu-echo uu-cat): -``` -make PROG_PREFIX=PREFIX_GOES_HERE install +```bash +$ make PROG_PREFIX=PREFIX_GOES_HERE install ``` To install the multicall binary: -``` -make MULTICALL=y install +```bash +$ make MULTICALL=y install ``` Set install parent directory (default value is /usr/local): -``` +```bash # DESTDIR is also supported -make PREFIX=/my/path install +$ make PREFIX=/my/path install ``` Uninstallation Instructions --------------------------- -Likewise, uninstalling requires `make`. +Uninstallation differs depending on how you have installed uutils. If you used +Cargo to install, use Cargo to uninstall. If you used GNU Make to install, use +Make to uninstall. + +### Cargo ### + +To uninstall uutils: +```bash +$ cargo uninstall uutils +``` + +### GNU Make ### To uninstall all utilities: -``` -make uninstall +```bash +$ make uninstall ``` To uninstall every program with a set prefix: -``` -make PROG_PREFIX=PREFIX_GOES_HERE uninstall +```bash +$ make PROG_PREFIX=PREFIX_GOES_HERE uninstall ``` To uninstall the multicall binary: -``` -make MULTICALL=y uninstall +```bash +$ make MULTICALL=y uninstall ``` To uninstall from a custom parent directory: -``` +```bash # DESTDIR is also supported -make PREFIX=/my/path uninstall +$ make PREFIX=/my/path uninstall ``` Test Instructions @@ -177,23 +197,23 @@ $ cargo test --features "chmod mv tail" --no-default-features ### GNU Make ### To simply test all available utilities: -``` -make test +```bash +$ make test ``` To test all but a few of the available utilities: -``` -make SKIP_UTILS='UTILITY_1 UTILITY_2' test +```bash +$ make SKIP_UTILS='UTILITY_1 UTILITY_2' test ``` To test only a few of the available utilities: -``` -make UTILS='UTILITY_1 UTILITY_2' test +```bash +$ make UTILS='UTILITY_1 UTILITY_2' test ``` To include tests for unimplemented behavior: -``` -make UTILS='UTILITY_1 UTILITY_2' SPEC=y test +```bash +$ make UTILS='UTILITY_1 UTILITY_2' SPEC=y test ``` Run Busybox Tests @@ -203,18 +223,18 @@ This testing functionality is only available on *nix operating systems and requires `make`. To run busybox's tests for all utilities for which busybox has tests -``` -make busytest +```bash +$ make busytest ``` To run busybox's tests for a few of the available utilities -``` -make UTILS='UTILITY_1 UTILITY_2' busytest +```bash +$ make UTILS='UTILITY_1 UTILITY_2' busytest ``` To pass an argument like "-v" to the busybox test runtime -``` -make UTILS='UTILITY_1 UTILITY_2' RUNTEST_ARGS='-v' busytest +```bash +$ make UTILS='UTILITY_1 UTILITY_2' RUNTEST_ARGS='-v' busytest ``` Contribute @@ -231,15 +251,15 @@ Utilities | base32 | expr | csplit | | base64 | install | dd | | basename | ls | df | -| cat | more | join | -| chgrp | od (`--strings` and 128-bit data types missing) | numfmt | -| chmod | printf | pr | -| chown | sort | runcon | -| chroot | split | stty | +| cat | more | numfmt | +| chgrp | od (`--strings` and 128-bit data types missing) | pr | +| chmod | printf | runcon | +| chown | sort | stty | +| chroot | split | | | cksum | tail | | | comm | test | | | cut | date | | -| dircolors | | | +| dircolors | join | | | dirname | | | | du | | | | echo | | | diff --git a/src/stdbuf/Cargo.toml b/src/stdbuf/Cargo.toml index 205406298..f595180ba 100644 --- a/src/stdbuf/Cargo.toml +++ b/src/stdbuf/Cargo.toml @@ -10,13 +10,11 @@ path = "stdbuf.rs" [dependencies] getopts = "0.2.14" +tempdir = "0.3.5" uucore = { path="../uucore" } -libstdbuf = { path="libstdbuf" } [build-dependencies] -cc = "1.0" -glob = "0.2" -libstdbuf = { path = "libstdbuf" } +libstdbuf = { path="libstdbuf" } [[bin]] name = "stdbuf" diff --git a/src/stdbuf/build.rs b/src/stdbuf/build.rs index fedd0f8a4..0c0c01bc8 100644 --- a/src/stdbuf/build.rs +++ b/src/stdbuf/build.rs @@ -1,56 +1,25 @@ -extern crate cc; -extern crate glob; - use std::env; -use std::process::Command; - -use glob::glob; +use std::fs; +use std::path::Path; #[path = "../../mkmain.rs"] mod mkmain; -#[cfg(target_os = "macos")] -mod platform { - pub const DYLIB_EXT: &'static str = "dylib"; - pub const DYLIB_FLAGS: [&'static str; 3] = ["-dynamiclib", "-undefined", "dynamic_lookup"]; -} - #[cfg(target_os = "linux")] mod platform { - pub const DYLIB_EXT: &'static str = "so"; - pub const DYLIB_FLAGS: [&'static str; 1] = ["-shared"]; + pub const DYLIB_EXT: &'static str = ".so"; +} + +#[cfg(target_os = "macos")] +mod platform { + pub const DYLIB_EXT: &'static str = ".dylib"; } -// FIXME: this entire thing is pretty fragile fn main() { mkmain::main(); - let cc = env::var("CC").unwrap_or("gcc".to_string()); - let out_dir = env::var("OUT_DIR").unwrap(); - - let entry = glob(&format!("{}/../../../deps/liblibstdbuf-*.a", out_dir)).unwrap() - .next() - .unwrap() - .unwrap(); - - cc::Build::new() - .flag("-Wall") - .flag("-Werror") - .pic(true) - .file("libstdbuf.c") - .compile("libstdbuf.a"); - - // XXX: we have to link manually because apparently cc-rs does not support shared libraries - let mut link = Command::new(cc); - for flag in platform::DYLIB_FLAGS.iter() { - link.arg(flag); - } - link.arg("-o") - .arg(format!("{}/libstdbuf.{}", out_dir, platform::DYLIB_EXT)) - .arg(format!("{}/libstdbuf.a", out_dir)) - .arg(entry); - if !link.spawn().unwrap().wait().unwrap().success() { - panic!("linking failed"); - } + let libstdbuf = format!("{}/../../{}/{}/deps/liblibstdbuf{}", env::var("CARGO_MANIFEST_DIR").unwrap(), env::var("CARGO_TARGET_DIR").unwrap_or("target".to_string()), env::var("PROFILE").unwrap(), platform::DYLIB_EXT); + + fs::copy(libstdbuf, Path::new(&out_dir).join("libstdbuf.so")).unwrap(); } diff --git a/src/stdbuf/libstdbuf.c b/src/stdbuf/libstdbuf.c deleted file mode 100644 index b7ee1370f..000000000 --- a/src/stdbuf/libstdbuf.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "libstdbuf.h" - -void __attribute ((constructor)) -stdbuf_init (void) -{ - stdbuf(); -} diff --git a/src/stdbuf/libstdbuf.h b/src/stdbuf/libstdbuf.h deleted file mode 100644 index d8ae3c70a..000000000 --- a/src/stdbuf/libstdbuf.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef UUTILS_LIBSTDBUF_H -#define UUTILS_LIBSTDBUF_H - -void stdbuf(void); - -#endif diff --git a/src/stdbuf/libstdbuf.rs b/src/stdbuf/libstdbuf.rs deleted file mode 100644 index ff8a1e502..000000000 --- a/src/stdbuf/libstdbuf.rs +++ /dev/null @@ -1,51 +0,0 @@ -extern crate libc; - -#[macro_use] -extern crate uucore; - -use libc::{c_int, size_t, c_char, FILE, _IOFBF, _IONBF, _IOLBF}; -use std::env; -use std::io::Write; -use std::ptr; - -extern { - static stdin: *mut FILE; - static stdout: *mut FILE; - static stderr: *mut FILE; -} - -fn set_buffer(stream: *mut FILE, value: &str) { - let (mode, size): (c_int, size_t) = match value { - "0" => (_IONBF, 0 as size_t), - "L" => (_IOLBF, 0 as size_t), - input => { - let buff_size: usize = match input.parse() { - Ok(num) => num, - Err(e) => crash!(1, "incorrect size of buffer!: {}", e) - }; - (_IOFBF, buff_size as size_t) - } - }; - let res: c_int; - unsafe { - let buffer: *mut c_char = ptr::null_mut(); - assert!(buffer.is_null()); - res = libc::setvbuf(stream, buffer, mode, size); - } - if res != 0 { - crash!(res, "error while calling setvbuf!"); - } -} - -#[no_mangle] -pub unsafe extern "C" fn stdbuf() { - if let Ok(val) = env::var("_STDBUF_E") { - set_buffer(stderr, &val); - } - if let Ok(val) = env::var("_STDBUF_I") { - set_buffer(stdin, &val); - } - if let Ok(val) = env::var("_STDBUF_O") { - set_buffer(stdout, &val); - } -} diff --git a/src/stdbuf/libstdbuf/Cargo.toml b/src/stdbuf/libstdbuf/Cargo.toml index cffcfe00a..0018e9541 100644 --- a/src/stdbuf/libstdbuf/Cargo.toml +++ b/src/stdbuf/libstdbuf/Cargo.toml @@ -6,8 +6,13 @@ authors = [] [lib] name = "libstdbuf" path = "libstdbuf.rs" -crate-type = ["staticlib"] +# XXX: the rlib is just to prevent Cargo from spitting out a warning +crate-type = ["cdylib", "rlib"] [dependencies] uucore = { path="../../uucore" } libc = "0.2" +cpp = "0.3" + +[build-dependencies] +cpp_build = "0.3" diff --git a/src/stdbuf/libstdbuf/build.rs b/src/stdbuf/libstdbuf/build.rs new file mode 100644 index 000000000..9d9896f58 --- /dev/null +++ b/src/stdbuf/libstdbuf/build.rs @@ -0,0 +1,8 @@ +extern crate cpp_build; + +use cpp_build::Config; + +fn main() { + Config::new().pic(true) + .build("libstdbuf.rs"); +} diff --git a/src/stdbuf/libstdbuf/libstdbuf.rs b/src/stdbuf/libstdbuf/libstdbuf.rs index 8c6e7f9d9..464731541 100644 --- a/src/stdbuf/libstdbuf/libstdbuf.rs +++ b/src/stdbuf/libstdbuf/libstdbuf.rs @@ -1,4 +1,6 @@ extern crate libc; +#[macro_use] +extern crate cpp; #[macro_use] extern crate uucore; @@ -7,10 +9,27 @@ use libc::{c_int, size_t, c_char, FILE, _IOFBF, _IONBF, _IOLBF}; use std::env; use std::ptr; +cpp!{{ + #include + + extern "C" { + void __stdbuf(void); + + void __attribute((constructor)) + __stdbuf_init(void) { + __stdbuf(); + } + + FILE *__stdbuf_get_stdin() { return stdin; } + FILE *__stdbuf_get_stdout() { return stdout; } + FILE *__stdbuf_get_stderr() { return stderr; } + } +}} + extern { - static stdin: *mut FILE; - static stdout: *mut FILE; - static stderr: *mut FILE; + fn __stdbuf_get_stdin() -> *mut FILE; + fn __stdbuf_get_stdout() -> *mut FILE; + fn __stdbuf_get_stderr() -> *mut FILE; } fn set_buffer(stream: *mut FILE, value: &str) { @@ -37,14 +56,14 @@ fn set_buffer(stream: *mut FILE, value: &str) { } #[no_mangle] -pub unsafe extern fn stdbuf() { +pub unsafe extern "C" fn __stdbuf() { if let Ok(val) = env::var("_STDBUF_E") { - set_buffer(stderr, &val); + set_buffer(__stdbuf_get_stderr(), &val); } if let Ok(val) = env::var("_STDBUF_I") { - set_buffer(stdin, &val); + set_buffer(__stdbuf_get_stdin(), &val); } if let Ok(val) = env::var("_STDBUF_O") { - set_buffer(stdout, &val); + set_buffer(__stdbuf_get_stdout(), &val); } } diff --git a/src/stdbuf/stdbuf.rs b/src/stdbuf/stdbuf.rs index 48caf8303..c6689ab09 100644 --- a/src/stdbuf/stdbuf.rs +++ b/src/stdbuf/stdbuf.rs @@ -10,20 +10,23 @@ */ extern crate getopts; +extern crate tempdir; #[macro_use] extern crate uucore; use getopts::{Matches, Options}; -use std::io; +use tempdir::TempDir; +use std::fs::File; +use std::io::{self, Write}; use std::os::unix::process::ExitStatusExt; use std::path::PathBuf; use std::process::Command; -use uucore::fs::{canonicalize, CanonicalizeMode}; static NAME: &'static str = "stdbuf"; static VERSION: &'static str = env!("CARGO_PKG_VERSION"); -static LIBSTDBUF: &'static str = "libstdbuf"; + +const STDBUF_INJECT: &'static [u8] = include_bytes!(concat!(env!("OUT_DIR"), "/libstdbuf.so")); enum BufferType { Default, @@ -50,12 +53,12 @@ enum OkMsg { #[cfg(target_os = "linux")] fn preload_strings() -> (&'static str, &'static str) { - ("LD_PRELOAD", ".so") + ("LD_PRELOAD", "so") } #[cfg(target_os = "macos")] fn preload_strings() -> (&'static str, &'static str) { - ("DYLD_LIBRARY_PATH", ".dylib") + ("DYLD_LIBRARY_PATH", "dylib") } #[cfg(not(any(target_os = "linux", target_os = "macos")))] @@ -184,30 +187,14 @@ fn set_command_env(command: &mut Command, buffer_name: &str, buffer_type: Buffer } } -fn exe_path() -> io::Result { - let exe_path = try!(std::env::current_exe()); - let absolute_path = try!(canonicalize(exe_path, CanonicalizeMode::Normal)); - Ok(match absolute_path.parent() { - Some(p) => p.to_path_buf(), - None => absolute_path.clone() - }) -} - -fn get_preload_env() -> (String, String) { +fn get_preload_env(tmp_dir: &mut TempDir) -> io::Result<(String, PathBuf)> { let (preload, extension) = preload_strings(); - let mut libstdbuf = LIBSTDBUF.to_owned(); - libstdbuf.push_str(extension); - // First search for library in directory of executable. - let mut path = exe_path().unwrap_or_else(|_| crash!(1, "Impossible to fetch the path of this executable.")); - path.push(libstdbuf.clone()); - if path.exists() { - match path.as_os_str().to_str() { - Some(s) => { return (preload.to_owned(), s.to_owned()); }, - None => crash!(1, "Error while converting path.") - }; - } - // We assume library is in LD_LIBRARY_PATH/ DYLD_LIBRARY_PATH. - (preload.to_owned(), libstdbuf) + let inject_path = tmp_dir.path().join("libstdbuf").with_extension(extension); + + let mut file = File::create(&inject_path)?; + file.write_all(STDBUF_INJECT)?; + + Ok((preload.to_owned(), inject_path)) } pub fn uumain(args: Vec) -> i32 { @@ -244,7 +231,9 @@ pub fn uumain(args: Vec) -> i32 { } let command_name = &args[command_idx as usize]; let mut command = Command::new(command_name); - let (preload_env, libstdbuf) = get_preload_env(); + + let mut tmp_dir = return_if_err!(1, TempDir::new("stdbuf")); + let (preload_env, libstdbuf) = return_if_err!(1, get_preload_env(&mut tmp_dir)); command.args(&args[(command_idx as usize) + 1 ..]).env(preload_env, libstdbuf); set_command_env(&mut command, "_STDBUF_I", options.stdin); set_command_env(&mut command, "_STDBUF_O", options.stdout);