1. Session About C programming under Linux Fossconf (Feb 27 2009 - Mar 1 2009) Mohan R C under Linux
2. Why C? Four Steps GNU tool for preprocessing GNU tool for compiling GNU tool for linking GCC Displaying Symbol table Stripping Libraries Static Library Shared Library Make Autotools Packages References Overview
3. *nix systems are C's Homegrounds C is not all about Alt+F9 and Ctrl+F9 You can see the full usage of C in *nix systems. World is moving towards ARM. C is a good friend to ARM. A developer will be happy If his software sucks little memory and run so fast. Why C?
4. Preprocessing: Its a process to resolve C macros in a C Source File. Compiling: Its a process to convert C Source File into Assembly Source File. Assembling: Its a process to convert Assembly Source File into Binary Object File. Linking: Its a process to make the Binary Object File into an Executable Program Four Steps
5. 'cpp' to preprocess C macros: 'cpp' is used to process C macros in a C Source File. $ cat > main.c #define TRUE 1 int main(int argc, char **argv) { int true = TRUE; return(0); } $ cpp main.c # 1 "main.c" # 1 "<built-in>" # 1 "<command-line>" # 1 "main.c" int main(int argc, char **argv) { int true = 1; return(0); } $ GNU tool for preprocessing
6. 'cc1' for Compile: 'cc1' is used to convert C Source File to Assembly Source File. $ cat > main.c #include <stdio.h> int main(int argc, char **argv) { printf(“Hello World”); return(0); } $ cpp main.c main.i $ # the below command line is executed in 'ubuntu 8.10' $ /usr/lib/gcc/i486-linux-gnu/4.3.2/cc1 main.i main Execution times (seconds) preprocessing : 0.00 ( 0%) usr 0.00 ( 0%) sys 0.01 (20%) wall 11 kB ( 2%) ggc parser : 0.02 (67%) usr 0.00 ( 0%) sys 0.03 (60%) wall 138 kB (23%) ggc thread pro- & epilogue: 0.01 (33%) usr 0.00 ( 0%) sys 0.00 ( 0%) wall 1 kB ( 0%) ggc TOTAL : 0.03 0.00 0.05 594 kB $ ls main.c main.i main.s $ cat main.s .file "main.i" .section .rodata .LC0: .string "Hello World” [long output continues...] $ GNU tool for Compiling
7. 'as' the GNU Assembler: 'as' is used to convert Assembly Source file into Binary Object file. Its default output is a.out, but we can't use it as an executable unless resolving its symbols. $ cat > main.c #include <stdio.h> int main(int argc, char **argv) { printf(“Hello World”); return(0); } $ cpp main.c main.i $ /usr/lib/gcc/i486-linux-gnu/4.3.2/cc1 main.i >/dev/null 2>&1 ; ls main.c main.i main.s $ as main.s ; ls a.out main.c main.i main.s $ ./a.out bash: ./a.out: Permission Denied $ chmod 755 ./a.out $ ./a.out bash: ./a.out: cannot execute binary file $ rm a.out $ as main.s -o main.o $ file * main.c: ASCII C program text main.i: ASCII C program text main.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped main.s: ASCII assembler program text $ GNU tool for Assembling
8. 'collect2' for linking: 'collect2' is used to resolve undefined symbols in a binary object file. $ gcc -static -v main.o /usr/lib/libc.a Using built-in specs. Target: i486-linux-gnu Thread model: posix gcc version 4.3.2 (Ubuntu 4.3.2-1ubuntu12) COMPILER_PATH=/usr/lib/gcc/i486-linux-gnu/4.3.2/:/usr/lib/gcc/i486-linux-gnu/4.3.2/:/usr/lib/gcc/i486-linux-gnu/:/usr/lib/gcc/i486-linux-gnu/4.3.2/:/usr/lib/gcc/i486-linux-gnu/:/usr/lib/gcc/i486-linux-gnu/4.3.2/:/usr/lib/gcc/i486-linux-gnu/ LIBRARY_PATH=/usr/lib/gcc/i486-linux-gnu/4.3.2/:/usr/lib/gcc/i486-linux-gnu/4.3.2/:/usr/lib/gcc/i486-linux-gnu/4.3.2/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/i486-linux-gnu/4.3.2/../../../:/lib/:/usr/lib/ COLLECT_GCC_OPTIONS='-static' '-v' '-mtune=generic' /usr/lib/gcc/i486-linux-gnu/4.3.2/collect2 -m elf_i386 --hash-style=both -static -z relro /usr/lib/gcc/i486-linux-gnu/4.3.2/../../../../lib/crt1.o /usr/lib/gcc/i486-linux-gnu/4.3.2/../../../../lib/crti.o /usr/lib/gcc/i486-linux-gnu/4.3.2/crtbeginT.o -L/usr/lib/gcc/i486-linux-gnu/4.3.2 -L/usr/lib/gcc/i486-linux-gnu/4.3.2 -L/usr/lib/gcc/i486-linux-gnu/4.3.2/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/i486-linux-gnu/4.3.2/../../.. main.o /usr/lib/libc.a --start-group -lgcc -lgcc_eh -lc --end-group /usr/lib/gcc/i486-linux-gnu/4.3.2/crtend.o /usr/lib/gcc/i486-linux-gnu/4.3.2/../../../../lib/crtn.o $ ls a.out main.c main.i main.o main.s $ ./a.out Hello World $ GNU tool for Linking
9. 'gcc' The GNU Compiler Collection: No need to use all four tools everytime. 'gcc' is a program which uses these four and more tools to generate executables from Source Files. $ cat > main.c #include <stdio.h> int main(int argc, char **argv) { printf(“Hello World”); return(0); } $ gcc main.c $ file * a.out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.8, dynamically linked, not stripped main.c: ASCII C program text $ ./a.out Hello World $ rm a.out ; gcc main.c -o helloworld ; ls helloworld main.c $ ./helloworld Hello World $ rm helloworld ; gcc -E main.c > main.i # -E will stop gcc after preprocessing. $ gcc -S main.i # -S will stop gcc after generating Assembly Source File. $ gcc -c main.s # -c will stop gcc after converting Assembly Source File into Binary Object file. $ gcc -static main.o /usr/lib/libc.a -o helloworld # This will create statically linked program called 'helloworld' $ file * helloworld: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.8, statically linked, not stripped main.c: ASCII C program text main.i: ASCII C program text main.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped main.s: ASCII assembler program text $ ./helloworld Hello World $
10. 'nm' symbol table fetcher: 'nm' is used to display symbol table from Executable file / Binary Object file. $ cat > main.c #include <stdio.h> int main(int argc, char **argv) { printf(“Hello World”); return(0); } $ gcc -c main.c $ nm main.o 00000000 T main U puts $ gcc -static main.o /usr/lib/libc.a -o helloworld $ file * helloworld: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.8, statically linked, not stripped main.c: ASCII C program text main.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped $ nm helloworld | grep puts 08048bd0 T _IO_puts 08065940 T fputs_unlocked 08048bd0 W puts $ nm -f sysv helloworld | grep puts _IO_puts |08048bd0| T | FUNC|00000171| |.text fputs_unlocked |08065940| T | FUNC|0000006f| |.text puts |08048bd0| W | FUNC|00000171| |.text $ Important Symbol Types: T – Symbol in .text section, U – Undefined symbol. Displaying symbol table
11. 'strip' The Physiotherapist: 'strip' will take out symbols table from the executable and make it slim. $ cat > main.c #include <stdio.h> int main(int argc, char **argv) { printf(“Hello World”); return(0); } $ gcc main.c -o helloworld $ file helloworld helloworld: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.8, dynamically linked (uses shared libs), not stripped $ nm helloworld | grep ' U ' U __libc_start_main@@GLIBC_2.0 U puts@@GLIBC_2.0 $ du -h helloworld 12K helloworld $ strip helloworld $ nm helloworld nm: helloworld: no symbols $ du -h helloworld 8.0K helloworld $ file helloworld helloworld: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.8, dynamically linked (uses shared libs), stripped $ Stripping
12. Creating reusable functions: 1. One or more functions and their binary code clubbed in a file is called library. 2. Different programs can use same library. 3. Programmer don't want to rewrite already written function. 4. While compiling, Programs copying function binary code from the library to its original executable is called static linking. 5. Libraries which are static ends with .a extension. 6. On execution, Programs loading the function binary code dynamically from a special library is called dynamic linking. 7. Libraries which have dynamic linking capability are called shared libraries. Shared library files will end with .so.x.x.x or .so extension. Libraries
14. $ ls helloworld.c helloworld_functions.c helloworld.h $ gcc -c helloworld_functions.c $ gcc -c helloworld.c $ ls helloworld.c helloworld_functions.c helloworld_functions.o helloworld.h helloworld.o $ ar cr libhelloworld.a helloworld_functions.o $ ranlib libhelloworld.a $ ls helloworld.c helloworld_functions.c helloworld_functions.o helloworld.h helloworld.o libhelloworld.a $ gcc -static -o helloworld helloworld.o libhelloworld.a $ file * helloworld: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.8, statically linked, not stripped helloworld.c: ASCII C program text helloworld_functions.c: ASCII C program text helloworld_functions.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped helloworld.h: ASCII C program text helloworld.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped libhelloworld.a: current ar archive $ ./helloworld Hello World Hello everyone
15. $ rm helloworld; gcc -o helloworld helloworld.o -lhelloworld /usr/bin/ld: cannot find -lhelloworld collect2: ld returned 1 exit status $ gcc -L”`pwd`” -o helloworld helloworld.o -lhelloworld $ ./helloworld Hello World Hello everyone $ rm helloworld; export LIBRARY_PATH=”`pwd`:${LIBRARY_PATH}”; gcc -o helloworld helloworld.o -lhelloworld $ ./helloworld Hello World Hello everyone $ -L DIRECTORY This option enable 'gcc' to look into the given DIRECTORY while searching for libraries. -I DIRECTORY This option enable 'gcc' to look into the given DIRECTORY while searching for header files. LIBRARY_PATH List of colen seperated directories where those directories will be searched to find libraries. C_INCLUDE_PATH List of colen seperated directories where those directories will be searched to find header files. 'ranlib' Creates symbol index and stores it in the same static archive to speed up linking.
19. LD_LIBRARY_PATH A list of colen seperated directories which will be searched while loading shared libraries dynamically. Shared library should follow below naming standard. lib<NAME>.so.<INTERFACE_CHANGE_VERSION_NUMBER>.<MINOR_NUMBER>.<RELEASE_NUMBER> libhelloworld.so.0.0.1 <NAME> = helloworld <INTERFACE_CHANGE_VERSION_NUMBER> = 0 <MINOR_NUMBER> = 0 <RELEASE_NUMBER> = 0 Also we should create symbolic name with extension .so to make the shared library searchable for gcc.'gcc' can find shared libraries only with extension as .so $ ln -s libhelloworld.so.0.0.1 libhelloworld.so 'ldconfig': This command will update, build and rebuild shared library cache for dynamic loading. $ sudo ldconfig -v # will rebuild library cache from the directories mentioned in /etc/ld.so.conf $ ldconfig -p # this will show currently cached shared libraries. Once we put our shared libraries in system wide directories(/lib, /usr/lib, /usr/local/lib), no need to use LD_LIBRARY_PATH. 'ldconfig' will cache our library automatically.
20. 'ldd': ' ldd ' is used to show dependency libraries for a given Executable/Shared library. $ ldd /bin/ls linux-gate.so.1 => (0xb7f68000) librt.so.1 => /lib/tls/i686/cmov/librt.so.1 (0xb7f33000) libselinux.so.1 => /lib/libselinux.so.1 (0xb7f19000) libacl.so.1 => /lib/libacl.so.1 (0xb7f10000) libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7db2000) libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0xb7d99000) /lib/ld-linux.so.2 (0xb7f4e000) libdl.so.2 => /lib/tls/i686/cmov/libdl.so.2 (0xb7d95000) libattr.so.1 => /lib/libattr.so.1 (0xb7d90000) $ 'gdb': ' gdb ' is used for 'core' file postmartem. Whenever a program malfunctions, OS will dump its memory image into a file called 'core'. 'gdb' uses this file to see what happends to it. $ ulimit -c unlimited $ cat > create_core.c #include <stdio.h> int main(int argc, char **argv) { main(); return(0); } $ gcc -ggdb -pg -o create_core create_core.c $ ./create_core Segmentation fault (core dumpped) $
21. $ gdb -c core create_core GNU gdb 6.8-debian Copyright (C) 2008 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "i486-linux-gnu"... warning: Can't read pathname for load map: Input/output error. Reading symbols from /lib/tls/i686/cmov/libc.so.6...done. Loaded symbols for /lib/tls/i686/cmov/libc.so.6 Reading symbols from /lib/ld-linux.so.2...done. Loaded symbols for /lib/ld-linux.so.2 Core was generated by `./create_core'. Program terminated with signal 11, Segmentation fault. [New process 7598] #0 0xb7ea04fa in mcount () from /lib/tls/i686/cmov/libc.so.6 (gdb) bt #0 0xb7ea04fa in mcount () from /lib/tls/i686/cmov/libc.so.6 #1 0x080484ea in main (argc=Cannot access memory at address 0x1 ) at create_core.c:3 (gdb) quit $ 'gprof' 'gprof' is used to show details about how the program uses systems resources. Generally used for performance tweeking. $ gcc -pg -o test test.c $ ./test $ ls gmon.out test test.c $ gprof test > test_ profile.txt $
22. 'make' command is used to compile,install and uninstall programs. It takes instructions from 'makefile' or 'Makefile' and compile according to the instructions. Makefile follows the below format. TARGET : DEPENDENCY ... COMMAND ... DEPENDENCY may be another TARGET. COMMAND can be one ore more for a TARGET. The following is the format to run commands for a specific target using make. $ make TARGET Make
23. Using 'make' to build programs: $ cat > helloworld.h #include <stdio.h> int say_hello_to_world(void); int say_hello_to_this_person(const char *person); $ cat > helloworld_functions.c #include “helloworld.h” int say_hello_to_world(void) { printf(“Hello World”); return(0); } int say_hello_to_this_person(const char *person) { printf(“Hello %s”, person); return(0); } $ cat > helloworld.c #include “helloworld.h” int main(int argc char **argv) { say_hello_to_world(); say_hello_to_this_person(“everyone”); return(0); } $
26. What is Autotools? A collection of programs workes togather to create Makefile which contains targets sutable for building and deploying the program in various systems. Why we need Autotools? Writing Makefile to automate build process in different architectures is a burden work. Autotools simplifies this work by generating Makefile. What all we call as Autotools? There are lot of commands jointly called as autotools, But the below ones are the important commands. autoscan Creates configure.scan file with default autoconf macros by reading the source files in the current directory. We need customize this file by adding our own autoconf macros and rename it to configure.ac. aclocal Creating local aclocal.m4 file with automake macros for autoconf. Libtoolize Used to create static and dynamic libraries. Gettextize Adds support for Internationalization. autoconf Creates configure from configure.ac autoheader Creates config.h.in by reading sources in current directory. config.h file will contain C macros which we can use it in our source programs. automake Creates Makefile.in from Makefile.am configure When we run this autoconf generated script, this will create Makefile from Makefile.in and also config.h from config.h.in. Once Makefile generated, we can use 'make' command to build different targets. Autotools
28. $ ls helloworld.c helloworld_functions.c helloworld.h Makefile.am $ autoscan; ls autoscan.log configure.scan helloworld.c helloworld_functions.c helloworld.h Makefile.am $ cat configure.scan # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS) AC_CONFIG_SRCDIR([helloworld_functions.c]) AC_CONFIG_HEADER([config.h]) # Checks for programs. AC_PROG_CC # Checks for libraries. # Checks for header files. # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST # Checks for library functions. AC_CONFIG_FILES([Makefile]) AC_OUTPUT $
29. $ vi configure.scan $ mv configure.scan configure.ac; cat configure.ac # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) AC_INIT([helloworld], [0.1], [someone@somewhere.com]) AM_INIT_AUTOMAKE([-Wall]) LT_INIT AC_CONFIG_SRCDIR([helloworld_functions.c]) AC_CONFIG_HEADER([config.h]) # Checks for programs. AC_PROG_CC AM_PROG_CC_C_O # Checks for libraries. # Checks for header files. AC_CHECK_HEADER([stdio.h],[echo "Congrats!! stdio.h found."],[echo "Sorry!! stdio.h not found." && exit 1]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST # Checks for library functions. AC_CONFIG_FILES([Makefile]) AC_OUTPUT $
30. $ aclocal ; ls aclocal.m4 autom4te.cache autoscan.log configure.ac helloworld.c helloworld_functions.c helloworld.h Makefile.am $ libtoolize --copy --install libtoolize: putting auxiliary files in `.'. libtoolize: copying file `./config.guess' libtoolize: copying file `./config.sub' libtoolize: copying file `./install-sh' libtoolize: copying file `./ltmain.sh' libtoolize: Consider adding `AC_CONFIG_MACRO_DIR([m4])' to configure.ac and libtoolize: rerunning libtoolize, to keep the correct libtool macros in-tree. libtoolize: Consider adding `-I m4' to ACLOCAL_AMFLAGS in Makefile.am. $ autoconf $ autoheader $ automake --copy --add-missing configure.ac:13: installing `./compile' configure.ac:6: installing `./missing' Makefile.am: installing `./INSTALL' Makefile.am: required file `./NEWS' not found Makefile.am: required file `./README' not found Makefile.am: required file `./AUTHORS' not found Makefile.am: required file `./ChangeLog' not found Makefile.am: installing `./COPYING' Makefile.am: installing `./depcomp' $ touch NEWS README AUTHORS ChangeLog $ automake --copy --add-missing $ ls aclocal.m4 AUTHORS autom4te.cache autoscan.log ChangeLog compile config.guess config.h.in config.sub configure configure.ac COPYING depcomp helloworld.c helloworld_functions.c helloworld.h INSTALL install-sh ltmain.sh Makefile.am Makefile.in missing NEWS README $
31. Instead of all the above commands, we can use ' autoreconf ' after creating configure.ac. $ autoreconf --verbose --install autoreconf: Entering directory `.' autoreconf: configure.ac: not using Gettext autoreconf: running: aclocal autoreconf: configure.ac: tracing autoreconf: running: libtoolize --install --copy libtoolize: putting auxiliary files in `.'. libtoolize: copying file `./config.guess' libtoolize: copying file `./config.sub' libtoolize: copying file `./install-sh' libtoolize: copying file `./ltmain.sh' libtoolize: Consider adding `AC_CONFIG_MACRO_DIR([m4])' to configure.ac and libtoolize: rerunning libtoolize, to keep the correct libtool macros in-tree. libtoolize: Consider adding `-I m4' to ACLOCAL_AMFLAGS in Makefile.am. autoreconf: running: /usr/bin/autoconf autoreconf: running: /usr/bin/autoheader autoreconf: running: automake --add-missing --copy --no-force configure.ac:13: installing `./compile' configure.ac:6: installing `./missing' Makefile.am: installing `./INSTALL' Makefile.am: required file `./NEWS' not found Makefile.am: required file `./README' not found Makefile.am: required file `./AUTHORS' not found Makefile.am: required file `./ChangeLog' not found Makefile.am: installing `./COPYING' Makefile.am: installing `./depcomp' autoreconf: automake failed with exit status: 1 $ touch NEWS README AUTHORS ChangeLog $ autoreconf --install libtoolize: Consider adding `AC_CONFIG_MACRO_DIR([m4])' to configure.ac and libtoolize: rerunning libtoolize, to keep the correct libtool macros in-tree. libtoolize: Consider adding `-I m4' to ACLOCAL_AMFLAGS in Makefile.am. $ file configure configure: POSIX shell script text executable $
32. $ ./configure [long output ...] checking dependency style of gcc... (cached) gcc3 checking whether gcc and cc understand -c and -o together... yes checking stdio.h usability... yes checking stdio.h presence... yes checking for stdio.h... yes Congrats!! stdio.h found checking for an ANSI C-conforming const... yes configure: creating ./config.status config.status: creating Makefile config.status: creating config.h config.status: executing depfiles commands config.status: executing libtool commands $ make all [long output ...] $ make install DESTDIR=”${HOME}/helloworld-0.1-i686” [long output ...] $ cd $ find helloworld-0.1-i686 helloworld-0.1-i686/ helloworld-0.1-i686/usr helloworld-0.1-i686/usr/local helloworld-0.1-i686/usr/local/lib helloworld-0.1-i686/usr/local/lib/libhelloworld.so helloworld-0.1-i686/usr/local/lib/libhelloworld.a helloworld-0.1-i686/usr/local/lib/libhelloworld.so.0.0.0 helloworld-0.1-i686/usr/local/lib/libhelloworld.la helloworld-0.1-i686/usr/local/lib/libhelloworld.so.0 helloworld-0.1-i686/usr/local/include helloworld-0.1-i686/usr/local/include/helloworld.h helloworld-0.1-i686/usr/local/bin helloworld-0.1-i686/usr/local/bin/helloworld $ cd - $ make dist-bzip2 [long output ...] $ file helloworld-0.1.tar.bzip2 helloworld-0.1.tar.bz2: bzip2 compressed data, block size = 900k $
33. Tarball(GNU tarball): A tar file contains source codes and a Makefile('configure' script if it is a Autotools based software) to compile the source codes and build executables of the software. Package: A file which contains compiled binary executables and meta files of a software. Debian Package: A Binary package which will be installed through dpkg. Debian and its derivatives(Knopix, Ubuntu, Mint etc.,) uses this kind of files to install softwares into the system. RPM Package: A Binary package similar to Debian Package, but specifically used in RedHat based distributions(Fedora, Mandriva, OpenSUSE etc.,) Ports Collection, pkgsrc, OpenPKG: A Makefile based software installation system for FreeBSD, NetBSD, OpenBSD systems which will be used to compile, install, uninstall softwares. Portage: A shell script based software installation system for Gentoo and its derivatives (Sabayon etc.,). .tgz: A compiled binary package used by Slackware and its derivatives (Zenwalk, Vector Linux etc.,). .pet: A compiled binary package similar to Slackware's .tgz packages used by puppylinux. Packages
34. Creating .pet package: # wget http://www.tcpdump.org/release/libpcap-1.0.0.tar.gz # ls libpcap-1.0.0.tar.gz # tar xvzf libpcap-1.0.0.tar.gz [long output...] # ls libpcap-1.0.0 libpcap-1.0.0.tar.gz # cd libpcap-1.0.0 # ./configure --prefix=”/usr” --sysconfdir=”/etc” --localstatedir=”/var” [long output...] # make all [long output...] # make install DESTDIR=”`pwd`-i686” [long output...] # cd .. # ls libpcap-1.0.0 libpcap-1.0.0-i686 libpcap-1.0.0.tar.gz