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

GHC 9.4.5 x86_64, linker error during static build with stack #1

Closed
paulcadman opened this issue Aug 9, 2023 · 15 comments
Closed

GHC 9.4.5 x86_64, linker error during static build with stack #1

paulcadman opened this issue Aug 9, 2023 · 15 comments

Comments

@paulcadman
Copy link

Firstly, thanks for maintaining this project. I wondered if you'd be able to help debug a build issue when using the GHC 9.4.5 container, or suggest something we could try.

We're trying to use ghc-musl to produce static builds for the juvix project but are experiencing a linker issue with the build.

We're using ghc-musl:9.4.5 on x86_64.

The build works with a standard (i.e distributed by GHC) distribution of GHC 9.4.5.

Reproduction steps

  • I used the following script to do the build build.sh.gz
    • The stack command is stack install --allow-different-user --system-ghc --ghc-options='-static -split-sections -optl-static'
    • We link against a static runtime library that we build using clang
  • I launched the container using docker run -v $PWD/build.sh:/build.sh --rm -ti glcr.b-data.ch/ghc/ghc-musl:9.4.5 /bin/bash
  • The resulting transcript of the build session: typescript.gz (after gzip -d this is best viewed using less because of recorded ANSI escapes).

Linker error during build

/usr/lib/gcc/x86_64-alpine-linux-musl/12.2.1/../../../../x86_64-alpine-linux-musl/bin/ld: /usr/lib/gcc/x86_64-alpine-linux-musl/12.2.1/crtbe
ginT.o: relocation R_X86_64_32 against hidden symbol `__TMC_END__' can not be used when making a shared object
/usr/lib/gcc/x86_64-alpine-linux-musl/12.2.1/../../../../x86_64-alpine-linux-musl/bin/ld: failed to set dynamic section sizes: bad value
collect2: error: ld returned 1 exit status

<no location info>: error:
    `gcc' failed in phase `Linker'. (Exit code: 1)

Upstream issue?

I found this issue which is related https://gitlab.haskell.org/ghc/ghc/-/issues/20168. The solution given there is to configure GHC to use its internal linker (used by ghci). However this does not seem like an ideal solution, we should use the system linker for this (as noted in the GHC documentation, the internal linker has known bugs, and they'd like to remove it).

@benz0li
Copy link
Owner

benz0li commented Aug 9, 2023

Cross reference: utdemir/ghc-musl#28

@benz0li
Copy link
Owner

benz0li commented Aug 9, 2023

Maybe --ghc-options='-optl-fuse-ld=gold -static -split-sections -optl-static' helps.

@benz0li
Copy link
Owner

benz0li commented Aug 9, 2023

@paulcadman See also commercialhaskell/stack#3420

@paulcadman
Copy link
Author

paulcadman commented Aug 9, 2023

Maybe --ghc-options='-optl-fuse-ld=gold -static -split-sections -optl-static' helps.

Thanks for the suggestion, I get the same linker error with these options.

@benz0li
Copy link
Owner

benz0li commented Aug 9, 2023

Do you have all the required options set according to commercialhaskell/stack#3420 (comment)?

@paulcadman
Copy link
Author

Do you have all the required options set according to commercialhaskell/stack#3420 (comment)?

Not exactly these options, but we have set of options to produce the static builds successfully with GHC 9.2.7 on alpine: https://github.com/anoma/juvix/blob/e0aadef2988d96804b3a65de741c5cbcccc5ab9a/.github/workflows/linux-static-binary.yaml#L38

@benz0li
Copy link
Owner

benz0li commented Aug 9, 2023

Do you have all the required options set according to commercialhaskell/stack#3420 (comment)?

Not exactly these options, but we have set of options to produce the static builds successfully with GHC 9.2.7 on alpine: https://github.com/anoma/juvix/blob/e0aadef2988d96804b3a65de741c5cbcccc5ab9a/.github/workflows/linux-static-binary.yaml#L38

Cross references:

(I assume the latter link is where the crtbeginT hack is coming from)

Unfortunately, I can not help any further.

@paulcadman
Copy link
Author

