Skip to main content

hyperscan_src/
lib.rs

1//! hyperscan-src: 将 intel/hyperscan C++ 源码打包为 Rust crate,通过 cmake 从源码编译。
2//!
3//! # 设计原理
4//!
5//! 本 crate 使用 **openssl-src 模式**:cmake 调用放在 `lib.rs` 而非 `build.rs`。
6//! 原因:将 cmake 调用放入 lib.rs 后,下游 crate(hypervectorscan-sys)在其 `build.rs`
7//! 中通过函数调用执行。此时所有 `cargo:rustc-link-*` 指令都在 hypervectorscan-sys 的
8//! build script 进程内发出 → Cargo 能正确将这些链接指令应用到最终产物。
9//!
10//! 如果放在本 crate 的 build.rs,link 指令会因为 crate 间隔离而无法传递到最终二进制。
11//!
12//! # 系统依赖
13//!
14//! 编译本 crate 需要:
15//! - cmake ≥ 3.x
16//! - C++ 编译器(gcc / clang)
17//! - ragel
18//! - boost-dev
19//!
20//! 这些依赖仅在启用 `vendored` feature 时需要。缺少时 cmake 的 configure 阶段会报错,
21//! 错误信息会通过 cargo 输出清晰的提示。
22
23use std::path::PathBuf;
24
25/// 构建配置
26pub struct Build {
27    fat_runtime: bool,
28    build_avx512: bool,
29    build_avx512vbmi: bool,
30}
31
32/// 构建产物路径信息
33pub struct Artifacts {
34    /// 头文件目录(包含 hs/hs.h)
35    pub include_dir: PathBuf,
36    /// 库文件目录(libhs.a, libhs_runtime.a)
37    pub lib_dir: PathBuf,
38    /// 链接的库名列表
39    pub libs: Vec<String>,
40}
41
42impl Build {
43    /// 创建默认构建配置。
44    ///
45    /// 默认启用 FAT_RUNTIME(运行时 CPU 特性检测),避免在不支持 AVX-512 的 CPU 上
46    /// 因预编译二进制包含 AVX-512 指令而导致 SIGILL。
47    pub fn new() -> Self {
48        Build {
49            fat_runtime: true,
50            build_avx512: false,
51            build_avx512vbmi: false,
52        }
53    }
54
55    /// 启用/禁用 FAT_RUNTIME(运行时 CPU 分发,默认启用)
56    pub fn fat_runtime(&mut self, v: bool) -> &mut Self {
57        self.fat_runtime = v;
58        self
59    }
60    /// 启用 AVX512 指令集支持(x86_64 可选)
61    pub fn avx512(&mut self, v: bool) -> &mut Self {
62        self.build_avx512 = v;
63        self
64    }
65    /// 启用 AVX512VBMI 指令集支持(x86_64 可选,依赖 BUILD_AVX512)
66    pub fn avxvnni(&mut self, v: bool) -> &mut Self {
67        self.build_avx512vbmi = v;
68        self
69    }
70
71    /// 执行 cmake 构建,编译 Hyperscan 静态库。
72    ///
73    /// 此函数内部:
74    /// 1. 调用 `cmake::Config::new("hyperscan")` 配置构建
75    /// 2. 设置必要的 cmake flags(静态库、Release、FAT_RUNTIME 等)
76    /// 3. 调用 `config.build()` 执行编译+安装
77    /// 4. 通过 `println!("cargo:rustc-link-*")` 输出链接指令
78    ///    (这些指令由调用者进程发出,因此能正确应用到最终二进制)
79    /// 5. 返回包含头文件/库文件路径的 Artifacts
80    pub fn build(&mut self) -> Artifacts {
81        println!(
82            "cargo:warning=Vendored Hyperscan build — requires: cmake, C++ compiler, ragel, boost-dev"
83        );
84        let source_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("hyperscan");
85        let mut config = cmake::Config::new(source_dir);
86        config
87            .define("BUILD_STATIC_LIBS", "ON")
88            .define("BUILD_SHARED_LIBS", "OFF")
89            .define("CMAKE_BUILD_TYPE", "Release")
90            .define("CMAKE_INSTALL_LIBDIR", "lib")
91            .define("BUILD_EXAMPLES", "OFF")
92            .define("BUILD_BENCHMARKS", "OFF");
93
94        if self.fat_runtime {
95            config.define("FAT_RUNTIME", "ON");
96        }
97        if self.build_avx512 {
98            config.define("BUILD_AVX512", "ON");
99        }
100        if self.build_avx512vbmi {
101            config.define("BUILD_AVX512VBMI", "ON");
102        }
103
104        let dst = config.build();
105
106        // Some cmake versions install to lib64 or multiarch paths;
107        // search lib/, lib64/, lib/<arch>-linux-gnu/ — first containing libhs.a wins.
108        let lib_dir = {
109            let candidates: Vec<PathBuf> = vec![
110                dst.join("lib"),
111                dst.join("lib64"),
112                dst.join(format!("lib/{}-linux-gnu", std::env::consts::ARCH)),
113            ];
114            candidates
115                .into_iter()
116                .find(|d| d.join("libhs.a").exists())
117                .unwrap_or_else(|| dst.join("lib"))
118        };
119
120        println!("cargo:rustc-link-search=native={}", lib_dir.display());
121        println!("cargo:rustc-link-lib=static=hs");
122        println!("cargo:rustc-link-lib=static=hs_runtime");
123
124        Artifacts {
125            include_dir: dst.join("include"),
126            lib_dir,
127            libs: vec!["hs".into(), "hs_runtime".into()],
128        }
129    }
130}