Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x86_64-musl: allow building dylibs with -crt-static #38075

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/librustc/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use syntax::symbol::Symbol;
use syntax::{ast, codemap};
use syntax::feature_gate::AttributeType;
use syntax_pos::{Span, MultiSpan};
use syntax::feature_gate::UnstableFeatures;

use rustc_back::PanicStrategy;
use rustc_back::target::Target;
Expand Down Expand Up @@ -499,6 +500,33 @@ impl Session {
println!("Total time spent computing symbol hashes: {}",
duration_to_secs_str(self.perf_stats.symbol_hash_time.get()));
}

/// Checks if the target is going to be statically linked to the C runtime
pub fn target_is_crt_static(&self) -> bool {
let requested_features = self.opts.cg.target_feature.split(',');
let unstable_options = self.opts.debugging_opts.unstable_options;
let is_nightly = UnstableFeatures::from_environment().is_nightly_build();
let found_negative = requested_features.clone().any(|r| r == "-crt-static");
let found_positive = requested_features.clone().any(|r| r == "+crt-static");

// If we switched from the default then that's only allowed on nightly, so
// gate that here.
if (found_positive || found_negative) && (!is_nightly || !unstable_options) {
self.fatal("specifying the `crt-static` target feature is only allowed \
on the nightly channel with `-Z unstable-options` passed \
as well");
}

// If the target we're compiling for requests a static crt by default,
// then see if the `-crt-static` feature was passed to disable that.
// Otherwise if we don't have a static crt by default then see if the
// `+crt-static` feature was passed.
if self.target.target.options.crt_static_default {
!found_negative
} else {
found_positive
}
}
}

pub fn build_session(sopts: config::Options,
Expand Down
13 changes: 8 additions & 5 deletions src/librustc_back/target/linux_musl_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,19 @@ pub fn opts() -> TargetOptions {
//
// Each target directory for musl has these object files included in it so
// they'll be included from there.
//
// Note that when linking dynamically, these won't be passed to the linker
base.pre_link_objects_exe.push("crt1.o".to_string());
base.pre_link_objects_exe.push("crti.o".to_string());
base.post_link_objects.push("crtn.o".to_string());

// MUSL support doesn't currently include dynamic linking, so there's no
// need for dylibs or rpath business. Additionally `-pie` is incompatible
// with `-static`, so we can't pass `-pie`.
base.dynamic_linking = false;
// Dynamically linking to MUSL is opt-in (via the -crt-static target
// feature). The `true`s here are not ultimate and depend on whether one is
// actually linking to MUSL dynamically.
base.dynamic_linking = true;
base.has_rpath = false;
base.position_independent_executables = false;
// actually only true if linking dynamically
base.position_independent_executables = true;

// These targets statically link libc by default
base.crt_static_default = true;
Expand Down
27 changes: 1 addition & 26 deletions src/librustc_driver/target_features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use syntax::ast;
use llvm::LLVMRustHasFeature;
use rustc::session::Session;
use rustc_trans::back::write::create_target_machine;
use syntax::feature_gate::UnstableFeatures;
use syntax::symbol::Symbol;
use libc::c_char;

Expand Down Expand Up @@ -48,31 +47,7 @@ pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session) {
}
}

let requested_features = sess.opts.cg.target_feature.split(',');
let unstable_options = sess.opts.debugging_opts.unstable_options;
let is_nightly = UnstableFeatures::from_environment().is_nightly_build();
let found_negative = requested_features.clone().any(|r| r == "-crt-static");
let found_positive = requested_features.clone().any(|r| r == "+crt-static");

// If the target we're compiling for requests a static crt by default,
// then see if the `-crt-static` feature was passed to disable that.
// Otherwise if we don't have a static crt by default then see if the
// `+crt-static` feature was passed.
let crt_static = if sess.target.target.options.crt_static_default {
!found_negative
} else {
found_positive
};

