<commit_before>extern crate amq_protocol_codegen;
extern crate amq_protocol_types;
extern crate handlebars;
extern crate serde;
#[macro_use] extern crate serde_derive;
extern crate serde_json;

use amq_protocol_codegen::*;
use amq_protocol_types::*;
use handlebars::{Handlebars,Helper,HelperDef,RenderContext,RenderError};

use std::collections::BTreeMap;
use std::env;
use std::fs::File;
use std::io::{Read, Write};
use std::path::Path;
use std::ascii::AsciiExt;

fn main() {
    let out_dir      = env::var("OUT_DIR").expect("OUT_DIR is not defined");
    let dest_path    = Path::new(&out_dir).join("generated.rs");
    let dest_path2   = Path::new(&out_dir).join("api.rs");
    let mut f        = File::create(&dest_path).expect("Failed to create generated.rs");
    let mut f2       = File::create(&dest_path2).expect("Failed to create api.rs");
    let mut full_tpl = String::new();
    let mut api_tpl = String::new();
    std::fs::File::open("templates/main.rs").expect("Failed to open main template").read_to_string(&mut full_tpl).expect("Failed to read main template");
    std::fs::File::open("templates/api.rs").expect("Failed to open main template").read_to_string(&mut api_tpl).expect("Failed to read main template");

    let mut handlebars = Handlebars::new();
    let mut data = BTreeMap::new();

    handlebars.register_escape_fn(handlebars::no_escape);
    handlebars.register_helper("snake", Box::new(snake_helper));
    handlebars.register_helper("camel", Box::new(camel_helper));
    handlebars.register_helper("map_parser", Box::new(map_parser_helper));
    handlebars.register_helper("map_assign", Box::new(map_assignment_helper));
    handlebars.register_helper("map_generator", Box::new(map_generator_helper));

    handlebars.register_template_string("full", full_tpl).expect("Failed to register full template");
    handlebars.register_template_string("api", api_tpl).expect("Failed to register api template");

    let specs     = AMQProtocolDefinition::load();
    data.insert("specs".to_string(), specs);
    writeln!(f, "{}", handlebars.render("full", &data).expect("Failed to render full template"));
    writeln!(f2, "{}", handlebars.render("api", &data).expect("Failed to render full template"));

    //writeln!(f, "{}", specs.codegen_full(&full_tpl)).expect("Failed to generate generated.rs");
}

fn get_specs(rc: &mut RenderContext) ->  serde_json::Map<String, serde_json::Value> {
  let data:  serde_json::Map<String, serde_json::Value> = serde_json::from_value(rc.context().data().clone()).unwrap();
  let specs: serde_json::Map<String, serde_json::Value> = serde_json::from_value(data.get("specs").unwrap().clone()).unwrap();

  specs
}

fn get_arguments(h: &Helper, rc: &mut RenderContext, class_id_index: usize, method_id_index: usize) -> Vec<AMQPArgument> {
  let class_id:  u16 = serde_json::from_value(h.param(class_id_index).unwrap().value().clone()).unwrap();
  let method_id: u16 = serde_json::from_value(h.param(method_id_index).unwrap().value().clone()).unwrap();

  let specs = get_specs(rc);

  let classes: Vec<AMQPClass> = serde_json::from_value(specs.get("classes").unwrap().clone()).unwrap();

  let arguments:Vec<AMQPArgument> = classes.iter().find(|c| c.id == class_id).and_then(|class| {
    class.methods.iter().find(|m| m.id == method_id)
  }).map(|m| m.arguments.clone()).unwrap();

  arguments
}

