| // The build for pcre2-sys currently does roughly the following: |
| // |
| // 1. Use the PCRE2 system library as reported by pkg-config if it exists |
| // and only if we don't explicitly want a static build. |
| // 2. Otherwise, statically build PCRE2 by hand. |
| // |
| // For step 1, we permit opting out of using the system library via either |
| // explicitly setting the PCRE2_SYS_STATIC environment variable or if we |
| // otherwise believe we want a static build (e.g., when building with MUSL). |
| // |
| // For step 2, we roughly follow the directions as laid out in |
| // pcre2/NON-AUTOTOOLS-BUILD. It's pretty straight-forward: copy a few files, |
| // set a few defines and then build it. We can get away with a pretty stripped |
| // down setup here since the PCRE2 build setup also handles various command |
| // line tools (like pcre2grep) and its test infrastructure, and we needn't |
| // concern ourselves with that. |
| // |
| // It is plausible that this build script will need to evolve to do better |
| // platform detection for the various PCRE2 settings, but this should work |
| // as-is on Windows, Linux and macOS. |
| |
| extern crate cc; |
| extern crate pkg_config; |
| |
| use std::process::Command; |
| use std::env; |
| use std::fs; |
| use std::path::{Path, PathBuf}; |
| |
| // Files that PCRE2 needs to compile. |
| const FILES: &'static [&'static str] = &[ |
| "pcre2_auto_possess.c", |
| "pcre2_compile.c", |
| "pcre2_config.c", |
| "pcre2_context.c", |
| "pcre2_convert.c", |
| "pcre2_dfa_match.c", |
| "pcre2_error.c", |
| "pcre2_extuni.c", |
| "pcre2_find_bracket.c", |
| "pcre2_jit_compile.c", |
| "pcre2_maketables.c", |
| "pcre2_match.c", |
| "pcre2_match_data.c", |
| "pcre2_newline.c", |
| "pcre2_ord2utf.c", |
| "pcre2_pattern_info.c", |
| "pcre2_serialize.c", |
| "pcre2_string_utils.c", |
| "pcre2_study.c", |
| "pcre2_substitute.c", |
| "pcre2_substring.c", |
| "pcre2_tables.c", |
| "pcre2_ucd.c", |
| "pcre2_valid_utf.c", |
| "pcre2_xclass.c", |
| ]; |
| |
| fn main() { |
| println!("cargo:rerun-if-env-changed=PCRE2_SYS_STATIC"); |
| |
| let target = env::var("TARGET").unwrap(); |
| let out = PathBuf::from(env::var_os("OUT_DIR").unwrap()); |
| |
| // Don't link to a system library if we want a static build. |
| let want_static = pcre2_sys_static().unwrap_or(target.contains("musl")); |
| if !want_static && pkg_config::probe_library("libpcre2-8").is_ok() { |
| return; |
| } |
| |
| // For a static build, make sure our PCRE2 submodule has been loaded. |
| if has_git() && !Path::new("pcre2/.git").exists() { |
| Command::new("git") |
| .args(&["submodule", "update", "--init"]) |
| .status() |
| .unwrap(); |
| } |
| |
| // Set some config options. We mostly just use the default values. We do |
| // this in lieu of patching config.h since it's easier. |
| let mut builder = cc::Build::new(); |
| builder |
| .define("PCRE2_CODE_UNIT_WIDTH", "8") |
| .define("HAVE_STDLIB_H", "1") |
| .define("HAVE_MEMMOVE", "1") |
| .define("HEAP_LIMIT", "20000000") |
| .define("LINK_SIZE", "2") |
| .define("MATCH_LIMIT", "10000000") |
| .define("MATCH_LIMIT_DEPTH", "10000000") |
| .define("MAX_NAME_COUNT", "10000") |
| .define("MAX_NAME_SIZE", "32") |
| .define("NEWLINE_DEFAULT", "2") |
| .define("PARENS_NEST_LIMIT", "250") |
| .define("PCRE2_STATIC", "1") |
| .define("STDC_HEADERS", "1") |
| .define("SUPPORT_PCRE2_8", "1") |
| .define("SUPPORT_UNICODE", "1"); |
| if target.contains("windows") { |
| builder.define("HAVE_WINDOWS_H", "1"); |
| } |
| |
| enable_jit(&target, &mut builder); |
| |
| // Copy PCRE2 headers. Typically, `./configure` would do this for us |
| // automatically, but since we're compiling by hand, we do it ourselves. |
| let include = out.join("include"); |
| fs::create_dir_all(&include).unwrap(); |
| fs::copy("pcre2/src/config.h.generic", include.join("config.h")).unwrap(); |
| fs::copy("pcre2/src/pcre2.h.generic", include.join("pcre2.h")).unwrap(); |
| |
| // Same deal for chartables. Just use the default. |
| let src = out.join("src"); |
| fs::create_dir_all(&src).unwrap(); |
| fs::copy( |
| "pcre2/src/pcre2_chartables.c.dist", |
| src.join("pcre2_chartables.c"), |
| ).unwrap(); |
| |
| // Build everything. |
| builder |
| .include("pcre2/src") |
| .include(&include) |
| .file(src.join("pcre2_chartables.c")); |
| for file in FILES { |
| builder.file(Path::new("pcre2/src").join(file)); |
| } |
| |
| if env::var("PCRE2_SYS_DEBUG").unwrap_or(String::new()) == "1" { |
| builder.debug(true); |
| } |
| builder.compile("libpcre2.a"); |
| } |
| |
| fn has_git() -> bool { |
| Command::new("git").arg("--help") |
| .status() |
| .map(|s| s.success()) |
| .unwrap_or(false) |
| } |
| |
| fn pcre2_sys_static() -> Option<bool> { |
| match env::var("PCRE2_SYS_STATIC") { |
| Err(_) => None, |
| Ok(s) => { |
| if s == "1" { |
| Some(true) |
| } else if s == "0" { |
| Some(false) |
| } else { |
| None |
| } |
| } |
| } |
| } |
| |
| // On `aarch64-apple-ios` clang fails with the following error. |
| // |
| // Undefined symbols for architecture arm64: |
| // "___clear_cache", referenced from: |
| // _sljit_generate_code in libforeign.a(pcre2_jit_compile.o) |
| // ld: symbol(s) not found for architecture arm64 |
| // |
| // aarch64-apple-tvos https://bugreports.qt.io/browse/QTBUG-62993?gerritReviewStatus=All |
| // aarch64-apple-darwin https://github.com/Homebrew/homebrew-core/pull/57419 |
| // x86_64-apple-ios disabled for device–simulator consistency (not tested) |
| // x86_64-apple-tvos disabled for device–simulator consistency (not tested) |
| // armv7-apple-ios assumed equivalent to aarch64-apple-ios (not tested) |
| // armv7s-apple-ios assumed equivalent to aarch64-apple-ios (not tested) |
| // i386-apple-ios assumed equivalent to aarch64-apple-ios (not tested) |
| // x86_64-apple-ios-macabi disabled out of caution (not tested) (needs attention) |
| // |
| // We may want to monitor developments on the `aarch64-apple-darwin` front as they may end up |
| // propagating to all `aarch64`-based targets and the `x86_64` equivalents. |
| fn enable_jit(target: &str, builder: &mut cc::Build) { |
| if !target.starts_with("aarch64-apple") && |
| !target.contains("apple-ios") && |
| !target.contains("apple-tvos") { |
| builder.define("SUPPORT_JIT", "1"); |
| } |
| } |