gcc/ld does not follow symbolic linked files when linking - gcc

I'm currently switch from ubuntu 11.04 (gcc 4.5) to ubuntu 12.04 (but I have the same problem with ubuntu 11.10 too, gcc 4.6) and am not able to compile some of my projects anymore.
I have a library, lets call it liba, which I build myself so I get
liba.so.0.0.1 (real library)
liba.so.0 -> liba.so.0.0.1 (symbolic link)
liba.so -> liba.so.0.0.1 (symbolic link)
but when I try to build a program using liba with:
gcc -o myprogram myprogram.c -la
I get an error that my library can not be found:
/usr/bin/ld.bfd.real: cannot find -la
On the other hand if I delete liba.so and rename liba.so.0.0.1 to liba.so everything works fine. Alternatively calling gcc with the full shared library its file name works find:
gcc -o myprogram myprogram.c -l:liba.so.0.0.1
Unfortunately due to versioning reasons in my build system these two solutions are not desirable to me.
Ideas?
EDIT: nevermind I found the problem is with 'new' vmware not supporting symlinks in shared folders. USing NFS now and everything is fine.

Make sure the location where liba lives is mentioned in /etc/ld.so.conf and run ldconfig. Alternativly you can give the search path with -Lpath.

Related

Modify default library search dirs that gcc passes to ld

I want to force new GCC 12 on my old debian (that only has GCC 6 by default) to use fresh libstdc++ headers with new header-only features, but link with old stdlibc++,gcc_s (and other system/compiler libs used by GCC6) to keep binary compatibility with native runtime of old debian (so that users of old GCC6 can link with my binaries without having GCC12).
Of course I know that some functionality in the old runtime will be missing, and ABI is also different, but I guess I can fight with that. Afterall RedHat seems to be using similar scheme for their devtoolset packages (they try to link missing functionality of new runtime statically to your binary if these symbols are not found in native old runtime)
So far I am stuck with -L arguments that GCC is passing to ld.
Here is complete output of /usr/local/gcc12/bin/x86_64-linux-gnu-gcc-12 main.cpp -Wl,-v -v command for simple hello-world main.cpp:
https://pastebin.com/JhYSfg4x
The question: Where does GCC take all these -L paths from, and how do I remove/modify them? I don't want to accidentally link with new version of libraries that were built with GCC12:
-L/usr/lib/gcc/x86_64-linux-gnu -L/usr/local/gcc12/lib/gcc/x86_64-linux-gnu/12 -L/usr/local/gcc12/lib/gcc/x86_64-linux-gnu/12/../../../../lib64 -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/lib/gcc -L/usr/local/gcc12/lib/gcc/x86_64-linux-gnu/12/../../.. /tmp/ccXfhCs4.o
System ld.conf does not mention any paths to /usr/local/gcc12 folder.
-nostdlib and -nodefaultlibs are removing some standard -l flags, but they are not doing anything to -L flags.
Update: I ended up just removing all *.a, .so, *.la files from include, lib and lib64 folders of gcc12, and I also added -L path to native libraries. This way I am sure gcc12 can't pickup one of its libraries for li nking. Not sure if this is good solution, but it works.

How to Compile Ncurses Program for Native Windows Use

I'm trying to compile a C program using Ncurses on Windows. I compiled it successfully using GCC and it works perfectly if I run it in Cygwin or MSYS2. However, if I try to run it in the Windows Command Prompt, I get this error:
Error opening terminal: xterm-256color.
Is it possible to compile it to run using the native Windows console? This is how I've been compiling it:
gcc -o PROGRAMNAME main.c -lncurses
I also have the Cygwin and Msys dlls for Ncurses copied into the directory of the compiled executable.
Update
So I figured out how to get the program to run. I deleted all the DLLs from the project folder and then added "C:\msys64\usr\bin" to my PATH environment variable. However, I would still like to know if there's a way to get this to work if I were to distribute it, since it's still relying on my installation of MSYS2.
Update 2
Gave up and just used pdcurses and it works fine.
Update 3
Nevermind, found a solution! See below.
I figured out a solution. I'll post it here in case anyone else has this same issue. Thanks to Thomas Dickey for your help!
Install the mingw-w64 toolchain and any other packages you need to compile your project (this is mostly where I messed up)
Make sure to include the /mingw64/include/ncurses directory when compiling, or else gcc won't be able to find curses.h
Include /mingw64/bin as a static directory or copy over the necessary dlls to the same folder as the directory
I ended up with this to compile:
gcc -I/mingw64/include/ncurses -o PROGRAMNAME main.c -lncurses -L/mingw64/bin -static

How to link and compile using specific library version installed at custom location?

I am trying to compile a program which uses GSL, in fact I am already able to compile it successfully on my local machine using
g++ -o program program.c prog0.o -L/usr/local/lib -lgsl -lgslcblas -lm
My problem is that I need to compile this program on a work machine in a shared system, but I know the program will not compile with an up to date version of GSL, so I need to install and use an older version.
I did this on my own system using the default installation, so the relevant files are located in /usr/local/lib on my local machine, and the compilation works for me with the above command.
But since the work machine is in a shared system, I cannot mess with the default directories, so I installed the correct GSL version on the work machine in my directory under /home/myname/gsl/.
So on the work machine the folder /home/myname/gsl/lib contains the same relevant files as the folder /usr/local/lib on my machine.
Now I did various attempts to try and tell g++ to use this custom installation folder, which I thought would come down to
g++ -o program program.c prog0.o -L/home/myname/gsl/lib -lgsl -lgslcblas -lm
but no success. No matter what I did g++ always used the GSL version installed on the shared system, even using just
g++ -o program program.c prog0.o
I only started programming C/C++ not long ago and only know the very basics of how to compile programs, so this linking thing is still always confusing me..
But as far as I can tell -L/dir/ should tell g++ to use the library in /dir/ and -lgsl -lgslcblas are the files which it should look for in that library... ?
But it seems g++ doesn't care what library I tell it here, it always seems to use whatever is in the PATH of the shared work system, which seems to include this up-to-date version of GSL that I cannot use. But I also cannot change the PATH since I only have access to my own subdirectories on the work system..
So how do I tell g++ to ignore the default version of GSL and use the one I installed manually at /home/myname/gsl/ ?
I figured out the answer, it is actually simple. The problem was just my lack of understanding proper usage of outside libraries and trying to fix the compilation command was the wrong approach.
In the code in program.c, gsl was included with
#include <gsl/gsl_blas.h>
and so on. Of course, the "<>" directly tell the compiler to look in known include directories, where the up-to-date GSL is installed on the shared system.. So the way to use a custom version was just to instead use
#include "/home/myname/gsl/lib/gsl_blas.h"
and so on, directly specifying that I want to use my custom installation.
I then compiled with
g++ -o program program.c prog0.o /home/myname/gsl/lib/libgsl.so /home/myname/gsl/lib/libgslcblas.so -lm
and it compiles successfully.
(This brought up some other unclarities for me, but at least this specific problem is solved.)

Fedora 21 with clang, without gcc

Can you (reasonably) get Fedora 21 to where it only has llvm/clang/libc++/libc++abi? (I found some things suggesting no, but they were all about 3 years old, and llvm/clang has come a long way since then.)
With a fresh install, I tried
yum install gcc gcc-c++
(downloaded, built, installed llvm/cfe(clang)/compiler-rt/libcxx/libcxxabi from svn)
yum remove gcc gcc-c++
added to /etc/profile: export CC=/usr/local/bin/clang \ export CXX=/usr/local/bin/clang++
(in case of hard wiring)
ln -s /usr/local/bin/clang /usr/local/bin/gcc
ln -s /usr/local/bin/clang /usr/local/bin/cc
ln -s /usr/local/bin/clang++ /usr/local/bin/g++
ln -s /usr/local/bin/clang++ /usr/local/bin/c++
ldconfig
I was all happy, then went to build something, and I got:
ld: cannot find crtbegin.o
ld: cannot find -lgcc
ld: cannot find -lgcc_s
clang -v includes
Found candidate GCC installation: /usr/lib/gcc/x86_64-redhat-linux/4.9.2
ldconfig && ldconfig -p | grep libgcc does show
libgcc_s.so.1 (libc6,x86-64) => /lib64/libgcc_s.so.1
And /lib64 is a symlink to /usr/lib64. And, /usr/lib64/libgcc_s.so.1 is a symlink to /usr/lib64/libgcc_s-4.9.2-20150212.so.1, which exists as a real file (92816 bytes.)
So, I don't get what ld's problem is on -lgcc_s. crtbegin is nowhere to be found, and gcc (no _s) is nowhere to be found.
yum install libgcc says it's already installed and latest version, nothing to do.
Since I have an installed clang source build, can I re-build clang, this time using clang rather than gcc, to get rid of the dependency? (Maybe then the "candidate GCC installation" bit goes away.)
Can I force -stdlib=c++ and -lc++abi to be default, or at least have libc++ and libc++abi installed without gcc?
Having spent some time trying to get clang to work with libc++ and libc++abi without GCC, I have found that it is indeed possible, even if a bit problematic given the current state of LLVM/clang. In addition to small test programs, I've been able to build CMake and some other software packages written in C++ with no GCC installed, and with the resulting binaries being independent of libstdc++; they only depend on libc++/libc++abi according to ldd output. Unfortunately, I haven't been able to build clang itself with clang that was build using GCC. I've been experimenting on different Linux platforms (Fedora 21 32-bit, Amazon Linux release 2015.3 (RPM-based) 64-bit, CentOS 7.1 64-bit, and Ubuntu 14.04 64-bit).
Even though one can build software with clang using libc++/libc++abi without dependency on libstdc++ and without GCC compiler present, a typical Linux installation is so tied to libgcc and libstdc++ that getting rid of these is not practical. Try removing these two packages and you will see how much of the system depends on them. Even on FreeBSD 10.1, with clang being the default compiler and no GCC installed, libgcc.a, libgcc_s.so, and a few crt*.o files are used when building a program as revealed by the -v option. Also, on FreeBSD 10.1, resulting binaries depend on libgcc according to ldd. On Ubuntu, which has dpkg as the package manager, the files
libgcc.a
libgcc_s.so
crtbegin.o
crtbeginT.o
crtbeginS.o
crtendS.o
crtend.o
are in the libgcc-devel package, while on an RPM-based system, such as Fedora, these are in the gcc package. In addition, you might possibly need these files, even though I didn't need them for the code I tried building:
crtfastmath.o
crtprec32.o
crtprec80.o
crtprec64.o
Thus one might argue that the aforementioned files better belong in libgcc, rather than in gcc. As far as I can tell, the following needs to be done on an RPM-based system before removing the gcc package:
1) Create the symlink
libgcc_s.so -> libgcc_s.so.1
in whatever directory libgcc_s.so.1 is located.
2) Copy the crt*.o files listed above to that directory.
3) In the same directory create the symlink (libstdc++.so.x should already be there; x is a number):
libstdc++.so -> libstdc++.so.x
You only need this if you are going to use libstdc++; this isn't needed if you only plan to use libc++. On some
systems libstdc++.so, which is a symlink to libstdc++.so.x belonging to the libstdc++ package, is placed by the libstdc++-devel package into the GCC library directory, so you can remove that directory after uninstalling GCC and just create the symlink in the same directory where libstdc++.so.x lives.
Now you should be able to do the following:
1) Build a C program:
clang progname.c
2) Build a C++ program using libstdc++ headers/libs:
clang++ -I<location of headers> progname.cpp
On RPM-based systems I've looked at, the libstdc++ headers are part of the libstdc++-devel package and their location can be found from rpm -ql on the package.
3) Build a C++ program using libc++ headers/libs:
clang++ -I/<location of headers> progname.cpp -nodefaultlibs -lc++ -lc++abi -lm -lc -lgcc -lgcc_s
The location of the headers is wherever they were installed when you built LLVM+clang etc.
Please see http://libcxx.llvm.org/ for additional information. When building C++ code using libc++/libc++abi, you may use -stdlib=libc++ instead of the -I flag, but in my testing that only worked with clang built from source, not with clang installed from a repository (you can install clang from repo and use it to build libc++/libc++abi; or you can use gcc to build libc++(abi), then remove gcc and use the libs with the repo-provided clang).
When configuring a software package to build it using clang + libc++, you might need to set the following:
LIBS="-nodefaultlibs -lc++ -lc++abi -lm -lc -lgcc_s -lgcc"
CXX=clang++
CXXFLAGS="-stdlib=libc++"
CC=clang
Please note that to configure CMake source in order to build it I had to use a wrapper script like this:
#!/bin/bash
MYLFLAGS="-nodefaultlibs -lc++ -lc++abi -lm -lc -lgcc_s -lgcc"
# Catch the case when we only want to compile; this helps us avoid some warnings:
if echo "$#" | egrep "(^-c | -c | -c$)" >/dev/null 2>&1; then
MYLFLAGS=""
fi
/usr/local/bin/clang++ -stdlib=libc++ "$#" $MYLFLAGS
It might be useful for other purposes as well.
For more information please see my article at http://www.omniprog.info/clang_no_gcc.html

Why is my shared library not found?

I'm trying to compile an example program that links to the shared library produced by Sundown. I'm compiling the program like so.
$ gcc -o sd sundown.c -L. -lsundown
Yet, when I run it I get the following error.
./sd: error while loading shared libraries: libsundown.so: cannot open shared object
file: No such file or directory
The output of ls is.
$ ls
libsundown.so libsundown.so.1 sundown.c sd
Why is the shared library not found by ld?
Short solution:
add . (or whatever it is from your -L flag) to your LD_LIBRARY_PATH. When you run sd, it'll look for libraries in the standard places and the LD_LIBRARY_PATH. Note that since you've added ., this will only work if you run sd from the same directory libsundown.so is in.
I plan on distributing the compiled binary. How can I do so that the library can be distributed without forcing people to edit their LD_LIBRARY_PATH?
You should install libsundown.so in one of the standard places, like /usr/lib or /usr/local/lib. You can do that with an installer or a make file, or something as simple as a INSTALL or README that tells the user to stick the libraries there and ensure the permissions are set to something sensible.
On Centos systems with /usr/lib and /usr/lib64, if you install 64-bit libs manually into /usr/lib then at runtime, the library may not be visible even though at build time it is visible (I used autotools and it was able to find my zopfli library from /usr/lib without any problem). When I execute the my_binary that links to /usr/lib/libzopfli.so.1 I got
libzopfli.so.1 => not found
After moving libzopfly.so.1 from /usr/lib to /usr/lib64, then everything works fine.

Resources