fn map_parser_helper(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
  println!("val1: {:?}", h.param(0));
  let val = h.param(0).unwrap().value().clone();
  let arg:AMQPArgument = serde_json::from_value(val).unwrap();

  let rendered = match arg.amqp_type {
    AMQPType::Boolean        => {
      let arguments = get_arguments(h, rc, 1, 2);
      println!("arguments:\n{:?}", arguments);

      //if it's the first of a list of booleans, write a bits!( ... ), otherwise do nothing
      let position = arguments.iter().position(|a| a.name == arg.name).unwrap();
      let should_parse_bits = {
        position == 0 ||
        arguments[position-1].amqp_type != AMQPType::Boolean
      };

      if !should_parse_bits {
        "".to_string()
      } else {
        let mut bit_args: Vec<AMQPArgument> = arguments.iter().skip(position).take_while(|a| a.amqp_type == AMQPType::Boolean).cloned().collect();
        bit_args.reverse();
        //FIXME: assuming there are less than 8 elements
        let offset = 8 - bit_args.len();

        let mut handlebars = Handlebars::new();
        let mut data = BTreeMap::new();
        let mut bits_tpl = String::new();
        std::fs::File::open("templates/bits_parse.rs").expect("Failed to open bits template").read_to_string(&mut bits_tpl).expect("Failed to read bits template");

        handlebars.register_escape_fn(handlebars::no_escape);
        handlebars.register_helper("snake", Box::new(snake_helper));
        handlebars.register_template_string("bits", bits_tpl).expect("Failed to register bits template");

        let args: serde_json::Value =  serde_json::to_value(bit_args).unwrap();
        data.insert("arguments".to_string(), args);
        data.insert("offset".to_string(), serde_json::to_value(offset).unwrap());

        handlebars.render("bits", &data).unwrap()
      }
    },
    AMQPType::ShortShortInt  => format!("{} : {} >>", snake_case(&arg.name), "be_i8"),
    AMQPType::ShortShortUInt => format!("{} : {} >>", snake_case(&arg.name), "be_u8"),
    AMQPType::ShortInt       => format!("{} : {} >>", snake_case(&arg.name),"be_i16"),
    AMQPType::ShortUInt      => format!("{} : {} >>", snake_case(&arg.name),"be_u16"),
    AMQPType::LongInt        => format!("{} : {} >>", snake_case(&arg.name),"be_i32"),
    AMQPType::LongUInt       => format!("{} : {} >>", snake_case(&arg.name),"be_u32"),
    AMQPType::LongLongInt    => format!("{} : {} >>", snake_case(&arg.name),"be_i64"),
    AMQPType::LongLongUInt   => format!("{} : {} >>", snake_case(&arg.name),"be_u64"),
    AMQPType::ShortString    => format!("{} : {} >>", snake_case(&arg.name),"map!(short_string, |s:&str| s.to_string())"),
    AMQPType::LongString     => format!("{} : {} >>", snake_case(&arg.name),"map!(long_string,  |s:&str| s.to_string())"),
    AMQPType::FieldTable     => format!("{} : {} >>", snake_case(&arg.name),"field_table"),
    AMQPType::Timestamp      => format!("{} : {} >>", snake_case(&arg.name),"be_u64"),
    _                        => unimplemented!(),
  };
  try!(rc.writer.write(&rendered.as_bytes()));

  Ok(())
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct NameId {
  pub name: String,
  pub id:   usize,
}

fn map_assignment_helper(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
  let val = h.param(0).unwrap().value().clone();
  let arg:AMQPArgument = serde_json::from_value(val).unwrap();

  let rendered = match arg.amqp_type {
    AMQPType::Boolean        => {
      let arguments = get_arguments(h, rc, 1, 2);
      println!("arguments:\n{:?}", arguments);

      //if it's the first of a list of booleans, write a bits!( ... ), otherwise do nothing
      let position = arguments.iter().position(|a| a.name == arg.name).unwrap();
      let should_parse_bits = {
        position == 0 ||
        arguments[position-1].amqp_type != AMQPType::Boolean
      };

      if !should_parse_bits {
        "".to_string()
      } else {
        let mut bit_args: Vec<AMQPArgument> = arguments.iter().skip(position).take_while(|a| a.amqp_type == AMQPType::Boolean).cloned().collect();
        bit_args.reverse();
        let bit_args:Vec<NameId> = bit_args.iter().enumerate().map(|(i,val)| NameId { name: val.name.clone(), id: i }).collect();

        let mut handlebars = Handlebars::new();
        let mut data = BTreeMap::new();
        let mut bits_tpl = String::new();
        std::fs::File::open("templates/bits_assign.rs").expect("Failed to open bits template").read_to_string(&mut bits_tpl).expect("Failed to read bits template");

        handlebars.register_escape_fn(handlebars::no_escape);
        handlebars.register_helper("snake", Box::new(snake_helper));
        handlebars.register_template_string("bits", bits_tpl).expect("Failed to register bits template");

        let args: serde_json::Value =  serde_json::to_value(bit_args).unwrap();
        data.insert("arguments".to_string(), args);

        handlebars.render("bits", &data).unwrap()
      }
    },
    _ => format!("{}: {},", snake_case(&arg.name), snake_case(&arg.name)),
  };
  try!(rc.writer.write(&rendered.as_bytes()));

  Ok(())
}

fn map_generator_helper(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
  println!("val1: {:?}", h.param(0));
  let val = h.param(0).unwrap().value().clone();
  let arg:AMQPArgument = serde_json::from_value(val).unwrap();

  let rendered = match arg.amqp_type {
    AMQPType::Boolean        => {
      let arguments = get_arguments(h, rc, 1, 2);
      println!("arguments:\n{:?}", arguments);

      //if it's the first of a list of booleans, write a bits!( ... ), otherwise do nothing
      let position = arguments.iter().position(|a| a.name == arg.name).unwrap();
      let should_parse_bits = {
        position == 0 ||
        arguments[position-1].amqp_type != AMQPType::Boolean
      };

      if !should_parse_bits {
        "".to_string()
      } else {
        let mut bit_args: Vec<AMQPArgument> = arguments.iter().skip(position).take_while(|a| a.amqp_type == AMQPType::Boolean).cloned().collect();

        let mut handlebars = Handlebars::new();
        let mut data = BTreeMap::new();
        let mut bits_tpl = String::new();
        std::fs::File::open("templates/bits_gen.rs").expect("Failed to open bits template").read_to_string(&mut bits_tpl).expect("Failed to read bits template");

        handlebars.register_escape_fn(handlebars::no_escape);
        handlebars.register_helper("snake", Box::new(snake_helper));
        handlebars.register_template_string("bits", bits_tpl).expect("Failed to register bits template");

        let args: serde_json::Value =  serde_json::to_value(bit_args).unwrap();
        data.insert("arguments".to_string(), args);

        handlebars.render("bits", &data).unwrap()
      }
    },
    AMQPType::ShortShortInt  => format!(">> {}(&method.{})", "gen_be_i8", snake_case(&arg.name)),
    AMQPType::ShortShortUInt => format!(">> {}(&method.{})", "gen_be_u8", snake_case(&arg.name)),
    AMQPType::ShortInt       => format!(">> {}(&method.{})", "gen_be_i16", snake_case(&arg.name)),
    AMQPType::ShortUInt      => format!(">> {}(&method.{})", "gen_be_u16", snake_case(&arg.name)),
    AMQPType::LongInt        => format!(">> {}(&method.{})", "gen_be_i32", snake_case(&arg.name)),
    AMQPType::LongUInt       => format!(">> {}(&method.{})", "gen_be_u32", snake_case(&arg.name)),
    AMQPType::LongLongInt    => format!(">> {}(&method.{})", "gen_be_i64", snake_case(&arg.name)),
    AMQPType::LongLongUInt   => format!(">> {}(&method.{})", "gen_be_u64", snake_case(&arg.name)),
    AMQPType::ShortString    => format!(">> {}(&method.{})", "gen_short_string", snake_case(&arg.name)),
    AMQPType::LongString     => format!(">> {}(&method.{})", "gen_long_string", snake_case(&arg.name)),
    AMQPType::FieldTable     => format!(">> {}(&method.{})", "gen_field_table", snake_case(&arg.name)),
    AMQPType::Timestamp      => format!(">> {}(&method.{})", "gen_be_u64", snake_case(&arg.name)),
    _                        => unimplemented!(),
  };
  try!(rc.writer.write(rendered.as_bytes()));

  Ok(())
}
<commit_msg>build: silence warnings<commit_after>extern crate amq_protocol_codegen;
extern crate amq_protocol_types;
extern crate handlebars;
extern crate serde;
#[macro_use] extern crate serde_derive;
extern crate serde_json;

use amq_protocol_codegen::*;
use amq_protocol_types::*;
use handlebars::{Handlebars,Helper,RenderContext,RenderError};

use std::collections::BTreeMap;
use std::env;
use std::fs::File;
use std::io::{Read, Write};
use std::path::Path;

fn main() {
    let out_dir      = env::var("OUT_DIR").expect("OUT_DIR is not defined");
    let dest_path    = Path::new(&out_dir).join("generated.rs");
    let dest_path2   = Path::new(&out_dir).join("api.rs");
    let mut f        = File::create(&dest_path).expect("Failed to create generated.rs");
    let mut f2       = File::create(&dest_path2).expect("Failed to create api.rs");
    let mut full_tpl = String::new();
    let mut api_tpl = String::new();
    std::fs::File::open("templates/main.rs").expect("Failed to open main template").read_to_string(&mut full_tpl).expect("Failed to read main template");
    std::fs::File::open("templates/api.rs").expect("Failed to open main template").read_to_string(&mut api_tpl).expect("Failed to read main template");

    let mut handlebars = Handlebars::new();
    let mut data = BTreeMap::new();

    handlebars.register_escape_fn(handlebars::no_escape);
    handlebars.register_helper("snake", Box::new(snake_helper));
    handlebars.register_helper("camel", Box::new(camel_helper));
    handlebars.register_helper("map_parser", Box::new(map_parser_helper));
    handlebars.register_helper("map_assign", Box::new(map_assignment_helper));
    handlebars.register_helper("map_generator", Box::new(map_generator_helper));

    handlebars.register_template_string("full", full_tpl).expect("Failed to register full template");
    handlebars.register_template_string("api", api_tpl).expect("Failed to register api template");

    let specs     = AMQProtocolDefinition::load();
    data.insert("specs".to_string(), specs);
    writeln!(f, "{}", handlebars.render("full", &data).expect("Failed to render full template")).expect("Failed to write generated.rs");
    writeln!(f2, "{}", handlebars.render("api", &data).expect("Failed to render api template")).expect("Failed to write api.rs");
}

fn get_specs(rc: &mut RenderContext) ->  serde_json::Map<String, serde_json::Value> {
  let data:  serde_json::Map<String, serde_json::Value> = serde_json::from_value(rc.context().data().clone()).unwrap();
  let specs: serde_json::Map<String, serde_json::Value> = serde_json::from_value(data.get("specs").unwrap().clone()).unwrap();

  specs
}

fn get_arguments(h: &Helper, rc: &mut RenderContext, class_id_index: usize, method_id_index: usize) -> Vec<AMQPArgument> {
  let class_id:  u16 = serde_json::from_value(h.param(class_id_index).unwrap().value().clone()).unwrap();
  let method_id: u16 = serde_json::from_value(h.param(method_id_index).unwrap().value().clone()).unwrap();

  let specs = get_specs(rc);

  let classes: Vec<AMQPClass> = serde_json::from_value(specs.get("classes").unwrap().clone()).unwrap();

  let arguments:Vec<AMQPArgument> = classes.iter().find(|c| c.id == class_id).and_then(|class| {
    class.methods.iter().find(|m| m.id == method_id)
  }).map(|m| m.arguments.clone()).unwrap();

  arguments
}

fn map_parser_helper(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
  println!("val1: {:?}", h.param(0));
  let val = h.param(0).unwrap().value().clone();
  let arg:AMQPArgument = serde_json::from_value(val).unwrap();

  let rendered = match arg.amqp_type {
    AMQPType::Boolean        => {
      let arguments = get_arguments(h, rc, 1, 2);
      println!("arguments:\n{:?}", arguments);

      //if it's the first of a list of booleans, write a bits!( ... ), otherwise do nothing
      let position = arguments.iter().position(|a| a.name == arg.name).unwrap();
      let should_parse_bits = {
        position == 0 ||
        arguments[position-1].amqp_type != AMQPType::Boolean
      };

      if !should_parse_bits {
        "".to_string()
      } else {
        let mut bit_args: Vec<AMQPArgument> = arguments.iter().skip(position).take_while(|a| a.amqp_type == AMQPType::Boolean).cloned().collect();
        bit_args.reverse();
        //FIXME: assuming there are less than 8 elements
        let offset = 8 - bit_args.len();

        let mut handlebars = Handlebars::new();
        let mut data = BTreeMap::new();
        let mut bits_tpl = String::new();
        std::fs::File::open("templates/bits_parse.rs").expect("Failed to open bits template").read_to_string(&mut bits_tpl).expect("Failed to read bits template");

        handlebars.register_escape_fn(handlebars::no_escape);
        handlebars.register_helper("snake", Box::new(snake_helper));
        handlebars.register_template_string("bits", bits_tpl).expect("Failed to register bits template");

        let args: serde_json::Value =  serde_json::to_value(bit_args).unwrap();
        data.insert("arguments".to_string(), args);
        data.insert("offset".to_string(), serde_json::to_value(offset).unwrap());

        handlebars.render("bits", &data).unwrap()
      }
    },
    AMQPType::ShortShortInt  => format!("{} : {} >>", snake_case(&arg.name), "be_i8"),
    AMQPType::ShortShortUInt => format!("{} : {} >>", snake_case(&arg.name), "be_u8"),
    AMQPType::ShortInt       => format!("{} : {} >>", snake_case(&arg.name),"be_i16"),
    AMQPType::ShortUInt      => format!("{} : {} >>", snake_case(&arg.name),"be_u16"),
    AMQPType::LongInt        => format!("{} : {} >>", snake_case(&arg.name),"be_i32"),
    AMQPType::LongUInt       => format!("{} : {} >>", snake_case(&arg.name),"be_u32"),
    AMQPType::LongLongInt    => format!("{} : {} >>", snake_case(&arg.name),"be_i64"),
    AMQPType::LongLongUInt   => format!("{} : {} >>", snake_case(&arg.name),"be_u64"),
    AMQPType::ShortString    => format!("{} : {} >>", snake_case(&arg.name),"map!(short_string, |s:&str| s.to_string())"),
    AMQPType::LongString     => format!("{} : {} >>", snake_case(&arg.name),"map!(long_string,  |s:&str| s.to_string())"),
    AMQPType::FieldTable     => format!("{} : {} >>", snake_case(&arg.name),"field_table"),
    AMQPType::Timestamp      => format!("{} : {} >>", snake_case(&arg.name),"be_u64"),
    _                        => unimplemented!(),
  };
  try!(rc.writer.write(&rendered.as_bytes()));

  Ok(())
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct NameId {
  pub name: String,
  pub id:   usize,
}

fn map_assignment_helper(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
  let val = h.param(0).unwrap().value().clone();
  let arg:AMQPArgument = serde_json::from_value(val).unwrap();

  let rendered = match arg.amqp_type {
    AMQPType::Boolean        => {
      let arguments = get_arguments(h, rc, 1, 2);
      println!("arguments:\n{:?}", arguments);

      //if it's the first of a list of booleans, write a bits!( ... ), otherwise do nothing
      let position = arguments.iter().position(|a| a.name == arg.name).unwrap();
      let should_parse_bits = {
        position == 0 ||
        arguments[position-1].amqp_type != AMQPType::Boolean
      };

      if !should_parse_bits {
        "".to_string()
      } else {
        let mut bit_args: Vec<AMQPArgument> = arguments.iter().skip(position).take_while(|a| a.amqp_type == AMQPType::Boolean).cloned().collect();
        bit_args.reverse();
        let bit_args:Vec<NameId> = bit_args.iter().enumerate().map(|(i,val)| NameId { name: val.name.clone(), id: i }).collect();

        let mut handlebars = Handlebars::new();
        let mut data = BTreeMap::new();
        let mut bits_tpl = String::new();
        std::fs::File::open("templates/bits_assign.rs").expect("Failed to open bits template").read_to_string(&mut bits_tpl).expect("Failed to read bits template");

        handlebars.register_escape_fn(handlebars::no_escape);
        handlebars.register_helper("snake", Box::new(snake_helper));
        handlebars.register_template_string("bits", bits_tpl).expect("Failed to register bits template");

        let args: serde_json::Value =  serde_json::to_value(bit_args).unwrap();
        data.insert("arguments".to_string(), args);

        handlebars.render("bits", &data).unwrap()
      }
    },
    _ => format!("{}: {},", snake_case(&arg.name), snake_case(&arg.name)),
  };
  try!(rc.writer.write(&rendered.as_bytes()));

  Ok(())
}

fn map_generator_helper(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
  println!("val1: {:?}", h.param(0));
  let val = h.param(0).unwrap().value().clone();
  let arg:AMQPArgument = serde_json::from_value(val).unwrap();

  let rendered = match arg.amqp_type {
    AMQPType::Boolean        => {
      let arguments = get_arguments(h, rc, 1, 2);
      println!("arguments:\n{:?}", arguments);

      //if it's the first of a list of booleans, write a bits!( ... ), otherwise do nothing
      let position = arguments.iter().position(|a| a.name == arg.name).unwrap();
      let should_parse_bits = {
        position == 0 ||
        arguments[position-1].amqp_type != AMQPType::Boolean
      };

      if !should_parse_bits {
        "".to_string()
      } else {
        let bit_args: Vec<AMQPArgument> = arguments.iter().skip(position).take_while(|a| a.amqp_type == AMQPType::Boolean).cloned().collect();

        let mut handlebars = Handlebars::new();
        let mut data = BTreeMap::new();
        let mut bits_tpl = String::new();
        std::fs::File::open("templates/bits_gen.rs").expect("Failed to open bits template").read_to_string(&mut bits_tpl).expect("Failed to read bits template");

        handlebars.register_escape_fn(handlebars::no_escape);
        handlebars.register_helper("snake", Box::new(snake_helper));
        handlebars.register_template_string("bits", bits_tpl).expect("Failed to register bits template");

        let args: serde_json::Value =  serde_json::to_value(bit_args).unwrap();
        data.insert("arguments".to_string(), args);

        handlebars.render("bits", &data).unwrap()
      }
    },
    AMQPType::ShortShortInt  => format!(">> {}(&method.{})", "gen_be_i8", snake_case(&arg.name)),
    AMQPType::ShortShortUInt => format!(">> {}(&method.{})", "gen_be_u8", snake_case(&arg.name)),
    AMQPType::ShortInt       => format!(">> {}(&method.{})", "gen_be_i16", snake_case(&arg.name)),
    AMQPType::ShortUInt      => format!(">> {}(&method.{})", "gen_be_u16", snake_case(&arg.name)),
    AMQPType::LongInt        => format!(">> {}(&method.{})", "gen_be_i32", snake_case(&arg.name)),
    AMQPType::LongUInt       => format!(">> {}(&method.{})", "gen_be_u32", snake_case(&arg.name)),
    AMQPType::LongLongInt    => format!(">> {}(&method.{})", "gen_be_i64", snake_case(&arg.name)),
    AMQPType::LongLongUInt   => format!(">> {}(&method.{})", "gen_be_u64", snake_case(&arg.name)),
    AMQPType::ShortString    => format!(">> {}(&method.{})", "gen_short_string", snake_case(&arg.name)),
    AMQPType::LongString     => format!(">> {}(&method.{})", "gen_long_string", snake_case(&arg.name)),
    AMQPType::FieldTable     => format!(">> {}(&method.{})", "gen_field_table", snake_case(&arg.name)),
    AMQPType::Timestamp      => format!(">> {}(&method.{})", "gen_be_u64", snake_case(&arg.name)),
    _                        => unimplemented!(),
  };
  try!(rc.writer.write(rendered.as_bytes()));

  Ok(())
}
<|endoftext|>


<commit_before>extern crate gcc;
#[macro_use] extern crate lazy_static;
extern crate regex;
extern crate semver;

use regex::Regex;
use semver::Version;
use std::env;
use std::ffi::OsStr;
use std::io::{self, ErrorKind};
use std::path::PathBuf;
use std::process::Command;

lazy_static!{
    /// LLVM version used by this version of the crate.
    static ref CRATE_VERSION: Version = {
        let crate_version = Version::parse(env!("CARGO_PKG_VERSION"))
            .expect("Crate version is somehow not valid semver");
        Version {
            major: crate_version.major / 10,
            minor: crate_version.major % 10,
            .. crate_version
        }
    };

    /// Filesystem path to an llvm-config binary for the correct version.
    static ref LLVM_CONFIG_PATH: PathBuf = {
        // Try llvm-config via PATH first.
        if let Some(name) = locate_system_llvm_config() {
            return name.into();
        } else {
            println!("Didn't find usable system-wide LLVM.");
        }

        // Did the user give us a binary path to use? If yes, try
        // to use that and fail if it doesn't work.
        let binary_prefix_var = format!("LLVM_SYS_{}_PREFIX",
                                        env!("CARGO_PKG_VERSION_MAJOR"));
        if let Some(path) = env::var_os(&binary_prefix_var) {
            let mut pb: PathBuf = path.into();
            pb.push("bin");
            pb.push("llvm-config");

            let ver = llvm_version(&pb)
                .expect(&format!("Failed to execute {:?}", &pb));
            if is_compatible_llvm(&ver) {
                return pb;
            } else {
                panic!("LLVM binaries specified by {} are the wrong version.
                        (Found {}, need {}.)", binary_prefix_var, ver, *CRATE_VERSION);
            }
        } else {
            println!("{} not set, not using precompiled binaries", binary_prefix_var);
        }

        // No binaries. Offer to download and compile a blessed version,
        // but only with positive confirmation. It's a fairly large download,
        // takes a while and could get wiped out by a `cargo clean` so it's
        // useful if doing an install but is in general not recommended.
        let autobuild_var = format!("LLVM_SYS_{}_AUTOBUILD",
                                    env!("CARGO_PKG_VERSION_MAJOR"));
        match env::var_os(&autobuild_var) {
            Some(ref x) => {
                if x == "YES" {
                    unimplemented!();
                } else {
                    println!("{} must be exactly \"YES\" to enable autobuild (is {:?})",
                             autobuild_var, x);
                }
            }
            None => {
                println!("{} not set, will not automatically compile LLVM",
                         autobuild_var);
            }
        }

        panic!("Could not find a compatible version of LLVM");
    };
}

/// Try to find a system-wide version of llvm-config that is compatible with
/// this crate.
///
/// Returns None on failure.
fn locate_system_llvm_config() -> Option<&'static str> {
    match llvm_version("llvm-config") {
        Ok(ref version) if is_compatible_llvm(version) => {
            // Compatible version found. Nice.
            return Some("llvm-config");
        },
        Ok(version) => {
            // Version mismatch. Will try further searches, but warn that
            // we're not using the system one.
            println!("Found LLVM version {} on PATH, but need {}.",
                     version, *CRATE_VERSION);
        },
        Err(ref e) if e.kind() == ErrorKind::NotFound => {
            // Looks like we failed to execute any llvm-config. Keep
            // searching.
        },
        // Some other error, probably a weird failure. Give up.
        Err(e) => panic!("Failed to search PATH for llvm-config: {}", e),
    }

    None
}

/// Check whether the given version of LLVM is blacklisted,
/// returning `Some(reason)` if it is.
fn is_blacklisted_llvm(llvm_version: &Version) -> Option<&'static str> {
    static BLACKLIST: &'static [(u64, u64, u64, &'static str)] = &[];

    let blacklist_var = format!("LLVM_SYS_{}_IGNORE_BLACKLIST",
                                env!("CARGO_PKG_VERSION_MAJOR"));
    if let Some(x) = env::var_os(&blacklist_var) {
        if &x == "YES" {
            println!("cargo:warning=Ignoring blacklist entry for LLVM {}", llvm_version);
            return None;
        } else {
            println!("cargo:warning={} is set but not exactly \"YES\"; blacklist is still honored.",
                     &blacklist_var);
        }
    }

    for &(major, minor, patch, reason) in BLACKLIST.iter() {
        let bad_version = Version {
            major: major, minor: minor, patch: patch,
            pre: vec![], build: vec![],
        };

        if &bad_version == llvm_version {
            return Some(reason);
        }
    }
    None
}

