More on g++

Introduction

g++ is a tool for preprocessing, compilation, assembly and linking of source code to generate an executable file or library.

Installation

As easy as:

sudo apt update

sudo apt install g++

General Syntax

  • General syntax to run g++ compiler is:

    g++ <flags_with_params> <source_files>

  • The above command takes a bunch of source files along with some flags and generates an executable file or a library file.

  • Flags are very important because they can control the way compilation occurs.

  • For example, if we have a single source file main.cpp and need to generate an executable file named out, the basic syntax for this task is g++ main.cpp -o out

  • Here, main.cpp is a source file and -o is a flag to specify the output filename. out is the name of the output executable file.

  • Command can be as complex as g++ -Wall -std=c++14 -I/some/path/to/include/dir -O3 -c -fpermissive -fPIE -o objectfile.o sourcefile1.cpp sourcefile2.cpp sourcefile2.cpp -L/path/to/library/dir -lsomelibrary1 lsomelibrary2

  • Here, -W -std -O -c -f -o -L -l are the flags along with their parameters and sourcefile1.cpp sourcefile2.cpp sourcefile2.cpp are three source files.

Some important flags

  • -o Specifies the output filename
  • -I Specifies the dir to look for header files
  • -L Specifies the dir to look for libraries
  • -l Specifies the name of a library to link to
  • -g To enable debugging
  • -std Specifies the C++ language standard
  • -O Specifies the Optimization level
  • -W Specifies the Warning option

Order doesn’t matter (except in few cases)

  • flags and source files can be written in any order. (with some exceptions while linking libraries, discussed below)

  • Take a simple C++ code main.cpp

    1
    2
    3
    4
    5
    6
    7
    #include <iostream>

    int main()
    {
    std::cout << "Hello, world!" << std::endl;
    return 0;
    }
  • Any of the following commands can be used to generate the executable file main

    g++ main.cpp -o main

    g++ -o main main.cpp

    g++ main.cpp -omain

    g++ -omain main.cpp

  • As you can see, it doesn’t matter in what order you keep -o flag and source file main.cpp

  • Moreover, it doen’t matter if you keep a space after -o flag or not.

  • Now, lets add some more flags: -Wall to show all the warnings, -g to enable debugging, and -std to specify C++ standard.

  • All the commands below produces identical output:

    g++ -Wall -g -std=c++14 main.cpp -o main

    g++ -Wall main.cpp -g -omain -std=c++14

    g++ main.cpp -Wall -omain -g -std=c++14

  • Now, lets try this with more than one source file

Multiple files

  • We can compile this with any of following commands:

    g++ main.cpp add.cpp subtract.cpp -o main (Simplest way)

    g++ -g -std=c++14 -Wall main.cpp add.cpp subtract.cpp -o main (With some flags)

    g++ -Wall add.cpp -std=c++14 -o main main.cpp -g subtract.cpp (Jumble up everything and it still works)

Creating Library

  • Executable file is a standalone file, which can be executed i.e run as a program. Whereas a library is a collection of stuff that can be invoked from the executable files.
  • All the examples above show how to create an executable file.
  • There are two types of library:
    • Static Library
    • Dynamic Library

Creating Static Library

  • Static library is nothing but a precompiled source file that can be linked to generate an executable file or other library.

Static Library

  • First flow chart shows how an executable is generated by processing all the source files via the whole pipeline.

  • Second flow chart shows object files are generated in intermediate steps and are linked later to generate an executable file.

  • These object files can be viewed as static libraries that are linked to main.o to produce an executable file.

  • This can be done using following commands:

    g++ -c main.cpp add.cpp subtract.cpp (Generate Object files)

    g++ main.o add.o subtract.o -o main (Generate executable from object files)

  • Moreover, we can mix up source files and object files while generating executable file:

    g++ -c add.cpp subtract.cpp

    g++ main.cpp add.o subtract.o -o main

  • Here, add.o and subtract.o are the object files acting as library for main.cpp

  • Now, lets try to bundle up these object files into a single file, which we can call Static Library

    g++ -c add.cpp subtract.cpp (first generate add.o and subtract.o)

    ar rc my_first_library add.o subtract.o (Bundle/Archive the object files to a single file my_first_library)

    g++ main.cpp my_first_library -o main (Now, use this library to produce the executable file)

  • Thats it! You have sucessfully created and used your first Static Library.

  • ar is called archiver. A tool used to create, modify, and extract from archives.

  • You can see the list of files in archive using: ar -t my_first_library

Still some work left …

  • Well, now let’s look into some naming conventions and standard ways of linking a static library.

  • Generally, static library is named as: lib<library_name>.a

  • And is linked as:

    g++ <source_files> -o <output_filename> -L<path/to/lib> -l<name_of_lib>

  • So, correct way of linking a static library in above example is:

    g++ -c add.cpp subtract.cpp (first generate add.o and subtract.o)

    ar rc libmy_first_library.a add.o subtract.o (Bundle/Archive the object files to a single file)

    g++ main.cpp -o main -L. -lmy_first_library (Now, use this library to produce the executable file)

Creating Dynamic Library

  • Dynamic library are not linked with the executable file during compilation process. They are linked during execution. i.e. linked dynamically.

  • Dynamic library is named as: lib<library_name>.so

  • Commands to create dynamic library for above example are:

    g++ -c add.cpp subtract.cpp (First generate object files as before)

    g++ -shared add.o subtract.o -o libmy_first_shared_library.so (generate a shared library form the object files)

    g++ main.cpp -o main -L. -lmy_first_shared_library (Now create an executable by linking the dynamic library)

  • Now, if you run ./main, it will probably give an error.

  • That’s because the executable main needs to know where to search for library libmy_first_shared_library.so.

  • We can add the search path to the environment variable LD_LIBRARY_PATH so that main finds it.

    export LD_LIBRARY_PATH=/path/to/dynamic_library

  • Now, when you run ./main, it should work perfectly.

  • You can also see all the dynamic dependencies/libraries linked to main by using command ldd main. i.e. List Dynamic Dependencies of executable file main

Order Matters here..

  • While generating the executable main by linking static or dynamic library in above example, we have used:

    g++ main.cpp -o main -L. -lname_of_lib

  • But as the flags are position independent, we may try to compile with:

    g++ -o main -L. -lname_of_lib main.cpp

  • But this time, it shows error stating undefined reference

  • The source file main.cpp uses the functions add and subtract, which is found inside the linked library.

  • g++ is designed in such a way that dependent stuff must be mentioned beforehand.

  • As main.cpp is dependent on -lname_of_lib , main.cpp must be written before -lname_of_lib

  • Other flags can be kept anywhere.