libcruby-sys 0.7.5

Ruby bindings
Documentation
use std::{env,fs};
use std::path::Path;
use std::process::Command;

fn main() {
  // TODO: Clean this all up. There has to be a prettier way.
  let target = env::var("TARGET").expect("TARGET required");
  let manifest_dir_str = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR required");
  let version_str = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION required").replace(".", "-");

  let root = Path::new(manifest_dir_str.as_str());

  let lib_root_str = env::var("HELIX_LIB_DIR").unwrap_or(manifest_dir_str.clone());
  let lib_root = Path::new(lib_root_str.as_str());

  // Best way I could find to tell if we're packaging vs just building
  let is_packaging = root.parent().expect("root has no parent").ends_with("target/package");
  let libname32 = format!("helix-runtime-{}.i386", version_str);
  let libname64 = format!("helix-runtime-{}.x86_64", version_str);
  let libname = if target.starts_with("x86_64") { libname64.clone() } else { libname32.clone() };

  // Not required for non-Windows, but it needs to be part of the package
  if is_packaging && (!lib_root.join(format!("{}.lib", libname32)).exists() ||
                      !lib_root.join(format!("{}.lib", libname64)).exists()) {
    panic!("{}.lib and {}.lib must exist when packaging. Please run ./prepackage.sh and set HELIX_LIB_DIR.", libname32, libname64);
  }

  if target.contains("windows") && !lib_root.join(format!("{}.lib", libname)).exists() {
    panic!("{}.lib must exist when running. Set HELIX_LIB_DIR to ruby/windows_build for development.", libname);
  }

  if target.contains("windows") {
    let out_dir_str = env::var("OUT_DIR").expect("OUT_DIR required");

    let out_dir = Path::new(out_dir_str.as_str());

    // Read info about current Ruby install
    let raw_ruby_info = Command::new("ruby")
                                .arg(root.join("ruby_info.rb"))
                                .output()
                                .expect("failed to get Ruby info");
    let raw_ruby_output = String::from_utf8_lossy(&raw_ruby_info.stdout);
    let mut raw_ruby_lines = raw_ruby_output.lines();
    let ruby_libdir = Path::new(raw_ruby_lines.next().expect("Ruby info has no libdir"));
    let libruby = raw_ruby_lines.next().expect("Ruby info has no LIBRUBY");
    let libruby_so = raw_ruby_lines.next().expect("Ruby info has no LIBRUBY_SO");
    if raw_ruby_lines.next() != None {
      panic!("Unexpected information returned in Ruby info");
    }

    let ruby_libname = libruby_so.split('.').next().expect("can't extract Ruby lib name");

    // Copy .dll.a file to .lib since Rust msvc looks for .lib files only
    fs::copy(ruby_libdir.join(libruby), out_dir.join(ruby_libname).with_extension("lib"))
        .expect("unable to copy libruby");

    // Set up linker
    println!("cargo:rustc-flags=-L {libpath} -l dylib={libruby} -L {root} -l helix-runtime:{libname}",
              libpath=out_dir.to_str().expect("can't get str from out_dir"),
              libruby=ruby_libname,
              root=lib_root.to_str().expect("can't get str from root dir"),
              libname=libname);
  }
}