Skip to content

Commit

Permalink
Add --target to the clang args earlier
Browse files Browse the repository at this point in the history
Because the --target was passed after the include path detection, in
cases of cross-compilation, the include path detection would add paths
relevant to the host (e.g. /usr/include/x86_64_linux-gnu on x86_64 linux
while targeting something else), possibly breaking things along the way.
  • Loading branch information
glandium authored and emilio committed Aug 14, 2020
1 parent d55b063 commit 802561e
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 66 deletions.
67 changes: 1 addition & 66 deletions src/ir/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -507,46 +507,12 @@ impl<'ctx> WhitelistedItemsTraversal<'ctx> {
}
}

const HOST_TARGET: &'static str =
include_str!(concat!(env!("OUT_DIR"), "/host-target.txt"));

/// Returns the effective target, and whether it was explicitly specified on the
/// clang flags.
fn find_effective_target(clang_args: &[String]) -> (String, bool) {
use std::env;

let mut args = clang_args.iter();
while let Some(opt) = args.next() {
if opt.starts_with("--target=") {
let mut split = opt.split('=');
split.next();
return (split.next().unwrap().to_owned(), true);
}

if opt == "-target" {
if let Some(target) = args.next() {
return (target.clone(), true);
}
}
}

// If we're running from a build script, try to find the cargo target.
if let Ok(t) = env::var("TARGET") {
return (t, false);
}

(HOST_TARGET.to_owned(), false)
}

impl BindgenContext {
/// Construct the context for the given `options`.
pub(crate) fn new(options: BindgenOptions) -> Self {
// TODO(emilio): Use the CXTargetInfo here when available.
//
// see: https://reviews.llvm.org/D32389
let (effective_target, explicit_target) =
find_effective_target(&options.clang_args);

let index = clang::Index::new(false, true);

let parse_options =
Expand All @@ -555,26 +521,11 @@ impl BindgenContext {
let translation_unit = {
let _t =
Timer::new("translation_unit").with_output(options.time_phases);
// NOTE: The effective_target == HOST_TARGET check wouldn't be sound
// normally in some cases if we were to call a binary (if you have a
// 32-bit clang and are building on a 64-bit system for example).
// But since we rely on opening libclang.so, it has to be the same
// architecture and thus the check is fine.
let clang_args = if explicit_target ||
effective_target == HOST_TARGET
{
Cow::Borrowed(&options.clang_args)
} else {
let mut args = Vec::with_capacity(options.clang_args.len() + 1);
args.push(format!("--target={}", effective_target));
args.extend_from_slice(&options.clang_args);
Cow::Owned(args)
};

clang::TranslationUnit::parse(
&index,
"",
&clang_args,
&options.clang_args,
&options.input_unsaved_files,
parse_options,
).expect("libclang error; possible causes include:
Expand All @@ -587,22 +538,6 @@ If you encounter an error missing from this list, please file an issue or a PR!"
};

let target_info = clang::TargetInfo::new(&translation_unit);

#[cfg(debug_assertions)]
{
if let Some(ref ti) = target_info {
if effective_target == HOST_TARGET {
assert_eq!(
ti.pointer_width / 8,
mem::size_of::<*mut ()>(),
"{:?} {:?}",
effective_target,
HOST_TARGET
);
}
}
}

let root_module = Self::build_root_module(ItemId(0));
let root_module_id = root_module.id().as_module_id_unchecked();

Expand Down
56 changes: 56 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1914,6 +1914,35 @@ pub struct Bindings {
module: proc_macro2::TokenStream,
}

pub(crate) const HOST_TARGET: &'static str =
include_str!(concat!(env!("OUT_DIR"), "/host-target.txt"));

/// Returns the effective target, and whether it was explicitly specified on the
/// clang flags.
fn find_effective_target(clang_args: &[String]) -> (String, bool) {
let mut args = clang_args.iter();
while let Some(opt) = args.next() {
if opt.starts_with("--target=") {
let mut split = opt.split('=');
split.next();
return (split.next().unwrap().to_owned(), true);
}

if opt == "-target" {
if let Some(target) = args.next() {
return (target.clone(), true);
}
}
}

// If we're running from a build script, try to find the cargo target.
if let Ok(t) = env::var("TARGET") {
return (t, false);
}

(HOST_TARGET.to_owned(), false)
}

impl Bindings {
/// Generate bindings for the given options.
pub(crate) fn generate(
Expand All @@ -1931,6 +1960,20 @@ impl Bindings {

options.build();

let (effective_target, explicit_target) =
find_effective_target(&options.clang_args);

// NOTE: The effective_target == HOST_TARGET check wouldn't be sound
// normally in some cases if we were to call a binary (if you have a
// 32-bit clang and are building on a 64-bit system for example).
// But since we rely on opening libclang.so, it has to be the same
// architecture and thus the check is fine.
if !(explicit_target || effective_target == HOST_TARGET) {
options
.clang_args
.insert(0, format!("--target={}", effective_target));
};

fn detect_include_paths(options: &mut BindgenOptions) {
if !options.detect_include_paths {
return;
Expand Down Expand Up @@ -2045,6 +2088,19 @@ impl Bindings {
let time_phases = options.time_phases;
let mut context = BindgenContext::new(options);

#[cfg(debug_assertions)]
{
if effective_target == HOST_TARGET {
assert_eq!(
context.target_pointer_size(),
std::mem::size_of::<*mut ()>(),
"{:?} {:?}",
effective_target,
HOST_TARGET
);
}
}

{
let _t = time::Timer::new("parse").with_output(time_phases);
parse(&mut context)?;
Expand Down

0 comments on commit 802561e

Please sign in to comment.