mozjpeg-sys 0.5.7

FFI bindings for MozJPEG v3.3.1. MozJPEG is automatically built and linked statically. Requires nasm and a C compiler.
extern crate dunce;
extern crate cc;
#[cfg(feature = "nasm_simd")]
extern crate nasm_rs;
use std::path::{Path, PathBuf};
use std::fs;
use std::env;
use std::io::Write;

fn main() {
    let mut c = cc::Build::new();
    let root = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
    let config_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("include");
    let vendor = dunce::canonicalize(root.join("vendor")).unwrap();

    fs::create_dir_all(&config_dir).unwrap();

    println!("cargo:include={}", env::join_paths(&[&config_dir, &vendor]).unwrap().to_str().unwrap());
    c.include(&config_dir);
    c.include(&vendor);

    c.warnings(false);

    let files = &[
        "vendor/jcapimin.c", "vendor/jcapistd.c", "vendor/jccoefct.c", "vendor/jccolor.c",
        "vendor/jcdctmgr.c", "vendor/jcext.c", "vendor/jchuff.c", "vendor/jcinit.c",
        "vendor/jcmainct.c", "vendor/jcmarker.c", "vendor/jcmaster.c", "vendor/jcomapi.c",
        "vendor/jcparam.c", "vendor/jcphuff.c", "vendor/jcprepct.c", "vendor/jcsample.c",
        "vendor/jctrans.c", "vendor/jdapimin.c", "vendor/jdapistd.c", "vendor/jdatadst.c",
        "vendor/jdatasrc.c", "vendor/jdcoefct.c", "vendor/jdcolor.c", "vendor/jddctmgr.c",
        "vendor/jdhuff.c", "vendor/jdinput.c", "vendor/jdmainct.c", "vendor/jdmarker.c",
        "vendor/jdmaster.c", "vendor/jdmerge.c", "vendor/jdphuff.c", "vendor/jdpostct.c",
        "vendor/jdsample.c", "vendor/jdtrans.c", "vendor/jerror.c", "vendor/jfdctflt.c",
        "vendor/jfdctfst.c", "vendor/jfdctint.c", "vendor/jidctflt.c", "vendor/jidctfst.c",
        "vendor/jidctint.c", "vendor/jidctred.c", "vendor/jmemmgr.c", "vendor/jmemnobs.c",
        "vendor/jquant1.c", "vendor/jquant2.c", "vendor/jutils.c",
    ];

    for file in files.iter() {
        c.file(file);
    }

    let abi = if cfg!(feature = "jpeg80_abi") {
        "80"
    } else if cfg!(feature = "jpeg70_abi") {
        "70"
    } else {
        "62"
    };
    println!("cargo:lib_version={}", abi);

    let mut jconfigint_h = fs::File::create(config_dir.join("jconfigint.h")).unwrap();
    write!(jconfigint_h, r#"
        #define BUILD "{timestamp}-mozjpeg-sys"
        #ifndef INLINE
            #if defined(__GNUC__)
                #define INLINE inline __attribute__((always_inline))
            #elif defined(_MSC_VER)
                #define INLINE __forceinline
            #else
                #define INLINE inline
            #endif
        #endif
        #define PACKAGE_NAME "{PACKAGE_NAME}"
        #define VERSION "{VERSION}"
        #define SIZEOF_SIZE_T {SIZEOF_SIZE_T}
        "#,
        timestamp = std::time::UNIX_EPOCH.elapsed().unwrap().as_secs(),
        PACKAGE_NAME = env::var("CARGO_PKG_NAME").unwrap(),
        VERSION = env::var("CARGO_PKG_VERSION").unwrap(),
        SIZEOF_SIZE_T = if cfg!(target_pointer_width = 32) {"4"} else {"8"}
    ).unwrap();
    drop(jconfigint_h); // close the file

    let mut jconfig_h = fs::File::create(config_dir.join("jconfig.h")).unwrap();
    write!(jconfig_h, r#"
        #define JPEG_LIB_VERSION {JPEG_LIB_VERSION}
        #define LIBJPEG_TURBO_VERSION 0
        #define BITS_IN_JSAMPLE 8
        #define STDC_HEADERS 1
        #define HAVE_STDLIB_H 1
        #define HAVE_UNSIGNED_CHAR 1
        #define HAVE_UNSIGNED_SHORT 1
        #define MEM_SRCDST_SUPPORTED 1
        "#,
        JPEG_LIB_VERSION = abi
    ).unwrap();

    if cfg!(feature = "arith_enc") {
        jconfig_h.write_all(b"#define C_ARITH_CODING_SUPPORTED 1\n").unwrap();
        c.file("vendor/jcarith.c");
    }
    if cfg!(feature = "arith_dec") {
        jconfig_h.write_all(b"#define D_ARITH_CODING_SUPPORTED 1\n").unwrap();
        c.file("vendor/jdarith.c");
    }


    if cfg!(feature = "arith_enc") || cfg!(feature = "arith_dec") {
        c.file("vendor/jaricom.c");
    }

    if cfg!(feature = "turbojpeg_api") {
        c.file("vendor/turbojpeg.c");
        c.file("vendor/transupp.c");
        c.file("vendor/jdatadst-tj.c");
        c.file("vendor/jdatasrc-tj.c");
    }

    #[cfg(feature = "nasm_simd")]
    {
        c.include("vendor/simd");
        jconfig_h.write_all(b"#define WITH_SIMD 1\n").unwrap();

        if cfg!(target_arch = "x86_64") {
            c.file("vendor/simd/jsimd_x86_64.c");
        } else if cfg!(target_arch = "x86") {
            c.file("vendor/simd/jsimd_i386.c");
        } else if cfg!(target_arch = "mips") {
            c.file("vendor/simd/jsimd_mips.c");
        } else if cfg!(target_arch = "powerpc") || cfg!(target_arch = "powerpc64") {
            c.file("vendor/simd/jsimd_powerpc.c");
        } else if cfg!(target_arch = "arm") {
            c.file("vendor/simd/jsimd_arm.c");
        } else if cfg!(target_arch = "aarch64") {
            c.file("vendor/simd/jsimd_arm64.c");
        }
        build_nasm(&vendor);
    }
    drop(jconfig_h); // close the file

    if !cfg!(feature = "nasm_simd") {
        c.file("vendor/jsimd_none.c");
    }

    c.compile(&format!("mozjpeg{}", abi));
}

