C is the programming language used for the kernel and C++ the object oriented alternative to C. Both are supported by gcc.
To compile it (-o hello produces hello as output file instead of the default a.out)
gcc -o hello hello.c
Check that the file hello as the executable permission and run it
./hello
If programs are getting bigger, they get split in multiple file. This has different advantages. A file can be reused somewhere else. Not every thing has to be recompiled just the file edited. Here the hello world program split in two files:
Example 15.3. hello c function
#include <stdio.h> void printhello(void) { printf("Hello World!\n"); }
Now gcc has to be called differently:
gcc -c hello.c
gcc -c printhello.c
The result is not a running program. The two object files hello.o and printhello.o are produced. The-c option tells gcc to do so and not producing absolute addresses. To get a running program the object files have to be put together using a linker. Instead of calling the linker ld directlygcc can be called.
Gccstands for Gnu Compiler Collection and not Gnu C Compiler. Gcc can be used for different things: C compiler, assembler, linker, ...
The following command links the two object files into the program hello:
gcc hello.o printhello.o -o hello
Now it can be run with
./hello
To access the command line parameters and the environmental variables of the parent process declare main as follows:
int main(int argc, char *argv[], char *envp[]) { return(0); }
argc contains how many parameters are passed. There is always one, the command line that has called the C program.
argv[] is an pointer to an array containing all command line parameters available
envp[] is a pointer to an array containing all environmental parameters as strings formatted NAME=value, luckily you do not have to search trough them, there is a function that gets the values assigned to the names. Example how to get the hostname:
#include <stdlib.h> char* host; host = getenv("HOSTNAME");
The return function exits and gives back a number to the parent process.
IDE's seem the way to go and the first results might be quickly be achieved, however when in trouble, the command line options and concepts have to be understood even when working with a IDE. Additionally IDE's offer so much functionality, as automatic documentation, publishing and archiving code, version control, gui support for various libraries, debugging, code analyze, multiple language support, and many or too many more. So often if you open an IDE you do not get the overview and struggle with the project files.
emerge codeblocks for C++ using it works without autotools and make file. It is a ready to go environment that works as desired. Libraries have to be added under Project > Build Options > Linker Settings where the library name without lib or l has to be added. Command line arguments can be set under Project > Set programs arguments. Codeblocks is also available for Windows.
anjuta is and IDE for gnome
Kdevelop is a very big Integrated Development Environment (IDE) to create your own programs in various programming languages and endless options and features. For small programs the size of the program is smaller than the size of the makefile that Kdevelop has created for you and you spend more time troubleshooting Kdevelop than writing your own program. Maybe the situation looks different when you are a professional programmer or you work in a team. For a hobby programmer, Kdevelop is probably an overshoot.
eclipse has is a huge IDE originally developed for java, but has all kind of plugins available for any kind of programming languages.
Or why not keep it simple and use just an editor with syntax highlighting, gcc and make your makefile (or Makefile) using an editor. Do not forget to add -g to your makefile to have the info required to debug in your program. Then compile it in a console by calling make. This way has the obvious advantage that you know what is going on and you can concentrate yourself to the creation of your own program.
working with eclipse the CDT has to be installed, this is best done via marketplace. Marketplace should be available under help (if not install marketplace). Then the CDT has to be found, the Marketplace Yoxos has it. There appear many packages that are related to CDT with big icons, so it takes a while to find the small icon of the CDT.
Everything to be seen in eclipse is a Perspective, so open the C/C++ perspective. When done with it open the Debug Perspective to test your code.
If there is just one c file as the hello.c
then make and makefile
are not useful, since a single gcc
call will do everything. However when there are many different files it is obviously desired to not compile
every file when just one got changed. However when one got changed, then the onces depending on the changed
one need to compiled as well. The main goal of the makefile
is to write down the dependency and have the
program make to do all necessary but not more. By the way, make is not restricted to C programming, it can
call other command lines not containing gcc commands.
To know what has changed make looks at the modification dates of the files, therefore make sure your clock is running well!
Example makefile
created by a text editor and put in the directory where c and h files reside.
Very important is that the indents are done with the tab character. Make also sure that you editor really inserts tab and not spaces.
<target filename>
:<source filename>
.c<source filename>
.h gcc -g <filename>.c -o <filename> clean: rm -f *.o # is the character to define the line as comment
The first line starts with a file name, that is used as target. It defines a dependency rule, when one of its source file is newer then the target file, then
the second line is executed (and more when present). Lines containing commands must begin with the tab character.
The third line containing the word clean is a phony target, since no file named clean exists. Calling make clean executes all commands put below the third line.
The makefile for the split hello world file would look like:
hello: hello.o printhello.o gcc hello.o printhello.o -o hello hello.o: hello.c gcc -c hello.c printhello.o:printhello.c gcc -c printhello.c clean: rm -f *.o
To not edit everywhere when the make file is getting used for a new project or if the files get a new name or if you want to set standard compiler options, you can work with variables:
name=hello include=printhello $(name): $(name).o $(include).o gcc $(name).o $(include).o -o $(name) $(name).o: $(name).c gcc -c $(name).c $(include).o:$(include).c gcc -c $(include).c clean: rm -f *.o
If some files are in other directories then the -I option can be used to pass the path:
-I/<path to file>
To compile, open a shell and go to directory, then type make.
Per default the destination files of gcc are called a.out. The option -o selects an other name.
Having added the clean section in the makefile as shown above, the command make clean cleans the directory from object files no longer used.
Finally be aware that gcc is normally used to emerge <Gentoo ebuilds>
and is therefore set to
produce code optimized for speed. The variables defined in
/etc/make.conf
are passed to gcc, so check those
options
CHOST="i686-pc-linux-gnu" CFLAGS="-O2 -march=athlon-xp -pipe -fomit-frame-pointer" CXXFLAGS="${CFLAGS}" MAKEOPTS="-j2"
Those options are OK, but the -fomit-frame-pointer produces long reaction time when you debug your c
program. Therefore you might consider to change /etc/make.conf
while you are in a longer debug session.
Built runnable binaries can be copied to /usr/local/bin
to be used outside of the development environment. Better would be putting just links
there to your executable and add a version number to your executable file name. So you are prepared for new
versions. However you should not copy executables manually, you should install them following the rules of
your Linux distribution to not make a mess. For Gentoo this means you should write an ebuild.
I don't think you want to debug in a console, so use a front end for dgb the console debugger. By the way, also the big development environments as Kdevelop are no more than a front end for gdb when it comes to debug.
Make sure you complied it with the option -g that adds information for the debugger into the executable. Executables under Linux are not just raw program code, as used in embedded systems and other operating systems, they are formatted elf files. Elf files have different section and using the -g option the debugging section is added. To observe the hello executable:
readelf --all hello
objdump -h hello
Maybe make refuses to recompile after just editing the makefile, so edit the source file or delete the executable.
to debug in the console start gdb by gdb<my program>
Then type some commands as:
Table 15.1. gdb
run | run the program until it exits, finds a break point or error |
print <variable name>
|
show contents of a variable |
quit | quit gdb |
break <function name>
|
set a breakpoint to a function |
next | single step |
nexti | single step |
help | show help |
Insight is an other front-end for gdb. It uses tk.tcl and wants it in a certain location, otherwise it fails.
To execute a program type ./<filename> ./ is your current directory so bash finds the executable.
To use Libraries include
#include <math.h>
to the source code, but this might not be enough.
/usr/lib
contains the mathematic
library libm. To use it with gcc you must tell gcc by adding -lm that you want it. -l stands for including
libraries and m is the short name of libm, where lib gets wiped off. So the gcc command line in the
makefile becomes:
gcc -g <source>.c -lm -o <source>
This has to be done for all libraries. The only exception is glibc the global C library.
For the libncurses add: -lcurses
For libraries not in /usr/lib
the option -L
can be used to tell gcc where they are.
-L /usr/X11R6/lib
Instead of finding out where the libraries are and use this hard coded pkg-config can be used. It will be available after emerge pkgconfig. To see what it does call it as:
pkg-config --libs --cflags modbus
and when you have libmodbus installed you get: -lmodbus
After this test you will understand what the following does:
gcc random-test-slave.c -o random-test-slave `pkg-config --libs --cflags modbus`
If code is used again and again, then it is time to put it into a library and make it easily available. The code is compiled as usual with the -c option so the linker will not be involved. The following shows how the split hello world program makes use of a library:
gcc -c printhello.c
The output is a object file printhello.o. A number of such files can be added into a library archive <library>.a
ar r<library>
.a <code1>
.o <code2>
.o
For the printhello.o the command looks as:
ar r libhello.a printhello.o
After running ar, ranlib can be used to add an index of the contents to the file to speed up its use.
ranlib libhello.a
Using the following commands the content of a library can be observed
ar t libhello.a
nm -s libhello.a
After having the library it can be used as:
gcc -o hello hello.c libhello.a
or
gcc -o<program> <program>
.c /<path to>
/<library>
.
a
or as standard libraries in /usr/lib
but telling
with -L where the library is
gcc -o<program> <program>
.c -L/<path to library>
-l<library-lib>
or for the hello world
gcc -o hello hello.c -L/<path>
-lhello
Note, that using this commands the library code is inserted to the program, therefore it is called statically linked libraries. With each program using the library code, a copy of the library code is loaded into the memory.
Statically linked libraries can reside multiple times in the memory. More ideal would be loading the library into memory with the first program demanding it and then share it with all demanding programs. This is the concept of the dynamically linked libraries. Those files end with .so (shared object) suffixes in their names.
Since the library and program are separate files there is a potential for a version conflict. Additionally dynamically linked libraries must be known by the operating system, this is an additional potential to run in troubles.
Version numbers are added to the files. To have a certain flexibility when the version numbers do not match exactly, there is a major and a minor version number. The shared object files appear therefore in multiple forms:
realname |
/usr/lib/libhello.so.1.0 |
Holds the code and is therefore the shared object file |
|
soname |
/usr/lib/libhello.so.1 |
Is a link to realname and allows an evolution |
|
linkername |
/usr/lib/libhello.so |
Name that the linker uses |
When the program gets loaded by the run-time linker, /lib/ld.so or /lib/ld-linux.so, Linux needs to
know where the library is, this information comes out of the linker cache
/etc/ld.so.conf
that is a binary file and ldconfig updates it.
The directories where shared objects are to be expected are listed in: /etc/ld.so.conf. If it will not be found in the linker cache (where just the most recent are) then it will scan certain directories.
The addresses where the code in dynamically linked libraries are placed can not be fixed. Therefore Position Independent Code (PIC) is required that is created with the gcc option -fPIC. To build a shared object compile the code as:
gcc -fPIC -c printhello.c
Then link it to a shared object
ld -shared -soname libhello.so.1 -o libhello.so.1.0 -lc printhello.o
then as root, copy libhello.so.1.0 to /usr/lib
,
/lib
or
/usr/local/lib
>
create necessary links and cache
ldconfig -v -n
Now an application to test the shared object is necessary. Assuming the shared object has been put
in /usr/lib
the following command applies:
gcc -o hello hello.c -L/usr/lib -lhello
And now it can be tested:
./hello
To observe what the system knows about it and to get information when trouble shooting, the following commands can be used:
To see dependency of the test program hello:
ldd hello
linux-gate.so.1 => (0xffffe000)
libhello.so.1 => /usr/lib/libhello.so.1 (0xb7f73000)
libc.so.6 => /lib/libc.so.6 (0xb7e4b000)
/lib/ld-linux.so.2 (0xb7f99000)
To see other stuff about the program (as 32 bit or 64 bit):
file hello
hello: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.9, dynamically linked (uses shared libs), not stripped
To see whats inside the shared object:
nm libhello.so.1.0
00001f4c a _DYNAMIC
00001ff4 a _GLOBAL_OFFSET_TABLE_
00002004 A __bss_start
00000276 t __i686.get_pc_thunk.bx
00002004 A _edata
00002004 A _end
00000250 T printhello
U puts@@GLIBC_2.0
Or even more
objdump -x libhello.so.1.0
Inside the shared object there two functions can be added that will be called each time the library is accessed. The following is a sample code that prints those events to the screen:
Example 15.4. Dynamic library
void _init() { printf("Inside _init()\n"); } void _fini() { printf("Inside _fini()\n"); }
There is not just gcc. there is clang http://clang.llvm.org/ a C language front-end for the llvm compiler infrastructure https://llvm.org/