/// Check whether the given LLVM version is compatible with this version of
/// the crate.
fn is_compatible_llvm(llvm_version: &Version) -> bool {
    if let Some(reason) = is_blacklisted_llvm(llvm_version) {
        println!("Found LLVM {}, which is blacklisted: {}", llvm_version, reason);
        return false;
    }

    let strict = env::var_os(format!("LLVM_SYS_{}_STRICT_VERSIONING",
                                     env!("CARGO_PKG_VERSION_MAJOR"))).is_some()
        || cfg!(feature="strict-versioning");
    if strict {
        llvm_version.major == CRATE_VERSION.major &&
            llvm_version.minor == CRATE_VERSION.minor
    } else {
        llvm_version.major >= CRATE_VERSION.major ||
            (llvm_version.major == CRATE_VERSION.major &&
             llvm_version.minor >= CRATE_VERSION.minor)
    }
}

/// Get the output from running `llvm-config` with the given argument.
///
/// Lazily searches for or compiles LLVM as configured by the environment
/// variables.
fn llvm_config(arg: &str) -> String {
    llvm_config_ex(&*LLVM_CONFIG_PATH, arg)
        .expect("Surprising failure from llvm-config")
}

/// Invoke the specified binary as llvm-config.
///
/// Explicit version of the `llvm_config` function that bubbles errors
/// up.
fn llvm_config_ex<S: AsRef<OsStr>>(binary: S, arg: &str)
        -> io::Result<String> {
    Command::new(binary)
        .arg(arg)
        .arg("--link-static")   // Don't use dylib for >= 3.9
        .output()
        .map(|output| String::from_utf8(output.stdout)
            .expect("Output from llvm-config was not valid UTF-8"))
}

/// Get the LLVM version using llvm-config.
fn llvm_version<S: AsRef<OsStr>>(binary: S) -> io::Result<Version> {
    let version_str = try!(llvm_config_ex(binary.as_ref(), "--version"));

    // LLVM isn't really semver and uses version suffixes to build
    // version strings like '3.8.0svn', so limit what we try to parse
    // to only the numeric bits.
    let re = Regex::new(r"^(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)")
        .unwrap();
    let m = re.find(&version_str)
        .expect("Could not determine LLVM version from llvm-config.");

    Ok(Version::parse(&version_str[m.start()..m.end()]).unwrap())
}

/// Get the names of the dylibs required by LLVM, including the C++ standard
/// library.
fn get_system_libraries() -> Vec<String> {
    llvm_config("--system-libs")
        .split(&[' ', '\n'] as &[char])
        .filter(|s| !s.is_empty())
        .map(|flag| {
            if cfg!(target_env = "msvc") {
                // Same as --libnames, foo.lib
                assert!(flag.ends_with(".lib"));
                &flag[..flag.len() - 4]
            } else {
                // Linker flags style, -lfoo
                assert!(flag.starts_with("-l"));
                &flag[2..]
            }
        })
        .chain(get_system_libcpp())
        .map(str::to_owned)
        .collect::<Vec<String>>()
}

/// Get the library that must be linked for C++, if any.
fn get_system_libcpp() -> Option<&'static str> {
    if cfg!(target_env = "msvc") {
        // MSVC doesn't need an explicit one.
        None
    } else if cfg!(target_os = "macos") {
        // On OS X 10.9 and later, LLVM's libc++ is the default. On earlier
        // releases GCC's libstdc++ is default. Unfortunately we can't
        // reasonably detect which one we need (on older ones libc++ is
        // available and can be selected with -stdlib=lib++), so assume the
        // latest, at the cost of breaking the build on older OS releases
        // when LLVM was built against libstdc++.
        Some("c++")
    } else {
        // Otherwise assume GCC's libstdc++.
        // This assumption is probably wrong on some platforms, but would need
        // testing on them.
        Some("stdc++")
    }
}

/// Get the names of libraries to link against.
fn get_link_libraries() -> Vec<String> {
    // Using --libnames in conjunction with --libdir is particularly important
    // for MSVC when LLVM is in a path with spaces, but it is generally less of
    // a hack than parsing linker flags output from --libs and --ldflags.
    llvm_config("--libnames")
        .split(&[' ', '\n'] as &[char])
        .filter(|s| !s.is_empty())
        .map(|name| {
            // --libnames gives library filenames. Extract only the name that
            // we need to pass to the linker.
            if cfg!(target_env = "msvc") {
                // LLVMfoo.lib
                assert!(name.ends_with(".lib"));
                &name[..name.len() - 4]
            } else {
                // libLLVMfoo.a
                assert!(name.starts_with("lib") && name.ends_with(".a"));
                &name[3..name.len() - 2]
            }
        })
        .map(str::to_owned)
        .collect::<Vec<String>>()
}

fn get_llvm_cflags() -> String {
    let output = llvm_config("--cflags");

    // llvm-config includes cflags from its own compilation with --cflags that
    // may not be relevant to us. In particularly annoying cases, these might
    // include flags that aren't understood by the default compiler we're
    // using. Unless requested otherwise, clean CFLAGS of options that are
    // known to be possibly-harmful.
    let no_clean = env::var_os(format!("LLVM_SYS_{}_NO_CLEAN_CFLAGS",
                                       env!("CARGO_PKG_VERSION_MAJOR"))).is_some();
    if no_clean || cfg!(target_env = "msvc") {
        // MSVC doesn't accept -W... options, so don't try to strip them and
        // possibly strip something that should be retained. Also do nothing if
        // the user requests it.
        return output;
    }

    llvm_config("--cflags").split(&[' ', '\n'][..])
        .filter(|word| !word.starts_with("-W"))
        .collect::<Vec<_>>()
        .join(" ")
}

fn main() {
    let libdir = llvm_config("--libdir");

    // Export information to other crates
    println!("cargo:config_path={}", LLVM_CONFIG_PATH.display()); // will be DEP_LLVM_CONFIG_PATH
    println!("cargo:libdir={}", libdir); // DEP_LLVM_LIBDIR

    // Link LLVM libraries
    println!("cargo:rustc-link-search=native={}", libdir);
    for name in get_link_libraries() {
        println!("cargo:rustc-link-lib=static={}", name);
    }

    // Link system libraries
    for name in get_system_libraries() {
        println!("cargo:rustc-link-lib=dylib={}", name);
    }

    // Link libffi if the user requested this workaround.
    // See https://bitbucket.org/tari/llvm-sys.rs/issues/12/
    let force_ffi = env::var_os(format!("LLVM_SYS_{}_FFI_WORKAROUND",
                                        env!("CARGO_PKG_VERSION_MAJOR")))
        .is_some();
    if force_ffi {
        println!("cargo:rustc-link-lib=dylib={}", "ffi");
    }

    // Build the extra wrapper functions.
    std::env::set_var("CFLAGS", get_llvm_cflags());
    gcc::compile_library("libtargetwrappers.a", &["wrappers/target.c"]);
}
<commit_msg>build: stop using deprecated gcc::compile_library<commit_after>extern crate gcc;
#[macro_use] extern crate lazy_static;
extern crate regex;
extern crate semver;

use regex::Regex;
use semver::Version;
use std::env;
use std::ffi::OsStr;
use std::io::{self, ErrorKind};
use std::path::PathBuf;
use std::process::Command;