#[cfg(feature = "nasm_simd")]
fn build_nasm(vendor_dir: &Path) {
    let simd_include = format!("-I{}/", vendor_dir.join("simd").display()); // MUST have slash!
    let win_include = format!("-I{}/", vendor_dir.join("win").display());
    let mut flags = vec![simd_include.as_str(), win_include.as_str()];
    if std::env::var("PROFILE").map(|s| "debug" == s).unwrap_or(false) {
        flags.push("-g");
    }

    if cfg!(target_os = "linux") {
        flags.push("-DELF");
    }

    let x86_64 = [
        "vendor/simd/jfdctflt-sse-64.asm", "vendor/simd/jccolor-sse2-64.asm", "vendor/simd/jcgray-sse2-64.asm",
        "vendor/simd/jchuff-sse2-64.asm", "vendor/simd/jcsample-sse2-64.asm", "vendor/simd/jdcolor-sse2-64.asm",
        "vendor/simd/jdmerge-sse2-64.asm", "vendor/simd/jdsample-sse2-64.asm", "vendor/simd/jfdctfst-sse2-64.asm",
        "vendor/simd/jfdctint-sse2-64.asm", "vendor/simd/jidctflt-sse2-64.asm", "vendor/simd/jidctfst-sse2-64.asm",
        "vendor/simd/jidctint-sse2-64.asm", "vendor/simd/jidctred-sse2-64.asm", "vendor/simd/jquantf-sse2-64.asm",
        "vendor/simd/jquanti-sse2-64.asm",
    ];
    let x86 = [
        "vendor/simd/jsimdcpu.asm", "vendor/simd/jfdctflt-3dn.asm", "vendor/simd/jidctflt-3dn.asm",
        "vendor/simd/jquant-3dn.asm", "vendor/simd/jccolor-mmx.asm", "vendor/simd/jcgray-mmx.asm",
        "vendor/simd/jcsample-mmx.asm", "vendor/simd/jdcolor-mmx.asm", "vendor/simd/jdmerge-mmx.asm",
        "vendor/simd/jdsample-mmx.asm", "vendor/simd/jfdctfst-mmx.asm", "vendor/simd/jfdctint-mmx.asm",
        "vendor/simd/jidctfst-mmx.asm", "vendor/simd/jidctint-mmx.asm", "vendor/simd/jidctred-mmx.asm",
        "vendor/simd/jquant-mmx.asm", "vendor/simd/jfdctflt-sse.asm", "vendor/simd/jidctflt-sse.asm",
        "vendor/simd/jquant-sse.asm", "vendor/simd/jccolor-sse2.asm", "vendor/simd/jcgray-sse2.asm",
        "vendor/simd/jchuff-sse2.asm", "vendor/simd/jcsample-sse2.asm", "vendor/simd/jdcolor-sse2.asm",
        "vendor/simd/jdmerge-sse2.asm", "vendor/simd/jdsample-sse2.asm", "vendor/simd/jfdctfst-sse2.asm",
        "vendor/simd/jfdctint-sse2.asm", "vendor/simd/jidctflt-sse2.asm", "vendor/simd/jidctfst-sse2.asm",
        "vendor/simd/jidctint-sse2.asm", "vendor/simd/jidctred-sse2.asm", "vendor/simd/jquantf-sse2.asm",
        "vendor/simd/jquanti-sse2.asm",
    ];

    let files: &[_] = if cfg!(target_arch = "x86_64") {
        flags.push("-D__x86_64__");
        &x86_64
    } else if cfg!(target_arch = "x86") {
        &x86
    } else {
        panic!("The mozjpeg-sys SIMD build script is incomplete for this platform");
    };

    let name = if cfg!(target_env = "msvc") {
        "mozjpegsimd.lib"
    } else {
        "libmozjpegsimd.a"
    };

    nasm_rs::compile_library_args(name, files, &flags);
    println!("cargo:rustc-link-lib=static=mozjpegsimd");
}