From aadfc25111e3ac3d3bf927eb761303d08da29d17 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Thu, 9 Feb 2023 15:34:55 -0600 Subject: [PATCH] Correctly fix C++ compilation w/ clang++ on FreeBSD When cross compiling, we are forced to emit the `--target=` compiler flag, but this can break clang++ C++ builds on FreeBSD if the triple isn't set to a value that causes clang++ to infer the use of libc++ instead of libstdc++ (the latter of which does not support C++11 and beyond on FreeBSD). By manually specifying the usage of `-std=libc++` we avoid the need to know which version of FreeBSD we are targeting (as we do not have that information from the rust target triple and cannot infer it from the host as we are cross-compiling). Note that we were already specifying a default stdlib value libc++ for `cpp_link_stdlib` under FreeBSD but that is not sufficient. There are other solutions that would work when not cross compiling such as omitting the `--target` altogether, but there's no compelling reason to add more code if this solution works for both native and cross-compiling cases. This fix supersedes #788. See relevant discussions in #785 and #788. --- src/lib.rs | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d26ba67bd..377bd26a8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1720,26 +1720,30 @@ impl Build { } else if target.contains("aarch64") { cmd.args.push("--target=aarch64-unknown-windows-gnu".into()) } - } else if target.ends_with("-freebsd") && self.get_host()?.ends_with("-freebsd") - { - // clang <= 13 on FreeBSD doesn't support a target triple without at least - // the major os version number appended; e.g. use x86_64-unknown-freebsd13 - // or x86_64-unknown-freebsd13.0 instead of x86_64-unknown-freebsd. - // The current version is appended. If it doesn't align with your goals, pass - // .flag("--target=...") in the build script or adjust CXXFLAGS accordingly. - let stdout = std::process::Command::new("freebsd-version") - .output() - .map_err(|e| { - Error::new( - ErrorKind::ToolNotFound, - &format!("Error executing freebsd-version: {}", e), - ) - })? - .stdout; - let stdout = String::from_utf8_lossy(&stdout); - let os_ver = stdout.split('-').next().unwrap(); + } else if target.ends_with("-freebsd") { + // FreeBSD only supports C++11 and above when compiling against libc++ + // (available from FreeBSD 10 onwards). Under FreeBSD, clang uses libc++ by + // default on FreeBSD 10 and newer unless `--target` is manually passed to + // the compiler, in which case its default behavior differs: + // * If --target=xxx-unknown-freebsdX(.Y) is specified and X is greater than + // or equal to 10, clang++ uses libc++ + // * If --target=xxx-unknown-freebsd is specified (without a version), + // clang++ cannot assume libc++ is available and reverts to a default of + // libstdc++ (this behavior was changed in llvm 14). + // + // This breaks C++11 (or greater) builds if targeting FreeBSD with the + // generic xxx-unknown-freebsd triple on clang 13 or below *without* + // explicitly specifying that libc++ should be used. + // When cross-compiling, we can't infer from the rust/cargo target triple + // which major version of FreeBSD we are targeting, so we need to make sure + // that libc++ is used (unless the user has explicitly specified otherwise). + // There's no compelling reason to use a different approach when compiling + // natively. + if self.cpp && self.cpp_set_stdlib.is_none() { + cmd.push_cc_arg("-stdlib=libc++".into()); + } - cmd.push_cc_arg(format!("--target={}{}", target, os_ver).into()); + cmd.push_cc_arg(format!("--target={}", target).into()); } else { cmd.push_cc_arg(format!("--target={}", target).into()); }