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

Static linking breaks with Postgres 12 #27

Closed
golddranks opened this issue Feb 16, 2020 · 6 comments
Closed

Static linking breaks with Postgres 12 #27

golddranks opened this issue Feb 16, 2020 · 6 comments

Comments

@golddranks
Copy link
Contributor

I tried to investigate the problems I mentioned having in #25 (comment) . Turns out my linking problems were not about OpenSSL at all. It was the combination of Postgres 12 libpq and static linking with Musl that broke the build.

Here's a script demonstrating the problem, using a simple C example program. (It uses Docker image I build as a part of my project https://gitlab.com/rust_musl_docker/image ):

#!/bin/sh -eu

> test.c cat << EOF
#include <libpq-fe.h>

int main() {
	PQconnectStart("test");
}
EOF

> build_test.sh cat << EOF
#!/bin/sh
musl-gcc -c -I/musl/include test.c
musl-gcc -static -o test test.o -L /musl/lib/ -lpq
EOF

chmod 0755 build_test.sh

echo "Building a binary with Postgres 11.7"

docker run -it --rm \
	-v "$PWD:/libworkdir" \
	registry.gitlab.com/rust_musl_docker/image/base:openssl-1.1.1d_postgres-11.7 \
	./build_test.sh

echo "Building a binary with Postgres 12.0"

docker run -it --rm \
	-v "$PWD:/libworkdir" \
	registry.gitlab.com/rust_musl_docker/image/base:openssl-1.1.1d_postgres-12.0 \
	./build_test.sh

If I add the linker flags -lpgport and -lpgcommon like this:

musl-gcc -static -o test test.o -L /musl/lib/ -lpq -lpgport -lpgcommon

... it manages to build the binary.

I'm sure it's the same problem I'm encountering with pq-sys because adding those linker flags to the flags Rust passes to cc makes the binary to link.

I'm currently trying to engage with Postgres community to check whether the dependency to those two libraries are intentional or is there something I'm missing, so we'll know exactly what to fix.

@golddranks
Copy link
Contributor Author

I got some helpful pointers from Postgres IRC. Linking a mailing list posts with the info here:

https://www.postgresql.org/message-id/CACS8yHKjrFOoTKKFOOted4d%2B16oN438DE0ydtp9y5QrxvcGp2w%40mail.gmail.com

https://www.postgresql.org/message-id/CACS8yHL0gbL3ECONrDygcBioTQBY%3DoVG-KGWB6%2BN7spG%2BeSMQw%40mail.gmail.com

It seems, indeed that to link PostgreSQL 12.0 libpq, libpgcommon and libpgport need to be linked as well.

They aren't needed for PostgreSQL 11.x and earlier, so how to fix this in build.rs needs some thought.

@golddranks
Copy link
Contributor Author

Jotting down some notes after delving into https://github.com/sgrif/pq-sys/blob/master/build.rs#L79 after some years.

pkg-config and the Windows equivalent are at the moment enabled only by a feature, so most people are unlikely to end up using them. If pkg-config info is correct, it should work, but at the moment, even that isn't correct. PostgreSQL's pkg-config is missing -lpgcommon and -lpgport from Requires.private in libpq.pc. I'm going to fill in a bug report to PostgreSQL about that.

Anyway, the real question here seems to be, how to ensure correct linking in the default case, which is by calling pg_config and checking some environment variables.

At the moment only the pq linking flag is passed to rustc. In case of Postgres 12.0, pgcommon and pgport need to be passed to. I'm going to try the simplest thing: check from pg_config the version and add custom logic.

@emk
Copy link

emk commented Jan 4, 2021

Hello! Thank you for maintaining libpq-sys, and thank you to @golddranks for diagnosising this issue.

