blob: 94879816cc63d26a04dd37e8b70dca293589abb2 [file] [log] [blame] [edit]
// 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");
}
}