summaryrefslogtreecommitdiff
path: root/build.rs
blob: d348f7c0145b8f4b48feb96c0e85171b59623226 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use std::env;
use std::fs::File;
use std::io::{BufRead, BufReader, Error, ErrorKind, Result};
use std::ops::Bound;
use std::path::{Path, PathBuf};
use std::process::Command;

trait CommandExt {
    fn execute(&mut self) -> Result<()>;
}

impl CommandExt for Command {
    /// Execute the command and return an error if it exited with a failure status.
    fn execute(&mut self) -> Result<()> {
        self.status()
            .and_then(|status| {
                if status.success() {
                    Ok(())
                } else {
                    Err(Error::new(ErrorKind::Other, "non-zero exit code"))
                }
            })
            .map_err(|_| {
                Error::new(
                    ErrorKind::Other,
                    format!("The command {:?} did not run successfully.", self),
                )
            })
    }
}

fn use_custom_lua<S: AsRef<str>>(include_dir: &S, lib_dir: &S, lua_lib: &S) -> Result<String> {
    let mut version_found = String::new();

    // Find LUA_VERSION_NUM
    let mut lua_h_path = PathBuf::from(include_dir.as_ref());
    lua_h_path.push("lua.h");
    let f = File::open(lua_h_path)?;
    let reader = BufReader::new(f);
    for line in reader.lines() {
        let line = line?;
        let parts = line.split_whitespace().collect::<Vec<_>>();
        if parts.len() == 3 && parts[1] == "LUA_VERSION_NUM" {
            version_found = parts[2].to_string();
        }
    }

    println!("cargo:rustc-link-search=native={}", lib_dir.as_ref());
    println!("cargo:rustc-link-lib={}", lua_lib.as_ref());

    Ok(version_found)
}

fn build_glue<P: AsRef<Path> + std::fmt::Debug>(include_paths: &[P]) {
    let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());

    // Ensure the presence of glue.rs
    // if build_dir.join("glue.rs").exists() {
    //     return;
    // }

    let mut config = cc::Build::new();

    for path in include_paths {
        config.include(path);
    }

    // Compile and run glue.c
    let glue = build_dir.join("glue");

    config
        .get_compiler()
        .to_command()
        .arg("src/ffi/glue/glue.c")
        .arg("-o")
        .arg(&glue)
        .execute()
        .unwrap();

    Command::new(glue)
        .arg(build_dir.join("glue.rs"))
        .execute()
        .unwrap();
}

fn main() {
    let include_dir = env::var("LUA_INCLUDE_DIR").unwrap_or(String::new());
    let lib_dir = env::var("LUA_LIB_DIR").unwrap_or(String::new());
    let lua_lib = env::var("LUA_LIB_NAME").unwrap_or(String::new());

    println!("cargo:rerun-if-env-changed=LUA_INCLUDE_DIR");
    println!("cargo:rerun-if-env-changed=LUA_LIB_DIR");
    println!("cargo:rerun-if-env-changed=LUA_LIB_NAME");
    println!("cargo:rerun-if-changed=src/ffi/glue/glue.c");

    if include_dir != "" && lib_dir != "" && lua_lib != "" {
        let _version = use_custom_lua(&include_dir, &lib_dir, &lua_lib).unwrap();
        build_glue(&[include_dir]);
        return;
    }

    // Find lua via pkg-config

    let lua = pkg_config::Config::new()
        .range_version((Bound::Included("5.3"), Bound::Excluded("5.4")))
        .probe("lua")
        .unwrap();

    build_glue(&lua.include_paths);
}