Tutorial

Compiling & Linking

The complete text of all three chapters plus the examples is combined in this TUTORIAL FILE. All examples are C programs to be compiled under Linux using the gcc.

Chapter 01 - Compiling, Linking, and Libraries ---------------------------------------------- "The Legend of Zelda: A Link to the Past" [SNES] NOTE: Use a csh (C-Shell). = 01.01 === Compiling ====================================== In Example_01/ is a small program with the filename main.cpp To compile it with the GNU C++ Compiler type: #> g++ main.cpp The result will be an executable called a.out -rwxrwxr-x 1 abisler visualis 12966 2003-10-19 14:47 a.out This file has the eXecutable-flags set which means it can be executed from a shell: #> ./a.out The C++-compile creates an executable, because the main.cpp file contains a main()-function ! To give the executable a different name the option -o can be used: #> g++ -o myExe main.cpp #> ./myExe Note: Instead of g++, gcc can be used, too. It's basically the same compiler. = 01.02 === Linking ======================================== Remove the executables: #> rm myExe a.out The cpp-file is compiled and linked, automatically. "When you invoke GCC, it normally does preprocessing, compilation, assembly and linking." [from the g++ manual pages] To make this process more visible, we can tell the compiler to stop after compiling (and assembling) using the option -c : " -c Compile or assemble the source files, but do not link. The linking stage simply is not done. The ultimate output is in the form of an object file for each source file." #> g++ -c main.cpp Now, the compiler creates the so-called object file main.o Trying to execute main.o results in an error... #> ./main.o ./main.o: Permission denied. ... because so far it's not an executable: -rw-rw-r-- 1 abisler visualis 2236 2003-10-19 15:07 main.o The missing part is the 'run time system'. To create the executable we have to invoke the linker by calling g++ again. But this time, only the object file is given as a parameter: #> g++ main.o #> ./a.out = 01.03 === Compiler Output ================================ To get more output from the compiler the option -v (verbose) can be used: #> g++ -v -o myExe main.cpp Reading specs from /usr/lib/gcc-lib/i486-suse-linux/3.3/specs Configured with: ../configure --enable-threads=posix --prefix=/usr --with-local-prefix=/usr/local --infodir=/usr/share/info --mandir=/usr/share/man --libdir=/usr/lib --enable-languages=c,c++,f77,objc,java,ada --disable-checking --enable-libgcj --with-gxx-include-dir=/usr/include/g++ --with-slibdir=/lib --with-system-zlib --enable-shared --enable-__cxa_atexit i486-suse-linux Thread model: posix gcc version 3.3 20030226 (prerelease) (SuSE Linux) /usr/lib/gcc-lib/i486-suse-linux/3.3/cc1plus -quiet -v -D__GNUC__=3 -D__GNUC_MINOR__=3 -D__GNUC_PATCHLEVEL__=0 -D_GNU_SOURCE main.cpp -D__GNUG__=3 -quiet -dumpbase main.cpp -auxbase main -version -o /tmp/ccAnYNsT.s GGC heuristics: --param ggc-min-expand=47 --param ggc-min-heapsize=31979 GNU C++ version 3.3 20030226 (prerelease) (SuSE Linux) (i486-suse-linux) compiled by GNU C version 3.3 20030226 (prerelease) (SuSE Linux). #include "..." search starts here: #include <...> search starts here: /usr/include/g++ /usr/include/g++/i486-suse-linux /usr/include/g++/backward /usr/local/include /usr/lib/gcc-lib/i486-suse-linux/3.3/include /usr/i486-suse-linux/include /usr/include End of search list. /usr/lib/gcc-lib/i486-suse-linux/3.3/../../../../i486-suse-linux/bin/as -V -Qy -o /tmp/ccZnalmZ.o /tmp/ccAnYNsT.s GNU assembler version 2.13.90.0.18 (i486-suse-linux) using BFD version 2.13.90.0.18 20030121 (SuSE Linux) /usr/lib/gcc-lib/i486-suse-linux/3.3/collect2 --eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o myExe /usr/lib/gcc-lib/i486-suse-linux/3.3/../../../crt1.o /usr/lib/gcc-lib/i486-suse-linux/3.3/../../../crti.o /usr/lib/gcc-lib/i486-suse-linux/3.3/crtbegin.o -L/usr/lib/gcc-lib/i486-suse-linux/3.3 -L/usr/lib/gcc-lib/i486-suse-linux/3.3/../../../../i486-suse-linux/lib -L/usr/lib/gcc-lib/i486-suse-linux/3.3/../../.. /tmp/ccZnalmZ.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc-lib/i486-suse-linux/3.3/crtend.o /usr/lib/gcc-lib/i486-suse-linux/3.3/../../../crtn.o Most of this can be ignored. Helpful are the informations about the header search pathes - in case that a header cannot be included: #include "..." search starts here: #include <...> search starts here: ... The line /usr/lib/gcc-lib/i486-suse-linux/3.3/cc1plus denotes the call of the compiler with the parameter main.cpp /usr/lib/gcc-lib/i486-suse-linux/3.3/../../../../i486-suse-linux/bin/as denotes the call of the assembler. /usr/lib/gcc-lib/i486-suse-linux/3.3/collect2 denotes the call of the linker with the output parameter -o myExe = 01.04 === Linking of Several Files ======================= In Example_02/ are 2 cpp-files: main.cpp and function_add.cpp Compile them & execute the built binary: (binary is a synonym for executable) #> g++ -o myExe main.cpp function_add.cpp #> ./myExe Now we compile the the source files, but link only main.o #> rm myExe #> g++ -c main.cpp #> g++ -c function_add.cpp #> g++ -o myExe main.o main.o(.text+0x30): In function `main': : undefined reference to `add(int, int)' collect2: ld returned 1 exit status The real linker program is called 'ld'. "ld returned 1 exit status" means, that the linker could not complete the linking process and had to stop. The error occurred because of the undefined reference to the function add(). To resolve that reference we have to link main.o together with function_add.o #> g++ -o myExe main.o function_add.o #> ./myExe = 01.05 === Creating Libraries ============================= In Case we have a bunch of object files, which belong to the same problem space or module, they can be collected in a so-called library. A library can not be executed. It first has to be linked together with the object file, which contains the main()-function. A library is basically a container for precompiled files. As long as the source code of the lib doesn't change, the lib's content is not altered and therefore you just need to link it to your binary without compiling the lib's source code again and again. There are two kinds of libraries: static and dynamic The static library has the filename extension .a, the dynamic library has the extension .so (for: shared object). The static lib is linked with the main-object file to one (huge) binary. The dynamic lib is not invoked into the same file, but a reference to it is created, which is resolved at runtime (when the program is started). The advantage is, that different programs can SHARE the same lib (at runtime). It has to be loaded only once into memory! Also, when a source file is altered only the lib has to be compiled but not the binary. There are two mechanisms to enable the program to find its shared objects. One is: the environment variable LD_LIBRARY_PATH contains the search pathes, which should lead to the wanted lib: setenv LD_LIBRARY_PATH .:/usr/local/lib:mySearchPathes The other is explained later. = 01.05.01 === Creating a Static Library =================== To create a static lib from the source file function_add.cpp compile it: #> g++ -c -static function_add.cpp and then type: #> g++ -ar -o libMyLib.a function_add.o ...doesn't work for unknown reasons :( = 01.05.02 === Creating a Dynamic Library ================== To create a dynamic lib from the source file function_add.cpp compile it: #> g++ -c function_add.cpp and then type: #> g++ -shared -o libMyLib.so function_add.o Library filenames should always begin with 'lib' and end with .so (or .a) Now we compile main.cpp and link it with the lib: #> g++ -c main.cpp #> g++ -o myExe libMyLib.so main.o #> ./myExe = 01.06 === Dependencies =================================== To see which dynamic libs the executable is using type: #> ldd myExe libMyLib.so => ./libMyLib.so (0x40016000) libstdc++.so.5 => /usr/lib/libstdc++.so.5 (0x40020000) libm.so.6 => /lib/libm.so.6 (0x400d8000) libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x400fa000) libc.so.6 => /lib/libc.so.6 (0x40102000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) The open reference libMyLib.so is resolved with the file in the current directory: ./libMyLib.so The other libs are system libs. #> mv libMyLib.so .. #> ./myExe ./myExe: error while loading shared libraries: libMyLib.so: cannot open shared object file: No such file or directory This is a typical error message in case a shared object cannot be found. #> ldd myExe libMyLib.so => not found The ldd-command marks the references, which could not be resolved, with 'not found'. To find a lib in another directory the environment variable LD_LIBRARY_PATH has to contain its dir: #> setenv LD_LIBRARY_PATH .:.. #> ldd myExe libMyLib.so => ../libMyLib.so (0x40015000) The colon : separates the pathes. = Appendix A === Naming Conventions ======================== Possible filename extensions: header files: file.h file.hpp C++ source code files: file.cc file.cp file.cxx file.cpp file.c++ file.C We use: .hpp and .cpp (Advantage: the regular expression *pp refers to both header and source files!) --- --- --- Library filenames: libMyName.so

(C) by n-o-d