// If we switched from the default then that's only allowed on nightly, so
// gate that here.
if (found_positive || found_negative) && (!is_nightly || !unstable_options) {
sess.fatal("specifying the `crt-static` target feature is only allowed \
on the nightly channel with `-Z unstable-options` passed \
as well");
}

if crt_static {
if sess.target_is_crt_static() {
cfg.insert((tf, Some(Symbol::intern("crt-static"))));
}
}
23 changes: 17 additions & 6 deletions src/librustc_trans/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ pub fn default_output_for_target(sess: &Session) -> config::CrateType {
/// Checks if target supports crate_type as output
pub fn invalid_output_for_target(sess: &Session,
crate_type: config::CrateType) -> bool {
match (sess.target.target.options.dynamic_linking,
match (sess.target.target.options.dynamic_linking && !sess.target_is_crt_static(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm I think this isn't quite accurate for MSVC where you can statically link msvcrt but still create DLLs (I believe)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following that logic, it should also be possible to build MUSL dylibs (.so libraries) that statically link to libc but link dynamically to other libraries I think (maybe not?). Do we want to support that as well?

If not then I can just add a !musl || here I think.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose if it's possible we should allow it. AFAIK it just gave a weird linker error when I tried with musl awhile back. That's probably b/c we were using wrong startup objects or something like that?

Ideally we'd avoid as many !musl conditions as possible...

sess.target.target.options.executables, crate_type) {
(false, _, config::CrateTypeCdylib) |
(false, _, config::CrateTypeProcMacro) |
Expand Down Expand Up @@ -668,6 +668,9 @@ fn link_natively(sess: &Session,
let (pname, mut cmd, extra) = get_linker(sess);
cmd.env("PATH", command_path(sess, extra));

let musl = sess.target.target.llvm_target.contains("musl");
let crt_static = sess.target_is_crt_static();

let root = sess.target_filesearch(PathKind::Native).get_lib_path();
cmd.args(&sess.target.target.options.pre_link_args);

Expand All @@ -676,8 +679,12 @@ fn link_natively(sess: &Session,
} else {
&sess.target.target.options.pre_link_objects_dll
};
for obj in pre_link_objects {
cmd.arg(root.join(obj));
// When dynamically linking to MUSL we don't need to pass our startup
// objects as those will be provided by the MUSL toolchain
if !musl || crt_static {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm this is always something I wish we could sink into the target specs rather than have here... Does anything leap to mind for you as an easy way to do that?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does anything leap to mind for you as an easy way to do that?

pre_link_objects_crt_static and pre_link_objects_crt_dynamic? 😄

BTW, is pre_link_args "setable" from JSON files? This field feels like a Rust distribution implementation detail because the objects get prepended with the sysroot's absolute path. I doubt custom targets will be able to use this field lest they modify the sysroot ...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I think all options are configurable from json files now (we round-trip through that format to read our own options IIRC).

I mean all the options in the custom target specs are already super specific... I guess I wouldn't really have a problem with those.

for obj in pre_link_objects {
cmd.arg(root.join(obj));
}
}

{
Expand All @@ -686,8 +693,11 @@ fn link_natively(sess: &Session,
objects, out_filename, outputs, trans);
}
cmd.args(&sess.target.target.options.late_link_args);
for obj in &sess.target.target.options.post_link_objects {
cmd.arg(root.join(obj));
// Same as above
if !musl || crt_static {
for obj in &sess.target.target.options.post_link_objects {
cmd.arg(root.join(obj));
}
}
cmd.args(&sess.target.target.options.post_link_args);

Expand Down Expand Up @@ -813,8 +823,9 @@ fn link_args(cmd: &mut Linker,
let mut args = args.iter().chain(more_args.iter()).chain(used_link_args.iter());
let relocation_model = sess.opts.cg.relocation_model.as_ref()
.unwrap_or(&empty_str);
let crt_static = sess.target_is_crt_static();
if (t.options.relocation_model == "pic" || *relocation_model == "pic")
&& !args.any(|x| *x == "-static") {
&& !args.any(|x| *x == "-static") && !crt_static {
cmd.position_independent_executable();
}
}
Expand Down