Skip to main content

jpegxl_src/
lib.rs

1/*
2 * This file is part of jpegxl-rs.
3 *
4 * jpegxl-rs is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * jpegxl-rs is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with jpegxl-rs.  If not, see <https://www.gnu.org/licenses/>.
16 */
17
18#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
19
20use core::panic;
21use std::{
22    env,
23    path::{Path, PathBuf},
24};
25
26fn source_dir() -> PathBuf {
27    env::var("DEP_JXL_PATH").map_or_else(
28        |_| Path::new(env!("CARGO_MANIFEST_DIR")).join("libjxl"),
29        PathBuf::from,
30    )
31}
32
33#[cfg_attr(coverage_nightly, coverage(off))]
34/// Builds the JPEG XL library.
35///
36/// # Panics
37///
38/// This function will panic if the source directory does not exist or is not a directory.
39pub fn build() {
40    let source = source_dir();
41    assert!(
42        source.exists() && source.is_dir(),
43        "Source directory {} does not exist",
44        source.display()
45    );
46
47    let mut config = cmake::Config::new(source);
48    config
49        .define("BUILD_TESTING", "OFF")
50        .define("BUILD_SHARED_LIBS", "OFF")
51        .define("JPEGXL_ENABLE_TOOLS", "OFF")
52        .define("JPEGXL_ENABLE_DOXYGEN", "OFF")
53        .define("JPEGXL_ENABLE_MANPAGES", "OFF")
54        .define("JPEGXL_ENABLE_BENCHMARK", "OFF")
55        .define("JPEGXL_ENABLE_EXAMPLES", "OFF")
56        .define("JPEGXL_ENABLE_JNI", "OFF")
57        .define("JPEGXL_ENABLE_SJPEG", "OFF")
58        .define("JPEGXL_ENABLE_OPENEXR", "OFF")
59        .define("JPEGXL_ENABLE_JPEGLI", "OFF")
60        .define("JPEGXL_BUNDLE_LIBPNG", "OFF");
61
62    if let Ok(p) = std::thread::available_parallelism() {
63        config.env("CMAKE_BUILD_PARALLEL_LEVEL", format!("{p}"));
64    }
65
66    if cfg!(asan) {
67        config
68            .env("SANITIZER", "asan")
69            .cflag("-g -DADDRESS_SANITIZER -fsanitize=address")
70            .cxxflag("-g -DADDRESS_SANITIZER -fsanitize=address")
71            .define("JPEGXL_ENABLE_TCMALLOC", "OFF");
72    } else if cfg!(tsan) {
73        config
74            .env("SANITIZER", "tsan")
75            .cflag("-g -DTHREAD_SANITIZER -fsanitize=thread")
76            .cxxflag("-g -DTHREAD_SANITIZER -fsanitize=thread")
77            .define("JPEGXL_ENABLE_TCMALLOC", "OFF");
78    }
79
80    if cfg!(windows) {
81        assert!(!cfg!(tsan), "Thread sanitizer is not supported on Windows");
82
83        // For CMake pre-checking
84        let exeflags = "MSVCRTD.lib".to_string();
85
86        config
87            .define(
88                "CMAKE_VS_GLOBALS",
89                "UseMultiToolTask=true;EnforceProcessCountAcrossBuilds=true",
90            ) // Enable parallel builds
91            .define("CMAKE_MSVC_RUNTIME_LIBRARY", "MultiThreaded")
92            .define("CMAKE_EXE_LINKER_FLAGS", exeflags)
93            .cflag("/Zl");
94    }
95
96    let prefix = config.build();
97
98    let lib_dir = {
99        let mut lib_dir = prefix.join("lib");
100        if lib_dir.exists() {
101            lib_dir
102        } else {
103            lib_dir.pop();
104            lib_dir.push("lib64");
105            if lib_dir.exists() {
106                lib_dir
107            } else {
108                panic!(
109                    "Could not find the library directory, please check the files in {prefix:?}"
110                );
111            }
112        }
113    };
114    println!("cargo:rustc-link-search=native={}", lib_dir.display());
115
116    println!("cargo:rustc-link-lib=static=jxl");
117    println!("cargo:rustc-link-lib=static=jxl_cms");
118    println!("cargo:rustc-link-lib=static=jxl_threads");
119
120    println!("cargo:rustc-link-lib=static=hwy");
121    println!("cargo:rustc-link-lib=static=brotlidec");
122    println!("cargo:rustc-link-lib=static=brotlienc");
123    println!("cargo:rustc-link-lib=static=brotlicommon");
124
125    if cfg!(any(target_vendor = "apple", target_os = "freebsd")) {
126        println!("cargo:rustc-link-lib=c++");
127    } else if cfg!(target_os = "linux") {
128        println!("cargo:rustc-link-lib=stdc++");
129    }
130}
131
132#[cfg(test)]
133mod tests {
134    use super::*;
135
136    #[test]
137    #[cfg_attr(coverage_nightly, coverage(off))]
138    fn test_source_dir() {
139        let mut path = source_dir();
140        assert!(path.is_dir());
141
142        path.push("lib/include/jxl/codestream_header.h");
143        assert!(path.exists());
144    }
145}