lazy_static!{
    /// LLVM version used by this version of the crate.
    static ref CRATE_VERSION: Version = {
        let crate_version = Version::parse(env!("CARGO_PKG_VERSION"))
            .expect("Crate version is somehow not valid semver");
        Version {
            major: crate_version.major / 10,
            minor: crate_version.major % 10,
            .. crate_version
        }
    };

    /// Filesystem path to an llvm-config binary for the correct version.
    static ref LLVM_CONFIG_PATH: PathBuf = {
        // Try llvm-config via PATH first.
        if let Some(name) = locate_system_llvm_config() {
            return name.into();
        } else {
            println!("Didn't find usable system-wide LLVM.");
        }

        // Did the user give us a binary path to use? If yes, try
        // to use that and fail if it doesn't work.
        let binary_prefix_var = format!("LLVM_SYS_{}_PREFIX",
                                        env!("CARGO_PKG_VERSION_MAJOR"));
        if let Some(path) = env::var_os(&binary_prefix_var) {
            let mut pb: PathBuf = path.into();
            pb.push("bin");
            pb.push("llvm-config");

            let ver = llvm_version(&pb)
                .expect(&format!("Failed to execute {:?}", &pb));
            if is_compatible_llvm(&ver) {
                return pb;
            } else {
                panic!("LLVM binaries specified by {} are the wrong version.
                        (Found {}, need {}.)", binary_prefix_var, ver, *CRATE_VERSION);
            }
        } else {
            println!("{} not set, not using precompiled binaries", binary_prefix_var);
        }

        // No binaries. Offer to download and compile a blessed version,
        // but only with positive confirmation. It's a fairly large download,
        // takes a while and could get wiped out by a `cargo clean` so it's
        // useful if doing an install but is in general not recommended.
        let autobuild_var = format!("LLVM_SYS_{}_AUTOBUILD",
                                    env!("CARGO_PKG_VERSION_MAJOR"));
        match env::var_os(&autobuild_var) {
            Some(ref x) => {
                if x == "YES" {
                    unimplemented!();
                } else {
                    println!("{} must be exactly \"YES\" to enable autobuild (is {:?})",
                             autobuild_var, x);
                }
            }
            None => {
                println!("{} not set, will not automatically compile LLVM",
                         autobuild_var);
            }
        }

        panic!("Could not find a compatible version of LLVM");
    };
}

/// Try to find a system-wide version of llvm-config that is compatible with
/// this crate.
///
/// Returns None on failure.
fn locate_system_llvm_config() -> Option<&'static str> {
    match llvm_version("llvm-config") {
        Ok(ref version) if is_compatible_llvm(version) => {
            // Compatible version found. Nice.
            return Some("llvm-config");
        },
        Ok(version) => {
            // Version mismatch. Will try further searches, but warn that
            // we're not using the system one.
            println!("Found LLVM version {} on PATH, but need {}.",
                     version, *CRATE_VERSION);
        },
        Err(ref e) if e.kind() == ErrorKind::NotFound => {
            // Looks like we failed to execute any llvm-config. Keep
            // searching.
        },
        // Some other error, probably a weird failure. Give up.
        Err(e) => panic!("Failed to search PATH for llvm-config: {}", e),
    }

    None
}

/// Check whether the given version of LLVM is blacklisted,
/// returning `Some(reason)` if it is.
fn is_blacklisted_llvm(llvm_version: &Version) -> Option<&'static str> {
    static BLACKLIST: &'static [(u64, u64, u64, &'static str)] = &[];

    let blacklist_var = format!("LLVM_SYS_{}_IGNORE_BLACKLIST",
                                env!("CARGO_PKG_VERSION_MAJOR"));
    if let Some(x) = env::var_os(&blacklist_var) {
        if &x == "YES" {
            println!("cargo:warning=Ignoring blacklist entry for LLVM {}", llvm_version);
            return None;
        } else {
            println!("cargo:warning={} is set but not exactly \"YES\"; blacklist is still honored.",
                     &blacklist_var);
        }
    }

    for &(major, minor, patch, reason) in BLACKLIST.iter() {
        let bad_version = Version {
            major: major, minor: minor, patch: patch,
            pre: vec![], build: vec![],
        };

        if &bad_version == llvm_version {
            return Some(reason);
        }
    }
    None
}

/// Check whether the given LLVM version is compatible with this version of
/// the crate.
fn is_compatible_llvm(llvm_version: &Version) -> bool {
    if let Some(reason) = is_blacklisted_llvm(llvm_version) {
        println!("Found LLVM {}, which is blacklisted: {}", llvm_version, reason);
        return false;
    }

    let strict = env::var_os(format!("LLVM_SYS_{}_STRICT_VERSIONING",
                                     env!("CARGO_PKG_VERSION_MAJOR"))).is_some()
        || cfg!(feature="strict-versioning");
    if strict {
        llvm_version.major == CRATE_VERSION.major &&
            llvm_version.minor == CRATE_VERSION.minor
    } else {
        llvm_version.major >= CRATE_VERSION.major ||
            (llvm_version.major == CRATE_VERSION.major &&
             llvm_version.minor >= CRATE_VERSION.minor)
    }
}

/// Get the output from running `llvm-config` with the given argument.
///
/// Lazily searches for or compiles LLVM as configured by the environment
/// variables.
fn llvm_config(arg: &str) -> String {
    llvm_config_ex(&*LLVM_CONFIG_PATH, arg)
        .expect("Surprising failure from llvm-config")
}

/// Invoke the specified binary as llvm-config.
///
/// Explicit version of the `llvm_config` function that bubbles errors
/// up.
fn llvm_config_ex<S: AsRef<OsStr>>(binary: S, arg: &str)
        -> io::Result<String> {
    Command::new(binary)
        .arg(arg)
        .arg("--link-static")   // Don't use dylib for >= 3.9
        .output()
        .map(|output| String::from_utf8(output.stdout)
            .expect("Output from llvm-config was not valid UTF-8"))
}

/// Get the LLVM version using llvm-config.
fn llvm_version<S: AsRef<OsStr>>(binary: S) -> io::Result<Version> {
    let version_str = try!(llvm_config_ex(binary.as_ref(), "--version"));

    // LLVM isn't really semver and uses version suffixes to build
    // version strings like '3.8.0svn', so limit what we try to parse
    // to only the numeric bits.
    let re = Regex::new(r"^(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)")
        .unwrap();
    let m = re.find(&version_str)
        .expect("Could not determine LLVM version from llvm-config.");

    Ok(Version::parse(&version_str[m.start()..m.end()]).unwrap())
}

/// Get the names of the dylibs required by LLVM, including the C++ standard
/// library.
fn get_system_libraries() -> Vec<String> {
    llvm_config("--system-libs")
        .split(&[' ', '\n'] as &[char])
        .filter(|s| !s.is_empty())
        .map(|flag| {
            if cfg!(target_env = "msvc") {
                // Same as --libnames, foo.lib
                assert!(flag.ends_with(".lib"));
                &flag[..flag.len() - 4]
            } else {
                // Linker flags style, -lfoo
                assert!(flag.starts_with("-l"));
                &flag[2..]
            }
        })
        .chain(get_system_libcpp())
        .map(str::to_owned)
        .collect::<Vec<String>>()
}

/// Get the library that must be linked for C++, if any.
fn get_system_libcpp() -> Option<&'static str> {
    if cfg!(target_env = "msvc") {
        // MSVC doesn't need an explicit one.
        None
    } else if cfg!(target_os = "macos") {
        // On OS X 10.9 and later, LLVM's libc++ is the default. On earlier
        // releases GCC's libstdc++ is default. Unfortunately we can't
        // reasonably detect which one we need (on older ones libc++ is
        // available and can be selected with -stdlib=lib++), so assume the
        // latest, at the cost of breaking the build on older OS releases
        // when LLVM was built against libstdc++.
        Some("c++")
    } else {
        // Otherwise assume GCC's libstdc++.
        // This assumption is probably wrong on some platforms, but would need
        // testing on them.
        Some("stdc++")
    }
}

/// Get the names of libraries to link against.
fn get_link_libraries() -> Vec<String> {
    // Using --libnames in conjunction with --libdir is particularly important
    // for MSVC when LLVM is in a path with spaces, but it is generally less of
    // a hack than parsing linker flags output from --libs and --ldflags.
    llvm_config("--libnames")
        .split(&[' ', '\n'] as &[char])
        .filter(|s| !s.is_empty())
        .map(|name| {
            // --libnames gives library filenames. Extract only the name that
            // we need to pass to the linker.
            if cfg!(target_env = "msvc") {
                // LLVMfoo.lib
                assert!(name.ends_with(".lib"));
                &name[..name.len() - 4]
            } else {
                // libLLVMfoo.a
                assert!(name.starts_with("lib") && name.ends_with(".a"));
                &name[3..name.len() - 2]
            }
        })
        .map(str::to_owned)
        .collect::<Vec<String>>()
}

fn get_llvm_cflags() -> String {
    let output = llvm_config("--cflags");

    // llvm-config includes cflags from its own compilation with --cflags that
    // may not be relevant to us. In particularly annoying cases, these might
    // include flags that aren't understood by the default compiler we're
    // using. Unless requested otherwise, clean CFLAGS of options that are
    // known to be possibly-harmful.
    let no_clean = env::var_os(format!("LLVM_SYS_{}_NO_CLEAN_CFLAGS",
                                       env!("CARGO_PKG_VERSION_MAJOR"))).is_some();
    if no_clean || cfg!(target_env = "msvc") {
        // MSVC doesn't accept -W... options, so don't try to strip them and
        // possibly strip something that should be retained. Also do nothing if
        // the user requests it.
        return output;
    }

    llvm_config("--cflags").split(&[' ', '\n'][..])
        .filter(|word| !word.starts_with("-W"))
        .collect::<Vec<_>>()
        .join(" ")
}

fn main() {
    let libdir = llvm_config("--libdir");

    // Export information to other crates
    println!("cargo:config_path={}", LLVM_CONFIG_PATH.display()); // will be DEP_LLVM_CONFIG_PATH
    println!("cargo:libdir={}", libdir); // DEP_LLVM_LIBDIR

    // Link LLVM libraries
    println!("cargo:rustc-link-search=native={}", libdir);
    for name in get_link_libraries() {
        println!("cargo:rustc-link-lib=static={}", name);
    }

    // Link system libraries
    for name in get_system_libraries() {
        println!("cargo:rustc-link-lib=dylib={}", name);
    }

    // Link libffi if the user requested this workaround.
    // See https://bitbucket.org/tari/llvm-sys.rs/issues/12/
    let force_ffi = env::var_os(format!("LLVM_SYS_{}_FFI_WORKAROUND",
                                        env!("CARGO_PKG_VERSION_MAJOR")))
        .is_some();
    if force_ffi {
        println!("cargo:rustc-link-lib=dylib={}", "ffi");
    }

    // Build the extra wrapper functions.
    std::env::set_var("CFLAGS", get_llvm_cflags());
    gcc::Build::new()
        .file("wrappers/target.c")
        .compile("targetwrappers");
}
<|endoftext|>


<commit_before>extern crate gcc;
#[macro_use] extern crate lazy_static;
extern crate regex;
extern crate semver;

use regex::Regex;
use semver::Version;
use std::env;
use std::ffi::OsStr;
use std::io::{self, ErrorKind};
use std::path::PathBuf;
use std::process::Command;

lazy_static!{
    /// LLVM version used by this version of the crate.
    static ref CRATE_VERSION: Version = {
        let crate_version = Version::parse(env!("CARGO_PKG_VERSION"))
            .expect("Crate version is somehow not valid semver");
        Version {
            major: crate_version.major / 10,
            minor: crate_version.major % 10,
            .. crate_version
        }
    };

    /// Filesystem path to an llvm-config binary for the correct version.
    static ref LLVM_CONFIG_PATH: PathBuf = {
        // Try llvm-config via PATH first.
        if let Some(name) = locate_system_llvm_config() {
            return name.into();
        } else {
            println!("Didn't find usable system-wide LLVM.");
        }

        // Did the user give us a binary path to use? If yes, try
        // to use that and fail if it doesn't work.
        let binary_prefix_var = format!("LLVM_SYS_{}_PREFIX",
                                        env!("CARGO_PKG_VERSION_MAJOR"));
        if let Some(path) = env::var_os(&binary_prefix_var) {
            let mut pb: PathBuf = path.into();
            pb.push("bin");
            pb.push("llvm-config");

            let ver = llvm_version(&pb)
                .expect(&format!("Failed to execute {:?}", &pb));
            if is_compatible_llvm(&ver) {
                return pb;
            } else {
                panic!("LLVM binaries specified by {} are the wrong version.
                        (Found {}, need {}.)", binary_prefix_var, ver, *CRATE_VERSION);
            }
        } else {
            println!("{} not set, not using precompiled binaries", binary_prefix_var);
        }

        // No binaries. Offer to download and compile a blessed version,
        // but only with positive confirmation. It's a fairly large download,
        // takes a while and could get wiped out by a `cargo clean` so it's
        // useful if doing an install but is in general not recommended.
        let autobuild_var = format!("LLVM_SYS_{}_AUTOBUILD",
                                    env!("CARGO_PKG_VERSION_MAJOR"));
        match env::var_os(&autobuild_var) {
            Some(ref x) => {
                if x == "YES" {
                    unimplemented!();
                } else {
                    println!("{} must be exactly \"YES\" to enable autobuild (is {:?})",
                             autobuild_var, x);
                }
            }
            None => {
                println!("{} not set, will not automatically compile LLVM",
                         autobuild_var);
            }
        }

        panic!("Could not find a compatible version of LLVM");
    };
}

/// Try to find a system-wide version of llvm-config that is compatible with
/// this crate.
///
/// Returns None on failure.
fn locate_system_llvm_config() -> Option<&'static str> {
    match llvm_version("llvm-config") {
        Ok(ref version) if is_compatible_llvm(version) => {
            // Compatible version found. Nice.
            return Some("llvm-config");
        },
        Ok(version) => {
            // Version mismatch. Will try further searches, but warn that
            // we're not using the system one.
            println!("Found LLVM version {} on PATH, but need {}.",
                     version, *CRATE_VERSION);
        },
        Err(ref e) if e.kind() == ErrorKind::NotFound => {
            // Looks like we failed to execute any llvm-config. Keep
            // searching.
        },
        // Some other error, probably a weird failure. Give up.
        Err(e) => panic!("Failed to search PATH for llvm-config: {}", e),
    }

    None
}

