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

Workaround for FreeBSD linking to outdated system libs #21788

Merged
merged 2 commits into from
Jun 10, 2017

Conversation

ararslan
Copy link
Member

FreeBSD's system libgcc_s declares its GCC version as 4.6, which is too old to build Julia. Since gfortran doesn't come installed by default, when it's installed it's done so through a GCC port, which includes its own libgcc_s. Linking to libgfortran from the port and to the system's libgcc_s causes versioning issues which wreck the build.

This PR works around this issue by determining the version of GCC used for gfortran, then linking in the libgcc_s corresponding to that version everywhere. It's a bit of a kludge, but it gets the job done.
With this change, all libraries which need to link to libgcc_s link to the proper version.

@ararslan ararslan added building Build system, or building Julia or its dependencies system:freebsd Affects only FreeBSD labels May 11, 2017
@ararslan ararslan requested review from vtjnash and tkelman May 11, 2017 03:33
Make.inc Outdated
FCFLAGS += -Wl,-rpath=$(GCCPATH)
JFFLAGS += -Wl,-rpath=$(GCCPATH)

# This ensures we get the right RPATH even if we're missing FFLAGS somewhere
Copy link
Contributor

Choose a reason for hiding this comment

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

where does this cause problems if this is left out?

Copy link
Member Author

Choose a reason for hiding this comment

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

I can't recall, honestly.

Copy link
Contributor

Choose a reason for hiding this comment

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

would be be ideal if we can add as few flags as were necessary to get things to work

Copy link
Member Author

Choose a reason for hiding this comment

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

Okay, probably easiest to only add it to FC then, since that's guaranteed to end up everywhere the flags are needed.

deps/llvm.mk Outdated
# Part of the FreeBSD libgcc_s kludge
ifeq ($(OS),FreeBSD)
ifneq ($(GCCPATH),)
LLVM_CMAKE += -DCMAKE_INSTALL_RPATH="\$$ORIGIN:$(GCCPATH)"
Copy link
Contributor

Choose a reason for hiding this comment

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

this isn't already set to anything?

Copy link
Member Author

Choose a reason for hiding this comment

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

Not for LLVM. Looks like the only CMake dependencies that set that flag are libgit2 and mbedtls.

Copy link
Contributor

Choose a reason for hiding this comment

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

aren't you putting it in CMAKE_COMMON? make sure that doesn't overwrite any existing settings

Copy link
Member Author

Choose a reason for hiding this comment

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

Added logic that avoids overriding those settings.

Copy link
Contributor

Choose a reason for hiding this comment

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

which cmake dependencies don't currently set this? maybe cleaner to always do in CMAKE_COMMON on freebsd, if that doesn't hurt anything on its own?

Copy link
Member Author

Choose a reason for hiding this comment

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

Seems like a good idea.

Copy link
Member Author

@ararslan ararslan May 12, 2017

Choose a reason for hiding this comment

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

All CMake dependencies should have the RPATH include $ORIGIN, and indeed we're doing it explicitly and separately for libgit2, libssh2, and mbedtls, so perhaps we should just define it centrally in CMAKE_COMMON for all platforms?

_GCCMAJOR := $(shell $(FC) -dumpversion | cut -d'.' -f1)
_GCCMINOR := $(shell $(FC) -dumpversion | cut -d'.' -f2)

# The ports system uses major and minor for GCC < 5 (e.g. gcc49 for GCC 4.9), otherwise major only
Copy link
Contributor

Choose a reason for hiding this comment

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

We have a bit of code that uses -print-search-dirs to set a STD_LIB_PATH variable in the Windows cross-compile case, would that give the same path you're looking for here?

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't think so, since the path where GCC lives when installed from ports isn't in the default ld search path. Though maybe I'm misunderstanding what you mean.

Copy link
Contributor

Choose a reason for hiding this comment

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

it's a flag for gcc to tell you its own search paths which should be where it's installed

Copy link
Member Author

Choose a reason for hiding this comment

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

I played around with that a bit but this solution actually seems cleaner than what I could come up with using that flag.

