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

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.

Related

How to deploy a shared library?

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.

Makefile not generating object code or executable

I'm trying to write a makefile that generates assembly code, object code, and an executable from a .c file. This is the contents of my makefile:
good_echo.s: good_echo.c
gcc -S -fstack-protector-all good_echo.c
good_echo.o: good_echo.s
gcc -S good_echo.s -o good_echo.o
good_echo: good_echo.o
gcc -v good_echo.o -o good_echo
clean:
rm -f good_echo.o good_echo.s good_echo
When I enter make into terminal, it only generates the assembly code. Can someone explain what's going on?
If you check the GNU make manual How make Processes a Makefile you'll notice this sentence:
make reads the makefile in the current directory and begins by processing the first rule.
Followed by in the next paragraph:
If some other rule is not depended on by the goal (or anything it depends on, etc.), that rule is not processed, unless you tell make to do so (with a command such as make clean).
Here your first rule says to build good_echo.s, and none of the other targets are prerequistes of that, so it's the only one built.
If you run make good_echo then all will be built. Alternatively you can ensure that the rule to build the target good_echo is the first rule in your makefile.
Or, you can use an often-used idiom and create a target all as the first rule which depends on the things you want to generate:
all: good_echo
To be clear, other than the first rule in the makefile it's not important in which order the rules are defined.
ETA
As pointed out by Joseph Quinsey in the comments, your rule here:
good_echo.o: good_echo.s
gcc -S good_echo.s -o good_echo.o
is incorrect. The -S option tells the compiler to stop after generating assembly and write it out, but already have assembly as your input. You want an object file, so you should use the -c option to tell the compiler to stop after generating an object file (and not try to link):
good_echo.o: good_echo.s
gcc -c good_echo.s -o good_echo.o
To be more clear: the compiler can infer what type of input it's given by using the extension to the file (in this case .s means assembly)--or you can force it with the -x option if you prefer--but it won't infer the type of output you want: you always have to tell it that with options such as -c, -S, and -E. If you don't use any of those then it will run all steps and try to generate an executable program.

How to make scons make gcc with assembly file during compilation?

For example, I've got a 'b.c' file, I compile and generate the code, while I wish to see an intermediate assembly file, I can do under shell like this:
gcc -S b.c
gcc -c b.c
gcc b.o -o b
My question is, how to specify inside scons SConstruct, with all these steps, to make sure I get b.s, b.o and 'b' executable? Seems scons only support functions like Program, Object, Library, so I only get b.o and 'b'. But how to make out 'b.s', while I don't wish to introduce any duplicated work by the compiler(to save time).
Thanks.

Update include path in linux

I have few header files in /my/path/to/file folder. I know how to include these files in new C program but everytime I need to type full path to header file before including it. Can I set some path variable in linux such that it automatically looks for header files ?
You could create a makefile. A minimal example would be:
INC_PATH=/my/path/to/file
CFLAGS=-I$(INC_PATH)
all:
gcc $(CFLAGS) -o prog src1.c src2.c
From here you could improve this makefile in many ways. The most important, probably, would be to state compilation dependencies (so only modified files are recompiled).
As a reference, here you have a link to the GNU make documentation.
If you do not want to use makefiles, you can always set an environment variable to make it easier to type the compilation command:
export MY_INC_PATH=/my/path/to/file
Then you could compile your program like:
gcc -I${MY_INC_PATH} -o prog src1.c src2.c ...
You may want to define MY_INC_PATH variable in the file .bashrc, or probably better, create a file in a handy place containing the variable definition. Then, you could use source to set that variable in the current shell:
source env.sh
I think, however, that using a makefile is a much preferable approach.
there is a similar question and likely better solved (if you are interested in a permanent solution): https://stackoverflow.com/a/558819/1408096
Try setting C_INCLUDE_PATH (for C header files) or CPLUS_INCLUDE_PATH (for C++ header files).
Kudos:jcrossley3
I'm not in Linux right now and I can't be bothered to reboot to check if everything's right, but have you tried making symbolic links? For example, if you are on Ubuntu:
$ cd /usr/include
$ sudo ln -s /my/path/to/file mystuff
So then when you want to include stuf, you can use:
#include <mystuff/SpamFlavours.h>

Strip Linux kernel sources according to .config

Is there any efficient way (maybe by abusing the gcc preprocessor?) to get a set of stripped kernel sources where all code not needed according to .config is left out?
Well got some steps into a solution.
First, one can obtain the used compiler commands by
make KBUILD_VERBOSE=1 | tee build.log
grep '^ gcc' build.log
For now, I select only one gcc command line for further steps. For example the build of kernel/kmod.c, it looks like:
gcc <LIST OF MANY OPTIONS> -c -o kernel/kmod.o kernel/kmod.c
I now remove the option -c, -o ... and add -E, thus disabling compilation and writing preprocessor output to the screen. Further I add -fdirectives-only to prevent macro expansion and -undef to remove the GNU defined macro definitions. -nostdinc to remove the standard c headers is already added by the kernel makefile.
Now includes are still included and thus expanded on the preprocessor output. Thus I pipe the input file through grep removing them: grep -v '#include' kernel/kmod.c. Now only one include is left: autoconf.h is included by the Makefile's command line. This is great as it actually defines the macros used by #ifdef CONFIG_... to select the active kernel code.
The only thing left is to filter out the preprocessor comments and the remaining #defines from autoconf.h by means of grep -v '^#'.
The whole pipe looks like:
grep -v '#include' kernel/kmod.c | gcc -E -fdirectives-only -undef <ORIGINAL KERNEL BUILD GCC OPTIONS WITHOUT -c AND -o ...> - |grep -v '^#'
and the result is a filtered version of kernel/kmod.c containing the code that is actually build into kmod.o.
Questions remain: How to do that for the whole source tree? Are there files that are actually build but never used and stripped at linking?
Kernel Minimization Script :
A project inspired by this question and providing an easy answer...
It contains a Python script that generate a minimized sources code during build time. The new minimized source tree will only contain used sources. (project page)
Info :
The script is tested working with the kernel v4.14.x, however building the kernel one more time from those generated minimized sources require to copy make files and Kconfig files etc... at least we could easily isolate only used source for investigations and development
Usage :
cd /kernel/sources
make
wget https://github.com/Hitachi-India-Pvt-Ltd-RD/minimization/raw/master/minimize.py
export PATH=$PATH:`pwd`
make C=2 CHECK=minimize.py CF="-mindir ../path-to-minimized-source-tree/"
Note & Reminder :
If we are building within and against the targeted machine, we also have the make localmodconfig command that shrink the current config file with only the currently used modules, if used before "Minimization" it will generate further more stripped sources
Compile everything and use atime to find out which files were not used. It might not be very accurate but it's probably worth a try.

Resources