GCC (FIXME: clean it up) - alex-aleyan/linux_wiki GitHub Wiki

Based on: "An Introduction to GCC: For the GNU Compilers GCC and G++"
http://www.network-theory.co.uk/

Chapter 1 Intro:

  • Pulbisher Website: http://www.network-theory.co.uk/gcc/intro/
  • GCC stands for GNU Compiler Collection
  • Besides C and C++, GCC supports:
    • Fortan
    • ADA
    • Java
  • GCC supports these platforms:
    • PC Processors
    • Microcontrollers
    • DSPs
    • 64-bit CPUs
  • GCC is a cross-compile meaning it's capable of producing executable files for a different system from the one used by GCC itself.
  • GCC can compile itself so it can be adapted to new systems.

Chapter 2 Cpmpiling a C Program:

  • Compilation: the process of converting a program from the textual source code, in a programming language such as C or C++, into machine code, the sequence of 1’s and 0’s used to control the central processing unit (CPU) of the computer.

  • Executable File (aka Binary File): stores the machine code produced by compilation.

  • Hello World:

    • the -o option below specifies the name of the output file. if not specified, the a.out is produced by gcc.
    • the -Wall (Warnings All) option turns on all commonly used warnings.
    • if output file with the same name already exists, it's overwritten.

    gcc -Wall hello.c -o hello #where -o specified the output file

    #include <stdio.h>
    
    int main (void)
    {
      printf("Hello World!\n");
    return 0;
    }
    
  • Resource: GNU C Library Reference Manual

  • Compiling multiple source files:

    • Allows the individual parts to be compiled independently.
    • the #include "file.h" looks in the current director
    • the #include <file.h> searches in the system header files and does NOT look in the current directory. main.c:
#include <stdio.h>

int main (void)
{
	hello("world");
return 0;
}

hello.h:

void hello (const char * name);

hello.c:

#include <stdio.h>
#include "hello_func.h"

void hello (const char * name)
{
	printf ("Hello, %s!\n", name);
}
  • Compiling files independently:
    • When programs are stored in independent source files, only the files which have changed need to be recompiled.
    • a 2-stage process:
      • the source files are compiled separately to produce object files
      • the object files (*.o files) produced by compilation are linked together to produce a single executable. An object file contains machine code where references to the memory addresses of functions (or variables) in other files are left undefined (the linker fills in these missing addresses).
  • Creating Object Files from Source Files:
    • performing gcc -Wall -c main.c produces the object file main.o containing the machine code for the main function which contains reference to the external function hello.
    • performing gcc -Wall -c hello_func.c produces the object file hello_func.o
    • the gcc does not requre the hello_func.h file to be compiled since it's automatically included in the main.c and hello_func.c
