How to deploy a shared library? - linux

I would like to "quickly" deploy a shared library on my Ubuntu. It is for a short term project so I don't want to use auto-tools here, but do everything manually.
So I built my library with this:
%.o: %.c
$(CC) -fPIC -c $(CFLAGS) -o $# $< -MMD -MF $(#:.o=.d)
lib%.so: %.o | dist
$(CC) -shared -o dist/$# $^
dist:
mkdir -p dist
install: lib
mkdir -p $(PREFIX)/lib/foobar
mkdir -p $(PREFIX)/include/foobar
cp dist/*.so $(PREFIX)/lib/foobar
cp dist/*.h $(PREFIX)/include/foobar
ldconfig $(PREFIX)/lib/foobar/
In another project, I would like to use libfoo.so now located in /usr/lib/foobar/libfoo.so. So I've built it with:
$(CC) test.c -lfoo
Unfortunately I have this issue:
/usr/bin/ld: cannot find -lfoo
I now that I can do -L/usr/lib/foobar/libfoo.so but this location should be known by my operating system.
Am I forced to put it directly into /usr/lib? I have the same issue with /usr/local/lib which doesn't seem to be the default route to be used with gcc ... -l...
How should I normally deploy a shared library?

The list of directories from ld.so.conf has system-wide impact; the runtime linker will search those dirs when starting any dynamic binary. Unless you actually want additional system-wide overhead, it's more efficient to privately search another dir on a custom / as-needed basis. Private-search is ideally suited for cases of 1-off or single-use or rarely-used custom libs.
For the 1 or few bins that reference those libs, bins can be rebuilt with a directive for the runtime linker to privately search 1+ custom dirs; eg:
gcc -L/usr/local/lib64 -Wl,-rpath=/usr/local/lib64 -lblah
For more details, see gcc and ld manual pages for the respective options -Wl, and -rpath.

To make a directory known to the dynamic linker (ld.so) so that it can be found at run-time without depending on LD_LIBRARY_PATH:
list it in /etc/ld.so.conf (or in an include file under /etc/ld.so.conf.d, if the main /etc/ld.so.conf file has an appropriate include statement to enable this)
then run /sbin/ldconfig
As regards the build-time linker (ld), it is normal to expect to have to specify the library location explicitly using the -L flag on the compiler, normally with the directory as argument e.g. -L/usr/lib/foobar. However, according to the manual page for the compile-time linker, ld, the search path for libraries does contain (after everything else) the directories referenced by /etc/ld.so.conf. So although ld.so.conf is primarily intended for use with the run-time linker as the name suggests, the build-time linker will in fact find your library once you have listed the directory there.

Related

What is the principal difference between make command and running build .sh script?

In this Linux manual is written that make is:
a utility for building and maintaining groups of programs (and other
types of files) from source code.
Description The purpose of the make utility is to determine
automatically which pieces of a large program need to be re-compiled,
and issue the commands necessary to recompile them.
What does automatic determination mean here? What is the principal/significant difference between running make or just running ./build.sh where I have my build scripts?
What is the principal/significant difference between running make or just running ./build.sh where I have my build scripts?
make can be easily used in such a way that it only rebuilds what needs to be rebuilt (and nothing more than that).
Comparative example
Consider a project to be built, program, consisting of the following files:
main.c
foo.c
bar.c
foo.h
bar.h
For this discussion, let's assume that foo.c and bar.c only include (i.e.: depend on) foo.h and bar.c, respectively.
With a build.sh script which simply consists of commands for building a software like the following:
gcc -c foo.c
gcc -c bar.c
gcc -c main.c
gcc foo.o bar.o main.o -o program
If just foo.h gets modified, this project needs to be rebuild. With this approach, this will be done by re-running build.sh, which compiles all the source files. Note, that neither bar.o nor main.o would actually need to be generated again, since the files bar.c, bar.h, main.c didn't changed and they don't depend on foo.h at all (i.e.: they are not affected by a change in foo.h).
With make however, if used properly, a dependence graph is generated, so that only the files that need to be updated would be generated again: in this case foo.c and program.
That relies on the dependency relationship between the source files and object files (among other things) being properly specified to make. This is achieved by means of a makefile:
program: main.o foo.o bar.o
gcc -o $# $^
foo.c: foo.h
bar.c: bar.h
Basically, it is explicitly specifying that:
program depends on main.o, foo.o and bar.o.
foo.c depends on foo.h.
bar.c depends on bar.c.
and implicitly:
main.o depends on main.c
foo.o depends on foo.c
bar.o depends on bar.c
That way, make knows what has to be rebuilt or updated whenever something changes and it updates only that instead of building everything from scratch.

How to understand "Building Separate Files" for a Linux kernel module?

Excerpted from the Linux kernel documentation:
2.4 Building Separate Files
It is possible to build single files that are part of a module.
This works equally well for the kernel, a module, and even for
external modules.
Example (The module foo.ko, consist of bar.o and baz.o):
make -C $KDIR M=$PWD bar.lst
make -C $KDIR M=$PWD baz.o
make -C $KDIR M=$PWD foo.ko
make -C $KDIR M=$PWD /
I can't understand what these commands mean.
make -C $KDIR M=$PWD bar.lst
Does it mean: look for bar.c and compile it into bar.1st?
make -C $KDIR M=$PWD foo.ko
Does it mean: look for all *.o and link them into foo.ko? Does it also look for *.1st?
make -C $KDIR M=$PWD /
What does it mean?
First let's understand
make -C $KDIR M=$PWD [target]
here target can be anything defined as target (i.e. bar.o : )
mostly we use dependency in make file.
in given example three files
foo.c
bar.c
baz.c
foo.c has module_init i.e entry point
the statement states that we can build all files at once.
or single files individually and link them together finally.
in a nutshell you can try compiling just bar.c without compiling other two files. producing only bar.o
once all .o files are generated you can create.ko file.
refer linux/fs/ufs/Makefile
in you can compile once ufs.ko or
balloc.o cylinder.o dir.o file.o ialloc.o inode.o etc.
and compile ufs to create ufs.ko
Those commands all mean "do whatever the makefile says is necessary to build the named target". What the set of actions involved in doing that is I can't say and will depend entirely on what the specific target is.
If you want to know, specifically, what make will do for a given command give it the -n argument.

Dynamic library in Linux

When we creating a binary using the Dynamic library we apply gcc -o binary main.o -L. -lmylib -Wl,-rpath,. where -L. indicate that linker must search library in current directory. Why without -Wl,-rpath,. we can't use the dynamic library?
There are several directories in the system where ld.so looks for libraries. If your library is not in a directory from that list, you have two alternatives:
Specify path to it in the LD_LIBRARY_PATH variable;
Write path to it in the rpath of the binary.
You can change/view rpath of the binary using chrpath.
Difference betwee -rpath and -L:
-rpath=dir
Add a directory to the runtime library search path. This is used
when linking an ELF executable with shared objects. All -rpath
arguments are concatenated and passed to the runtime linker, which
uses them to locate shared objects at runtime.
vs.
-L searchdir
--library-path=searchdir
Add path searchdir to the list of paths that ld will search for
archive libraries and ld control scripts.
( What's the difference between -rpath and -L? )
By default, ld.so searches in the directories specified by LD_LIBRARY_PATH. If your shared lib isn't in one of those, it won't be found.
The -rpath option to ld causes it to store a pathname in the executable that ld.so will look in.

how to tell "gmake" to use another version of GCC? (Linux)

I have the usual gcc on my machine (at /usr/bin/gcc), and another one (newer) is linked when I setup the environment for a certain framework which I'm working on.
And I would like to compile with the old one I have on /usr/bin/gcc, instead of using the newer one.
I have to use "gmake" command for the compilation (custom compilation setup).
Without changing the PATH, how could I "tell" gmake to use a different gcc?
from command line:
gmake CC=/usr/bin/gcc
Use
make CC=/opt/bin/my-gcc
And make sure that for compilation you use $(CC) instead of direct gcc:
foo.o: foo.c
$(CC) -c foo.c -o foo.o
If you use default compilation patters the gmake uses CC variable by default
In your makefile, define a variable for your preferred compiler.
CC=/usr/bin/gcc
And after your target, use the variable.
a.o : a.c
$(CC) ...

What is the difference between -I and -L in makefile?

What is the usage of the -I and -L flags in a makefile?
These are typically part of the linker command line, and are either supplied directly in a target action, or more commonly assigned to a make variable that will be expanded to form link command. In that case:
-L is the path to the directories containing the libraries. A search path for libraries.
-l is the name of the library you want to link to.
For instance, if you want to link to the library ~/libs/libabc.a you'd add:
-L$(HOME)/libs -labc
To take advantage of the default implicit rule for linking, add these flags to the variable LDFLAGS, as in
LDFLAGS+=-L$(HOME)/libs -labc
It's a good habit to separate LDFLAGS and LIBS, for example
# LDFLAGS contains flags passed to the compiler for use during linking
LDFLAGS = -Wl,--hash-style=both
# LIBS contains libraries to link with
LIBS = -L$(HOME)/libs -labc
program: a.o b.o c.o
$(CC) $(LDFLAGS) $^ $(LIBS) -o $#
# or if you really want to call ld directly,
# $(LD) $(LDFLAGS:-Wl,%=%) $^ $(LIBS) -o $#
Even if it may work otherwise, the -l... directives are supposed to go after the objects that reference those symbols. Some optimizations (-Wl,--as-needed is the most obvious) will fail if linking is done in the wrong order.
To really grok a makefile, you need to also have a good understanding of the command lines for all of the components of your project's toolchain. Options like -I and -L are not understood by make itself. Rather, make is attempting to create a command line that will execute a tool to transform a prerequisite file into a target file.
Often, that is a C or C++ source file being compiled to an object file, and eventually linked to get an executable file.
In that case, you need to see the manual for your compiler, and especially the bits related to the command line options it understands.
All that said in generic terms, those specific options are pretty standard among compilers and linkers. -I adds a directory to the list of places searched by the compiler for a file named on a #include line, and -L adds a directory to the list of places searched by the linker for a library named with the -l option.
The bottom line is that the "language" of a makefile is a combination of the syntax of the makefile itself, your shell as known to make (usually /bin/sh or something similar), common shell commands (such as rm, cp, install, etc.), and the commands specific to your compiler and linker (e.g. typing gcc -v --help at your shell prompt will give you a nearly complete (and extremely long) list of the options understood by gcc as one starting point).
One thing to note is that these are the options passed to the compiler/linker.
So you should be looking at the compiler man pages/documentation to know their role.

Resources