/// Check whether the given version of LLVM is blacklisted,
/// returning `Some(reason)` if it is.
fn is_blacklisted_llvm(llvm_version: &Version) -> Option<&'static str> {
    static BLACKLIST: &'static [(u64, u64, u64, &'static str)] = &[];

    let blacklist_var = format!("LLVM_SYS_{}_IGNORE_BLACKLIST",
                                env!("CARGO_PKG_VERSION_MAJOR"));
    if let Some(x) = env::var_os(&blacklist_var) {
        if &x == "YES" {
            println!("cargo:warning=Ignoring blacklist entry for LLVM {}", llvm_version);
            return None;
        } else {
            println!("cargo:warning={} is set but not exactly \"YES\"; blacklist is still honored.",
                     &blacklist_var);
        }
    }

    for &(major, minor, patch, reason) in BLACKLIST.iter() {
        let bad_version = Version {
            major: major, minor: minor, patch: patch,
            pre: vec![], build: vec![],
        };

        if &bad_version == llvm_version {
            return Some(reason);
        }
    }
    None
}

/// Check whether the given LLVM version is compatible with this version of
/// the crate.
fn is_compatible_llvm(llvm_version: &Version) -> bool {
    if let Some(reason) = is_blacklisted_llvm(llvm_version) {
        println!("Found LLVM {}, which is blacklisted: {}", llvm_version, reason);
        return false;
    }

    let strict = env::var_os(format!("LLVM_SYS_{}_STRICT_VERSIONING",
                                     env!("CARGO_PKG_VERSION_MAJOR"))).is_some()
        || cfg!(feature="strict-versioning");
    if strict {
        llvm_version.major == CRATE_VERSION.major &&
            llvm_version.minor == CRATE_VERSION.minor
    } else {
        llvm_version.major >= CRATE_VERSION.major ||
            (llvm_version.major == CRATE_VERSION.major &&
             llvm_version.minor >= CRATE_VERSION.minor)
    }
}

/// Get the output from running `llvm-config` with the given argument.
///
/// Lazily searches for or compiles LLVM as configured by the environment
/// variables.
fn llvm_config(arg: &str) -> String {
    llvm_config_ex(&*LLVM_CONFIG_PATH, arg)
        .expect("Surprising failure from llvm-config")
}

/// Invoke the specified binary as llvm-config.
///
/// Explicit version of the `llvm_config` function that bubbles errors
/// up.
fn llvm_config_ex<S: AsRef<OsStr>>(binary: S, arg: &str)
        -> io::Result<String> {
    Command::new(binary)
        .arg(arg)
        .arg("--link-static")   // Don't use dylib for >= 3.9
        .output()
        .map(|output| String::from_utf8(output.stdout)
            .expect("Output from llvm-config was not valid UTF-8"))
}

/// Get the LLVM version using llvm-config.
fn llvm_version<S: AsRef<OsStr>>(binary: S) -> io::Result<Version> {
    let version_str = try!(llvm_config_ex(binary.as_ref(), "--version"));

    // LLVM isn't really semver and uses version suffixes to build
    // version strings like '3.8.0svn', so limit what we try to parse
    // to only the numeric bits.
    let re = Regex::new(r"^(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)")
        .unwrap();
    let m = re.find(&version_str)
        .expect("Could not determine LLVM version from llvm-config.");

    Ok(Version::parse(&version_str[m.start()..m.end()]).unwrap())
}

/// Get the names of the dylibs required by LLVM, including the C++ standard
/// library.
fn get_system_libraries() -> Vec<String> {
    llvm_config("--system-libs")
        .split(&[' ', '\n'] as &[char])
        .filter(|s| !s.is_empty())
        .map(|flag| {
            if cfg!(target_env = "msvc") {
                // Same as --libnames, foo.lib
                assert!(flag.ends_with(".lib"));
                &flag[..flag.len() - 4]
            } else {
                // Linker flags style, -lfoo
                assert!(flag.starts_with("-l"));
                &flag[2..]
            }
        })
        .chain(get_system_libcpp())
        .map(str::to_owned)
        .collect::<Vec<String>>()
}

/// Get the library that must be linked for C++, if any.
fn get_system_libcpp() -> Option<&'static str> {
    if cfg!(target_env = "msvc") {
        // MSVC doesn't need an explicit one.
        None
    } else if cfg!(target_os = "macos") {
        // On OS X 10.9 and later, LLVM's libc++ is the default. On earlier
        // releases GCC's libstdc++ is default. Unfortunately we can't
        // reasonably detect which one we need (on older ones libc++ is
        // available and can be selected with -stdlib=lib++), so assume the
        // latest, at the cost of breaking the build on older OS releases
        // when LLVM was built against libstdc++.
        Some("c++")
    } else {
        // Otherwise assume GCC's libstdc++.
        // This assumption is probably wrong on some platforms, but would need
        // testing on them.
        Some("stdc++")
    }
}

/// Get the names of libraries to link against.
fn get_link_libraries() -> Vec<String> {
    // Using --libnames in conjunction with --libdir is particularly important
    // for MSVC when LLVM is in a path with spaces, but it is generally less of
    // a hack than parsing linker flags output from --libs and --ldflags.
    llvm_config("--libnames")
        .split(&[' ', '\n'] as &[char])
        .filter(|s| !s.is_empty())
        .map(|name| {
            // --libnames gives library filenames. Extract only the name that
            // we need to pass to the linker.
            if cfg!(target_env = "msvc") {
                // LLVMfoo.lib
                assert!(name.ends_with(".lib"));
                &name[..name.len() - 4]
            } else {
                // libLLVMfoo.a
                assert!(name.starts_with("lib") && name.ends_with(".a"));
                &name[3..name.len() - 2]
            }
        })
        .map(str::to_owned)
        .collect::<Vec<String>>()
}

fn get_llvm_cflags() -> String {
    let output = llvm_config("--cflags");

    // llvm-config includes cflags from its own compilation with --cflags that
    // may not be relevant to us. In particularly annoying cases, these might
    // include flags that aren't understood by the default compiler we're
    // using. Unless requested otherwise, clean CFLAGS of options that are
    // known to be possibly-harmful.
    let no_clean = env::var_os(format!("LLVM_SYS_{}_NO_CLEAN_CFLAGS",
                                       env!("CARGO_PKG_VERSION_MAJOR"))).is_some();
    if no_clean || cfg!(target_env = "msvc") {
        // MSVC doesn't accept -W... options, so don't try to strip them and
        // possibly strip something that should be retained. Also do nothing if
        // the user requests it.
        return output;
    }

    llvm_config("--cflags").split(&[' ', '\n'][..])
        .filter(|word| !word.starts_with("-W"))
        .collect::<Vec<_>>()
        .join(" ")
}

fn main() {
    let libdir = llvm_config("--libdir");

    // Export information to other crates
    println!("cargo:config_path={}", LLVM_CONFIG_PATH.display()); // will be DEP_LLVM_CONFIG_PATH
    println!("cargo:libdir={}", libdir); // DEP_LLVM_LIBDIR

    // Link LLVM libraries
    println!("cargo:rustc-link-search=native={}", libdir);
    for name in get_link_libraries() {
        println!("cargo:rustc-link-lib=static={}", name);
    }

    // Link system libraries
    for name in get_system_libraries() {
        println!("cargo:rustc-link-lib=dylib={}", name);
    }

    // Link libffi if the user requested this workaround.
    // See https://bitbucket.org/tari/llvm-sys.rs/issues/12/
    let force_ffi = env::var_os(format!("LLVM_SYS_{}_FFI_WORKAROUND",
                                        env!("CARGO_PKG_VERSION_MAJOR")))
        .is_some();
    if force_ffi {
        println!("cargo:rustc-link-lib=dylib={}", "ffi");
    }

    // Build the extra wrapper functions.
    std::env::set_var("CFLAGS", get_llvm_cflags());
    gcc::Build::new()
        .file("wrappers/target.c")
        .compile("targetwrappers");
}
<commit_msg>make patch version optional, defaulted to 0<commit_after>extern crate gcc;
#[macro_use] extern crate lazy_static;
extern crate regex;
extern crate semver;

use regex::Regex;
use semver::Version;
use std::env;
use std::ffi::OsStr;
use std::io::{self, ErrorKind};
use std::path::PathBuf;
use std::process::Command;

lazy_static!{
    /// LLVM version used by this version of the crate.
    static ref CRATE_VERSION: Version = {
        let crate_version = Version::parse(env!("CARGO_PKG_VERSION"))
            .expect("Crate version is somehow not valid semver");
        Version {
            major: crate_version.major / 10,
            minor: crate_version.major % 10,
            .. crate_version
        }
    };

    /// Filesystem path to an llvm-config binary for the correct version.
    static ref LLVM_CONFIG_PATH: PathBuf = {
        // Try llvm-config via PATH first.
        if let Some(name) = locate_system_llvm_config() {
            return name.into();
        } else {
            println!("Didn't find usable system-wide LLVM.");
        }

        // Did the user give us a binary path to use? If yes, try
        // to use that and fail if it doesn't work.
        let binary_prefix_var = format!("LLVM_SYS_{}_PREFIX",
                                        env!("CARGO_PKG_VERSION_MAJOR"));
        if let Some(path) = env::var_os(&binary_prefix_var) {
            let mut pb: PathBuf = path.into();
            pb.push("bin");
            pb.push("llvm-config");

            let ver = llvm_version(&pb)
                .expect(&format!("Failed to execute {:?}", &pb));
            if is_compatible_llvm(&ver) {
                return pb;
            } else {
                panic!("LLVM binaries specified by {} are the wrong version.
                        (Found {}, need {}.)", binary_prefix_var, ver, *CRATE_VERSION);
            }
        } else {
            println!("{} not set, not using precompiled binaries", binary_prefix_var);
        }

        // No binaries. Offer to download and compile a blessed version,
        // but only with positive confirmation. It's a fairly large download,
        // takes a while and could get wiped out by a `cargo clean` so it's
        // useful if doing an install but is in general not recommended.
        let autobuild_var = format!("LLVM_SYS_{}_AUTOBUILD",
                                    env!("CARGO_PKG_VERSION_MAJOR"));
        match env::var_os(&autobuild_var) {
            Some(ref x) => {
                if x == "YES" {
                    unimplemented!();
                } else {
                    println!("{} must be exactly \"YES\" to enable autobuild (is {:?})",
                             autobuild_var, x);
                }
            }
            None => {
                println!("{} not set, will not automatically compile LLVM",
                         autobuild_var);
            }
        }

        panic!("Could not find a compatible version of LLVM");
    };
}

/// Try to find a system-wide version of llvm-config that is compatible with
/// this crate.
///
/// Returns None on failure.
fn locate_system_llvm_config() -> Option<&'static str> {
    match llvm_version("llvm-config") {
        Ok(ref version) if is_compatible_llvm(version) => {
            // Compatible version found. Nice.
            return Some("llvm-config");
        },
        Ok(version) => {
            // Version mismatch. Will try further searches, but warn that
            // we're not using the system one.
            println!("Found LLVM version {} on PATH, but need {}.",
                     version, *CRATE_VERSION);
        },
        Err(ref e) if e.kind() == ErrorKind::NotFound => {
            // Looks like we failed to execute any llvm-config. Keep
            // searching.
        },
        // Some other error, probably a weird failure. Give up.
        Err(e) => panic!("Failed to search PATH for llvm-config: {}", e),
    }

    None
}

