computer science,

Concept of ABI in C++ Programming

Feb 05, 2021 · 7 mins read
Concept of ABI in C++ Programming
Share this

ABI or application binary interface is one of the most low-level elements that defines interactions between libraries, programs and the operating system.ABI is the interface between any two binaries either executables or libraries after compilation. ABI defines the interaction methodologies and underlying ALU manipulation and memory management that facilitates the interaction.

The interface defines how all parts of the code behave as machine code and interact with the hardware elements like registers, DRAM and memory.

Introduction

API or application program interface is a standard term used in the SW development industry. It is responsible for defining how, at the highest code development level, can a piece of code be interacted with. It defines the public functions, structures and data that can eb

Is CMake really needed?!

C++ is a widely used programming language owing to its powerful capabilities and fast operation. Among several other things, being a compiled language makes C++ really really fast.

While compilation is a topic for later, it can be understood naively as breaking down a code to its almost machine-level version and preprocessing parts as much as possible such that when executed, considerable sections of the code already have prepared answers or execute immediately on the processor and no time is spent in conversion of human-readable code into machine-compatible code at runtime.

The most common and rudimentary Hello World C++ program has one main.cpp file and it can be compiled using the following terminal command to obtain the binary.
~$ g++ main.cpp -o main // Compile
~$ ./main // Execute

If there are 3 files, namely si_int.cpp, com_int.cpp and the main.cpp where the two former files have functions to compute simple interest and compound interest, used(by importing) in the last main.cpp file to calculate results; they could be compiled using terminal command (for C++11)
~$ g++ si_int.cpp com_int.cpp main.cpp -o main -std=c++11 // Compile
~$ ./main // Execute

The two examples are indicative of the cumbersome process that could shape if there are more files, more dependencies, more libraries to link and other such unique requirements while code compilation; command-line compilation is certainly not the way to go.

For reassurance, here are some tags needed for g++ to achieve more features.  
-I<include path> - Specify a directory (to include files from)  
-L<library path> - Specify a library directory  
-0 - Turn ON optimizations by the compiler  
-l<library> - Link with library lib<library>.a
-Wall - Turn on Warnings during compilations  
-g - Generate flags for debugging during compilation (Used by GDB)  

Considering the challenges in compilation, CMake provides options to the user to configure the complete project and package it as per need be. The conditions, compilation tags, machine dependencies, language versions and many such parameters.

CMake is a high-level build-system customized for C++. CMake tracks and stores all flags and conditions that should be followed when the code is finally compiled and run. The liberty of allowing extensibility in code compilation conditions and external libraries/resources used makes CMake a very useful tool.

Nuances of CMake

The CMakeLists.txt has instructions that help developers design different build scenarios and conditional usage of generators, versions and more. Certain general CMake commands are used for some common operations. The common parameters, description and command to configure the same in a CMakeLists.txt are summarized here.

Note: Most of the command signatures are only short-hand signatures and do not show all the options and configurable parameters that CMake actually suppports. More detailed explanation(generally needed only if a very complex setup is employed) can be found on the official website of CMake.

  • Set string variables using actual string values   set(<variable_identifier> <string_value>)

  • Set string variables using another variable value   set(<variable_identifier> <${another_variable_identifier}>)

  • Append string variables using another variable value   string(APPEND <variable_identifier> <string_value>)

  • Set list variables using actual string values   set(<list_identifier> <string_value1> <string_value2>)

  • Set list variables using another list value   set(<list_identifier> <${another_list_identifier}>)

  • Append list variables using another list value   list(APPEND <list_identifier> <string_value>)

The string_value variable can be a file name as well. The identifiers can either be user defined for later use the script or from the common list of CMake supported variables like CMAKE_BUILD_TYPE and PROJECT_LINK_LIBS among others.

  • CMake Package version to be used. Versions > 3.0.0 are generally used though.  
    cmake_minimum_required(VERSION 3.18.0)

  • Operations dependent on OS type. CMake can generate different configurations depending on Linux/Apple/Windows OS.  if(APPLE)  // do something for APPLE OS   endif()     if(UNIX AND LINUX)   // do something for LINUX   endif())     if(WIN32)   // do something for WINDOWS OS   endif()

  • Software build type
    set(CMAKE_BUILD_TYPE Release/Debug)

  • C++ Version. For instance, C++11 in this case
    set(CMAKE_CXX_STANDARD 11)

  • Give a name to the project
    project(<string_value>)

  • An executable is built from the source file and assign the string_value as the name of the executable
    add_executable(<string_value> <code_file_name>)

  • Add the executable library to the compilation sequence
    add_library(<string_value> <library_type> <file_location>)   For example,
    add_library_(<libName> SHARED/STATIC src/lib_executable.cpp)   If STATIC, then the name of the library is libName.a and it is libName.so if SHARED

  • Include the header files from the source code into the build environment
    include_directories(<include_header_locations>)

  • While to set source code files to a string value, all files need to be mentioned manually, GLOB or GLOB_RECURSE allows for searching and selecting multiple source code files
    file(GLOB SOURCES "src/*.cpp")

  • Several properties need to define for the executable binary An example would be setting the language as CXX(for C++).   set_target_properties(cmake_usage_example PROPERTIES LINKER_LANGUAGE CXX)

  • Defining the location in the system for installation of the library.  
    install(TARGET <libray_name> DESTINATION <destination_location>)

  • Find the location of a library and store its reference in a temporary VARIABLE cache.
    find_package(<VARIABLE> <library_name> <path_to_library>)

  • Link an already extant library (either native library or third-party installed library or custom-built one ) to the current executable or library being created  
    target_link_libraries(<to_be_linked> options <to_link_ref>)   For example  
    target_link_libraries(libApp LINK_PUBLIC ${VARIABLE}) can be found from something like find_package

Example C++ Application & CMakeLists.txt

  • Install CMake and check version
    sudo make install cmake
    cmake --version

The following example is a simple C++ application. It has a class with functions for a few mathematical operations. The main script to be executed uses this class as need be. Finally, the Unix Makefiles CMake generator will be used to create the build system Makefile.

Repository Tree
Repository Tree

Finally, the project is executed using the steps:

  • We create a build folder to avoid cluttering built files with source code - mkdir -p build
  • cd into the folder and then run cmake .. where the two dots represent the presence of CMakeLists.txt in one folder prior; to generate the project files
  • Run make or make <executable> to compile the source code
  • ./cmake_usage_example to run the compiled sample code