Skip to content

feat: build script support earlier Nginx version #71

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Apr 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ In short, this SDK allows writing NGINX modules using the Rust language.
NGINX modules can be built against a particular version of NGINX. The following environment variables can be used to specify a particular version of NGINX or an NGINX dependency:

* `ZLIB_VERSION` (default 1.3.1) -
* `PCRE2_VERSION` (default 10.42)
* `OPENSSL_VERSION` (default 3.2.1)
* `PCRE2_VERSION` (default 10.42 for NGINX 1.22.0 and later, or 8.45 for earlier)
* `OPENSSL_VERSION` (default 3.2.1 for NGINX 1.22.0 and later, or 1.1.1w for earlier)
* `NGX_VERSION` (default 1.24.0) - NGINX OSS version
* `NGX_DEBUG` (default to false)- if set to true, then will compile NGINX `--with-debug` option

Expand Down
83 changes: 60 additions & 23 deletions nginx-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,16 @@ const ZLIB_DEFAULT_VERSION: &str = "1.3.1";
/// Key 1: Mark Adler's public key. For zlib 1.3.1 and earlier
const ZLIB_GPG_SERVER_AND_KEY_ID: (&str, &str) = (UBUNTU_KEYSEVER, "5ED46A6721D365587791E2AA783FCD8E58BCAFBA");
const ZLIB_DOWNLOAD_URL_PREFIX: &str = "https://github.com/madler/zlib/releases/download";
/// The default version of pcre2 to use if the `PCRE2_VERSION` environment variable is not present
/// The default version of pcre to use if the `PCRE2_VERSION` environment variable is not present
const PCRE1_DEFAULT_VERSION: &str = "8.45";
const PCRE2_DEFAULT_VERSION: &str = "10.42";
/// Key 1: Phillip Hazel's public key. For PCRE2 10.42 and earlier
const PCRE2_GPG_SERVER_AND_KEY_ID: (&str, &str) = (UBUNTU_KEYSEVER, "45F68D54BBE23FB3039B46E59766E084FB0F43D8");
const PCRE1_DOWNLOAD_URL_PREFIX: &str = "https://sourceforge.net/projects/pcre/files/pcre";
const PCRE2_DOWNLOAD_URL_PREFIX: &str = "https://github.com/PCRE2Project/pcre2/releases/download";
/// The default version of openssl to use if the `OPENSSL_VERSION` environment variable is not present
const OPENSSL_DEFAULT_VERSION: &str = "3.2.1";
const OPENSSL1_DEFAULT_VERSION: &str = "1.1.1w";
const OPENSSL3_DEFAULT_VERSION: &str = "3.2.1";
const OPENSSL_GPG_SERVER_AND_KEY_IDS: (&str, &str) = (
UBUNTU_KEYSEVER,
"\
Expand All @@ -48,11 +51,13 @@ const NGX_DEFAULT_VERSION: &str = "1.24.0";

/// Key 1: Konstantin Pavlov's public key. For Nginx 1.25.3 and earlier
/// Key 2: Sergey Kandaurov's public key. For Nginx 1.25.4
/// Key 3: Maxim Dounin's public key. At least used for Nginx 1.18.0
const NGX_GPG_SERVER_AND_KEY_IDS: (&str, &str) = (
UBUNTU_KEYSEVER,
"\
13C82A63B603576156E30A4EA0EA981B66B0D967 \
D6786CE303D9A9022998DC6CC8464D549AF75C0A",
D6786CE303D9A9022998DC6CC8464D549AF75C0A \
B0F4253373F8F6F510D42178520A9993A1C052F8",
);

const NGX_DOWNLOAD_URL_PREFIX: &str = "https://nginx.org/download";
Expand Down Expand Up @@ -196,34 +201,66 @@ build process:
integrity of the downloaded files will not be verified.
*/

fn zlib_archive_url() -> String {
let version = env::var("ZLIB_VERSION").unwrap_or_else(|_| ZLIB_DEFAULT_VERSION.to_string());
fn zlib_archive_url(version: &String) -> String {
format!("{ZLIB_DOWNLOAD_URL_PREFIX}/v{version}/zlib-{version}.tar.gz")
}

fn pcre2_archive_url() -> String {
let version = env::var("PCRE2_VERSION").unwrap_or_else(|_| PCRE2_DEFAULT_VERSION.to_string());
format!("{PCRE2_DOWNLOAD_URL_PREFIX}/pcre2-{version}/pcre2-{version}.tar.gz")
fn pcre_archive_url(version: &String) -> String {
// We can distinguish pcre1/pcre2 by checking whether the second character is '.', because the final version of pcre1 is 8.45 and the first one of pcre2 is 10.00.
if version.chars().nth(1).is_some_and(|c| c == '.') {
format!("{PCRE1_DOWNLOAD_URL_PREFIX}/{version}/pcre-{version}.tar.gz")
} else {
format!("{PCRE2_DOWNLOAD_URL_PREFIX}/pcre2-{version}/pcre2-{version}.tar.gz")
}
}

fn openssl_archive_url() -> String {
let version = env::var("OPENSSL_VERSION").unwrap_or_else(|_| OPENSSL_DEFAULT_VERSION.to_string());
format!("{OPENSSL_DOWNLOAD_URL_PREFIX}/openssl-{version}/openssl-{version}.tar.gz")
fn openssl_archive_url(version: &String) -> String {
if version.starts_with("1.1.1") {
let version_hyphened = version.replace('.', "_");
format!("{OPENSSL_DOWNLOAD_URL_PREFIX}/OpenSSL_{version_hyphened}/openssl-{version}.tar.gz")
} else {
format!("{OPENSSL_DOWNLOAD_URL_PREFIX}/openssl-{version}/openssl-{version}.tar.gz")
}
}

fn nginx_archive_url() -> String {
let version = env::var("NGX_VERSION").unwrap_or_else(|_| NGX_DEFAULT_VERSION.to_string());
fn nginx_archive_url(version: &String) -> String {
format!("{NGX_DOWNLOAD_URL_PREFIX}/nginx-{version}.tar.gz")
}

/// Returns a list of tuples containing the URL to a tarball archive and the GPG signature used
/// to validate the integrity of the tarball.
fn all_archives() -> Vec<(String, String)> {
let ngx_version = env::var("NGX_VERSION").unwrap_or_else(|_| NGX_DEFAULT_VERSION.into());
let zlib_version = env::var("ZLIB_VERSION").unwrap_or_else(|_| ZLIB_DEFAULT_VERSION.into());
// While Nginx 1.22.0 and later support pcre2 and openssl3, earlier ones only support pcre1 and openssl1. Here provides the appropriate (and as latest as possible) versions of these two dependencies as default, switching `***[major_version]_DEFAULT_VERSION` based on `is_after_1_22`. This facilitates to compile backport versions targeted for Nginx ealier than 1.22.0, which are still used in LTS releases of major Linux distributions.
let ngx_version_vec: Vec<i16> = ngx_version.split('.').map(|s| s.parse().unwrap_or(-1)).collect();
let is_after_1_22 = (ngx_version_vec.len() >= 2)
&& (ngx_version_vec[0] > 1 || (ngx_version_vec[0] == 1 && ngx_version_vec[1] >= 22));
// keep env name `PCRE2_VERSION` for compat
let pcre_version = env::var("PCRE2_VERSION").unwrap_or_else(|_| {
if is_after_1_22 {
PCRE2_DEFAULT_VERSION
} else {
PCRE1_DEFAULT_VERSION
}
.into()
});
let openssl_version = env::var("OPENSSL_VERSION").unwrap_or_else(|_| {
if is_after_1_22 {
OPENSSL3_DEFAULT_VERSION
} else {
OPENSSL1_DEFAULT_VERSION
}
.into()
});
fn url_pair(tar_url: String, pgp_ext: &str) -> (String, String) {
(tar_url.clone(), format!("{tar_url}.{pgp_ext}"))
}
vec![
(zlib_archive_url(), format!("{}.asc", zlib_archive_url())),
(pcre2_archive_url(), format!("{}.sig", pcre2_archive_url())),
(openssl_archive_url(), format!("{}.asc", openssl_archive_url())),
(nginx_archive_url(), format!("{}.asc", nginx_archive_url())),
url_pair(zlib_archive_url(&zlib_version), "asc"),
url_pair(pcre_archive_url(&pcre_version), "sig"),
url_pair(openssl_archive_url(&openssl_version), "asc"),
url_pair(nginx_archive_url(&ngx_version), "asc"),
]
}

Expand Down Expand Up @@ -512,20 +549,20 @@ fn extract_all_archives(cache_dir: &Path) -> Result<Vec<(String, PathBuf)>, Box<
/// Invoke external processes to run autoconf `configure` to generate a makefile for NGINX and
/// then run `make install`.
fn compile_nginx() -> Result<(PathBuf, PathBuf), Box<dyn StdError>> {
fn find_dependency_path<'a>(sources: &'a [(String, PathBuf)], name: &str) -> &'a PathBuf {
fn find_dependency_path<'a>(sources: &'a [(String, PathBuf)], name: &str) -> Result<&'a PathBuf, String> {
sources
.iter()
.find(|(n, _)| n == name)
.map(|(_, p)| p)
.unwrap_or_else(|| panic!("Unable to find dependency [{name}] path"))
.ok_or(format!("Unable to find dependency [{name}] path"))
}
let cache_dir = make_cache_dir()?;
let nginx_install_dir = nginx_install_dir(&cache_dir);
let sources = extract_all_archives(&cache_dir)?;
let zlib_src_dir = find_dependency_path(&sources, "zlib");
let openssl_src_dir = find_dependency_path(&sources, "openssl");
let pcre2_src_dir = find_dependency_path(&sources, "pcre2");
let nginx_src_dir = find_dependency_path(&sources, "nginx");
let zlib_src_dir = find_dependency_path(&sources, "zlib")?;
let openssl_src_dir = find_dependency_path(&sources, "openssl")?;
let pcre2_src_dir = find_dependency_path(&sources, "pcre2").or(find_dependency_path(&sources, "pcre"))?;
let nginx_src_dir = find_dependency_path(&sources, "nginx")?;
let nginx_configure_flags = nginx_configure_flags(&nginx_install_dir, zlib_src_dir, openssl_src_dir, pcre2_src_dir);
let nginx_binary_exists = nginx_install_dir.join("sbin").join("nginx").exists();
let autoconf_makefile_exists = nginx_src_dir.join("Makefile").exists();
Expand Down