I'm the author of rust-musl-builder, which provides support for statically linking a number of popular Rust libraries, including libpq-sys. It's weirdly popular, with over 750k downloads (I have no idea who's using it). I'm trying to upgrade to support PostgreSQL 13, and I'm hitting this same issue: emk/rust-musl-builder#111.

If there's anything I can do to help out with pq-sys and static linking, please let me know. Thank you to everyone who's been looking into this bug!

@davepacheco
Copy link

@golddranks I'm trying to do the same thing (in fact, I'm trying to build commit 8bc178b, which is branch golddranks/fix_libpq_12_linking -- the one from #28). With PostgreSQL 13 and gcc 7.3, I get an error about the multiply defined symbol pqsignal:

$ PQ_LIB_DIR=$HOME/postgres-install/lib PQ_LIB_STATIC=yes cargo build --all-targets
   Compiling pq-sys v0.4.6 (/home/ec2-user/pq-sys)
error: linking with `cc` failed: exit status: 1
  |
  = note: "cc" "-m64" "/home/ec2-user/pq-sys/target/debug/deps/pq_sys-aad7df9a5fa1f060.177qgd949ys9lpb7.rcgu.o" "/home/ec2-user/pq-sys/target/debug/deps/pq_sys-aad7df9a5fa1f060.272g37963h5m2uld.rcgu.o" "/home/ec2-user/pq-sys/target/debug/deps/pq_sys-aad7df9a5fa1f060.29yvxx88no77bxbs.rcgu.o" "/home/ec2-user/pq-sys/target/debug/deps/pq_sys-aad7df9a5fa1f060.2mnai312926rmqf3.rcgu.o" "/home/ec2-user/pq-sys/target/debug/deps/pq_sys-aad7df9a5fa1f060.3g5o1xfrzkmyuen.rcgu.o" "/home/ec2-user/pq-sys/target/debug/deps/pq_sys-aad7df9a5fa1f060.3he88g621g5bt2d.rcgu.o" "/home/ec2-user/pq-sys/target/debug/deps/pq_sys-aad7df9a5fa1f060.3qrt5h3cbs22zomo.rcgu.o" "/home/ec2-user/pq-sys/target/debug/deps/pq_sys-aad7df9a5fa1f060.3tr3pg7zd8igihbj.rcgu.o" "/home/ec2-user/pq-sys/target/debug/deps/pq_sys-aad7df9a5fa1f060.3y92dllpg2a46ch5.rcgu.o" "/home/ec2-user/pq-sys/target/debug/deps/pq_sys-aad7df9a5fa1f060.4sngz4h943kzt2d.rcgu.o" "/home/ec2-user/pq-sys/target/debug/deps/pq_sys-aad7df9a5fa1f060.5bpje562rh4jgnwv.rcgu.o" "/home/ec2-user/pq-sys/target/debug/deps/pq_sys-aad7df9a5fa1f060.96fk12unkvj6mvf.rcgu.o" "/home/ec2-user/pq-sys/target/debug/deps/pq_sys-aad7df9a5fa1f060.e66eevlqmoatqb1.rcgu.o" "/home/ec2-user/pq-sys/target/debug/deps/pq_sys-aad7df9a5fa1f060.1n27eg49i5jh6n5q.rcgu.o" "-Wl,--as-needed" "-L" "/home/ec2-user/pq-sys/target/debug/deps" "-L" "/home/ec2-user/postgres-install/lib" "-L" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-Wl,-Bstatic" "-Wl,--whole-archive" "-lpq" "-Wl,--no-whole-archive" "-Wl,--whole-archive" "-lpgcommon" "-Wl,--no-whole-archive" "-Wl,--whole-archive" "-lpgport" "-Wl,--no-whole-archive" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libtest-3599c5491d44663f.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libterm-1d56ea45a67842c8.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libgetopts-9749f7c936ebf9a7.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libunicode_width-627a220173eefff1.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_std-16ed15e5bfe21b9b.rlib" "-Wl,--start-group" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-2420485b9e5ef5e1.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libpanic_unwind-785e3cb61c4b1960.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libminiz_oxide-087191a88bdaa22d.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libadler-9981842c02975178.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libobject-6fb405869b015fde.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libaddr2line-d05c5c3c56004b7b.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libgimli-42d74d2097528b38.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd_detect-fb36534c113d2209.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_demangle-b56b9042c12b6535.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libhashbrown-491902d6cb3e76df.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_alloc-61834e0981b8c367.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libunwind-f78aa99d613a55bc.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcfg_if-53ee54cd7fed2c57.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liblibc-544ecdbd6cda3c58.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liballoc-379cc252b6943a79.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_core-8063eea38dcc5e62.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-5b228734afae15ee.rlib" "-Wl,--end-group" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcompiler_builtins-d6c7a399d95d173f.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-Wl,--eh-frame-hdr" "-Wl,-znoexecstack" "-L" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "/home/ec2-user/pq-sys/target/debug/deps/pq_sys-aad7df9a5fa1f060" "-Wl,--gc-sections" "-pie" "-Wl,-zrelro" "-Wl,-znow" "-nodefaultlibs"
  = note: /home/ec2-user/postgres-install/lib/libpgport.a(pqsignal.o): In function `pqsignal':
          pqsignal.c:(.text+0x0): multiple definition of `pqsignal'
          /home/ec2-user/postgres-install/lib/libpq.a(legacy-pqsignal.o):legacy-pqsignal.c:(.text+0x0): first defined here
          collect2: error: ld returned 1 exit status
          

error: aborting due to previous error

error: could not compile `pq-sys`

To learn more, run the command again with --verbose.
warning: build failed, waiting for other jobs to finish...
error: linking with `cc` failed: exit status: 1
  |
  = note: "cc" "-m64" "/home/ec2-user/pq-sys/target/debug/deps/smoke-f27a8dd9e97ba2e4.1hwmx3drt6bc1yk3.rcgu.o" "/home/ec2-user/pq-sys/target/debug/deps/smoke-f27a8dd9e97ba2e4.1phyoptspr06b9wx.rcgu.o" "/home/ec2-user/pq-sys/target/debug/deps/smoke-f27a8dd9e97ba2e4.2jjwso1h4ewv2gyy.rcgu.o" "/home/ec2-user/pq-sys/target/debug/deps/smoke-f27a8dd9e97ba2e4.36zx5qg5uef5y6lq.rcgu.o" "/home/ec2-user/pq-sys/target/debug/deps/smoke-f27a8dd9e97ba2e4.390l7zid2fawvw9p.rcgu.o" "/home/ec2-user/pq-sys/target/debug/deps/smoke-f27a8dd9e97ba2e4.3cfmp2uzpjj82jqf.rcgu.o" "/home/ec2-user/pq-sys/target/debug/deps/smoke-f27a8dd9e97ba2e4.3p1uc8lw6e8rxoxl.rcgu.o" "/home/ec2-user/pq-sys/target/debug/deps/smoke-f27a8dd9e97ba2e4.3qds5d4dprk4t5ev.rcgu.o" "/home/ec2-user/pq-sys/target/debug/deps/smoke-f27a8dd9e97ba2e4.3ypawrrypqdfawoz.rcgu.o" "/home/ec2-user/pq-sys/target/debug/deps/smoke-f27a8dd9e97ba2e4.519l3wawyw2ci4bh.rcgu.o" "/home/ec2-user/pq-sys/target/debug/deps/smoke-f27a8dd9e97ba2e4.52b7g86dqu03vrzj.rcgu.o" "/home/ec2-user/pq-sys/target/debug/deps/smoke-f27a8dd9e97ba2e4.dmcfzzjz2fmge39.rcgu.o" "/home/ec2-user/pq-sys/target/debug/deps/smoke-f27a8dd9e97ba2e4.2fczehrl2pdshl0k.rcgu.o" "-Wl,--as-needed" "-L" "/home/ec2-user/pq-sys/target/debug/deps" "-L" "/home/ec2-user/postgres-install/lib" "-L" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-Wl,-Bstatic" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libtest-3599c5491d44663f.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libterm-1d56ea45a67842c8.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libgetopts-9749f7c936ebf9a7.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libunicode_width-627a220173eefff1.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_std-16ed15e5bfe21b9b.rlib" "/home/ec2-user/pq-sys/target/debug/deps/libpq_sys-b0999ff5124879dc.rlib" "-Wl,--start-group" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-2420485b9e5ef5e1.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libpanic_unwind-785e3cb61c4b1960.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libminiz_oxide-087191a88bdaa22d.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libadler-9981842c02975178.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libobject-6fb405869b015fde.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libaddr2line-d05c5c3c56004b7b.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libgimli-42d74d2097528b38.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd_detect-fb36534c113d2209.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_demangle-b56b9042c12b6535.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libhashbrown-491902d6cb3e76df.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_alloc-61834e0981b8c367.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libunwind-f78aa99d613a55bc.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcfg_if-53ee54cd7fed2c57.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liblibc-544ecdbd6cda3c58.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liballoc-379cc252b6943a79.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_core-8063eea38dcc5e62.rlib" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-5b228734afae15ee.rlib" "-Wl,--end-group" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcompiler_builtins-d6c7a399d95d173f.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-Wl,--eh-frame-hdr" "-Wl,-znoexecstack" "-L" "/home/ec2-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "/home/ec2-user/pq-sys/target/debug/deps/smoke-f27a8dd9e97ba2e4" "-Wl,--gc-sections" "-pie" "-Wl,-zrelro" "-Wl,-znow" "-nodefaultlibs"
  = note: /usr/bin/ld: /home/ec2-user/pq-sys/target/debug/deps/libpq_sys-b0999ff5124879dc.rlib(snprintf.o): relocation R_X86_64_32S against `.rodata' can not be used when making a shared object; recompile with -fPIC
          /usr/bin/ld: /home/ec2-user/pq-sys/target/debug/deps/libpq_sys-b0999ff5124879dc.rlib(strerror.o): relocation R_X86_64_32 against `.rodata.str1.1' can not be used when making a shared object; recompile with -fPIC
          /usr/bin/ld: final link failed: Nonrepresentable section on output
          collect2: error: ld returned 1 exit status
          

error: aborting due to previous error

error: build failed

Sure enough, I have found that the pqsignal symbol appears in both libpq.a and libpgport.a, and they don't have the same contents. I don't see how this is supposed to work. Have you run into this?

@davepacheco
Copy link

I can easily reproduce my problem without any Rust. Here's a full example. The problem is that libpq.a has a pqsignal for compatibility reasons that's different from a pqsignal that's also exported by libpgport. This works for consumers using libpq.so because libpq.so statically includes all of libpgport, and that's presumably done in a way that prefers the symbol from libpq. Most users of static libraries wouldn't see this either because they're not using pqsignal (it was never documented), so that symbol will be skipped. But because Rust uses --whole-archive, which includes all symbols in the linked .a files, we wind up with two pqsignals, and we're in trouble.

Outside of Rust, you can work around this with the --allow-multiple-definitions linker flag, provided that you link the libraries in the right order. I tried this in my C example but I didn't try coaxing Cargo to use it.

I'm still testing it out, but I think a better solution suggested by @luqmana is this change to PR #28:

diff --git a/build.rs b/build.rs
index a39de43..5f513a7 100644
--- a/build.rs
+++ b/build.rs
@@ -108,8 +108,8 @@ fn main() {
     println!("cargo:rustc-link-lib={}", link_opts);
 
     if major_version >= 12 && link_opts.linking_type == Some(LinkType::Static) {
-        println!("cargo:rustc-link-lib=static=pgcommon");
-        println!("cargo:rustc-link-lib=static=pgport");
+        println!("cargo:rustc-link-lib=static-nobundle=pgcommon");
+        println!("cargo:rustc-link-lib=static-nobundle=pgport");
     }
 }

It does produce warnings at build time, but it seems to work.

@weiznich
Copy link
Collaborator

weiznich commented Dec 7, 2023

Essentially fixed by #46 which allows to build and statically link a vendored libpq version

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

No branches or pull requests

4 participants