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

Made pg_config path configurable per-target. #18

Closed
wants to merge 2 commits into from

Conversation

golddranks
Copy link
Contributor

Makes possible to fix rust-lang/rust#43486

When cross-compiling Diesel, libpq is compiled twice: once for the target system and once for the host system. This is because Diesel's codegen crates use libpq, and they need to run on the host system since they are compiler plugins. (In my case, the host system is linux+glibc and the target system is linux+musl) These systems need to use different libraries, but the current libpq build script accesses the same pg_config regardless. This change makes it possible to set the pg_config per-target which remedies this.

@golddranks
Copy link
Contributor Author

So, I pushed a commit that has a per-target version of PQ_LIB_STATIC too; for example PQ_LIB_STATIC_X86_64_UNKNOWN_LINUX_MUSL for the musl target. Since the compiler plugins are loaded dynamically, linking statically things with pq-sys built for the use of a plugin will break the build, so per-target variables are good to have.

So, there is now two sets of settings: the normal env variables and target-specific variables, which help with cross-compiling.

The current changes help me cross-compile using this Docker image: https://github.com/golddranks/rust_musl_docker , but at the moment I have to use my fork of pq-sys that understands these target-specific env variables, so I can't announce the image yet.

If you have comments or questions about the PR, I'll be happy to answer and/or improve the code.

Also, I'm not sure if I managed to explain clearly why having these config settings are needed, so don't be afraid to ask!

@golddranks
Copy link
Contributor Author

golddranks commented Aug 22, 2017

One thing I didn't implement yet is specifying target-specific lib paths directly, instead of consulting pg_config. If you think the target-specific vars are a sane way to configure the build, I'll send another commit later.

fn pg_config_output(command: &str) -> Option<String> {
Command::new("pg_config")

Copy link
Owner

Choose a reason for hiding this comment

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

✂️

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👀

@emk
Copy link

emk commented Oct 19, 2017

Thank you for figuring this out!

This is also breaking diesel with https://hub.docker.com/r/ekidd/rust-musl-builder/, which is how we deploy our in-house Diesel based tools at Faraday. We use an Ubuntu Docker container to produce static binaries, which we then release either directly to our users, or package as Alpine Docker images.

Is there anything I could do to help test this patch or help get it ready to merge?

@golddranks
Copy link
Contributor Author

golddranks commented Oct 19, 2017

Glad that I'm not the only one experiencing this! Let's make this happen!

Btw. since we both link stuff statically, might be interested in each other's solutions; here's my builder container. I put some effort into documenting it thoroughly: https://github.com/golddranks/rust_musl_docker

emk added a commit to emk/rust-musl-builder that referenced this pull request Oct 24, 2017
Fixes #27, or at least works around it.

This deals with the issues mentioned in
sgrif/pq-sys#18, and it relies heavily on ideas
from @golddranks and @clux.
@emk
Copy link

emk commented Oct 24, 2017

OK, a big thank you to everyone!

I've added workarounds and documentation for this issue in rust-musl-builder. Specifically, the following lines need to be added to Cargo.toml:

[dependencies]
# This is needed to make sure that Cargo statically links against
# `libssl`. This should happen automatically, but it doesn't.
openssl-sys = "0.9"

[patch.crates-io]
# This is needed to handle cross-compilation of libpq.
pq-sys = { git = 'https://github.com/golddranks/pq-sys' }

After that, it's just a matter of setting up a cross-compilation environment, which has its own wrinkles. But happily, that's not the job of pq-sys.

I think that cross-compilation is a relatively important use case:

  1. It allows building statically-linked Linux binaries that can be used on any distro. This is a really great Rust feature.
  2. It allows building Alpine-based Docker containers using multi-stage builds, which makes it much easier to put containerized Rust microservices into production without dragging along a full-fledged Linux distro.

Given that I think this is an important feature, I'm willing to help get the PR ready to merge. I'd also be willing to contribute a Docker-based test case that verifies that it's possible to build and link a fully-static diesel-based application.

Copy link

@emk emk left a comment

Choose a reason for hiding this comment

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

Thank you so much for preparing this PR! It has made my life much easier.

Reading through the code, here are a couple of ideas for things which might be tweaked. And at least one case where I'm probably doing something wrong, but I don't understand the issue yet. :-/

Thank you very much for this PR!


// Link unconditionally statically
if env::var_os("PQ_LIB_STATIC").is_some() {
println!("cargo:rustc-link-lib=static=pq");
Copy link

Choose a reason for hiding this comment

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

I've noticed that I need to include the following when linking diesel statically:

[dependencies]
# This is needed to make sure that Cargo statically links against
# `libssl`. This should happen automatically, but it doesn't.
openssl-sys = "0.9"

Is there an underlying issue here with ps-sys or openssl-sys when statically linking that we should deal with? Or am I just messing up? I have a very small test program here that might help figure this out.


// Examine the per-target env vars
if let Ok(target) = env::var("TARGET") {
let pg_config_for_target = format!("PQ_LIB_STATIC_{}", target.to_ascii_uppercase().replace("-", "_"));
Copy link

Choose a reason for hiding this comment

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

This requires us adding a new

println!("cargo:rerun-if-env-changed={}", pg_config_for_target);

...line somewhere in the script. Also, you probably mean pq_lib_static_for_target here. :-)

use std::ascii::AsciiExt;

if let Ok(target) = env::var("TARGET") {
let pg_config_for_target = &format!("PG_CONFIG_{}", target.to_ascii_uppercase().replace("-", "_"));
Copy link

Choose a reason for hiding this comment

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

This also requires something like:

println!("cargo:rerun-if-env-changed={}", pg_config_for_target);

It might be best to wrap env::var_os in a wrapper that always generates this println!, and then refactor all of build.rs to use it.

@@ -63,8 +58,56 @@ fn configured_by_vcpkg() -> bool {
false
}

fn static_or_not() {
Copy link
Owner

Choose a reason for hiding this comment

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

This method name seems odd to me. It has side effects but implies it returns a boolean. Can we have it return a value instead? Perhaps a 3 state enum?

@chrisdotcode
Copy link

Hey @golddranks, @sgrif, has there been any progress on this? Being able to statically link diesel is something I definitely need.

@emk
Copy link

emk commented Feb 22, 2018

I'm currently recommending this PR of diesel for all https://hub.docker.com/r/ekidd/rust-musl-builder/ builds. Nobody has reported any issues yet. :-)

@sgrif
Copy link
Owner

sgrif commented Feb 23, 2018

I'm going to close this, as there's unresolved feedback that's been sitting for more than 6 months. If someone would like to revive this feature and address the open feedback, I will be happy to accept it.

@golddranks
Copy link
Contributor Author

Just for the record (as there are inbound links to this thread), this was later pulled in as #19

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Nightlies since 2017-07-20 break when linking some libraries targeting Musl
4 participants