gcc -Wall -c main.c
gcc -Wall -c hello_func.c
  • Creating Executables from Object Files:
    • Since Linking is much faster than Compiling, recompiling only those files that have been modified and relinking the object files saves time!
    • use gcc to link the object files together and fill in the missing addresses of external functions.
    • No need to use the -Wall Warning Option since compilation has already been performed prior linking.
    • Linking fails only if a reference cannot be resolved.
    • Link order is such that the highest level in hierarchy must appear farthest to the left (main.o) and the lowest lever in hierarchy such as files containing the definition of a function should appear after the files that call the function (farther to the right). Some compilers and linkers search all object files regardless of the order.
    • gcc main.o hello_func.o -o hi_there
    • Thus, to update a single file, recompile that file only using gcc -c file.c and then link it using gcc main.o file.o -o main.run
  • Linking with External Libraries:
    • Library is a collection of precompiled object files which can be linked into programs.
    • Libraries are often used to provide system functions/interfaces.
    • The 2 types of libraries are:
      • Static Libraries
      • Shared Libraries (see Ch3)
  • Static Libraries:
    • Stored in special Archive Files
    • These Archive Files are created using GNU Archiver ar
    • These Static Libraries' Archive Files containing the Static Libraries in form of the machine code (object file) are used by Linker??? to resolve references to function at compile-time (see Ch10).
    • Static Libraries can be created using ar command.
    • The Static Libraries can be found in /usr/lib or /lib (Example" the math lib can be found as /usr/lib/libm.a or /usr/lib/x86_64-redhat-linux5E/lib64/libm.a on redhat), and the C Standard Library is stored in /usr/lib/libc.a (contains ANSI/ISO C functions)
    • The corresponding header file can be found in /usr/include/math.h
    • Additional directories can specified with command-line options and environment variables.
    • Link Order:
      • File to Library Linking performed in the left to right order meaning a library must be referenced after the source file containing the function sourced from that library: gcc -Wall main.c -lm -o calc
      • A library which calls an external function defined in another library should appear before the library containing the function. Example where GNU Linear Programming Library uses the libm.a library: gcc -Wall data.c -lglpk -lm
    • When a function from a given library is used, the corresponding header file has to be included within the source file and the corresponding static library has to be specified during compilation (the compiler needs to know about the location of the directories contining the included header and library files either via -I/pathToHeaderDir and -L/pathToLibDir options, or from the set path variable):

gcc -Wall main.c /usr/lib/libm.a -o calc.run OR USING A SHORTCUT 'l': gcc -Wall main.c -lm -o calc.run # where compiler links -lNAME to libNAME.a

#include <math.h> // HERE WE INCLUDE THE HEADER math.h FROM libm.a LIBRARY
#include <stdio.h>

int main (void)
{
  double x = sqrt (2.0);
  printf ("The square root of 2.0 is %f\n", x);
return 0;
}

Summary:

Static Lib Location:                   /usr/lib and /lib 
Corresponding Static Include Location: /usr/include and /include

#include "file.h" //look in current dir only
#include <file.h> //look in system header files only

gcc -Wall main.c hello.c -o main.run  #from source to exec, -Wall Warning All, -o allows to customize output file's name
gcc -Wall -c main.c hello.c           #from source files main.c and hello.c to object files main.o hello.o

gcc -Wall -I/pathToHeaderDir -L/pathToLibDir -c main.c hello.c -lalteralib -o main.run

Chapter 3 Compilation Options:

  • Other commonly used options:
    • The search paths used for locating libraries and include files.
    • Additional warnings options.
    • Diagnostics, preprocessor macros and C language dialects.
  • By default, GCC searches these directories (in the Include Path) for header files:
    • /usr/local/include/
    • /usr/include/
  • By default, GCC searches these directories (in the Search Path or Link Path) for library files:
    • /usr/local/lib/
    • /usr/lib/
  • Use the -I compiler option to add new directories to the begining of the Include Path.
  • Use the -L compiler option to add new directories to the begining of the Link Path
  • Example: gcc -Wall -I/opt/altera/include/ -L/opt/altera/lib main.c -lalteraLib
  • Note: Never place the absolute path of the header file withing the #include statement of the source file. The program will fail to compile on other systems if you do! Use -I option or INCLUDE_PATH variable instead!
  • Environment Variables:
    • Used by gcc during the search for header files and libraries.
    • Can be set automagically using /etc/profile, .bash_profile, /etc/bashrc or ~/.bashrc file.
    • Include Path (Header files):
      • The C_INCLUDE_PATH environment variable is used for C header files:
        • export C_INCLUDE_PATH=/pathToHeaderFileDIr:$C_INCLUDE_PATH
      • The CPLUS_INCLUDE_PATH environment variable is used for C++ header files:
        • export CPLUS_INCLUDE_PATH=/pathToHeaderFileDIr:$C_INCLUDE_PATH
      • The precedents is such that:
        • First, the directories specified with -I option are searched.
        • Second, the directories specified in the CPLUS_INCLUDE_PATH and C_INCLUDE_PATH
        • Lastly, the standard default directories /usr/local/include/, and /usr/include/ are searched.
    • Library Path (Library Files):
      • The LIBRARY_PATH environment variable is used for Link Path:
        • export LIBRARY_PATH=/pathToLibFileDIr:$LIBRARY_PATH
      • You can always link directly with individual library files by specifying the full path to the library (but the load path will still need to be specified separately for the executable to find it in case when shared libraries are used!):
        • gcc -Wall -I/opt/gdbm-1.8.3/include dbmain.c /opt/gdbm-1.8.3/lib/libgdbm.a
        • gcc -Wall -I/opt/gdbm-1.8.3/include dbmain.c /opt/gdbm-1.8.3/lib/libgdbm.so
      • The precedents is such that:
        • First, the directories specified with -L option are searched.
        • Second, the directories specified in the LIBRARY_PATlib/, and /usr/lib/
  • Library Types:
    • External Libraries come in 2 flavors:
      • Static Libraries with *.a files.
      • Shared Libraries with *.so files.
    • When linking against a static library, the machine code from the object files for any external functions used by the program is copied from the library into the final executable.
    • When linking against a Shared Libraries
      • the resulting executable contains only a small table of functions it requires instead of the complete machine code from the object file.
      • Before the executable file runs, the machine code for the external functions is copied into memory from the shared library file on disk by the operating system (dynamic linking).
      • Dynamic linking: by sharing one copy of a library between multiple programs, the executable files are smaller which saves disk space.
      • virtual memory mechanism allows one copy of a shared library in physical memory to be used by all running programs thus saving memory as well as disk space.
      • Shared Libraries make it possible to update a library without recompiling the programs which use it.
      • gcc compiles programs to use shared libraries by default on most systems, if they are available (even when static library libNAME.a is specified using -lNAME, the compiler first check for alternative shared library NAME.so; make sure the shared library is in the path! Using the linker option -rpath, the directory containing the shared library can be "hardcoded" into the executable but this method is not recommended; to force static linking, use -static option as gcc -Wall -static -I/<path>/inclue -L/<path>/lib main.c -lm).
      • Load Path (Used by executable for shared libraries):
        • The LD_LIBRARY_PATH environment variable is used to set the Load Path for the executable to find Shared Libraries when its run.
        • export LD_LIBRARY_PATH=/pathToHeaderFileDIr:$LD_LIBRARY_PATH
        • See /etc/ld.so.conf load configuration file for an alternative way to set a system wide path for Load Path.
  • C Language Standards:
    • By default, GCC compiler uses GNU C (GNU dialect of C).
    • GNU C features:
      • nested functions and variable-size arrays.
      • ANSI/SIO inclusibe: will compile most ANSI/ISO programs. If ANSI/ISO program is incompatible with the GNU C extentions, disable conflicting GNU C extentions dialect using ansi option, or by using glibc (GNU C Library)
      • Among non-standard keywords and macros defined by the GNU C Extentions are (see source GCC Reference Manual “Using GCC” ):
        • asm
        • inline
        • typeof
        • unix
        • vax
    • GCC dialect is selected using -std option; the -ansi and -pedantic options can be specified by themselves.
    • GNU C Library MACROS allow control over the support for:
      • POSIX Extentions: _POSIX_C_SOURCE
      • BSD extensions: _BSD_SOURCE.
      • SVID extensions: _SVID_SOURCE.
      • XOPEN extensions: _XOPEN_SOURCE.
      • GNU extensions: _GNU_SOURCE; enables all extension together with the POSIX extensions taking precedence over others; see source GNU C Library Reference Manual.
    • To make code portable across the platforms, you can completely disable GNU C Extensions and enforce ANSI/ISO standard by using the -pedantic and -ansi options in combination:gcc -Wall -ansi -pedantic main.c
    • Selecting specific standards:
      • -std=c89 or -std=iso9899:1990: The original ANSI/SIO C Language Standard.
      • -std=iso9899:199409: The ISO C language standard with ISO Amendment 1.
      • -std=c99 or -std=iso9899:1999: The revised ISO C language standard, published in 1999.
      • -std=gnu89 and -std=gnu99: C language standards with GNU extensions.
    • Warning options:
      • -Wall: Warning All.
      • -Wcomment (included in -Wall):warns about nested comments (occurs when a section of code containing comments is later commented out; fix by replacing commenting out section with #if #endif).
      • -Wformat (included in -Wall): warns about the incorrect use of format strings in functions such as printf and scanf.
      • -Wunused (included in -Wall): warns about unused variables
      • -Wimplicit (included in -Wall): warns about any functions that are used without being declared.
      • -Wreturn-type (included in -Wall): warns about functions that are defined without a return type but not declared void.
      • -W additional warning; make a habit to use -W and -Wall together!
      • -Wconversion: warns about implicit type conversions that could cause unexpected result.
      • -Wshadow: wanrs about the redeclaration of a variable name in a scope where it has already been declared.
      • -Wcast-qual: warns about pointers that are cast to remove a type qualifier, such as const.
      • -Wwrite-strings: implicitly gives all string constants defined in the program a const qualifier, causing a compile-time warning if there is an attempt to overwrite them.
      • -Wtraditional: warns about parts of the code which would be interpreted differently by an ANSI/ISO compiler and a “traditional” pre-ANSI compiler. When maintaining legacy software it may be necessary to investigate whether the traditional or ANSI/ISO interpretation was intended in the original code for warnings generated by this option
      • See source GCC Reference Manual "Using GCC" for more details. Summary:
C_INCLUDE_PATH        used for C header files
CPLUS_INCLUDE_PATH    used for C++ header files
Include Precedence:   /pathToInc, -I/pathToInc, C_INCLUDE_PATH, the standard default directories (/usr/local/include/ and /usr/include)

LIBRARY_PATH          used for library files
Include Precedence:   /pathToLib, -L/pathToLib, LIBRARY_PATH and -l (uses dirs specified in LIBRARY_PATH), the standard default directories (/usr/local/lib/ and /usr/lib)

Library Types: Static (.a) and Shared (.so)

-Wall: Warning All
-W: additional warning (use -W and -Wall together!)

gcc -Wall -I/opt/altera/include/ -L/opt/altera/lib main.c -lalteraLib
gcc -Wall -I../include/ main.c -o main.run

Chapter 4 Using the Preprocessor:

  • The Preprocessor: expands macros in source files before they are compiled.
  • The #ifdef #endif or #ifndef #def #endifpreprocessor conditional is the most common.
  • When the #ifdef macros are true and encountered by the preprocessor, the code enclosed is included until the #endif is encountered.
  • Methods to define a MACRO:
    • The gcc option -DNAME is used to define a preprocessor macro NAME from the command line: gcc -Wall -DTEST main.c.
    • The #define can be used within the source file or library header file to define a macro: #define MY_MACRO 1
  • MACROs defined by the compiler use the reserved namespace beginning with the double underscore %%__%% and can be listed using -dM option on an empty file: cpp -dM /dev/null
    • Note: some macros are listed without double-underscore. These macros are defined by gcc and can be desabled using -ansi option of gcc.
  • MACROs can be given any other value than 1 (1 is default value if not provided). The value is inserted into the source code where the MACRO appears (except the string. They don't get expanded inside the strings):

gcc -Wall -DNUM=50 main.c

#include <stdio.h>

//note: the #define statement within the source file has higher precedence over CL argument -DNUM.
#define NUM 5

int main (void)
{
 printf("Value of NUM is %d\n", NUM);
 return 0;
}
  • MACRO can take values of any form (good idea to surround the MACROs by parentheses withing the source file): gcc -Wall -DNUM="1+5" main.c:
#include <stdio.h>

int main (void)
{
 printf("Value of NUM is %d\n", 2 * (NUM) ); // notice (NUM) instead of just NUM
 return 0;
}
  • To define an empty MACRO use -DNAME=""; this macro is treated as defined by the #ifdef conditionals but expands to nothing and produces an error during compilation if expansion attempted.
  • To define a MACRO to contain quotes, the quote must be escaped as: -DMESSAGE="\"Hello, World!\"". See source “GNU Bash Reference Manual”
  • To print the source code with expanded MACROs, use -E option. This option runs the Preprocessing Stage only and stops before the Compiler Stage. Thus, it should be the only option used: gcc -E file.c. This option is also used to examine the effect of system header files, and finding declarations of system functions.
  • To save the output to a file, use -save-temps option as following: gcc -save-temps main.c
    • The main.i contains the preprocessed output.
    • The main.s contains assembly output.
    • The main.o is the object file (1's and 0's).
Methods to define Macro: 
  -D<NAME>=<VALUE> (-DSIX="1+5" -DDEFINED_EMPTY="") or #define
  -DMYMACRO="\"It's a string!\""
  -DMYMACRO="3+7"

List all MACROS:
  cpp -dM /dev/null

Show preprocessed: 
  gcc -DDEBUG -E main.c
  gcc -DDEBUG -DLOGFILEEXTEN="\".log\"" -save-temps main.c (.i - c; .s - assemb; .o - machine)

Chapter 5 Compiling for Debugging:

  • The debug option works by storing the names of functions and variables (and all the references to them), with their corresponding source code line-numbers, in a symbol table in object files and executables.
  • The -g debug option:
    • allows storing debugging info in the object file and executable file.
    • allows errors to be traced back from a specific machine instruction to the corresponding line in the source code.
    • allows the execution of a program to be traced in a debugger, such as the GNU Debugger gdb (see source "Debugging with GDB: The GNU Source-Level Debugger").
    • allows the values of variables to be examined while the program is running.
    • allows to find the circumstances of a program crash:
      • When a program exits abnormally, the operating system can write out a core file (usually named core)
      • The core file contains the in-memory state of the program at the time it crashed.
      • The core file's information combined with information from the symbol table produced by -g can be used to find the line where the program stopped, and the values of its variables at that point.
      • Whenever the error message core dumped is displayed, the operating system should produce a file called core (contains a complete copy of the pages of memory used by the program at the time it was terminated) in the current directory.
      • In bash, the ulimit command is used to control the maximum size of a core file.
        • To list the current maximum size of the core file: ulimit -c
        • To set the maximum size of the core file to be unlimited (true for current shell only; use .bash_profile to set permanently): ulimit -c unlimited
      • Using the GNU Debugger gdb we can print diagnostic info (notice both the executable and the core files are required):
        • gdb main.run core.XXXX
        • Using gdb's print command we can lookup the value of p as follows: (gdb) print p
        • stack backtrace: the command that allows to show the function calls and arguments up to the current point of execution: (gdb) backtrace
          • Using gdb's up and down commands, we can move to different levels in the stack trace.
          • See source "Debugging with GDB: The GNU Source-Level Debugger" for all commands available in gdb.

Summary:

gcc -Wall -g main.c -o main.run # enables executable debug
./main.run

gdb main.run core.XXXX
(gdb) help
(gdb) help stack
(gdb) print p
(gdb) backtrace
(gdb) up|down
#include <stdio.h>

int a (int * p);

int main(void)
{
        int *p = 0;
return a(p);
}

int a (int *p)
{
//should really do: if p=Null then return fail
        int y =*p;
        return y;
}

Chapter 6 Compiling with Optimization:

  • GCC is an optimizing compiler.

    • There are more than one machine code implementations of a given source code command (C).
    • Since assembly and machine languages are implemented per processor, the assembly generated differs from one processor to another.
    • Some CPUs provide large number of registers to hold intermediate result of calculations. Others store the intermediate results in memory which increases the cost of store and fetch!
  • Source-Level Optimization:

    • The first form of optimization used by GCC is performed at the source-code level (C language)
    • The 2 common Soure-Level Optimization Techniques:
      • Common Subexpression Elimination (CSE)
      • Function Inlining
    • Common Subexpression Elimination:
      • Performed automatically when optimization is turned on.
      • Increases the speed of code and reduces the size of code.
      • if an expression carries out the same calculation on the same values more than once, the calculation has to be carried out only once: x= (y+5)*1 + (y+5)*2 yields t=y+5; x = t*1 + t*2
    • Function Inlining:
      • Increases the efficiency of frequently called function by eliminating function-call overhead.
      • function-call overhead: When a function is called, the CPU carries out the call by:
        • First, storing the function arguments in the appropriate registers and memory locations
        • Second, jumping to the start of the function (bringing Virtual Memory Pages into Physical Memory or the CPU Cache).
        • Thirdly, beginning to execute the code.
        • Fourthly, returning to the original point of execution when the function call is complete.
      • function-call overhead is increases as the frequency of the function call increases and as the number of instructions carried out by the function decreases (invocation of the function requires more instructions than the function itself).
      • Should be used with accessor functions (sets and gets) in C++.
      • Inlining may result in further optimization such as common CSE!
      • GCC automatically selects functions for inlining and the optimization is carried out only withing each object file.
      • The inline keyword can be used to explicitly request (inlining is not guaranteed) the function to be inlined.
      • See source: "GCC Reference Manual: Using GCC" on details of inline and its use with static (the value within a function is retain after the call is performed) and extern qualifiers used to control the linkage of explicitly inlined functions!
  • Speed-Space Tradeoffs:

    • Used to either:
      • Produce faster code at the expense of increased size of the executable.
      • Produce smaller executable at the expense of speed of the code.
    • Loop Unrolling:
      • Increases the speed of loops by eliminating the end of loop condition on each iteration.
      • eliminates tests condition.
      • executes at the max speed.
      • allows the compiler to use parallelism (on processors that support it) since each assignment becomes independent.
      • Possible when Upper Bound and Lower bounds are know, or Upper is unknown but lower is know?
    • Scheduling:
      • The lowest level of optimization: rearranges instruction so that their results become available to later instruction at the right time which yields maximum parallel execution!
      • Improves the speed without increasing the size, but requires additional memory and compilation time.
      • Compiler decides the best ordering of individual instructions.
      • Takes advantage of Instruction Pipelining (multiple instructions executed in parallel on the same CPU).
  • Optimization Level:

    • Using -O<level> option, you can control the optimization level:
      • -O0 (default): gcc -Wall -O0 main.c GCC does not perform optimization on the source code at all. The best option to use when DEBUGGING.
      • -O1 or -O: gcc -Wall -O1 main.c performs the most common optimization that does not require speed-space trafeoff
        • executable is smaller and faster than with the -O0 option.
        • Instruction Scheduling is not used.
        • Can produce faster compiling than -O0 due to reduces amounts of data to be processed after simple optimization.
      • -O2: gcc -Wall -O2 main.c uses O1 with further optimization which includes Instruction Scheduling
        • Executable does not increase in size since the speed-trace tradeoffs are not implemented.
        • Requires more memory than -O1
        • The best choice of DEPLOYMENT of the program (exec is smaller and faster).
      • -O3: gcc -Wall -O3 main.c turns on function inlining in addition to -O2 optimizations.
        • may increase the size in addition to speed.
        • may make the program slower in cases where optimization is not favorable.
      • -funroll-loops: gcc -Wall -funroll-loops main.c turns on loop-unrolling.
        • independed of the other optimization options!
        • Increases the size of the executable.
        • may or may not be beneficial.
      • -Os: gcc -Wall -Os main.c reduces the size of an executable.
        • may produce faster code due to better cache usage!
  • To test the Speed of executable, use time command: time main.run where

    • real gives the total real time for the process to run (including time where other processes used the CPU)
    • user gives the actual CPU time spend on running the process (use this value to judge your executable's speed).
    • sys gives the time spent waiting for operating system calls.
  • Optimization and Debugging

    • GCC allows optimization to be used with debugging -g
    • Using debugging option -g is recommended for both development and deployment!
    • The optimization option -O2 and the debug option -g are both enabled by default for GNU packages!
  • Optimization and Compiler Warning:

    • Data-flow Analysis: when the compiler examines the use of all variables and their initial values as a part of the optimization process.
    • The -Wuninitialized option (inluced in -Wall) throws a warning when a variable is read without being initialized (content is random garbage).
    • May miss a complicated case of uninitialized variable or establish a false warning.
  • Summary:

Source Level Optimization:
  Common Sub-expression Elimination (CSE)
  Function In-lining
  Loop unrolling
  Scheduling (assembly level: instruction pipelining)

Optimization Levels:
  gcc -Wall -O0 main.c -lm -o main.run # GOOD FOR DEBUGGING
  time ./main.run

  gcc -Wall -O3 main.c -lm -o main.run # GOOD FOR DEPLOYMENT
  time ./main.run

  gcc -Wall -O3 -funroll-loops main.c -lm -o main.run # GOOD FOR DEPLOYMENT

  gcc -Wall -g -O3 -funroll-loops main.c

  time ./main.run #see the "user" column

Chapter 7 Compiling C++ Program:

  • GNU C is a true C++ compiler—it compiles C++ source code directly into assembly language without converting it to C first.
    • The C++ program is compiled the same was as a C program but g++ is used instead of gcc
      • Example: g++ -Wall hello.cc -o hello.run.
    • The C++ uses many of the same options as the C compiler gcc, but supports some additional options for controlling C++ language features.
    • The valid C++ file extensions"
      • .cc
      • .cpp
      • .cxx or .C (rather than the .c)
    • The -ansi option of the c++ requests compliance with the C++ standard instead of the C standard.
    • The C++ object files must always be linked using g++ in order to supply the appropriate C++ libraries. Otherwise undefined reference error will be caused.
  • Using the C++ Standard Libraries:
    • In accordance with the C++ standard, the header files for the C++ library itself do not use a file extension: #include <string>
  • Templates:
    • Provide the ability to define C++ classes which support generic programming techniques.
    • Can be considered as a powerful kind of macro facility.
    • How they work: when a templated class or function is used with a specific class or type, such as float or int, the corresponding template code is compiled with that type substituted in the appropriate places.
    • The C++ standard library libstdc++ supplied with GCC provides a wide range of generic container classes such as lists and queues, in addition to generic algorithms such as sorting.
      • The executables created by g++ using the C++ standard library will be linked to the shared library ‘libstdc++’, which is supplied as part of the default GCC installation.
      • There are several versions of this library—if you distribute executables using the C++ standard library you need to:
        • ensure that the recipient has a compatible version of libstdc++
        • or link your program statically using the command-line option -static
    • Providing your own templates:
      • Use the inclusion compilation model, where template definitions are placed in header files.
      • The header files can then be included with #include in each source file where they are needed.
      • Use #ifndef YOUCLASS_H to test if the class has already been parsed once if the file is included multiple times in the same context!
      • If a template function is used several times in a program it will be stored in more than one object file. The GNU Linker ensures that only one copy is placed in the final executable. Other linkers may report “multiply defined symbol” errors when they encounter more than one copy of a template function—a method of working with these linkers is described below.
      • To completely control the compilation of templates with g++, it is possible to require explicit instantiation of each occurrence of a template using the option -fno-implicit-templates (GNU Linker d.n require this method since its capable of eliminating duplicate definitions of template functions in object files; only required for systems with linker incapable of handling such duplicates):
        • #include "buffer.h"
        • template class Buffer<float>
        • g++ -Wall -fno-implicit-templates -c tprog.cc
        • g++ -Wall -fno-implicit-templates -c templates.cc
        • g++ tprog.o templates.o -o tprog.run
        • tprog.run
        • Using method above will result in the object code for all the template functions to be contained in the file templates.o. The tprog.o will not containg object code for template functions since it's compiled using -fno-implicit-templates option.
        • Disadvantage: it's necessary to know which template types are needed by the program since if the program is modified to use additional types, further explicit instantiation has to be added to the templates.cc:
          • #include "buffer.h"
          • template class Buffer<float>
          • template class Buffer<double>
          • template class Buffer<int>
          • The missing template instantiations can be determine at link time and added to the list of explicit instantiations by noting which functions are undefined
        • Explicit instantiation can be used to make libraries of precompiled template function by creating an object file containin all required instantiation of a template function as above.

Chapter 9 Troubleshooting:

  • The options described here work for both gcc and g++.
    • To displays a summary of the top-level GCC command line options: gcc --help
    • To displays complete list of the GCC command line options: gcc -v --help or gcc -v --help 2>&1 | more
  • Version Numbers:
    • To determine the version number of the GCC: gcc --version
    • To determine more detailed information on the version of the GCC: gcc -v
      • Which display the gcc versions as major-version.minor-version.micro-version
  • Verbose Compilation (useful when there is a problem with a compilation process itself):
    • The -v option is used to display detailed information about the exact sequence of commands used to compile and link a program: gcc -v -Wall hello.c
    • Displays:
      • Full directory paths used to search for header files and libraries.
      • The predefined preprocessor symbols, and the object files and libraries used for linking.

Summary:

GCC Command Line Options:
  gcc --help
  gcc -v --help

GCC Version:
  gcc --version
  gcc -v

To Compile Verbosely
gcc -v main.c

gcc -v -Wall -g -O3 main.c

Chapter 10: Compile-related tools:

  • Tools useful in combination with GCC:
    • ar: the GNU archiver used for creating libraries.
    • gprof: the GNU profiling testing program
    • gcov: the GNU coverage testing programa.
  • The ar (GNU Archiver)
    • Combines a collection of object files into a single archive file (library).
    • To generate a library:
      • create the source files containing the functions.
      • generate object files from each source file: gcc -Wall -c hey_fn.c hi_fn.c
      • combine the generated object files into a library: ar cr libmylib.a hey_fn.o hi_fn.o
        • where the cr obption stands for create and replace (if the library d.n. exist, create; if exists, replace)
    • To list the object files contained in the existing library, use the t option: ar t libmylib.a
    • To compile, and link a source file against the generated library: gcc -Wall main.c libmylib.a -o hello or gcc -Wall -L. main.c -llibmylib -o hello
      • The -L option is used to add the current directory to the library search path
  • The gprof (GNU Profiler):
    • used to measure the program's performance by recording:
      • the number of calls to each function.
      • the amount of time spent per function.
    • to speed up a program, first optimize the functions that consume the most run time
    • To use the profiler:
      • the program must be compiled and linked using the -pg option (use -pg option during compilation on each source file when more than 1 source file is used):
        • gcc -Wall -c -pg main.c
        • gcc -Wall -c -pg afunc.c
        • gcc -Wall -pg main.o -o main.run
      • run the program so it creates the gmon.out file:main.run
      • run the program using the profiler: gprof main.run which will produce next output:
        • The 1st column shows the percentage of time a function takes from the total run time (where the total run time is the 100%). The function that consumes the most of this time must be optimized firstly.
        • The calls column show the number of times a function is called.
        • The self seconds column show the total time spent in each function.
    • See source GNU gprof—The GNU Profiler, by Jay Fenlason and Richard Stallman for more details.
  • The gcov (GNU Coverage testing tool)
    • analyses the number of times each line of a program is executed during a run.
    • used to find areas of the code which are not used, or which are not exercised in testing.
    • often used in conjunction with the GNU Profiler gporf: gcc -Wall -fprofile-arcs -ftest-coverage cov.c
    • To use the coverage tool:
      • the program must be compiled and linked using the -ftest-coverage option:
        • gcc -Wall -fprofile-arcs -ftest-coverage main.c
        • gcc -Wall -fprofile-arcs -ftest-coverage myfunc.c
        • gcc -Wall -fprofile-arcs -ftest-coverage main.o myfunc.o -o main.run
      • the executable must be run:
        • main.run
        • The data from the run is written to:
          • .bb, .bbg, and .da in the work directory.
      • Analyze the generated data using gcov tool:
        • gcov main.run
        • which will produce annotated version of the original source file with the .gcov extension (the line counts will be in the first column and the lines of code that are not executed are marked with ######).
        • Open the generated file using your text editor: vim main.run.gcov Summary:

#To generate a static library:
gcc -Wall -c hey_fn.c hi_fn.c     #to generate the object files
ar cr libmylib.a hey_fn.o hi_fn.o #to generate a library using the generated object files

#To test the program performance with the profiler:
gcc -Wall -c -pg main.c
gcc -Wall -c -pg afunc.c
gcc -Wall -pg main.o -o main.run
./main.run      #run the executable which should produce gmon.out
gprof main.run  #run the executable again using the profiler

gcc -Wall -fprofile-arcs -ftest-coverage main.c -o main.run
gcov main.run
vim main.run.gcov

Chapter 11 How the Compiler works:

  • For GCC to transform the source files to an executable file, these tools are used:
    • the GNU Preprocessor: cpp
    • the GNU Compiler: gcc or g++
    • the GNU Assembler as
    • the GNU Linker ld. The complete
  • toolchain: the complete set of the compilation tools:
    • preprocessor
    • compiler
    • assembler
    • linker
  • GCC invocation performs:
    • preprocessing (expanding macros and included header files)
    • compilation (source to assembly)
    • assembly (assembly to machine code)
    • linking (machine codes are linked into a single executable)
    • Note: To see the detailed compilation, use -v option as mentioned before.
  • Preprocessor:
    • expands macros and included header files.
    • to inspect the preprocessed file, use -save-temps option.
    • Preprocessor performs this command: cpp hello.c > hello.i
    • the result of preprocessed source is placed into hello.i
      • .i for C programs
      • .ii for C++ programs
  • Compiler:
    • compiles preprocessed source code to assembly language (per processor specification since a given cpu package has its own set of assembly commands).
    • to inspect the assembly file, use -S option which produces the assembly file without creating an object file.
    • Compiler performs this command: gcc -Wall -S hello.i
      • the resulting assembly code is placed into hello.s
  • Assembler:
    • converts assembly code into machine code and generates an object file.
    • the assembler leaves the addresses of the external functions undefined, to be filled in later by the linker.
    • Assembler performs this command: as hello.s -o hello.o
  • Linker:
    • links the object files to create an executable.
    • requires many external functions from the system and the C run-time libraries (crt).
    • to inspect linking process, use: gcc hello.o

Chapter 12 Examining compiled files (Object Files and Executables):

  • Identifying Files with file command:
    • the file command determines characteristics (such as if it was compiled with dynamic or static linking) of an object file or an executable based on its content.
    • To use the file command: file main.run
      • whose output has next fields:
        • ELF|COFF: internal format of the executable file:
          • ELF (Executable and Linking Format)
          • COFF (Common Object File Format; older operating systems like MS-DOS)
        • 32-bit|64-bit: register word size.
        • LSB|MSB:
          • LSB (Least Significant Byte first aka Little Endian)
          • MSB (Most Significant Byte first aka Little Endian).
        • ntel|AMD|: the processor the executable was compiled for.
        • version 1 (SYSV): the version of the internal format of the file.
        • dynamically linked|statically linked:
          • dynamically linked: the executable uses shared libraries.
          • statically linked: indicated program was linked statically using -static option.
        • not stripped|stripped:
          • not stripped: The executable contains a symbol table.
          • stripped: the symbol table was removed (using the strip command).
    • The file command can be used on object files as well to get similar information:file main.o
    • Source: see POSIX Standard for UNIX systems
  • Examining the Symbol Table
    • both executable files and object filescan contain a symbol table (see Ch5)
    • the Symbol Table stores:
      • location of the external functions by name.
      • location of the variables by name
    • both can be displayed using nm command: nm main.run or nm main.o
    • the nm command has this output:
      • 1st column shows the hexadecimal offset (in memory? page?)
      • 2nd column contains symbols for the use by compiler/OS:
        • T indicates a function is defined withing the object file. Can be used on a library to see if it contains the definition of a specific function!
        • U indicates an undefined function which has to be resolved by the linker.
        • see source GNU Binutils manual for complete explanation
  • Finding dynamically linked libraries:
    • A program compiled using shared libraries requires those libraries to be loaded dynamically at run-time in order to call external functions.
    • Use the ldd command to list the shared libraries (aka shared library dependencies) required by the executable: ldd main.run
    • Typical output indicating shared library version 6 is used: libc.so.6 => /lib/libc.so.6 (0x40050000)
    • The ldd command can be used on a shared library to determine the chain of shared library dependencies.

makefile template

#use this compiler:
CC=gcc
CC_OPTIONS=-v -Wall -W -D_GNU_SOURCE -W -DGETPROTOBYNUMBER
CC_DEBUG_OPTIONS=-v -g --save-temps -Wall -W -D_GNU_SOURCE -W -DGETPROTOBYNUMBER
SERVER_TARGET=streamServer.run
SERVER_SRC=streamServer.c

# !!!Alternatively, use C_INCLUDE_PATH and CPLUS_INCLUDE_PATH in bashrc!!!
# Create macro for header files' incude directory
H_INCLUDES=./../../include
# Implements next wildcard: ./mylib/includes/h_files/*c
H_SOURCE=$(wildcard $(H_INCLUDES)/*.h)


all: server client


server:
	#$(CC) $(CC_OPTIONS) -I$(H_INCLUDES) $(SERVER_SRC) -o $(SERVER_TARGET)
	$(CC) $(CC_OPTIONS) $(SERVER_SRC) -o $(SERVER_TARGET)


client:
	#$(CC) $(CC_OPTIONS) -I$(H_INCLUDES) $(CLIENT_SRC) -o $(CLIENT_TARGET)
	$(CC) $(CC_OPTIONS) $(CLIENT_SRC) -o $(CLIENT_TARGET)


debug:
	$(CC) $(CC_DEBUG_OPTIONS) -I$(H_INCLUDES) $(TOP_SRC) -o $(TARGET)


clean : 
	rm -f *.run *.i *.o *.s core.*
⚠️ **GitHub.com Fallback** ⚠️