Unfortunately, I can not help any further.

Thanks very much for your help, much appreciated! 🥇

@benz0li
Copy link
Owner

benz0li commented Aug 9, 2023

@paulcadman Please try with the following:

build.sh

#!/usr/bin/env sh

set -x

# required to build the juvix runtime
apk add --update clang14

# install stack
curl https://github.com/commercialhaskell/stack/releases/download/v2.11.1/stack-2.11.1-linux-$(uname -m)-static.tar.gz -OL
tar xf stack-2.11.1-linux-$(uname -m)-static.tar.gz
cp stack-2.11.1-linux-$(uname -m)-static/stack /usr/local/bin

# stack permissions bug workaround
chown -R $(id -un):$(id -gn) ~

# clone and build Juvix
git clone --recursive --branch stack-lts-21.6 https://github.com/anoma/juvix.git
cd juvix
make runtime LIBTOOL=llvm14-ar
echo 'ld-options: -static -pthread' >> package.yaml
stack install --allow-different-user --system-ghc --ghc-options='-split-sections'

@benz0li
Copy link
Owner

benz0li commented Aug 9, 2023

@benz0li
Copy link
Owner

benz0li commented Aug 9, 2023

@paulcadman
Copy link
Author

Thank you - the combination of options you suggest works! 🎉

@benz0li
Copy link
Owner

benz0li commented Aug 10, 2023

Thank you - the combination of options you suggest works! 🎉

Please have this reviewed by a GHC expert – I am not one.

Regarding package.yml:

  1. Use ld-options: -static -pthread instead of ld-options: -static?
  2. Use cc-options: -static?

Regarding --ghc-options:

  1. Append -fPIC?
  2. Append -static -threaded?

(You could append -fllvm in addition to compile using the LLVM code generator.)

Or should all GHC options go into package.yml?

Ping @TravisCardwell (utdemir/ghc-musl) @mpilgrem (commercialhaskell/stack)

@TravisCardwell
Copy link

The options can be pretty confusing, IMHO.

Regarding package.yml:

  1. Use ld-options: -static -pthread instead of ld-options: -static?

This is what I do.

  • I am surprised that --ghc-options '-optl-static -optl-pthread' does not work. This should be equivalent to the ld-options in package.yml

These should indeed be equivalent.

  1. Use cc-options: -static?

I do not think that these are equivalent. The GHC -static flag is used to avoid shared Haskell libraries. It is enabled by default, but it does not hurt to set it explicitly. cc-options passes command-line arguments to the C compiler, and I do not think that -static is a recognized flag for GCC compilation. I have never tried setting it.

Regarding --ghc-options:

  1. Append -fPIC?

The -fPIC documentation says "generate position-independent code (code that can be put into shared libraries)," which sounds like it is not applicable to static compilation.

  1. Append -static -threaded?

The -static option is enabled by default, but it does not hurt to set it explicitly. The -threaded option should be set if a threaded runtime is needed.

Or should all GHC options go into package.yml?

I think that it is often fine to put such configuration in your .cabal file (or package.yml when using Hpack) when you only need to support building with a specific set of build tools. In other cases, you can follow the system-dependent parameters documentation, dynamically configuring flags using Autoconf (or a script).

BTW, I usually put static build configuration behind a Cabal flag, allowing me to develop easily and then confirm that static builds still work when appropriate (after big changes and before committing). Cabal syntax example:

flag static
  description: Build static executable
  default: False

executable example
  ...
  if flag(static)
    ld-options: -static -pthread

@paulcadman
Copy link
Author

paulcadman commented Aug 10, 2023

Thank you @TravisCardwell. I tried setting -optl-static in the ghc-options flag again and got the same error. There are few bugs open in stack about the handling of ghc-options, so it looks like I've hit one of those.

I've used your flags suggestion, the equivalent stack/hpack configuration (in package.yaml) is:

flags:
  static:
    description: Build static executable
    default: false
    manual: true

executables:
  example:
    ...
    when:
      - condition: flag(static)
        ld-options:
          - -pthread
          - -static

You then run stack build --flag example:static to set the flag.

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

3 participants