1
0
mirror of https://github.com/BurntSushi/ripgrep.git synced 2025-03-23 04:34:39 +02:00
ripgrep/crates/core/flags/doc/version.rs
Andrew Gallant e9abbc1a02 cargo: nuke 'simd-accel' from orbit
This feature causes nothing but problems and is frequently broken. The
only optimization it was enabling were SIMD optimizations for
transcoding. In particular, for UTF-16 transcoding. This is performed by
the [`encoding_rs`](https://github.com/hsivonen/encoding_rs) crate,
which specifically uses unstable portable SIMD APIs instead of the
stable non-portable SIMD APIs.

SIMD optimizations that apply to search have long been making use of
stable APIs, and are automatically enabled when your target supports
them. This is, IMO, the correct user experience and one that
`encoding_rs` refuses to support. I'm done dealing with it, so
transcoding will only use scalar code until the SIMD optimizations in
`encoding_rs` work on stable. (This doesn't mean that `encoding_rs` has
to change. This could also be fixed by stabilizing `std::simd`.)

Fixes #2748
2024-03-07 09:47:43 -05:00

178 lines
5.4 KiB
Rust

/*!
Provides routines for generating version strings.
Version strings can be just the digits, an overall short one-line description
or something more verbose that includes things like CPU target feature support.
*/
use std::fmt::Write;
/// Generates just the numerical part of the version of ripgrep.
///
/// This includes the git revision hash.
pub(crate) fn generate_digits() -> String {
let semver = option_env!("CARGO_PKG_VERSION").unwrap_or("N/A");
match option_env!("RIPGREP_BUILD_GIT_HASH") {
None => semver.to_string(),
Some(hash) => format!("{semver} (rev {hash})"),
}
}
/// Generates a short version string of the form `ripgrep x.y.z`.
pub(crate) fn generate_short() -> String {
let digits = generate_digits();
format!("ripgrep {digits}")
}
/// Generates a longer multi-line version string.
///
/// This includes not only the version of ripgrep but some other information
/// about its build. For example, SIMD support and PCRE2 support.
pub(crate) fn generate_long() -> String {
let (compile, runtime) = (compile_cpu_features(), runtime_cpu_features());
let mut out = String::new();
writeln!(out, "{}", generate_short()).unwrap();
writeln!(out).unwrap();
writeln!(out, "features:{}", features().join(",")).unwrap();
if !compile.is_empty() {
writeln!(out, "simd(compile):{}", compile.join(",")).unwrap();
}
if !runtime.is_empty() {
writeln!(out, "simd(runtime):{}", runtime.join(",")).unwrap();
}
let (pcre2_version, _) = generate_pcre2();
writeln!(out, "\n{pcre2_version}").unwrap();
out
}
/// Generates multi-line version string with PCRE2 information.
///
/// This also returns whether PCRE2 is actually available in this build of
/// ripgrep.
pub(crate) fn generate_pcre2() -> (String, bool) {
let mut out = String::new();
#[cfg(feature = "pcre2")]
{
use grep::pcre2;
let (major, minor) = pcre2::version();
write!(out, "PCRE2 {}.{} is available", major, minor).unwrap();
if cfg!(target_pointer_width = "64") && pcre2::is_jit_available() {
writeln!(out, " (JIT is available)").unwrap();
} else {
writeln!(out, " (JIT is unavailable)").unwrap();
}
(out, true)
}
#[cfg(not(feature = "pcre2"))]
{
writeln!(out, "PCRE2 is not available in this build of ripgrep.")
.unwrap();
(out, false)
}
}
/// Returns the relevant SIMD features supported by the CPU at runtime.
///
/// This is kind of a dirty violation of abstraction, since it assumes
/// knowledge about what specific SIMD features are being used by various
/// components.
fn runtime_cpu_features() -> Vec<String> {
#[cfg(target_arch = "x86_64")]
{
let mut features = vec![];
let sse2 = is_x86_feature_detected!("sse2");
features.push(format!("{sign}SSE2", sign = sign(sse2)));
let ssse3 = is_x86_feature_detected!("ssse3");
features.push(format!("{sign}SSSE3", sign = sign(ssse3)));
let avx2 = is_x86_feature_detected!("avx2");
features.push(format!("{sign}AVX2", sign = sign(avx2)));
features
}
#[cfg(target_arch = "aarch64")]
{
let mut features = vec![];
// memchr and aho-corasick only use NEON when it is available at
// compile time. This isn't strictly necessary, but NEON is supposed
// to be available for all aarch64 targets. If this isn't true, please
// file an issue at https://github.com/BurntSushi/memchr.
let neon = cfg!(target_feature = "neon");
features.push(format!("{sign}NEON", sign = sign(neon)));
features
}
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
{
vec![]
}
}
/// Returns the SIMD features supported while compiling ripgrep.
///
/// In essence, any features listed here are required to run ripgrep correctly.
///
/// This is kind of a dirty violation of abstraction, since it assumes
/// knowledge about what specific SIMD features are being used by various
/// components.
///
/// An easy way to enable everything available on your current CPU is to
/// compile ripgrep with `RUSTFLAGS="-C target-cpu=native"`. But note that
/// the binary produced by this will not be portable.
fn compile_cpu_features() -> Vec<String> {
#[cfg(target_arch = "x86_64")]
{
let mut features = vec![];
let sse2 = cfg!(target_feature = "sse2");
features.push(format!("{sign}SSE2", sign = sign(sse2)));
let ssse3 = cfg!(target_feature = "ssse3");
features.push(format!("{sign}SSSE3", sign = sign(ssse3)));
let avx2 = cfg!(target_feature = "avx2");
features.push(format!("{sign}AVX2", sign = sign(avx2)));
features
}
#[cfg(target_arch = "aarch64")]
{
let mut features = vec![];
let neon = cfg!(target_feature = "neon");
features.push(format!("{sign}NEON", sign = sign(neon)));
features
}
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
{
vec![]
}
}
/// Returns a list of "features" supported (or not) by this build of ripgrpe.
fn features() -> Vec<String> {
let mut features = vec![];
let pcre2 = cfg!(feature = "pcre2");
features.push(format!("{sign}pcre2", sign = sign(pcre2)));
features
}
/// Returns `+` when `enabled` is `true` and `-` otherwise.
fn sign(enabled: bool) -> &'static str {
if enabled {
"+"
} else {
"-"
}
}