mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 03:27:44 +00:00
stdbuf: add feat_external_stdbuf
Fixes https://github.com/uutils/coreutils/issues/6591 "feat_external_stdbuf": use an external libstdbuf.so for stdbuf instead of embedding it into the stdbuf binary. There are 2 use-cases: 1. Installation of uutils-coreutils using cargo install (e.g. from crates.io which supports only "cargo install" as installation method). In this case, installing libstdbuf.so is impossible, because "cargo install" installs only binary programs (no cdylib), thus libstdbuf.so must be embedded into stdbuf and written to /tmp at runtime. This is a hack, and may not work on some platforms, e.g. because the SELinux permissions may not allow stdbuf to write to /tmp, /tmp may be read-only, libstdbuf.so may not work at all without SELinux labels, etc. 2. Installation of uutils-coreutils using an external tool, e.g. dpkg/apt on debian. In this case, libstdbuf.so should be installed separately to its correct location and the environment variable LIBSTDBUF_PATH configures the installation path during the build. E.g. LIBSTDBUF_PATH="/lib/libstdbuf.so" Signed-off-by: Etienne Cordonnier <ecordonnier@snap.com>
This commit is contained in:
parent
83424751c1
commit
99aa51a9a9
5 changed files with 82 additions and 9 deletions
|
@ -3,6 +3,8 @@ linker = "x86_64-unknown-redox-gcc"
|
|||
|
||||
[env]
|
||||
PROJECT_NAME_FOR_VERSION_STRING = "uutils coreutils"
|
||||
# See feat_external_libstdbuf in src/uu/stdbuf/Cargo.toml
|
||||
LIBSTDBUF_DIR = "/usr/lib"
|
||||
|
||||
# libstdbuf must be a shared library, so musl libc can't be linked statically
|
||||
# https://github.com/rust-lang/rust/issues/82193
|
||||
|
|
|
@ -37,6 +37,9 @@ test_risky_names = []
|
|||
# * only build `uudoc` when `--feature uudoc` is activated
|
||||
uudoc = ["zip", "dep:uuhelp_parser"]
|
||||
## features
|
||||
## Optional feature for stdbuf
|
||||
# "feat_external_libstdbuf" == use an external libstdbuf.so for stdbuf instead of embedding it
|
||||
feat_external_libstdbuf = ["stdbuf/feat_external_libstdbuf"]
|
||||
# "feat_acl" == enable support for ACLs (access control lists; by using`--features feat_acl`)
|
||||
# NOTE:
|
||||
# * On linux, the posix-acl/acl-sys crate requires `libacl` headers and shared library to be accessible in the C toolchain at compile time.
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# spell-checker:ignore dpkg
|
||||
[package]
|
||||
name = "uu_stdbuf"
|
||||
description = "stdbuf ~ (uutils) run COMMAND with modified standard stream buffering"
|
||||
|
@ -23,6 +24,25 @@ libstdbuf = { package = "uu_stdbuf_libstdbuf", path = "src/libstdbuf" }
|
|||
tempfile = { workspace = true }
|
||||
uucore = { workspace = true, features = ["parser"] }
|
||||
|
||||
# "feat_external_libstdbuf": use an external libstdbuf.so for stdbuf instead of embedding it into
|
||||
# the stdbuf binary.
|
||||
# There are 2 use-cases:
|
||||
# 1. Installation of uutils-coreutils using cargo install (e.g. from crates.io
|
||||
# which supports only "cargo install" as installation method). In this case,
|
||||
# installing libstdbuf.so is impossible, because "cargo install" installs
|
||||
# only binary programs (no cdylib), thus libstdbuf.so must be embedded into
|
||||
# stdbuf and written to /tmp at runtime. This is a hack, and may not work
|
||||
# on some platforms, e.g. because the SELinux permissions may not allow
|
||||
# stdbuf to write to /tmp, /tmp may be read-only, libstdbuf.so may not work
|
||||
# at all without SELinux labels, etc.
|
||||
#
|
||||
# 2. Installation of uutils-coreutils using an external tool, e.g. dpkg/apt on
|
||||
# debian. In this case, libstdbuf.so should be installed separately to its
|
||||
# correct location and the environment variable LIBSTDBUF_DIR configures the
|
||||
# installation directory during the build. E.g. LIBSTDBUF_DIR="/usr/lib"
|
||||
[features]
|
||||
feat_external_libstdbuf = []
|
||||
|
||||
[[bin]]
|
||||
name = "stdbuf"
|
||||
path = "src/main.rs"
|
||||
|
|
|
@ -29,6 +29,26 @@ fn main() {
|
|||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rerun-if-changed=src/libstdbuf/src/libstdbuf.rs");
|
||||
|
||||
// Check for external stdbuf feature requirements
|
||||
#[cfg(feature = "feat_external_libstdbuf")]
|
||||
{
|
||||
if env::var("LIBSTDBUF_DIR").is_err() {
|
||||
eprintln!(
|
||||
"\n\x1b[31mError:\x1b[0m The 'feat_external_libstdbuf' feature requires the LIBSTDBUF_DIR environment variable to be set."
|
||||
);
|
||||
eprintln!(
|
||||
"\x1b[33mUsage:\x1b[0m LIBSTDBUF_DIR=/path/to/lib/directory cargo build --features feat_external_libstdbuf"
|
||||
);
|
||||
eprintln!(
|
||||
"\x1b[33mExample:\x1b[0m LIBSTDBUF_DIR=/usr/lib cargo build --features feat_external_libstdbuf"
|
||||
);
|
||||
eprintln!(
|
||||
"\nThis directory should point to where libstdbuf.so / libstdbuf.dylib will be installed on the target system."
|
||||
);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
let out_dir = env::var("OUT_DIR").expect("OUT_DIR not set");
|
||||
let target = env::var("TARGET").unwrap_or_else(|_| "unknown".to_string());
|
||||
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
// spell-checker:ignore (ToDO) tempdir dyld dylib optgrps libstdbuf
|
||||
|
||||
use clap::{Arg, ArgAction, ArgMatches, Command};
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::os::unix::process::ExitStatusExt;
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
|
@ -29,16 +27,19 @@ mod options {
|
|||
pub const COMMAND: &str = "command";
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "dragonfly"
|
||||
#[cfg(all(
|
||||
not(feature = "feat_external_libstdbuf"),
|
||||
any(
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "dragonfly"
|
||||
)
|
||||
))]
|
||||
const STDBUF_INJECT: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/libstdbuf.so"));
|
||||
|
||||
#[cfg(target_vendor = "apple")]
|
||||
#[cfg(all(not(feature = "feat_external_libstdbuf"), target_vendor = "apple"))]
|
||||
const STDBUF_INJECT: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/libstdbuf.dylib"));
|
||||
|
||||
enum BufferType {
|
||||
|
@ -137,7 +138,11 @@ fn set_command_env(command: &mut process::Command, buffer_name: &str, buffer_typ
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "feat_external_libstdbuf"))]
|
||||
fn get_preload_env(tmp_dir: &TempDir) -> UResult<(String, PathBuf)> {
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
|
||||
let (preload, extension) = preload_strings()?;
|
||||
let inject_path = tmp_dir.path().join("libstdbuf").with_extension(extension);
|
||||
|
||||
|
@ -147,6 +152,29 @@ fn get_preload_env(tmp_dir: &TempDir) -> UResult<(String, PathBuf)> {
|
|||
Ok((preload.to_owned(), inject_path))
|
||||
}
|
||||
|
||||
#[cfg(feature = "feat_external_libstdbuf")]
|
||||
fn get_preload_env(_tmp_dir: &TempDir) -> UResult<(String, PathBuf)> {
|
||||
let (preload, extension) = preload_strings()?;
|
||||
|
||||
// Use the directory provided at compile time via LIBSTDBUF_DIR environment variable
|
||||
// This will fail to compile if LIBSTDBUF_DIR is not set, which is the desired behavior
|
||||
const LIBSTDBUF_DIR: &str = env!("LIBSTDBUF_DIR");
|
||||
let path_buf = PathBuf::from(LIBSTDBUF_DIR)
|
||||
.join("libstdbuf")
|
||||
.with_extension(extension);
|
||||
if path_buf.exists() {
|
||||
return Ok((preload.to_owned(), path_buf));
|
||||
}
|
||||
|
||||
Err(USimpleError::new(
|
||||
1,
|
||||
format!(
|
||||
"External libstdbuf not found at configured path: {}",
|
||||
path_buf.display()
|
||||
),
|
||||
))
|
||||
}
|
||||
|
||||
#[uucore::main]
|
||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
let matches = uu_app().try_get_matches_from(args).with_exit_code(125)?;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue