scons executable + shared library in project directory - c

Here's a sample SConscript file:
env = Environment()
hello_lib = env.SharedLibrary('hello', ['libhello.c'])
exe = env.Program('main', ['main.c'], LIBS=hello_lib)
env.Install('/usr/lib', hello_lib)
env.Install('/usr/bin', exe)
env.Alias('install', '/usr/bin')
env.Alias('install', '/usr/lib')
It builds one shared library, and one executable linked to that library:
$ scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
gcc -o libhello.os -c -fPIC libhello.c
gcc -o libhello.so -shared libhello.os
gcc -o main.o -c main.c
gcc -o main main.o libhello.so
scons: done building targets.
Now, the issue is the created executable will not find the shared library when running it from the project directory,
which is quite natural, since neither the LD_LIBRARY_PATH env variable is set, or
any RPATH is set in the executable:
[fedora 00:07:10 2 ~] $ ./main
./main: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory
I can always set the LD_LIBRARY_PATH variable while developing, but this becomes cumbersome if the project has a directory hierarchy with several shared libraries in sub_directories.
The GNU autotools/libtool solves this by automagically set the RPATH of the executable to wherever the shared libraries are built in the project directory, which allows for easy running/testing the executable while developing. And it relinks the executable when installing it to leave out those RPATH which arn't needed anymore.
Is there anything similar to what autotools does that can be done with scons to ease testing the executables while developing ?
Is there any recommended way to build applications using shared libraries with scons, that makes it easy to run the executable from the build directory ?

You could modify each of the SConscript files which produce libraries, like so:
hello_lib = env.SharedLibrary('#/lib/hello', ['libhello.c'])
All of your shared libraries are now located in a single directory.
The SConscript which produces an executable becomes:
exe = env.Program('main', ['main.c'], LIBPATH='#/lib', LIBS=hello_lib)
Then you will be able to set LD_LIBRARY_PATH to $PWD/lib.

It looks like you are looking for the RPATH option in scons.
From the wiki page, the RPATH is described as scons as the following.
A list of paths to search for shared libraries when running programs.
Currently only used in the GNU linker (gnulink) and IRIX linker
(sgilink). Ignored on platforms and toolchains that don't support it.
Note that the paths added to RPATH are not transformed by scons in any
way: if you want an absolute path, you must make it absolute yourself.

Related

Forcing gcc to only look in one directory for library files

So I am making a C application and I have all the library files .so , .a etc in a ./lib directory in the same directory as my C application.
I am compiling my C application with the -L./lib flag.
But it seems to me that gcc still looks for libraries within /usr/lib /usr/local/lib etc .
Is there a way to force gcc to only look for library files in my ./lib directory?
So if I remove the ./lib folder the application won't compile because it can't find the libraries.

I want to know what happened when I use the command "g++ -o main main.o -L<directory> -l<lib_name>"

Supposing I have main.c main.o libheymath.so in current directory. I want to link them together to generate an executable file. I use command "g++ -o main main.o -L./ -lheymath" to realize that. But I don't know why I should indicate the library directory and name. As far as I know, when I run "./main" the system will load the shared library into memory in specific directories such as /lib and /use/lib and directories specified in LD_LIBRARY_PATH etc. but not what I have indicated. So what's the purpose of "-L./ -lheymath"?
working directory files:
main.c, main.o, libheymath.so
command:
g++ -o main main.o -L./ -lheymath
./main
-L allows to indicates a path where to look to find lib(s) at link time (it is not 'saved' in the produced executable to be reused when you will launch the executable)
-l indicates a lib you want to link with, this allows to check if some symbols are missing or not and to know the list of libs to load when you will launch the executable.
When you link the path of these libs is not saved into the executable because both executable and libs can be moved after the link (and may be installed on an other host)
Note LD_LIBRARY_PATH is used when you start an executable to find the dynamic libs, it is not used when you link objects/libs to make an executable

How can I "register" my library libfoo.so to link it with `-lfoo`?

How can I "register" my library foo.c, compiled to libfoo.so, to link it with -lfoo? Is it by appending its path to LD_LIBRARY_PATH? Is it by running sudo ldconfig?
For curiosity, who do I "register" it with? That is, which application "needs to know" what -lfoo means in order for gcc bar.c -lfoo to work? Is it the bash environment? Is it gcc? Is it the kernel?
Is any of this different for static libraries (eg. libfoo.a)?
If your library is not in a "standard" library directory such as (eg. /usr/local/lib or /usr/lib) then you'll need to tell the compiler it's location -L when you link it -l:
$ gcc -L/home/username/foo -Wall -o test main.c -lfoo
| |
|__ location of libfoo.so or libfoo.a |__ link libfoo.so or libfoo.a
GCC assumes that all libraries start with ‘lib’ and end with .so or .a
(.so is for shared object or shared libraries, and .a is for archive,
or statically linked libraries).
-L is the location to search for libraries linked to your executable
-l links the library to the executable (-lfoo can be translated as "link library libfoo.so")
When using shared libraries sometimes simply linking them is not enough (eg. if the library is not installed in a standard location such as the example shown above). This is where using LD_LIBRARY_PATH, rpath or ldconfig comes into play. Static library paths won't need to be set like shared libraries since they are compiled with the executable.
LD_LIBRARY_PATH
$ export LD_LIBRARY_PATH=/home/username/foo:$LD_LIBRARY_PATH
Exporting this variable informs the run-time linker to look in the specified location for the libfoo.so library that's associated with the executable. LD_LIBRARY_PATH is more or less a temporary, or convenient way of setting a library's location.
rpath
$ gcc -L/home/username/foo -Wl,-rpath=/home/username/foo -Wall -o test main.c -lfoo
rpath works similarly to LD_LIBRARY_PATH (as libraries can reside almost anywhere in userland), however, rpath is linked to the executable at compile time, and sets a "fixed" library location.
ldconfig
Ultimately what might be the best solution is to use ldconfig, which creates the necessary links and cache to the most recent shared libraries found in the standard library locations and ones you can specify. It does require elevated permissions (eg. sudo) to set paths up this way, and should be used with a certain degree of caution.
$ sudo cp /home/username/foo/libfoo.so /usr/local/lib
$ sudo chmod 0755 /usr/local/lib/libfoo.so
This copies the library into /usr/local/lib with permissions set to be readable by everyone.
$ sudo ldconfig
$ ldconfig -p | grep foo
libfoo.so (libc6) => /usr/local/lib/libfoo.so
Then we update the loader cache, and verify the path is set correctly.
$ gcc -Wall -o test main.c -lfoo
By using ldconfig, the -L option, LD_LIBRARY_PATH or rpath now shouldn't be needed.
Additional Information
↳ Shared Libraries With GCC on Linux

Prevent autotools from setting rpath when compiling my program

I'm working on an example autotools project which builds a shared library and a program. The program should link to the shared library. But when I build the program libtool will set the rpath like this:
RPATH=/usr/local/lib
which I don't want.
According to the Debian Wiki libtool isn't supposed to set the rpath when the library is in the default search path (libtool's role).
According to this site /usr/local/lib should be in the default search path of the linker.
The library and the program are build by the same autotools project, so the library is not installed when the program is build.
Does anybody have an idea why libtool sets the rpath anyway?
with readelf readelf -d libfftw3_mpi.so you can check if your lib contains such a attribute in the dynamic section.
with export LD_DEBUG=libs you can debug the search path used to find your libs
with chrpath -r the rpath can be changed
As answered in https://stackoverflow.com/a/33520976/4379130 by #bonoparte

C Shared Library : No Such File or Directory Upon Execution

first off, this is a programming assignment so you are aware.
Anyhow, what I am trying to do is include a shared library I wrote (a linked list from a previous project) in with my own shell I am writing. The issue I incur is that when I compile using my Makfile, the compile is successful. Then when I try to run my executable (let's say it's called prog), I get the following:
[terminal]# ./prog
./prog: error while loading shared libraries: libmylib.so: cannot open shared object file: No such file or directory
The following is my file structure for reference:
include
|_
common.h
List.h
Node.h
lib
|_
libmylib.a
libmylib.so
libsrc
|_
Makefile // This makefile builds the library correctly and puts it in lib via 'make install'
List.c
List.h
Node.c
Node.h
common.h
Makefile
prog.c
Here is my main Makefile
CC=gcc
CFLAGS=-g -Wall -Llib
LIBS=-lreadline -lncurses -lmylib
PROGS=library prog
all: $(PROGS)
library:
cd libsrc; make install
prog: prog.o
$(CC) $(CFLAGS) -o $# $< $(LIBS)
clean:
cd libsrc; make installclean
/bin/rm -f *.o $(PROGS) a.out core *.log
Any help or advice is appreciated, thanks!
The runtime dynamic linker does not know where to find your shared library.
Two options:
Set the LD_LIBRARY_PATH environment variable to include the absolute path to your lib directory:
LD_LIBRARY_PATH=/path/to/lib
export LD_LIBRARY_PATH
Hard-code the absolute path to your lib directory in the executable image by passing -R/path/to/lib to the linker (e.g. in your makefile, CFLAGS=... -Llib -R/path/to/lib.
The first option is flexible, in the sense that the shared library can be installed anywhere and even moved to another location, and the executable won't break as long as the environment variable is updated accordingly. But it does require the user (or system administrator) must set up the environment correctly.
The second option does not allow the shared library to be moved from its predefined installation directory, but removes the dependencies on a correctly setup environment.
Note that you won't need to do either if you install your shared library in a standard system-specific location (e.g. /usr/lib or /usr/lib64 on Unix/Linux) as the runtime linker will search such locations automatically.

Resources