deps/Makefile Outdated
@@ -163,6 +163,21 @@ DEP_LIBS_STAGED := $(filter-out suitesparse suitesparse-wrapper osxunwind,$(DEP_
## Common build target prefixes

default: | $(build_prefix)

# Part of the FreeBSD libgcc_s kludge
Copy link
Contributor

Choose a reason for hiding this comment

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

this doesn't look deps specific to me, we should maybe rearrange the patchelf definitions so they're available in the top level makefiles

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure what you mean about being deps-specific. Could you clarify?

Copy link
Contributor

Choose a reason for hiding this comment

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

this fits more with the kind of things the top-level Makefile does, rather than the rest of the things deps/Makefile does - not a big deal but it sticks out a little

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, it's a little ugly here. Though I'm not sure what the best way to structure the logic elsewhere would be, given that this has to happen before any dependencies are built (or at least before LLVM).

@ararslan ararslan force-pushed the aa/freebsd-gfortran branch 2 times, most recently from 260c7bd to 5094a1d Compare May 13, 2017 21:09
@tkelman
Copy link
Contributor

tkelman commented May 13, 2017

cc @iblis17 may want to take a look at this?

@iblislin
Copy link
Member

iblislin commented May 14, 2017

The default version of lang/gcc in ports tree has been upgraded to 5.4.0 a month ago[1].
Do we still have this issue, if we just tell our user upgrade the ports?

[1]. https://github.com/freebsd/freebsd-ports/blob/master/lang/gcc/Makefile

@ararslan
Copy link
Member Author

Yes, because it's an issue with FreeBSD's system libraries, not the ports. The only thing that would fix it on FreeBSD's side is for them to update libgcc_s to claim to be a newer GCC version or to rename libgcc_s to libcc_s, both of which have been proposed but no action has been taken AFAICT.

@iblislin
Copy link
Member

I guess i misunderstand the actual issue...
How to reproduce this build issue?

I'm using this config[1] on my CI.

[1]. https://gist.github.com/iblis17/b4dca8221dcb96efcccde24f9cc2fa8d

@ararslan
Copy link
Member Author

To reproduce, just clone Julia into some local directory and build without setting anything in Make.user. It should make it to near the end then fail with a version error when linking in BLAS.

For reference, the changes similar to those made in this PR are done automatically by the FreeBSD Ports system when the Makefile specifies USES=fortran. The changes here are to allow local builds without system libraries, which is useful for development and building for distribution.

@iblislin
Copy link
Member

@ararslan ok, I have an idea to leverage ports system.
I will try a BSDmakefile out, and see it make life easier or not.

@ararslan
Copy link
Member Author

ararslan commented May 14, 2017

My original solution to this was based on Ports, but I don't think we should make our build system depend on any particular external package provider, which is why I did it this way instead.

@iblislin
Copy link
Member

Ok, i got your point.
I am trying these patches.

@tkelman
Copy link
Contributor

tkelman commented May 14, 2017

it's useful to have both be an option, if it doesn't make for too much of a mess to support both "clone and make" builds as well as packager builds that use system libraries, custom file layouts, etc

@iblislin
Copy link
Member

iblislin commented May 14, 2017

@ararslan In /usr/ports/Mk/Uses/fortran.mk, there is an additional flag for LDFLAGS: -B${LOCALBASE}/bin. But this PR do not include it. I'm curious about what -B actually affect and how ports system deals with libgcc_s without patching libc++.so...

(I'm managing to add -B and remove contrib/fixup-freebsd-libs.sh

@ararslan
Copy link
Member Author

packager builds that use system libraries, custom file layouts, etc

There's already a Julia port in the Ports tree for that

I'm managing to add -B and remove contrib/fixup-freebsd-libs.sh

I don't think we should be using -B in this case, since that will make us link to GCC's libstdc++, if I'm not mistaken.

@iblislin
Copy link
Member

iblislin commented May 15, 2017

I don't think we should be using -B in this case, since that will make us link to GCC's libstdc++, if I'm not mistaken.

I revert deps/Makefile , add -B and got this

┌─[~/tmp/julia/usr/lib]
└─[iblis@abeing]% ldd ./libLLVM-3.9.so 
./libLLVM-3.9.so:
        librt.so.1 => /usr/lib/librt.so.1 (0x802a63000)
        libthr.so.3 => /lib/libthr.so.3 (0x802c68000)
        libz.so.6 => /lib/libz.so.6 (0x802e8f000)
        libm.so.5 => /lib/libm.so.5 (0x8030a6000)
        libc++.so.1 => /usr/lib/libc++.so.1 (0x8032cf000)
        libcxxrt.so.1 => /lib/libcxxrt.so.1 (0x803590000)
        libgcc_s.so.1 => /usr/local/lib/gcc5/libgcc_s.so.1 (0x8037b0000)
        libc.so.7 => /lib/libc.so.7 (0x800824000)

Is this effect we want?

But I encountered some issue blocking me generating sysimg.

@iblislin
Copy link
Member

@ararslan I build this PR from cloning it into a new dir, but got following error

LoadError("sysimg.jl", 362, LoadError("sparse/sparse.jl", 41, LoadError("sparse/umfpack.jl", 61, ErrorException("error compiling anonymous: could not load library \"libsuitesparse_wrapper\"\n/lib/libgcc_s.so.1: version GCC_4.6.0 required by /usr/local/lib/gcc5/libgfortran.so.3 not found"))))
*** This error is usually fixed by running `make clean`. If the error persists, try `make cleanall`. ***
gmake[1]: *** [Makefile:232: /usr/home/iblis/tmp/jl2/usr/lib/julia/sys.o] Error 1
gmake: *** [Makefile:109: julia-sysimg-release] Error 2

(this error msg is same as -B + remove fixup.sh)

I'm on an old -CURRENT

└─[iblis@abeing]% uname -a
FreeBSD abeing 12.0-CURRENT FreeBSD 12.0-CURRENT #4 r309367: Mon Dec 12 11:10:09 CST 2016     root@abeing:/usr/obj/usr/src/sys/GENERIC  amd64

@ararslan
Copy link
Member Author

Is this effect we want?

No, notice that the ldd output contains

        libc++.so.1 => /usr/lib/libc++.so.1 (0x8032cf000)
        libcxxrt.so.1 => /lib/libcxxrt.so.1 (0x803590000)

These system libraries link to /lib/libgcc_s.so.1, which will cause the problems you encountered. The fixup-freebsd-libs script patches those files such that they link to /usr/local/lib/gcc5/libgcc_s.so.1 instead.

@iblislin
Copy link
Member

I build this PR from cloning it into a new dir, but got following error

@ararslan ha, permission problem

diff --git a/contrib/fixup-freebsd-libs.sh b/contrib/fixup-freebsd-libs.sh
old mode 100644
new mode 100755

@iblislin
Copy link
Member

now my build stopped here

/usr/home/iblis/tmp/jl2/usr/lib/libc++.so.1: program header too large
gmake[4]: *** [lib/IR/CMakeFiles/AttributeCompatFuncTableGen.dir/build.make:90: lib/IR/AttributesCompatFunc.inc.tmp] Error 1
gmake[3]: *** [CMakeFiles/Makefile2:688: lib/IR/CMakeFiles/AttributeCompatFuncTableGen.dir/all] Error 2
gmake[2]: *** [Makefile:152: all] Error 2
gmake[1]: *** [/usr/home/iblis/tmp/jl2/deps/llvm.mk:526: scratch/llvm-3.9.1/build_Release/build-compiled] Error 2
gmake: *** [Makefile:85: julia-deps] Error 2

@ararslan
Copy link
Member Author

Are you using USE_SYSTEM_PATCHELF=1?

@iblislin
Copy link
Member

No, it's a clean clone.

USE_SYSTEM_PATCHELF is 0, I do the following checking as well

└─[iblis@abeing]% g df |cat
diff --git a/contrib/fixup-freebsd-libs.sh b/contrib/fixup-freebsd-libs.sh
old mode 100644
new mode 100755
diff --git a/deps/Makefile b/deps/Makefile
index 4e153791bd..34b0326b16 100644
--- a/deps/Makefile
+++ b/deps/Makefile
@@ -168,6 +168,7 @@ default: | $(build_prefix)
 ifeq ($(OS),FreeBSD)
 ifneq ($(BUILD_CUSTOM_LIBCXX),1)
 default: $(build_libdir)/libc++.so.1
+$(error ${USE_SYSTEM_PATCHELF})
 ifeq ($(USE_SYSTEM_PATCHELF),1)
 $(build_libdir)/libc++.so.1:
        -$(JULIAHOME)/contrib/fixup-freebsd-libs.sh $(PATCHELF) $(build_libdir) $(GCCPATH)
┌─[~/tmp/jl2]
| [Venv(py36)] [-- INSERT --]
└─[iblis@abeing]% gmake
Makefile:171: *** 0.  Stop.
gmake: *** [Makefile:85: julia-deps] Error 2

@ararslan
Copy link
Member Author

I was having that issue as well and I don't recall what it was I did to resolve it. Seems that patchelf expands the binary too much when inserting an RPATH into a library that doesn't already have one.

@ararslan
Copy link
Member Author

ararslan commented May 17, 2017

Ah. Now I remember. It was building a custom libc++ and libc++abi (ref #21792) that fixed it for me, as doing so allows it to bypass the patchelf hack here. So I'm not sure where we should go from here, but these GCC changes are critical to get FreeBSD building out of the box.

Edit: Perhaps building a custom libc++ should be the default on FreeBSD?

FreeBSD's system libgcc_s declares its GCC version as 4.6, which is too
old to build Julia. Since gfortran doesn't come installed by default,
when it's installed it's done so through a GCC port, which includes its
own libgcc_s. Linking to libgfortran from the port and to the system's
libgcc_s causes versioning issues which wreck the build.

This commit works around this issue by determining the version of GCC
used for gfortran, then linking in the libgcc_s corresponding to that
version everywhere. It's a bit of a kludge, but it gets the job done.
With this change, all libraries which need to link to libgcc_s link to
the proper version.
@ararslan
Copy link
Member Author

Rather than trying to get patchelf to bite off more than it can chew, I've made it so that BUILD_CUSTOM_LIBCXX is set to 1 if not already set on FreeBSD. This now requires #21792 in order to build on FreeBSD.

@iblislin
Copy link
Member

@ararslan now, it works fine!

@ararslan
Copy link
Member Author

Fantastic! Thanks for trying it out, @iblis17.

@ararslan
Copy link
Member Author

Now that #21792 has been merged, I rebuilt from this branch on FreeBSD after a gmake -C deps distcleanall and gmake cleanall and emptying the Make.user. Seems to be working great.

@ararslan ararslan merged commit 99f7336 into master Jun 10, 2017
@ararslan ararslan deleted the aa/freebsd-gfortran branch June 10, 2017 01:45
iblislin added a commit to iblislin/julia that referenced this pull request Jul 2, 2017
Tweak the order of libgcc_s in DT_NEEDED.
Make FreeBSD do not require `BUILD_CUSTOM_LIBCXX`.

See also: JuliaLang#21788, JuliaLang#22352
iblislin added a commit to iblislin/julia that referenced this pull request Jul 2, 2017
Tweak the order of libgcc_s in DT_NEEDED.
Make FreeBSD do not require `BUILD_CUSTOM_LIBCXX`.

See also: JuliaLang#21788, JuliaLang#22352
ararslan pushed a commit that referenced this pull request Jul 10, 2017
Tweak the order of libgcc_s in DT_NEEDED on FreeBSD so that building on FreeBSD does not require `BUILD_CUSTOM_LIBCXX`.

See also: #21788, #22352
jeffwong pushed a commit to jeffwong/julia that referenced this pull request Jul 24, 2017
Tweak the order of libgcc_s in DT_NEEDED on FreeBSD so that building on FreeBSD does not require `BUILD_CUSTOM_LIBCXX`.

See also: JuliaLang#21788, JuliaLang#22352
ararslan added a commit that referenced this pull request Apr 25, 2018
FreeBSD's system libgcc_s declares its GCC version as 4.6, which is too
old to build Julia. Since gfortran doesn't come installed by default,
when it's installed it's done so through a GCC port, which includes its
own libgcc_s. Linking to libgfortran from the port and to the system's
libgcc_s causes versioning issues which wreck the build.

This commit works around this issue by determining the version of GCC
used for gfortran, then linking in the libgcc_s corresponding to that
version everywhere. It's a bit of a kludge, but it gets the job done.
With this change, all libraries which need to link to libgcc_s link to
the proper version.

Ref #21788
(cherry picked from commit 7d83d99)
ararslan added a commit that referenced this pull request Apr 25, 2018
ararslan pushed a commit that referenced this pull request Apr 25, 2018
Tweak the order of libgcc_s in DT_NEEDED on FreeBSD so that building on FreeBSD does not require `BUILD_CUSTOM_LIBCXX`.

See also: #21788, #22352

Ref #22656
(cherry picked from commit d90c215)
ararslan added a commit that referenced this pull request May 2, 2018
FreeBSD's system libgcc_s declares its GCC version as 4.6, which is too
old to build Julia. Since gfortran doesn't come installed by default,
when it's installed it's done so through a GCC port, which includes its
own libgcc_s. Linking to libgfortran from the port and to the system's
libgcc_s causes versioning issues which wreck the build.

This commit works around this issue by determining the version of GCC
used for gfortran, then linking in the libgcc_s corresponding to that
version everywhere. It's a bit of a kludge, but it gets the job done.
With this change, all libraries which need to link to libgcc_s link to
the proper version.

Ref #21788
(cherry picked from commit 7d83d99)
ararslan added a commit that referenced this pull request May 2, 2018
ararslan pushed a commit that referenced this pull request May 2, 2018
Tweak the order of libgcc_s in DT_NEEDED on FreeBSD so that building on FreeBSD does not require `BUILD_CUSTOM_LIBCXX`.

See also: #21788, #22352

Ref #22656
(cherry picked from commit d90c215)
ararslan added a commit that referenced this pull request May 8, 2018
FreeBSD's system libgcc_s declares its GCC version as 4.6, which is too
old to build Julia. Since gfortran doesn't come installed by default,
when it's installed it's done so through a GCC port, which includes its
own libgcc_s. Linking to libgfortran from the port and to the system's
libgcc_s causes versioning issues which wreck the build.

This commit works around this issue by determining the version of GCC
used for gfortran, then linking in the libgcc_s corresponding to that
version everywhere. It's a bit of a kludge, but it gets the job done.
With this change, all libraries which need to link to libgcc_s link to
the proper version.

Ref #21788
(cherry picked from commit 7d83d99)
ararslan added a commit that referenced this pull request May 8, 2018
ararslan pushed a commit that referenced this pull request May 8, 2018
Tweak the order of libgcc_s in DT_NEEDED on FreeBSD so that building on FreeBSD does not require `BUILD_CUSTOM_LIBCXX`.

See also: #21788, #22352

Ref #22656
(cherry picked from commit d90c215)
ararslan added a commit that referenced this pull request May 27, 2018
FreeBSD's system libgcc_s declares its GCC version as 4.6, which is too
old to build Julia. Since gfortran doesn't come installed by default,
when it's installed it's done so through a GCC port, which includes its
own libgcc_s. Linking to libgfortran from the port and to the system's
libgcc_s causes versioning issues which wreck the build.

This commit works around this issue by determining the version of GCC
used for gfortran, then linking in the libgcc_s corresponding to that
version everywhere. It's a bit of a kludge, but it gets the job done.
With this change, all libraries which need to link to libgcc_s link to
the proper version.

Ref #21788
(cherry picked from commit 7d83d99)
ararslan added a commit that referenced this pull request May 27, 2018
ararslan pushed a commit that referenced this pull request May 27, 2018
Tweak the order of libgcc_s in DT_NEEDED on FreeBSD so that building on FreeBSD does not require `BUILD_CUSTOM_LIBCXX`.

See also: #21788, #22352

Ref #22656
(cherry picked from commit d90c215)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
building Build system, or building Julia or its dependencies system:freebsd Affects only FreeBSD
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants