summaryrefslogtreecommitdiff
path: root/libssh2-sys/build.rs
blob: 1ce43879cae8dc01b957df39db8e9cd1210fc609 (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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
extern crate pkg_config;

use std::env;
use std::fs::{self, File};
use std::io::prelude::*;
use std::path::PathBuf;
use std::process::Command;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(n) => n,
        Err(e) => panic!("\n{} failed with {}\n", stringify!($e), e),
    })
}

fn main() {
    match pkg_config::find_library("libssh2") {
        Ok(..) => return,
        Err(..) => {}
    }

    let mut cflags = env::var("CFLAGS").unwrap_or(String::new());
    let target = env::var("TARGET").unwrap();
    let windows = target.contains("windows");
    cflags.push_str(" -ffunction-sections -fdata-sections");

    if target.contains("i686") {
        cflags.push_str(" -m32");
    } else if target.contains("x86_64") {
        cflags.push_str(" -m64");
    }
    if !target.contains("i686") {
        cflags.push_str(" -fPIC");
    }

    match env::var("DEP_OPENSSL_ROOT") {
        Ok(s) => {
            cflags.push_str(&format!(" -I{}/include", s));
            cflags.push_str(&format!(" -L{}/lib", s));
        }
        Err(..) => {}
    }

    let dst = PathBuf::from(&env::var_os("OUT_DIR").unwrap());
    let root = t!(env::current_dir()).join("libssh2-1.5.0");

    let _ = fs::remove_dir_all(&dst.join("include"));
    let _ = fs::remove_dir_all(dst.join("lib"));
    let _ = fs::remove_dir_all(dst.join("build"));
    t!(fs::create_dir(dst.join("build")));

    if !windows {
        run(Command::new(root.join("configure"))
                    .env("CFLAGS", &cflags)
                    .current_dir(dst.join("build"))
                    .arg("--enable-shared=no")
                    .arg("--disable-examples-build")
                    .arg(format!("--prefix={}", dst.display())));
        run(Command::new(&make())
                    .arg(&format!("-j{}", env::var("NUM_JOBS").unwrap()))
                    .current_dir(dst.join("build/src")));
        run(Command::new(&make())
                    .arg("install")
                    .current_dir(dst.join("build")));

        // Unfortunately the pkg-config file generated for libssh2 indicates
        // that it depends on zlib, but most systems don't actually have a
        // zlib.pc, so pkg-config will say that libssh2 doesn't exist. We
        // generally take care of the zlib dependency elsewhere, so we just
        // remove that part from the pkg-config file
        let mut pc = String::new();
        let pkgconfig = dst.join("lib/pkgconfig/libssh2.pc");
        t!(t!(File::open(&pkgconfig)).read_to_string(&mut pc));
        let pc = pc.replace(",zlib", "");
        let bytes = pc.as_bytes();
        t!(t!(File::create(pkgconfig)).write_all(bytes));

    } else {
        t!(fs::create_dir(dst.join("lib")));

        if Command::new("make").arg("-v").output().is_ok() {
            run(Command::new("make")
                        .current_dir(root.join("win32"))
                        .arg("-fGNUmakefile")
                        .arg("WITH_WINCNG=1")
                        .arg("WITH_ZLIB=1")
                        .arg("lib"));
            t!(fs::remove_dir_all(root.join("win32/release")));
            t!(fs::copy(root.join("win32/libssh2.a"), dst.join("lib/libssh2.a")));
            t!(fs::remove_file(root.join("win32/libssh2.a")));
        } else {
            panic!("\n\ncurrently need `make` installed on windows\n");
        }

        let root = root.join("include");
        let dst = dst.join("include");
        t!(fs::create_dir_all(&dst));
        t!(fs::copy(root.join("libssh2.h"), dst.join("libssh2.h")));
        t!(fs::copy(root.join("libssh2_publickey.h"),
                    dst.join("libssh2_publickey.h")));
        t!(fs::copy(root.join("libssh2_sftp.h"), dst.join("libssh2_sftp.h")));
    }

    if windows {
        println!("cargo:rustc-link-lib=ws2_32");
        println!("cargo:rustc-link-lib=bcrypt");
        println!("cargo:rustc-link-lib=crypt32");
    }
    println!("cargo:rustc-link-search=native={}/lib", dst.display());
    println!("cargo:rustc-link-lib=static=ssh2");
    println!("cargo:root={}", dst.display());
    println!("cargo:include={}/include", dst.display());
}

fn make() -> &'static str {
    if cfg!(target_os = "freebsd") {"gmake"} else {"make"}
}

fn run(cmd: &mut Command) {
    println!("running: {:?}", cmd);
    let status = t!(cmd.status());
    if !status.success() {
        panic!("command did not succeed, exited with: {}", status);
    }
}