Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to build and install gcc with built-in rpath?

I'm trying to build and install my own gcc 4.7.2 in /usr/local to use in place of the gcc 4.4.6 in /usr. (This is on CentOS 6.3.)

gcc makes executables and dynamic libraries that dynamically link to its own dynamic libraries, e.g. libstdc++.so. How do I build and install gcc so that the generated binaries automatically get a linker -rpath option (-rpath /usr/local/lib64) that causes dynamic libraries in /usr/local/lib64 to be linked instead of those in /usr/lib64 or /lib64?

If it works properly, after I build an executable with the gcc without specifying "-Wl,-rpath=/usr/local/lib64", when I ldd the executable, it should show /usr/local/lib64/libstdc++.so.6 instead of /usr/lib64/libstdc++.so.6. Similarly for the libgcc_s.so.1.

I have tried different approaches, including specifying LDFLAGS_FOR_TARGET=-Wl,-rpath=/usr/local/lib64,-rpath=/usr/local/lib on the 'configure' command-line, but nothing worked.

like image 548
Joshua Chia Avatar asked Nov 11 '12 18:11

Joshua Chia


People also ask

What is Rpath in GCC?

In computing, rpath designates the run-time search path hard-coded in an executable file or library. Dynamic linking loaders use the rpath to find required libraries. Specifically, it encodes a path to shared libraries into the header of an executable (or another shared library).

What is Rpath and Rpath link?

The difference between -rpath and -rpath-link is that directories specified by -rpath options are included in the executable and used at runtime, whereas the -rpath-link option is only effective at link time.

What is Rpath in Linker?

RPATH is a mechanism to include a list of directories in a binary where required shared libraries may be available. These locations are considered by the dynamic loader ( ld*. so ) to locate the libraries that are required by a particular binary.

What does Rpath stand for?

RPATH stands for run-time search path. According to Wikipedia, “rpath designates the run-time search path hard-coded in an executable file or library.


1 Answers

If you don't want to export paths there's an alternative solution:

with your toolchain in the PATH:

gcc -dumpspecs > specsfile

edit specsfile and in the section link add your -rpath example:

*link:
%{!static:--eh-frame-hdr} -m %(link_emulation) %{shared:-shared}   %{!shared:     %{!static:       %{rdynamic:-export-dynamic}       -dynamic-linker %(dynamic_linker)}       %{static:-static}} -rpath /usr/local/lib64

at this point you can test if it work with:

g++ -specs=specsfile test.cpp
readelf -d a.out |grep RPATH

if it work you can make it permanent (no need to pass -specs everytime)

strace -fF -o /tmp/g++.log g++ test.cpp
grep specs /tmp/g++.log

the grep should show the paths where gcc look for the default specs file.

The specs files are flexible enough to allow conditional linking depending on variables, example:

{!static: %{mabi=n32:-rpath-link %R/lib32:%R/usr/lib32} %{mabi=64:-rpath-link %R/lib64:%R/usr/lib64} %{mabi=32:-rpath-link %R/lib:%R/usr/lib}}

should use different and multiple paths depending on mabi (untested, yet), %R should be the sysroot path, can be changed with needed full path.

There's also a --with-specs= option gcc configure eventually to be used at build time, not clear to me yet how to use with the link section (working on it).

--with-specs="%{shared:-Wl,-rpath -Wl,$(DESTDIR)/lib}%{!shared:-Wl,-rpath -Wl,$(DESTDIR)/lib}"

It work, I used both shared and not !shared just for test, probably some smarter condition should be used, note that it isn't reported with -dumpspecs.

Reading through some thread of the gcc mailing list I had the impression specs aren't liked by everyone (but if I'm not wrong 4.9 add another option --with-extra-specs) instead preferred way to do such customizations appears to be configure.host, but I'm done and not looking into it, have fun! :-)

see also: gcc faq rpath

update above

I don't know if you can set a pre-defined rpath, probably if you can would be in the linker ld of binutils not in gcc/g++, but why would you do that?

Just export LD_LIBRARY_PATH at runtime and LD_RUN_PATH at build time

export LD_LIBRARY_PATH=/usr/local/lib64:$LD_LIBRARY_PATH
ldd a.out

ldd should show the paths you exported.

To quote a message given when a shared library is built with libtool:

If you ever happen to want to link against installed libraries in a given directory, LIBDIR, you must either use libtool, and specify the full pathname of the library, or use the `-LLIBDIR' flag during linking and do at least one of the following:

  • add LIBDIR to the `LD_LIBRARY_PATH' environment variable during execution
  • add LIBDIR to the `LD_RUN_PATH' environment variable during linking
  • use the `-Wl,--rpath -Wl,LIBDIR' linker flag
  • have your system administrator add LIBDIR to `/etc/ld.so.conf'

See any operating system documentation about shared libraries for more information, such as the ld(1) and ld.so(8) manual pages.

for completeness the Makefile I used for testing the thing, all the configure options, environment variables (see boot ldflags) I tried didn't work, --enable-rpath included.

use with mkdir ~/gcc copy the Makefile below into ~/gcc then cd ~/gcc && make build-gcc

notice the options used are only for this test case, don't use as reference.

FETCH = aria2c --file-allocation=none -c -d dl
NICE = nice -n 19
PARALLEL = -j4
DESTDIR = $(HOME)/gcc/install
SRCDIR = $(HOME)/gcc/src

all:

# if more downloads are added just remove {dl,src}/*-my-stamp not the .bak
# the .bak should avoid to rebuild targets because of timestamp
touch_stamp = if [ -f [email protected] ]; then \
        touch -r [email protected] $@; \
    else \
        touch $@ [email protected]; \
    fi

dl/dl-my-stamp:
    $(FETCH) https://ftp.gnu.org/gnu/gcc/gcc-4.7.2/gcc-4.7.2.tar.bz2
    $(FETCH) http://ftp.gnu.org/gnu/gmp/gmp-4.3.2.tar.bz2
    $(FETCH) ftp://gcc.gnu.org/pub/gcc/infrastructure/mpc-0.8.1.tar.gz
    $(FETCH) https://ftp.gnu.org/gnu/mpfr/mpfr-2.4.2.tar.bz2
    $(FETCH) --check-certificate=false http://www.mirrorservice.org/sites/sourceware.org/pub/binutils/snapshots/binutils-2.24.51.tar.bz2 \
        ftp://sourceware.org/pub/binutils/snapshots/binutils-2.24.51.tar.bz2
    $(touch_stamp)

untar_dep = src/untar-my-stamp
src/untar-my-stamp: dl/dl-my-stamp
    mkdir -p src
    tar -C src -xjf dl/gcc-4.7.2.tar.bz2
    tar -C src -xjf dl/gmp-4.3.2.tar.bz2
    tar -C src -xzf dl/mpc-0.8.1.tar.gz
    tar -C src -xjf dl/mpfr-2.4.2.tar.bz2
    tar -C src -xjf dl/binutils-2.24.51.tar.bz2
    $(touch_stamp)

define configure-rule
$(1)_install = $(DESTDIR)/$(1)-install-my-stamp
$(1)_builddir = $$($(1)_dir)/build
$(DESTDIR)/$(1)-install-my-stamp: $$($(1)_deps)
    mkdir -p $$($(1)_builddir)
    cd $$($(1)_builddir) && \
        $$($(1)_env) ../configure --cache-file=$(SRCDIR)/$(1)-config.cache \
            $$($(1)_configure)
    $(NICE) make -C $$($(1)_builddir) $$($(1)_make_target) $(PARALLEL)
ifneq ($$($(1)_post_make),)
    $$($(1)_post_make)
endif
    touch $$@
.PHONY: build-$(1) clean-$(1)
build-$(1): $$($(1)_install)
clean-$(1):
    -rm -fr $$($(1)_builddir)
endef

gmp_dir = src/gmp-4.3.2
gmp_env =   CONFIG_SITE=$(SRCDIR)/config.site
gmp_configure = --prefix=$(DESTDIR) \
                --disable-shared --enable-static --enable-cxx
gmp_deps = $(untar_dep)
gmp_make_target = install
$(eval $(call configure-rule,gmp))

mpfr_dir = src/mpfr-2.4.2
mpfr_env =  CONFIG_SITE=$(SRCDIR)/config.site
mpfr_configure = --prefix=$(DESTDIR) \
                --disable-shared --enable-static \
                --with-gmp=$(DESTDIR)
mpfr_deps = $(untar_dep) $(gmp_install)
mpfr_make_target = install
$(eval $(call configure-rule,mpfr))

mpc_dir = src/mpc-0.8.1
mpc_env =   CONFIG_SITE=$(SRCDIR)/config.site
mpc_configure = --prefix=$(DESTDIR) \
                --disable-shared --enable-static \
                --with-gmp=$(DESTDIR) --with-mpfr=$(DESTDIR)
mpc_deps = $(untar_dep) $(gmp_install) $(mpfr_install)
mpc_make_target = install
$(eval $(call configure-rule,mpc))

gcc_dir = src/gcc-4.7.2
gcc_env =   CONFIG_SITE=$(SRCDIR)/config.site \
    CFLAGS="-I/usr/include/i386-linux-gnu" \
    CXXFLAGS="-I/usr/include/i386-linux-gnu"
gcc_configure = --prefix=$(DESTDIR) \
                --libdir=$(DESTDIR)/lib \
                --with-local-prefix=$(DESTDIR) \
                --with-gmp=$(DESTDIR) --with-mpfr=$(DESTDIR) \
                --with-mpc=$(DESTDIR) \
                --disable-bootstrap \
                --enable-languages=c,c++ \
                --disable-libgomp --disable-multilib \
                --disable-libmudflap --disable-libssp \
                --disable-libquadmath \
                --enable-rpath \
                MAKEINFO=missing
gcc_deps = $(untar_dep) $(gmp_install) $(mpfr_install) $(mpc_install)
gcc_make_target = 
gcc_post_make = make -C $(gcc_builddir) install
$(eval $(call configure-rule,gcc))

binutils_dir = src/binutils-2.24.51
#binutils_env = LDFLAGS=-Wl,-rpath\ $(DESTDIR)/lib
binutils_env = CONFIG_SITE=$(SRCDIR)/config.site \
    CFLAGS="-I/usr/include/i386-linux-gnu" \
    BOOT_LDFLAGS="-rpath-link=$(DESTDIR)/lib -rpath=$(DESTDIR)/lib"
binutils_configure = --prefix=$(DESTDIR) \
                --libdir=$(DESTDIR)/lib \
                --with-gmp=$(DESTDIR) \
                --enable-rpath
binutils_deps = $(untar_dep) $(gmp_install)
#binutils_make_target = install
binutils_post_make = make -C $(binutils_builddir) install
$(eval $(call configure-rule,binutils))


.PHONY: env
env:
    @echo export PATH=$(DESTDIR)/bin:\$$PATH
    @echo export LIBRARY_PATH=/usr/lib/i386-linux-gnu
like image 53
Alex Avatar answered Oct 23 '22 04:10

Alex