/// Check whether the given version of LLVM is blacklisted,
/// returning `Some(reason)` if it is.
fn is_blacklisted_llvm(llvm_version: &Version) -> Option<&'static str> {
    static BLACKLIST: &'static [(u64, u64, u64, &'static str)] = &[];

    let blacklist_var = format!("LLVM_SYS_{}_IGNORE_BLACKLIST",
                                env!("CARGO_PKG_VERSION_MAJOR"));
    if let Some(x) = env::var_os(&blacklist_var) {
        if &x == "YES" {
            println!("cargo:warning=Ignoring blacklist entry for LLVM {}", llvm_version);
            return None;
        } else {
            println!("cargo:warning={} is set but not exactly \"YES\"; blacklist is still honored.",
                     &blacklist_var);
        }
    }

    for &(major, minor, patch, reason) in BLACKLIST.iter() {
        let bad_version = Version {
            major: major, minor: minor, patch: patch,
            pre: vec![], build: vec![],
        };

        if &bad_version == llvm_version {
            return Some(reason);
        }
    }
    None
}

/// Check whether the given LLVM version is compatible with this version of
/// the crate.
fn is_compatible_llvm(llvm_version: &Version) -> bool {
    if let Some(reason) = is_blacklisted_llvm(llvm_version) {
        println!("Found LLVM {}, which is blacklisted: {}", llvm_version, reason);
        return false;
    }

    let strict = env::var_os(format!("LLVM_SYS_{}_STRICT_VERSIONING",
                                     env!("CARGO_PKG_VERSION_MAJOR"))).is_some()
        || cfg!(feature="strict-versioning");
    if strict {
        llvm_version.major == CRATE_VERSION.major &&
            llvm_version.minor == CRATE_VERSION.minor
    } else {
        llvm_version.major >= CRATE_VERSION.major ||
            (llvm_version.major == CRATE_VERSION.major &&
             llvm_version.minor >= CRATE_VERSION.minor)
    }
}

/// Get the output from running `llvm-config` with the given argument.
///
/// Lazily searches for or compiles LLVM as configured by the environment
/// variables.
fn llvm_config(arg: &str) -> String {
    llvm_config_ex(&*LLVM_CONFIG_PATH, arg)
        .expect("Surprising failure from llvm-config")
}

/// Invoke the specified binary as llvm-config.
///
/// Explicit version of the `llvm_config` function that bubbles errors
/// up.
fn llvm_config_ex<S: AsRef<OsStr>>(binary: S, arg: &str)
        -> io::Result<String> {
    Command::new(binary)
        .arg(arg)
        .arg("--link-static")   // Don't use dylib for >= 3.9
        .output()
        .map(|output| String::from_utf8(output.stdout)
            .expect("Output from llvm-config was not valid UTF-8"))
}

/// Get the LLVM version using llvm-config.
fn llvm_version<S: AsRef<OsStr>>(binary: S) -> io::Result<Version> {
    let version_str = try!(llvm_config_ex(binary.as_ref(), "--version"));

    // LLVM isn't really semver and uses version suffixes to build
    // version strings like '3.8.0svn', so limit what we try to parse
    // to only the numeric bits.
    let re = Regex::new(r"^(?P<major>\d+)\.(?P<minor>\d+)(?:\.(?P<patch>\d+))??")
        .unwrap();
    let c = re.captures(&version_str).expect(
        "Could not determine LLVM version from llvm-config.",
    );

    // some systems don't have a patch number but Version wants it so we just append .0 if it isn't
    // there
    let s = match c.name("patch") {
        None => format!("{}.0", &c[0]),
        Some(_) => c[0].to_string()
    };
    Ok(Version::parse(&s).unwrap())
}

/// Get the names of the dylibs required by LLVM, including the C++ standard
/// library.
fn get_system_libraries() -> Vec<String> {
    llvm_config("--system-libs")
        .split(&[' ', '\n'] as &[char])
        .filter(|s| !s.is_empty())
        .map(|flag| {
            if cfg!(target_env = "msvc") {
                // Same as --libnames, foo.lib
                assert!(flag.ends_with(".lib"));
                &flag[..flag.len() - 4]
            } else {
                // Linker flags style, -lfoo
                assert!(flag.starts_with("-l"));
                &flag[2..]
            }
        })
        .chain(get_system_libcpp())
        .map(str::to_owned)
        .collect::<Vec<String>>()
}

/// Get the library that must be linked for C++, if any.
fn get_system_libcpp() -> Option<&'static str> {
    if cfg!(target_env = "msvc") {
        // MSVC doesn't need an explicit one.
        None
    } else if cfg!(target_os = "macos") {
        // On OS X 10.9 and later, LLVM's libc++ is the default. On earlier
        // releases GCC's libstdc++ is default. Unfortunately we can't
        // reasonably detect which one we need (on older ones libc++ is
        // available and can be selected with -stdlib=lib++), so assume the
        // latest, at the cost of breaking the build on older OS releases
        // when LLVM was built against libstdc++.
        Some("c++")
    } else {
        // Otherwise assume GCC's libstdc++.
        // This assumption is probably wrong on some platforms, but would need
        // testing on them.
        Some("stdc++")
    }
}

/// Get the names of libraries to link against.
fn get_link_libraries() -> Vec<String> {
    // Using --libnames in conjunction with --libdir is particularly important
    // for MSVC when LLVM is in a path with spaces, but it is generally less of
    // a hack than parsing linker flags output from --libs and --ldflags.
    llvm_config("--libnames")
        .split(&[' ', '\n'] as &[char])
        .filter(|s| !s.is_empty())
        .map(|name| {
            // --libnames gives library filenames. Extract only the name that
            // we need to pass to the linker.
            if cfg!(target_env = "msvc") {
                // LLVMfoo.lib
                assert!(name.ends_with(".lib"));
                &name[..name.len() - 4]
            } else {
                // libLLVMfoo.a
                assert!(name.starts_with("lib") && name.ends_with(".a"));
                &name[3..name.len() - 2]
            }
        })
        .map(str::to_owned)
        .collect::<Vec<String>>()
}

fn get_llvm_cflags() -> String {
    let output = llvm_config("--cflags");

    // llvm-config includes cflags from its own compilation with --cflags that
    // may not be relevant to us. In particularly annoying cases, these might
    // include flags that aren't understood by the default compiler we're
    // using. Unless requested otherwise, clean CFLAGS of options that are
    // known to be possibly-harmful.
    let no_clean = env::var_os(format!("LLVM_SYS_{}_NO_CLEAN_CFLAGS",
                                       env!("CARGO_PKG_VERSION_MAJOR"))).is_some();
    if no_clean || cfg!(target_env = "msvc") {
        // MSVC doesn't accept -W... options, so don't try to strip them and
        // possibly strip something that should be retained. Also do nothing if
        // the user requests it.
        return output;
    }

    llvm_config("--cflags").split(&[' ', '\n'][..])
        .filter(|word| !word.starts_with("-W"))
        .collect::<Vec<_>>()
        .join(" ")
}

fn main() {
    let libdir = llvm_config("--libdir");

    // Export information to other crates
    println!("cargo:config_path={}", LLVM_CONFIG_PATH.display()); // will be DEP_LLVM_CONFIG_PATH
    println!("cargo:libdir={}", libdir); // DEP_LLVM_LIBDIR

    // Link LLVM libraries
    println!("cargo:rustc-link-search=native={}", libdir);
    for name in get_link_libraries() {
        println!("cargo:rustc-link-lib=static={}", name);
    }

    // Link system libraries
    for name in get_system_libraries() {
        println!("cargo:rustc-link-lib=dylib={}", name);
    }

    // Link libffi if the user requested this workaround.
    // See https://bitbucket.org/tari/llvm-sys.rs/issues/12/
    let force_ffi = env::var_os(format!("LLVM_SYS_{}_FFI_WORKAROUND",
                                        env!("CARGO_PKG_VERSION_MAJOR")))
        .is_some();
    if force_ffi {
        println!("cargo:rustc-link-lib=dylib={}", "ffi");
    }

    // Build the extra wrapper functions.
    std::env::set_var("CFLAGS", get_llvm_cflags());
    gcc::Build::new()
        .file("wrappers/target.c")
        .compile("targetwrappers");
}
<|endoftext|>


<commit_before>#[cfg(feature = "testing-helpers")]
extern crate rustc_version;

#[cfg(feature = "generate-parsing-rs")]
extern crate peg;

#[cfg(not(feature = "generate-parsing-rs"))]
fn generate_peg() {}
#[cfg(feature = "generate-parsing-rs")]
fn generate_peg() {
    let contents = match ::std::fs::read_to_string("src/parsing.rustpeg") {
        Ok(contents) => contents,
        Err(e) => panic!("{}", e),
    };

    let compiled = match ::peg::compile(&contents) {
        Ok(compiled) => compiled,
        Err(e) => panic!("{}", e),
    };

    if let Err(e) = ::std::fs::write("src/parsing.rs", compiled) {
        panic!("{}", e);
    }
}

#[cfg(not(feature = "testing-helpers"))]
fn detect_nightly() {}

#[cfg(feature = "testing-helpers")]
fn detect_nightly() {
    use rustc_version::{version_meta, Channel};
    if version_meta().unwrap().channel == Channel::Nightly {
        println!("cargo:rustc-cfg=feature=\"nightly\"");
    }
}

fn main() {
    detect_nightly();
    generate_peg();
}
<commit_msg>Fix rustfmt<commit_after>#[cfg(feature = "testing-helpers")]
extern crate rustc_version;

#[cfg(feature = "generate-parsing-rs")]
extern crate peg;

#[cfg(not(feature = "generate-parsing-rs"))]
fn generate_peg() {}
#[cfg(feature = "generate-parsing-rs")]
fn generate_peg() {
    let contents = match ::std::fs::read_to_string("src/parsing.rustpeg") {
        Ok(contents) => contents,
        Err(e) => panic!("{}", e),
    };

    let compiled = match ::peg::compile(&contents) {
        Ok(compiled) => compiled,
        Err(e) => panic!("{}", e),
    };

    if let Err(e) = ::std::fs::write("src/parsing.rs", compiled) {
        panic!("{}", e);
    }
}

#[cfg(not(feature = "testing-helpers"))]
fn detect_nightly() {}

#[cfg(feature = "testing-helpers")]
fn detect_nightly() {
    use rustc_version::{version_meta, Channel};
    if version_meta().unwrap().channel == Channel::Nightly {
        println!("cargo:rustc-cfg=feature=\"nightly\"");
    }
}

fn main() {
    detect_nightly();
    generate_peg();
}
<|endoftext|>


<commit_before>fn main() {
    if let Ok(custom) = ::std::env::var("CUSTOM_LIBFUZZER_PATH") {
        let custom_lib_path = ::std::path::PathBuf::from(&custom);
        let custom_lib_dir = custom_lib_path.parent().unwrap().to_string_lossy();

        let custom_lib_name = custom_lib_path.file_stem().unwrap().to_string_lossy();
        let custom_lib_name = custom_lib_name.trim_start_matches("lib");

        println!("cargo:rustc-link-search=native={}", custom_lib_dir);
        println!("cargo:rustc-link-lib=static={}", custom_lib_name);
        /* FIXME: this is assuming a C++ fuzzer, but should be customizable */
        println!("cargo:rustc-link-lib=stdc++");
    } else {
        let mut build = cc::Build::new();
        let sources = ::std::fs::read_dir("libfuzzer")
            .expect("listable source directory")
            .map(|de| de.expect("file in directory").path())
            .filter(|p| p.extension().map(|ext| ext == "cpp") == Some(true))
            .collect::<Vec<_>>();
        for source in sources.iter() {
            println!("cargo:rerun-if-changed={}", source.display());
            build.file(source.to_str().unwrap());
        }
        build.flag("-std=c++11");
        build.flag("-fno-omit-frame-pointer");
        build.flag("-w");
        build.cpp(true);
        build.compile("libfuzzer.a");
    }
}
<commit_msg>Add env var to select c++ std lib<commit_after>fn main() {
    if let Ok(custom) = ::std::env::var("CUSTOM_LIBFUZZER_PATH") {
        let custom_lib_path = ::std::path::PathBuf::from(&custom);
        let custom_lib_dir = custom_lib_path.parent().unwrap().to_string_lossy();

        let custom_lib_name = custom_lib_path.file_stem().unwrap().to_string_lossy();
        let custom_lib_name = custom_lib_name.trim_start_matches("lib");

        println!("cargo:rustc-link-search=native={}", custom_lib_dir);
        println!("cargo:rustc-link-lib=static={}", custom_lib_name);

        // Allow user to specify use of LLVM or GCC C++ stdlib, or none.
        // "cargo:rustc-link-lib=stdc++" is used by default for
        // backward-compatibility.
        // Note: google/oss-fuzz uses LLVM C++ stdlib as of 15 Jan 2020
        if let Ok(std_cxx_flag) = ::std::env::var("CUSTOM_LIBFUZZER_STD_CXX") {
            match std_cxx_flag.as_str() {
                "c++" => println!("cargo:rustc-link-lib=c++"),
                "stdc++" => println!("cargo:rustc-link-lib=stdc++"),
                "none" => (),
                _ => println!("cargo:rustc-link-lib=stdc++"),
            }
        }
    } else {
        let mut build = cc::Build::new();
        let sources = ::std::fs::read_dir("libfuzzer")
            .expect("listable source directory")
            .map(|de| de.expect("file in directory").path())
            .filter(|p| p.extension().map(|ext| ext == "cpp") == Some(true))
            .collect::<Vec<_>>();
        for source in sources.iter() {
            println!("cargo:rerun-if-changed={}", source.display());
            build.file(source.to_str().unwrap());
        }
        build.flag("-std=c++11");
        build.flag("-fno-omit-frame-pointer");
        build.flag("-w");
        build.cpp(true);
        build.compile("libfuzzer.a");
    }
}
<|endoftext|>


<commit_before>extern crate bindgen;
extern crate gcc;

use std::env;
use std::path::PathBuf;

fn main() {
	gcc::compile_library("libyoga.a", &["src/c/YGEnums.c", "src/c/YGNodeList.c", "src/c/Yoga.c"]);

	let bindings = bindgen::Builder::default()
		.no_unstable_rust()
		.hide_type("max_align_t") // This fails `cargo test` so disable for now
		.header("src/c/wrapper.h")
		.generate()
		.expect("Unable to generate bindings");

	let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());

	bindings.write_to_file(out_path.join("bindings.rs"))
		.expect("Unable to write bindings!");
}
<commit_msg>Code for an older version of C<commit_after>extern crate bindgen;
extern crate gcc;

use std::env;
use std::path::PathBuf;
use gcc::Config;

fn main() {
	let mut c = Config::new();

	c.flag("-std=c99");
	c.file("src/c/YGEnums.c");
	c.file("src/c/YGNodeList.c");
	c.file("src/c/Yoga.c");
	c.compile("libyoga.a");

	let bindings = bindgen::Builder::default()
		.no_unstable_rust()
		.hide_type("max_align_t") // This fails `cargo test` so disable for now
		.header("src/c/wrapper.h")
		.generate()
		.expect("Unable to generate bindings");

	let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());

	bindings.write_to_file(out_path.join("bindings.rs"))
		.expect("Unable to write bindings!");
}
<|endoftext|>


<commit_before>extern crate bindgen;

fn sdk_path(target: &str) -> Result<String, std::io::Error> {
    // Use environment variable if set
    println!("cargo:rerun-if-env-changed=COREAUDIO_SDK_PATH");
    if let Ok(path) = std::env::var("COREAUDIO_SDK_PATH") {
        return Ok(path);
    }

    use std::process::Command;

    let sdk = if target.contains("apple-darwin") {
        "macosx"
    } else if target == "x86_64-apple-ios" || target == "i386-apple-ios" {
        "iphonesimulator"
    } else if target == "aarch64-apple-ios"
        || target == "armv7-apple-ios"
        || target == "armv7s-apple-ios"
    {
        "iphoneos"
    } else {
        unreachable!();
    };
    let output = Command::new("xcrun")
        .args(&["--sdk", sdk, "--show-sdk-path"])
        .output()?
        .stdout;
    let prefix_str = std::str::from_utf8(&output).expect("invalid output from `xcrun`");
    Ok(prefix_str.trim_end().to_string())
}

fn build(sdk_path: Option<&str>, target: &str) {
    // Generate one large set of bindings for all frameworks.
    //
    // We do this rather than generating a module per framework as some frameworks depend on other
    // frameworks and in turn share types. To ensure all types are compatible across each
    // framework, we feed all headers to bindgen at once.
    //
    // Only link to each framework and include their headers if their features are enabled and they
    // are available on the target os.

    use std::env;
    use std::path::PathBuf;

    let mut headers: Vec<&'static str> = vec![];

    #[cfg(feature = "audio_toolbox")]
    {
        println!("cargo:rustc-link-lib=framework=AudioToolbox");
        headers.push("AudioToolbox/AudioToolbox.h");
    }

    #[cfg(feature = "audio_unit")]
    {
        println!("cargo:rustc-link-lib=framework=AudioToolbox");
        headers.push("AudioUnit/AudioUnit.h");
    }

    #[cfg(feature = "core_audio")]
    {
        println!("cargo:rustc-link-lib=framework=CoreAudio");

        if target.contains("apple-ios") {
            headers.push("CoreAudio/CoreAudioTypes.h");
        } else {
            headers.push("CoreAudio/CoreAudio.h");
        }
    }

    #[cfg(feature = "open_al")]
    {
        println!("cargo:rustc-link-lib=framework=OpenAL");
        headers.push("OpenAL/al.h");
        headers.push("OpenAL/alc.h");
    }

    #[cfg(all(feature = "core_midi"))]
    {
        if target.contains("apple-darwin") {
            println!("cargo:rustc-link-lib=framework=CoreMIDI");
            headers.push("CoreMIDI/CoreMIDI.h");
        }
    }

    println!("cargo:rerun-if-env-changed=BINDGEN_EXTRA_CLANG_ARGS");
    // Get the cargo out directory.
    let out_dir = PathBuf::from(env::var("OUT_DIR").expect("env variable OUT_DIR not found"));

    // Begin building the bindgen params.
    let mut builder = bindgen::Builder::default();

    // See https://github.com/rust-lang/rust-bindgen/issues/1211
    // Technically according to the llvm mailing list, the argument to clang here should be
    // -arch arm64 but it looks cleaner to just change the target.
    let target = if target == "aarch64-apple-ios" {
        "arm64-apple-ios"
    } else {
        target
    };
    builder = builder.size_t_is_usize(true);

    builder = builder.clang_args(&[&format!("--target={}", target)]);

    if let Some(sdk_path) = sdk_path {
        builder = builder.clang_args(&["-isysroot", sdk_path]);
    }
    if target.contains("apple-ios") {
        // time.h as has a variable called timezone that conflicts with some of the objective-c
        // calls from NSCalendar.h in the Foundation framework. This removes that one variable.
        builder = builder.blacklist_item("timezone");
        builder = builder.blacklist_item("objc_object");
    }

    let meta_header: Vec<_> = headers
        .iter()
        .map(|h| format!("#include <{}>\n", h))
        .collect();

    builder = builder.header_contents("coreaudio.h", &meta_header.concat());

    // Generate the bindings.
    builder = builder.trust_clang_mangling(false).derive_default(true);

    let bindings = builder.generate().expect("unable to generate bindings");

    // Write them to the crate root.
    bindings
        .write_to_file(out_dir.join("coreaudio.rs"))
        .expect("could not write bindings");
}

fn main() {
    let target = std::env::var("TARGET").unwrap();
    if !(target.contains("apple-darwin") || target.contains("apple-ios")) {
        panic!("coreaudio-sys requires macos or ios target");
    }

    let directory = sdk_path(&target).ok();
    build(directory.as_ref().map(String::as_ref), &target);
}
<commit_msg>Fix aarch64-apple-darwin build<commit_after>extern crate bindgen;

fn sdk_path(target: &str) -> Result<String, std::io::Error> {
    // Use environment variable if set
    println!("cargo:rerun-if-env-changed=COREAUDIO_SDK_PATH");
    if let Ok(path) = std::env::var("COREAUDIO_SDK_PATH") {
        return Ok(path);
    }

    use std::process::Command;

    let sdk = if target.contains("apple-darwin") {
        "macosx"
    } else if target == "x86_64-apple-ios" || target == "i386-apple-ios" {
        "iphonesimulator"
    } else if target == "aarch64-apple-ios"
        || target == "armv7-apple-ios"
        || target == "armv7s-apple-ios"
    {
        "iphoneos"
    } else {
        unreachable!();
    };
    let output = Command::new("xcrun")
        .args(&["--sdk", sdk, "--show-sdk-path"])
        .output()?
        .stdout;
    let prefix_str = std::str::from_utf8(&output).expect("invalid output from `xcrun`");
    Ok(prefix_str.trim_end().to_string())
}

fn build(sdk_path: Option<&str>, target: &str) {
    // Generate one large set of bindings for all frameworks.
    //
    // We do this rather than generating a module per framework as some frameworks depend on other
    // frameworks and in turn share types. To ensure all types are compatible across each
    // framework, we feed all headers to bindgen at once.
    //
    // Only link to each framework and include their headers if their features are enabled and they
    // are available on the target os.

    use std::env;
    use std::path::PathBuf;

    let mut headers: Vec<&'static str> = vec![];

    #[cfg(feature = "audio_toolbox")]
    {
        println!("cargo:rustc-link-lib=framework=AudioToolbox");
        headers.push("AudioToolbox/AudioToolbox.h");
    }

    #[cfg(feature = "audio_unit")]
    {
        println!("cargo:rustc-link-lib=framework=AudioToolbox");
        headers.push("AudioUnit/AudioUnit.h");
    }

    #[cfg(feature = "core_audio")]
    {
        println!("cargo:rustc-link-lib=framework=CoreAudio");

        if target.contains("apple-ios") {
            headers.push("CoreAudio/CoreAudioTypes.h");
        } else {
            headers.push("CoreAudio/CoreAudio.h");
        }
    }

    #[cfg(feature = "open_al")]
    {
        println!("cargo:rustc-link-lib=framework=OpenAL");
        headers.push("OpenAL/al.h");
        headers.push("OpenAL/alc.h");
    }

    #[cfg(all(feature = "core_midi"))]
    {
        if target.contains("apple-darwin") {
            println!("cargo:rustc-link-lib=framework=CoreMIDI");
            headers.push("CoreMIDI/CoreMIDI.h");
        }
    }

    println!("cargo:rerun-if-env-changed=BINDGEN_EXTRA_CLANG_ARGS");
    // Get the cargo out directory.
    let out_dir = PathBuf::from(env::var("OUT_DIR").expect("env variable OUT_DIR not found"));

    // Begin building the bindgen params.
    let mut builder = bindgen::Builder::default();

    // See https://github.com/rust-lang/rust-bindgen/issues/1211
    // Technically according to the llvm mailing list, the argument to clang here should be
    // -arch arm64 but it looks cleaner to just change the target.
    let target = if target == "aarch64-apple-ios" {
        "arm64-apple-ios"
    } else if target == "aarch64-apple-darwin" {
        "arm64-apple-darwin"
    } else {
        target
    };
    builder = builder.size_t_is_usize(true);

    builder = builder.clang_args(&[&format!("--target={}", target)]);

    if let Some(sdk_path) = sdk_path {
        builder = builder.clang_args(&["-isysroot", sdk_path]);
    }
    if target.contains("apple-ios") {
        // time.h as has a variable called timezone that conflicts with some of the objective-c
        // calls from NSCalendar.h in the Foundation framework. This removes that one variable.
        builder = builder.blacklist_item("timezone");
        builder = builder.blacklist_item("objc_object");
    }

    let meta_header: Vec<_> = headers
        .iter()
        .map(|h| format!("#include <{}>\n", h))
        .collect();

    builder = builder.header_contents("coreaudio.h", &meta_header.concat());

    // Generate the bindings.
    builder = builder.trust_clang_mangling(false).derive_default(true);

    let bindings = builder.generate().expect("unable to generate bindings");

    // Write them to the crate root.
    bindings
        .write_to_file(out_dir.join("coreaudio.rs"))
        .expect("could not write bindings");
}

fn main() {
    let target = std::env::var("TARGET").unwrap();
    if !(target.contains("apple-darwin") || target.contains("apple-ios")) {
        panic!("coreaudio-sys requires macos or ios target");
    }

    let directory = sdk_path(&target).ok();
    build(directory.as_ref().map(String::as_ref), &target);
}
<|endoftext|>


<commit_before>macro_rules! declare_deprecated_lint {
    (pub $name: ident, $_reason: expr) => {
        declare_lint!(pub $name, Allow, "deprecated lint")
    }
}

declare_deprecated_lint! {
/// **What it does:** Nothing. This lint has been deprecated.
///
/// **Deprecation reason:** This used to check for `assert!(a == b)` and recommend
/// replacement with `assert_eq!(a, b)`, but this is no longer needed after RFC 2011.
    pub SHOULD_ASSERT_EQ,
    "`assert!()` will be more flexible with RFC 2011"
}

declare_deprecated_lint! {
/// **What it does:** Nothing. This lint has been deprecated.
///
/// **Deprecation reason:** This used to check for `Vec::extend`, which was slower than
/// `Vec::extend_from_slice`. Thanks to specialization, this is no longer true.
    pub EXTEND_FROM_SLICE,
    "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice"
}

declare_deprecated_lint! {
/// **What it does:** Nothing. This lint has been deprecated.
///
/// **Deprecation reason:** `Range::step_by(0)` used to be linted since it's
/// an infinite iterator, which is better expressed by `iter::repeat`,
/// but the method has been removed for `Iterator::step_by` which panics
/// if given a zero
    pub RANGE_STEP_BY_ZERO,
    "`iterator.step_by(0)` panics nowadays"
}

declare_deprecated_lint! {
/// **What it does:** Nothing. This lint has been deprecated.
///
/// **Deprecation reason:** This used to check for `Vec::as_slice`, which was unstable with good
/// stable alternatives. `Vec::as_slice` has now been stabilized.
    pub UNSTABLE_AS_SLICE,
    "`Vec::as_slice` has been stabilized in 1.7"
}

declare_deprecated_lint! {
/// **What it does:** Nothing. This lint has been deprecated.
///
/// **Deprecation reason:** This used to check for `Vec::as_mut_slice`, which was unstable with good
/// stable alternatives. `Vec::as_mut_slice` has now been stabilized.
    pub UNSTABLE_AS_MUT_SLICE,
    "`Vec::as_mut_slice` has been stabilized in 1.7"
}

declare_deprecated_lint! {
/// **What it does:** Nothing. This lint has been deprecated.
///
/// **Deprecation reason:** This used to check for `.to_string()` method calls on values
/// of type `&str`. This is not unidiomatic and with specialization coming, `to_string` could be
/// specialized to be as efficient as `to_owned`.
    pub STR_TO_STRING,
    "using `str::to_string` is common even today and specialization will likely happen soon"
}

declare_deprecated_lint! {
/// **What it does:** Nothing. This lint has been deprecated.
///
/// **Deprecation reason:** This used to check for `.to_string()` method calls on values
/// of type `String`. This is not unidiomatic and with specialization coming, `to_string` could be
/// specialized to be as efficient as `clone`.
    pub STRING_TO_STRING,
    "using `string::to_string` is common even today and specialization will likely happen soon"
}

declare_deprecated_lint! {
/// **What it does:** Nothing. This lint has been deprecated.
///
/// **Deprecation reason:** This lint should never have applied to non-pointer types, as transmuting
/// between non-pointer types of differing alignment is well-defined behavior (it's semantically
/// equivalent to a memcpy). This lint has thus been refactored into two separate lints:
/// cast_ptr_alignment and transmute_ptr_to_ptr.
    pub MISALIGNED_TRANSMUTE,
    "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr"
}

/// **What it does:** Nothing. This lint has been deprecated.
///
/// **Deprecation reason:** This lint is too subjective, not having a good reason for being in clippy.
/// Additionally, compound assignment operators may be overloaded separately from their non-assigning
/// counterparts, so this lint may suggest a change in behavior or the code may not compile.
declare_deprecated_lint! {
    pub ASSIGN_OPS,
    "using compound assignment operators (e.g., `+=`) is harmless"
}

declare_deprecated_lint! {
/// **What it does:** Nothing. This lint has been deprecated.
///
/// **Deprecation reason:** The original rule will only lint for `if let`. After
/// making it support to lint `match`, naming as `if let` is not suitable for it.
/// So, this lint is deprecated.
    pub IF_LET_REDUNDANT_PATTERN_MATCHING,
    "this lint has been changed to redundant_pattern_matching"
}

declare_deprecated_lint! {
/// **What it does:** Nothing. This lint has been deprecated.
///
/// **Deprecation reason:** This lint used to suggest replacing `let mut vec =
/// Vec::with_capacity(n); vec.set_len(n);` with `let vec = vec![0; n];`. The
/// replacement has very different performance characteristics so the lint is
/// deprecated.
    pub UNSAFE_VECTOR_INITIALIZATION,
    "the replacement suggested by this lint had substantially different behavior"
}

declare_deprecated_lint! {
/// **What it does:** Nothing. This lint has been deprecated.
///
/// **Deprecation reason:** This lint has been superseded by the warn-by-default
/// `invalid_value` rustc lint.
    pub INVALID_REF,
    "superseded by rustc lint `invalid_value`"
}

declare_deprecated_lint! {
/// **What it does:** Nothing. This lint has been deprecated.
///
/// **Deprecation reason:** This lint has been superseded by #[must_use] in rustc.
    pub UNUSED_COLLECT,
    "`collect` has been marked as #[must_use] in rustc and that covers all cases of this lint"
}
<commit_msg>deprecated_lints: align doc comment indents with `pub LINT_NAME`<commit_after>macro_rules! declare_deprecated_lint {
    (pub $name: ident, $_reason: expr) => {
        declare_lint!(pub $name, Allow, "deprecated lint")
    }
}

declare_deprecated_lint! {
    /// **What it does:** Nothing. This lint has been deprecated.
    ///
    /// **Deprecation reason:** This used to check for `assert!(a == b)` and recommend
    /// replacement with `assert_eq!(a, b)`, but this is no longer needed after RFC 2011.
    pub SHOULD_ASSERT_EQ,
    "`assert!()` will be more flexible with RFC 2011"
}

declare_deprecated_lint! {
    /// **What it does:** Nothing. This lint has been deprecated.
    ///
    /// **Deprecation reason:** This used to check for `Vec::extend`, which was slower than
    /// `Vec::extend_from_slice`. Thanks to specialization, this is no longer true.
    pub EXTEND_FROM_SLICE,
    "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice"
}

declare_deprecated_lint! {
    /// **What it does:** Nothing. This lint has been deprecated.
    ///
    /// **Deprecation reason:** `Range::step_by(0)` used to be linted since it's
    /// an infinite iterator, which is better expressed by `iter::repeat`,
    /// but the method has been removed for `Iterator::step_by` which panics
    /// if given a zero
    pub RANGE_STEP_BY_ZERO,
    "`iterator.step_by(0)` panics nowadays"
}

declare_deprecated_lint! {
    /// **What it does:** Nothing. This lint has been deprecated.
    ///
    /// **Deprecation reason:** This used to check for `Vec::as_slice`, which was unstable with good
    /// stable alternatives. `Vec::as_slice` has now been stabilized.
    pub UNSTABLE_AS_SLICE,
    "`Vec::as_slice` has been stabilized in 1.7"
}

declare_deprecated_lint! {
    /// **What it does:** Nothing. This lint has been deprecated.
    ///
    /// **Deprecation reason:** This used to check for `Vec::as_mut_slice`, which was unstable with good
    /// stable alternatives. `Vec::as_mut_slice` has now been stabilized.
    pub UNSTABLE_AS_MUT_SLICE,
    "`Vec::as_mut_slice` has been stabilized in 1.7"
}

declare_deprecated_lint! {
    /// **What it does:** Nothing. This lint has been deprecated.
    ///
    /// **Deprecation reason:** This used to check for `.to_string()` method calls on values
    /// of type `&str`. This is not unidiomatic and with specialization coming, `to_string` could be
    /// specialized to be as efficient as `to_owned`.
    pub STR_TO_STRING,
    "using `str::to_string` is common even today and specialization will likely happen soon"
}

declare_deprecated_lint! {
    /// **What it does:** Nothing. This lint has been deprecated.
    ///
    /// **Deprecation reason:** This used to check for `.to_string()` method calls on values
    /// of type `String`. This is not unidiomatic and with specialization coming, `to_string` could be
    /// specialized to be as efficient as `clone`.
    pub STRING_TO_STRING,
    "using `string::to_string` is common even today and specialization will likely happen soon"
}

declare_deprecated_lint! {
    /// **What it does:** Nothing. This lint has been deprecated.
    ///
    /// **Deprecation reason:** This lint should never have applied to non-pointer types, as transmuting
    /// between non-pointer types of differing alignment is well-defined behavior (it's semantically
    /// equivalent to a memcpy). This lint has thus been refactored into two separate lints:
    /// cast_ptr_alignment and transmute_ptr_to_ptr.
    pub MISALIGNED_TRANSMUTE,
    "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr"
}

/// **What it does:** Nothing. This lint has been deprecated.
///
/// **Deprecation reason:** This lint is too subjective, not having a good reason for being in clippy.
/// Additionally, compound assignment operators may be overloaded separately from their non-assigning
/// counterparts, so this lint may suggest a change in behavior or the code may not compile.
declare_deprecated_lint! {
    pub ASSIGN_OPS,
    "using compound assignment operators (e.g., `+=`) is harmless"
}

declare_deprecated_lint! {
    /// **What it does:** Nothing. This lint has been deprecated.
    ///
    /// **Deprecation reason:** The original rule will only lint for `if let`. After
    /// making it support to lint `match`, naming as `if let` is not suitable for it.
    /// So, this lint is deprecated.
    pub IF_LET_REDUNDANT_PATTERN_MATCHING,
    "this lint has been changed to redundant_pattern_matching"
}

declare_deprecated_lint! {
    /// **What it does:** Nothing. This lint has been deprecated.
    ///
    /// **Deprecation reason:** This lint used to suggest replacing `let mut vec =
    /// Vec::with_capacity(n); vec.set_len(n);` with `let vec = vec![0; n];`. The
    /// replacement has very different performance characteristics so the lint is
    /// deprecated.
    pub UNSAFE_VECTOR_INITIALIZATION,
    "the replacement suggested by this lint had substantially different behavior"
}

declare_deprecated_lint! {
    /// **What it does:** Nothing. This lint has been deprecated.
    ///
    /// **Deprecation reason:** This lint has been superseded by the warn-by-default
    /// `invalid_value` rustc lint.
    pub INVALID_REF,
    "superseded by rustc lint `invalid_value`"
}

declare_deprecated_lint! {
    /// **What it does:** Nothing. This lint has been deprecated.
    ///
    /// **Deprecation reason:** This lint has been superseded by #[must_use] in rustc.
    pub UNUSED_COLLECT,
    "`collect` has been marked as #[must_use] in rustc and that covers all cases of this lint"
}
<|endoftext|>