#+INCLUDE: theme/style.org 
#+TITLE: CPP / C++ - Building Systems and Build Automation 
#+DESCRIPTION: cpp/c++ code examples and demonstrations.
#+STARTUP: content 

 + [[wiki:index][Index]]

* Building Systems 
** Building System 

Some building systems:

  + [[https://cmake.org/][CMake]] Meta building system which can generate project files and
    building scripts for platform-preferred building systems. For
    instance, it can generate Makefile for U*nix-like system, Ninja
    build scripts, Visual Studio solutions and so on.
    + Note: CMake may not be the best building system or not have the best
      IDEs. Now, it is supported by Microsft's Visual Studio and
      JetBrains' Clion IDE and others.
    + See:
      + [[http://cliutils.gitlab.io/modern-cmake/][An Introduction to Modern CMake]]
      + [[https://gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1][Effective Modern CMake]]
      + https://github.com/ttroy50/cmake-examples
      + [[https://cristianadam.eu/20181202/a-better-qnx-cmake-toolchain-file/][A Better QNX CMake Toolchain File - Cristian Adam]]

  + *GNU Autotool* (GNU Building System) - One of the most used building
    systems in open source projects for Unix-like operating systems,
    specially Linux.
    + Projects using GNU autotool have the files: configure.ac and
      Makefine.am. They often have the instruction for installing as:
      ./configure && make && make install. 
    + Projects using Autotools: Emacs editor; GIT version control
      system; GNU Core utils; GIMP image manipulation app.
    + Problems:
      + Brittle and poorly designed. 
      + Hard to read 
      + Hard to use and complicated
      + Requires many configuration files.
      + Does not work well on Windows 
      + Not famililar for Windows users.

  + [[https://github.com/microsoft/msbuild][MSBuild]] / *Visual Studio Solutions*
    * Building system used by Microsft Visual Studio IDE. The
      configuration files, _*.vcxproj_ and _*.sln_ of Visual Studio
      Solution are both building systems scripts and project
      configuration files.
    * Features:
      + Most used building system on MS-Windows for C# and C++ projects.
      + Some Windows frameworks such as MFC - Microsft Foundation and
        ATL - Active Template Library only support Visual Studio
        Solutions. 
    * Problems:
      + Only supported by Visual Studio IDE and Visual Studio Code Editor.
      + Only supported on Windows.
      + Lots of cryptic XML files, not human-readable and not intended
        to be edited directly.
      + The code from Visual Solution files cannot be reused. Any
        changes requires several clicks and browsing the IDE, thus not
        scalable.
      + Hard to use external libraries dependencies.
      + Hard to build from command line, require batch script hacks.
    * Note:
      + Visual Studio IDE, now has CMake support.
      + MSBuild engine now is open source available at https://github.com/microsoft/msbuild
    * See:
      + [[https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild?view=vs-2019][MSBuild concepts]] 
      + [[https://docs.microsoft.com/en-us/cpp/build/msbuild-visual-cpp?view=vs-2019][MSBuild on the command line - C++]]
      + [[https://docs.microsoft.com/en-us/cpp/build/projects-and-build-systems-cpp?view=vs-2019][C/C++ projects and build systems in Visual Studio]]
      + [[https://docs.microsoft.com/en-us/visualstudio/extensibility/internals/solution-dot-sln-file?view=vs-2019][Solution (.sln) file]] 
      + [[https://docs.microsoft.com/en-us/visualstudio/ide/solutions-and-projects-in-visual-studio?view=vs-2019][Solutions and projects in Visual Studio]]
      + [[https://devblogs.microsoft.com/cppblog/building-your-c-application-with-visual-studio-code/][Building your C++ application with Visual Studio Code]]

  + [[https://mesonbuild.com/][Meson]] - "Meson is an open source build system meant to be both
    extremely fast, and, even more importantly, as user friendly as
    possible. The main design point of Meson is that every moment a
    developer spends writing or debugging build definitions is a
    second wasted. So is every second spent waiting for the build
    system to actually start compiling code."
    + Features:
      + multiplatform support for Linux, macOS, Windows, GCC, Clang,
        Visual Studio and others 
      + supported languages include C, C++, D, Fortran, Java, Rust
      + built-in multiplatform dependency provider that works together
        with distro packages 
    + Side notes: 
      + Can generate Visual Studio Projects
      + Uses Ninja building system as backend.
      + Support CMake dependencies
      + Supports Conan package manager 
    + Projects using Meson:
      + [[https://gitlab.gnome.org/GNOME/nautilus][Nautilus]] 
      + [[https://github.com/systemd/systemd][SystemD]]
      + [[https://github.com/radare/radare2][Radare2]]
      + [[https://mesonbuild.com/Users.html][Full list]]
    + IDE Support:
      + [[https://wiki.gnome.org/Apps/Builder][Gnome Builder]]
      + [[https://www.kdevelop.org/][KDevelop]]
      + [[https://www.eclipse.org/cdt/][Eclipse CDT (Experimental support)]]
      + [[https://github.com/prozum/meson-cmake-wrapper][Meson CMake Wrapper]] => For IDEs that support CMake (Visual
        Studio, CLion, QTCreator, KDevelop) 
    + Problems:
      + Less IDE support and adoption than CMake and harder to use
        with IDEs.

  + *QMake* - QT Framework Building Systems
    + Problem: Brittle and only supported by QTCreator IDE.
    + Note: QT Now supports CMake

  + *KBuild* - Linux Kernel's building system. => Building system used
    for building Linux kernel image and kernel modules (device drivers).

  + [[https://build2.org/][build2]] - "build2 is an open source (MIT), cross-platform build
    toolchain for developing and packaging C++ code. It is a hierarchy
    of tools that includes the build system, package dependency manager
    (for package consumption), and project dependency manager (for
    project development)."
    + See: [[https://news.ycombinator.com/item?id=17188851][Build2, a Cargo-like dependency and build manager for C/C++ | Hacker News]]

  + [[https://xmake.io][xmake]] -  "xmake is a cross-platform build utility based on lua. The
    project focuses on making development and building easier and
    provides many features (.e.g package, install, plugin, macro,
    action, option, task ...), so that any developer can quickly pick
    it up and enjoy the productivity boost when developing and building
    project. "
    + Github: https://github.com/tboox/xmake
    + Advatange:
      + Lua-like syntax
      + Less verbose than CMake
      + Run lua scripts
      + Generation of projects, for instance Visual studio solutions.

  + [[https://docs.bazel.build/versions/master/bazel-overview.html][Bazel]] (Building system created by Google for C and C++.)
    + "Bazel is an open-source build and test tool similar to Make,
      Maven, and Gradle. It uses a human-readable, high-level build
      language. Bazel supports projects in multiple languages and
      builds outputs for multiple platforms. Bazel supports large
      codebases across multiple repositories, and large numbers of
      users."
    + Note: Written in Java. 

  + *Make* (GNU Make, BSD Make and NMake) - Simple and quick building
    system more used on Unix-like operating systems.
    + Disadvantages:
      + Fragmentation - There are many variants (GNU Make, BSD Make
        and NMake - Microsft's Make), although GNU Make is the most
        used one. 
      + Brittle
      + Hard to modify
      + Hard to add dependencies 

* Make and GNU Make - Makefiles 
*** Overview 

Despite being one of the oldest building systems for C and C++, dating
back to 1976, Make is still widely used on Unix-like operating
systems, such as Linux, BSD-variants, MacOSX and so on. Make is not
only useful for C or C++, the tool can also be used with any other
programming language or for any type of building automation such as
compiling Latex (Tex) files. 

Make Variants (Implementations):
   + GNU Make (Most used)
   + BSD Make
   + NMake - Microsft's Make

Note: 
 + This text assumes that the *Make* used is *GNU Make*

Advantages: 
   + Easier usage
   + Available on most Unix-like operating systems
   + Can be used for automating any type of building. 

Drawbacks: 

   + Makefiles uses tabs instead of spaces which makes it brittle and
     easier to break if the editor settings are not appropriate.

   + Fragmentation: there is no a single Make tool, actually there are
     many incompatible implementations, namely: BSD Make; GNU Make,
     mostly used on Linux; Microsft's Make or NMake.

   + Hard to use on Windows, Make requires many helper executables
     such as echo, cp, ls, rm, ...

   + Poor IDE support 

   + No scalable for large projects

   + Hard to change     

   + Hard to add dependencies

   + Hard to understand and modify

 *Command Line Summary*

|--------------------------------------------+----------------------------------------------------------------------------------------|
| Make Command                               | Description                                                                            |
|--------------------------------------------+----------------------------------------------------------------------------------------|
| $ make --version                           | Show version                                                                           |
| $ make --help                              | Show help                                                                              |
|                                            |                                                                                        |
| $ make                                     | Run the file 'Makefile' in the current directory, executing the 'all' target.          |
| $ make CC=clang CXX=clang++                | Target 'all' for current Makefile, but sets C compiler to clang and C++ one to clang++ |
| $ make <TARGET>                            | Run the target <TARGET>                                                                |
| $ make <TARGET> VAR1=VAL1 VAR2=VAL2        | Run some target named <TARGET> setting variable VAR1 to VAL1, VAR2 to VAL2.            |
| $ make clean                               | Run the target 'clean' for the Makefile in current directory.                          |
| $ make install                             | Run the target 'install' for the current Makefile                                      |
| $ make help                                | Run the target 'help' for the current Makefile.                                        |
|                                            |                                                                                        |
| $ make -C ~/path/dir~                        | Run the file 'Makefile' in the directory  ~/path/dir~, executes 'all' target.            |
| $ make -C ~/path/dir~ <TARGET>               | Executes target <TARGET> of Makefile in  ~/path/dir~                                     |
| $ make -f Other.make                       | Run the Makefile named 'Other.make' in current directory                               |
| $ make -f Other.make <TARGET>              | Run the target <TARGET> of Makefile named 'Other.make' in current directory.           |
| $ make -C ~/path/dir~ -f Other.make          | Run the Makefile named Other.make' in directory ~/path/dir~,  executes 'all' target      |
| $ make -C ~/path/dir~ -f Other.make <TARGET> | Run the Makefile named Other.make' in directory ~/path/dir~,  executes 'all' target      |
|                                            |                                                                                        |
|--------------------------------------------+----------------------------------------------------------------------------------------|

 *Common Make variables Summary*

|----------+------------------------------------------------|
| Variable | Description                                    |
|----------+------------------------------------------------|
| CC       | C compiler, most common value is 'gcc'         |
| CXX      | C++ Compiler, most common value is 'g++'       |
| LD       | Linker                                         |
|          |                                                |
| CFLAGS   | C compilation flags, i.e: -Wall -Wextra -g ... |
| CXXFLAGS | C++ compilation flags                          |
|          |                                                |
|          |                                                |
|----------+------------------------------------------------|


 *Target Shortcuts summary* 

|--------------+--------------------------------------------|
| Variable     | Description                                |
|--------------+--------------------------------------------|
| *Target*       |                                            |
| $@           | target file name                           |
| $(@D)        | target path (directory only)               |
| $(@F)        | target file name without directory         |
|              |                                            |
| *Dependencies* |                                            |
| $<           | name of first dependency                   |
| $*           | name of first dependency without extension |
| $^           | name of all dependencies of the target     |
| $(<D)        | path of first dependencies                 |
| $(<F)        | paths of all dependencies                  |
|              |                                            |
|--------------+--------------------------------------------|

 *Makefile Variable Tricks Summary*

|------------------------------------------+-----------------------------------------+----------------------------------------------|
| Trick                                    | Expansion                               | Description                                  |
|------------------------------------------+-----------------------------------------+----------------------------------------------|
| SRC     := $(wildcard src/*.cpp)         | SRC := src/fil1.cpp src/file2.cpp ...   | Gets all files with *.cpp extension in ./src |
| packs   := n0 n1 n2                      |                                         |                                              |
| packs-p := $(addprefix --pack ,$(packs)) | pack-p := --pack n1 --pack n2 --pack n3 | Add prefix --pack to each ~n[i]~               |
| pwd     := $(shell pwd)                  | pwd := /home/archbox/project1           | Expands to shell command output.             |
| ~${HOME}~                                  | /home/user/username                     | Expands to environment variable              |
| file    := ${HOME}/file1.exe             | /home/user/username/file1.exe           | -                                            |
|                                          |                                         |                                              |
|------------------------------------------+-----------------------------------------+----------------------------------------------|

Multi line variable assignment

#+BEGIN_SRC makefile 
  CFLAGS  = -DUSE_STDPERIPH_DRIVER
  CFLAGS += -c -fmessage-length=0 -g3 -gdwarf-2 -O0 -Wall -Wa,-adhlns="$@.lst"
  CFLAGS += -mthumb -mcpu=cortex-m4
  CFLAGS += -MMD -MP -MF"$@.d" -MT"$@.d"
  CFLAGS += -Iinc -Iinc/cmsis -Iinc/peripherals -Iinc/stm32f4xx
#+END_SRC

*** Project Example 

 *File: Makefile*

#+BEGIN_SRC sh
     #---------------------------------------------------#
     #     Compilation and Linker Settings               #
     #---------------------------------------------------#

  CXX = g++   # C++ Compiler
  CC  = gcc   # C Compiler

  CCFLAGS  =                          # C compiler flags
  CXXFLAGS = -std=c++1z -pedantic -Wall -Wextra # C++ Compiler flags

  LDFLAGS   =   # C Linker Flags
  LDXXFLAGS =   # C++ Linker flags

  # DEBUG = 1 => Enables debug building
  # DEBUG = 0 => Enable release building
  DEBUG ?= 0
  ifeq ($(DEBUG), 1)
      # (-g)  => Enable debug symbols
      # (-O0) => Disable optimizations
      # -DNDEBUG => Enable assertions
      CXXFLAGS  += -g -O0  -DNDEBUG
  else
       # Release mode =>> Enable optimization
       CXXFLAGS += -O3
       # Enable Link-time optimiztion
       LDXXFLAGS += # -flto -ffunction-sections -fdata-sections
  endif

  APP2_OBJS = app2.o stats.o

     #---------------------------------------------------#
     #     Makefile Rules                                #
     #---------------------------------------------------#

  # Main rule executed when use runs '$ make' without
  # any argument.
  #---------------------------------------------------
  all: app1.bin app2.bin

  # This rule builds the executable 'app1.bin'
  #----------------------------------------------------
  #  $^ => Refers to all dependencies (app1.o, app1.o)
  #  $@ => Refers to the target name, 'app1.bin'
  app1.bin : app1.o stats.o
          @echo -e "\n [INFO] Building executable 'app1.bin'"
          $(CXX) -o $@ $^ $(LDXXFLAGS)

  # This rule builds the executable 'app2.bin'
  #----------------------------------------------------
  #  $^ => Refers to all dependencies (app1.o, app1.o)
  #  $@ => Refers to the target name, 'app1.bin'
  app2.bin : $(APP2_OBJS)
          @echo -e "\n [INFO] Building executable 'app2.bin'"
          $(CXX) -o $@ $^ $(LDXXFLAGS)

  # Compiles all *.cpp files to *.o (object-code files) which
  # are inputs to the linker.
  #
  #--------------------------------------------------
  #  $< => Name of dependency (on right-hand size, example: someFile.cpp)
  #  $@ => Name of target (on the left-hand side)
  #
  %.o : %.cpp
          @echo -e "\n [INFO] Building object code: $<"
          $(CXX) -c $< -o $@  $(CXXFLAGS)

  # This rule runs the executable app1.bin, the dependency is 'app1.bin'
  #------------------------------------------------------------
  app1_run: app1.bin
          ./app1.bin

  # This rule deletes all object-codes (*.o, *.bin, *.so, *.dll, *.exe ...)
  #-------------------------------------------------------
  clean:
          @echo -e "\n [INFO] Cleaning compilation output."
          rm -rf -v *.o *.bin

  install: app1.bin app2.bin
          @echo -e "\n [INFO] Installing application to: $(INSTALL_PATH)"
          mkdir -p $(INSTALL_PATH)
          cp -rv $^ $(INSTALL_PATH)
#+END_SRC

 *File: stats.hpp*

#+BEGIN_SRC cpp 
   #include <iostream>
   #ifndef _STATS_HPP_
   #define _STATS_HPP_

   class Stats
   {
   public:
           Stats();
           ~Stats();
           Stats(const Stats&) = delete;
           Stats& operator=(const Stats&) = delete;
           void   add(double x);
           void   clear();
           double mean() const;
           double sum()  const;
           size_t count() const;	
   private:
           struct pimpl;
           pimpl* m_pimpl;
   };

   #endif 
#+END_SRC

 *File: stats.cpp* 

#+BEGIN_SRC cpp 
   #include <iostream>
   #include <cmath>
   #include <algorithm> 
   #include <vector>
   #include <numeric>

   #include <stats.hpp>

   struct Stats::pimpl {
      std::vector<double> dataset = {};
   };

   Stats::Stats(): m_pimpl(new Stats::pimpl)
   { }

   Stats::~Stats() {
       std::puts(" [INFO] ~Stats() destructor called. Ok. ");
       delete m_pimpl;
       m_pimpl = nullptr;
   }

   void Stats::add(double x) 
   {
       m_pimpl->dataset.push_back(x);
   }

   void Stats::clear()
   {
      m_pimpl->dataset.clear();
   }

   double Stats::sum() const
   {
       return std::accumulate( m_pimpl->dataset.begin()
                             , m_pimpl->dataset.end(), 0.0);
   }

   double Stats::mean() const 
   {
       return this->sum() / m_pimpl->dataset.size();
   }

   size_t Stats::count() const {
       return m_pimpl->dataset.size();
   }
#+END_SRC

 *File: app1.cpp* 

#+BEGIN_SRC cpp 
  #include <iostream>
  #include <stats.hpp> 

  int main()
  {
        std::cout << " [TRACE] Running application 'app1' - OK" << "\n";

        Stats st;
        st.add(10.0); st.add(20.6354); st.add(-5.62); st.add(8.623);
        st.add(20.0); st.add(20.6354); st.add(-5.62); st.add(8.623);

        std::cout << "  => st.count() = " << st.count() << "\n";
        std::cout << "  =>   st.sum() = " << st.sum() << "\n";
        std::cout << "  =>  st.mean() = " << st.mean() << "\n";

        return 0;
  }
#+END_SRC

 *File: app2.cpp* 

#+BEGIN_SRC cpp 
  #include <iostream>
  #include <string>

  #include "stats.hpp"

  int main(int argc, char** argv)
  {
       std::cout << " [INFO] Running application: 'app2' - OK" << "\n";

       if(argc < 2){
           return EXIT_FAILURE;
       }

       Stats st;

       for(int i = 1; i < argc; i++)
          try {
             st.add( std::stod(argv[i]) );
          } catch(std::invalid_argument const& ex)
          {
             std::cerr << " Error: invalid input <" << argv[i] << std::endl;
             return EXIT_FAILURE;	
          }

       std::cout << "  => st.count() = " << st.count() << "\n";
       std::cout << "  =>   st.sum() = " << st.sum() << "\n";
       std::cout << "  =>  st.mean() = " << st.mean() << "\n";	

       return EXIT_SUCCESS;
  }
#+END_SRC

  *Run target 'all'* (Release mode)

 + $ make => Runs rule 'all'

#+BEGIN_SRC sh 
  $ make

   [INFO] Building object code: app1.cpp
  g++    -c app1.cpp -o app1.o  -std=c++1z -pedantic -Wall -Wextra  -O3

   [INFO] Building object code: stats.cpp
  g++    -c stats.cpp -o stats.o  -std=c++1z -pedantic -Wall -Wextra  -O3

   [INFO] Building executable 'app1.bin'
  g++    -o app1.bin app1.o stats.o  

   [INFO] Building object code: app2.cpp
  g++    -c app2.cpp -o app2.o  -std=c++1z -pedantic -Wall -Wextra  -O3

   [INFO] Building executable 'app2.bin'
  g++    -o app2.bin app2.o stats.o  

#+END_SRC

 *Run target 'all'* (Debug Mode)

Run target 'all' which builds target 'app1.bin', 'app2.bin'

#+BEGIN_SRC sh 
  $ make DEBUG=1

   [INFO] Building object code: app1.cpp
  g++    -c app1.cpp -o app1.o  -std=c++1z -pedantic -Wall -Wextra  -g -O0  -DNDEBUG

   [INFO] Building object code: stats.cpp
  g++    -c stats.cpp -o stats.o  -std=c++1z -pedantic -Wall -Wextra  -g -O0  -DNDEBUG

   [INFO] Building executable 'app1.bin'
  g++    -o app1.bin app1.o stats.o 

   [INFO] Building object code: app2.cpp
  g++    -c app2.cpp -o app2.o  -std=c++1z -pedantic -Wall -Wextra  -g -O0  -DNDEBUG

   [INFO] Building executable 'app2.bin'
  g++    -o app2.bin app2.o stats.o 

#+END_SRC

Debug application 'app1.bin'

#+BEGIN_SRC sh
   $ gdb --silent app1.bin 
   Printing of typedefs defined in a class in on
   Reading symbols from app1.bin...done.

   (gdb) list
   1	#include <iostream>
   2	
   3	#include <stats.hpp> 
   ... ... ... ... 

   # Set breaking point at main() 
   (gdb) b main

   # Run program app1.bin 
   (gdb) r

   gdb) n
    [TRACE] Running application 'app1' - OK
   9		Stats st;

   (gdb) p st
   $1 = {
     m_pimpl = 0x616280
   }
 
   ... ...    ... ...    ... ...    ... ... 

  (gdb) p st->m_pimpl->dataset
  $5 = std::vector of length 8, capacity 8 = {10, 20.635400000000001, -5.6200000000000001, 
    8.6229999999999993, 20, 20.635400000000001, -5.6200000000000001, 8.6229999999999993}
  (gdb) 
#+END_SRC

 *Run target 'clean'*

Clean all compilation files: 

#+BEGIN_SRC sh 
   $ make clean

    [INFO] Cleaning compilation output.
   rm -rf -v *.o *.bin
   removed 'app1.o'
   removed 'app2.o'
   removed 'stats.o'
   removed 'app1.bin'
   removed 'app2.bin'
#+END_SRC

 *Run target 'app1.bin'*

#+BEGIN_SRC sh 
  $ make app1.bin

   [INFO] Building object code: app1.cpp
  g++    -c app1.cpp -o app1.o  -std=c++1z -pedantic -Wall -Wextra  -O3

   [INFO] Building object code: stats.cpp
  g++    -c stats.cpp -o stats.o  -std=c++1z -pedantic -Wall -Wextra  -O3

   [INFO] Building executable 'app1.bin'
  g++    -o app1.bin app1.o stats.o  
#+END_SRC

 *Run target 'app2.bin'*

#+BEGIN_SRC sh
  $ make app2.bin

   [INFO] Building object code: app2.cpp
  g++    -c app2.cpp -o app2.o  -std=c++1z -pedantic -Wall -Wextra  -O3

   [INFO] Building executable 'app2.bin'
  g++    -o app2.bin app2.o stats.o  
#+END_SRC

 *Run target 'app1_run'*

The target app1_run runs the executable 'app1.bin'. It is only
compiled if not built yet.

#+BEGIN_SRC sh 
  $ make app1_run

   [INFO] Building object code: app1.cpp
  g++    -c app1.cpp -o app1.o  -std=c++1z -pedantic -Wall -Wextra  -O3

   [INFO] Building object code: stats.cpp
  g++    -c stats.cpp -o stats.o  -std=c++1z -pedantic -Wall -Wextra  -O3

   [INFO] Building executable 'app1.bin'
  g++    -o app1.bin app1.o stats.o  
  ./app1.bin
   [TRACE] Running application 'app1' - OK
    => st.count() = 8
    =>   st.sum() = 77.2768
    =>  st.mean() = 9.6596
   [INFO] ~Stats() destructor called. Ok. 
#+END_SRC

Run target again: 

#+BEGIN_SRC sh 
  $ make app1_run
  ./app1.bin
   [TRACE] Running application 'app1' - OK
    => st.count() = 8
    =>   st.sum() = 77.2768
    =>  st.mean() = 9.6596
   [INFO] ~Stats() destructor called. Ok. 
#+END_SRC

 *Run target 'install'*

Run target 'make install'

#+BEGIN_SRC sh 
  $ make install INSTALL_PATH=/tmp/bin DEBUG=1

   [INFO] Building object code: app1.cpp
  g++    -c app1.cpp -o app1.o  -std=c++1z -pedantic -Wall -Wextra  -g -O0  -DNDEBUG

    ... ... ...   ... ... ...   ... ... ...   ... ... ...   ... ... ... 

   [INFO] Installing application to: /tmp/bin
  mkdir -p /tmp/bin
  cp -rv app1.bin app2.bin /tmp/bin
  'app1.bin' -> '/tmp/bin/app1.bin'
  'app2.bin' -> '/tmp/bin/app2.bin'
#+END_SRC

Test applications/executables: 

#+BEGIN_SRC sh 
  $ /tmp/bin/app2.bin 10.354 -9.243  100.523 5.6154
   [INFO] Running application: 'app2' - OK
    => st.count() = 4
    =>   st.sum() = 107.249
    =>  st.mean() = 26.8123
   [INFO] ~Stats() destructor called. Ok. 
#+END_SRC

*** Reading 

 *Documentation*

   * *GNU Make Manual*
     * <http://www.chiark.greenend.org.uk/doc/make-doc/make.html/index.html#SEC_Contents>

 *Useful Reading*

   * *Make (Software)* - Wikipedia 
     * <https://en.wikipedia.org/wiki/Make_(software)>

   * *Tutorial on writing makefiles*
     * <https://www.math.colostate.edu/~yzhou/computer/writemakefile.html>

   * *Practical Makefiles, by example* - John Tsiombikas
     * <http://nuclear.mutantstargoat.com/articles/make/>

   * *Creating a Basic Makefile* - Flex Technologies
     + <https://felixcrux.com/blog/creating-basic-makefile<> 

   * *Debugging make -Tips and tricks to get make working for you, not
     against you* - Peter Seebach
     * <https://www.ibm.com/developerworks/library/l-debugmake/index.html>

   * *What’s Wrong With GNU make?*
     + <http://www.conifersystems.com/whitepapers/gnu-make/>

   * *How can I configure my makefile for debug and release builds?*
     + <https://stackoverflow.com/questions/1079832>

 *Makefiles for Latex, Tex compilation* 

   + *latex and Makefiles*
     + <http://www.usenix.org.uk/content/latex.html>

   + *Makefiles for Latex*
     + <https://scaron.info/blog/makefiles-for-latex.html>

   + *A simple Makefile for LaTeX projects.*
     + <https://gist.github.com/Nemo157/539229>

   + *Continuous integration and automatic deployment of LaTeX files*
     + <https://ljvmiranda921.github.io/notebook/2018/02/04/continuous-integration-for-latex/>

 *Makefiles for general automation*

   + *Reproducibility with Make*
     + <https://the-turing-way.netlify.com/make/make.html>

   + *GNU Make for Reproducible Data Analysis*
     + <http://zmjones.com/make/>

   + *Using Make for reproducible scientific analysis*
     + <https://www.software.ac.uk/blog/2016-10-06-using-make-reproducible-scientific-analyses>

   + *Reproducible bioinformatics pipelines using Make*
     + <http://byronjsmith.com/make-bml/>

   + *Reproducible Data Processing: Make + Docker*
     + <https://towardsdatascience.com/towards-efficient-and-reproducible-ml-workflows-part-1-analysis-a98c945d7616>

   + *Makefiles for R/LaTex Projects*
     + <https://dzone.com/articles/makefiles-rlatex-projects>

   + *Makefiles in Python Projects*
     + <https://krzysztofzuraw.com/blog/2016/makefiles-in-python-projects.html>

   + *Makefiles with Python*
     + <https://blog.horejsek.com/makefile-with-python/>

   + *Makefile for Python projects* - GIST
     + <https://gist.github.com/lumengxi/0ae4645124cd4066f676>
* GNU Autotools Building System  
** Overview 

  * Autotools
    + =>> GNU Building System or umbrela name for _autoconf_, _automake_
      and _libtool_. GNU autotools is used by many open-source Linux
      projects and embedded Linux.

  * Some Projects using GNU Autotools:
    + [[https://github.com/emacs-mirror/emacs][GNU Emacs]]
    + [[https://github.com/bminor/glibc][GNU Glibc]] (GNU C Runtime Library used in Linux)
    + [[https://github.com/gcc-mirror/gcc/blob/master/configure.ac][GNU GCC Compiler]]
    + [[https://gitlab.freedesktop.org/NetworkManager/NetworkManager/blob/master/configure.ac][NetworkManager]] (Linux network manager daemon)
    + [[https://github.com/hishamhm/htop/blob/master/configure.ac][Htop tool]] - htop is an interactive text-mode process viewer.
    + [[https://github.com/nghttp2/nghttp2/blob/master/configure.ac][Nhttp2]] - (Implementation of the Hypertext Transfer Protocol version 2 in C.)
    + [[https://github.com/mingw-deb/libffi/blob/master/configure][LibFFI]]
    + [[https://github.com/wireapp/libsodium/blob/master/configure.ac][LibSodium]]

  * Used mostly in Unix-like or POSIX-like operating systems,
    specially Linux.

  * Motivation:
    * Deal with legacy systems or software
    * Learn about alternative building systems
    * Maintenance of existing open source projects
    * Possible porting GNU autotools to CMake 
    * Embedded Linux

  * Supported *IDEs - Integrated Development Environments*
    * Eclipse IDE
      + [[https://www.eclipse.org/linuxtools/][Linux Tools Plugin]]
      + [[https://wiki.eclipse.org/CDT/Autotools/User_Guide][Eclipse CDT Autotools User Guide]]
    * NetBeans
      * [[http://plugins.netbeans.org/plugin/51647/cppgnuautotools][CppGnuAutoTools Plugin]]
    * QTCreator
      * [[https://doc.qt.io/qtcreator/creator-projects-autotools.html][Autotools Project Manager Plugin]]

  * Availalble for:
    + Linux, MacOSX, FreeBSD, OpenBSD, NetBSD and so on.

  * Documentation:
    * [[http://www.gnu.org/software/autoconf/][GNU Autoconf]]
    * [[http://www.gnu.org/software/automake/automake.html][GNU Automake]]
    * [[http://www.gnu.org/software/libtool/libtool.html][GNU Libtool]]

  * Supported Programming Languages
    * C
    * C++
    * Objective C
    * Fortran
    * Fortran77
    * Erlang 

  * Terminal Documentation:
    * $ info automake
    * $ info autoconf
    * $ info libtool 

  * Common build configuration facilities
    + $ ./configure 
    + $ make
    + $ make install   => Install application.
    + $ ... ... ..
** Reference Card 

 *Installation* 

Install on Fedora Linux Distribution: 

#+BEGIN_SRC sh 
  $ sudo dnf install autoconf automake
#+END_SRC

Install on Ubuntu or Debian Linux Distributions: 

#+BEGIN_SRC sh 
  $ apt-get install autoconf automake 
#+END_SRC

 *GNU Make Command for GNU autotools* 

|--------------------+-----------------------------------------------------------------------------|
| Make Command       | Description                                                                 |
|--------------------+-----------------------------------------------------------------------------|
| $ make             | Build application                                                           |
| $ make -j4         | Build applciation using 4 threads                                           |
|                    |                                                                             |
| $ make check       | Run tests                                                                   |
|                    |                                                                             |
| $ make clean       | Clean compilation files                                                     |
| $ make distclean   | Remove generated autools files.                                             |
|                    |                                                                             |
| $ make install     | Install application in the system to: /usr/loca/bin, /etc, ...              |
| $ make intallcheck | Check installation                                                          |
| $ make uninstall   | Remove installation files                                                   |
|                    |                                                                             |
| $ make dist        | Create source distribution tarball                                          |
| $ make distcheck   | Similar to make dist, but checks if the compilation, the creates a tarball. |
|                    |                                                                             |
|--------------------+-----------------------------------------------------------------------------|

 *Most Configuration variables* 

|----------+--------------------------------+---|
| Variable | Description                    |   |
|----------+--------------------------------+---|
| CC       | C compiler                     |   |
| CXX      | C++ compuler                   |   |
|          |                                |   |
| CPPFLAGS | C and C++ Preprocessor flags   |   |
| CFLAGS   | Flags of the C compiler        |   |
| CXXFLAGS | Flags of the C++ compiler      |   |
|          |                                |   |
| LDFLAGS  | Linker Flags                   |   |
| LIBS     | Libraries passed to the linker |   |
|          |                                |   |
|----------+--------------------------------+---|

 *Useful ./configure (Autotools) command line switches* 

Those are useful and recurring command line switches for building open
source applications or libraries from source. 

 + Show ./configure help   

#+BEGIN_SRC sh 
  $ ./configure --help 
#+END_SRC

 + General ./configure usage example. 

#+BEGIN_SRC sh 

  # ---- Example 1 --------------------#
  # Install to /usr, /usr/bin, /usr/include, /usr/lib, /usr/lib64 on Linux 
  $ ./configure  
  $ make 
  $ make install 

  # ---- Example 2 --------------------#
  $ ./configure  --with-feature1 --without-feature2 --eanable-option1 --enable-option2=no 
  $ make 
  $ make install 

  # ---- Example 3 --------------------#
  # Install to custom location (directory)
  $ ./configure --prefix=/my/custom/location  --with-feature1 \
       --without-feature2 --eanable-option1 --enable-option2=no --disable-option3

  $ make -j4 # Build using 4 threads (faster)
  $ make install 
#+END_SRC

  
 *Autotools workflow for users* 

STEP 1: User run ./configure selecting build options; 

#+BEGIN_SRC sh 
  # Install application in default directory
  $ ./configure
 
  # Install the application in another directory 
  $ ./configure --prefix=/home/user/juliuscaesar/opt
#+END_SRC

STEP 2: Run (GNU) make for building. 

#+BEGIN_SRC sh 
  $ make 

  # Run GNY make with 4 threads 
  $ make -j4 

  # Run $ make and $ make install in a single step 
  $ make -j4 && sudo make install 
#+END_SRC

STEP 3: Install. 

#+BEGIN_SRC sh 
  $ make install 

  # If permission is needed 
  $ sudo make install 
#+END_SRC

 *Developer Worflow* 

STEP 1:
  + => Create files:
    + _configure.ac_  for *autoconf* - written in a language similar to
      Bash (Bourne Shell Script) which is processed by *M4* macro
      processor.
      + Note: It is necessary to take care with whitespaces in macro invocations.
    + _Makefile.am_ for *automake*. 


STEP 2: 
 + => The developer runs autoreconf that  generates the files
   ./configure and Makefile.in

STEP 3: 
 + => Test the generated files by running:
   + $ ./configure && make && make install.
** Example: Basic GNU autotools project 
*** Project Files 
File: main.cpp 

#+BEGIN_SRC cpp 
  #include <iostream>

  int main()
  {
    std::cout << "Hello world autotools" << std::endl;
    return 0;
  }
#+END_SRC

File: configure.ac 

#+BEGIN_SRC sh 
   #------- File: configure.ac ----------#
   #-------------------------------------# 

   # app => Is the file name without extensions
   # 0.1 => Is the version 
   AC_INIT( [app], [0.1], [maintener@email.com])

   # Require at least autoconf version >= 2.68 
   AC_PREREQ([2.68])  
   AM_INIT_AUTOMAKE([-Wall -Wextra])

   # ./configure creates a Makefile
   AC_CONFIG_FILES([Makefile])

   # Find and check C compiler 
   AC_PROG_CC
   # Find and check a C++ compiler 
   AC_PROG_CXX 
   AC_OUTPUT 
#+END_SRC

File: Makefile.am 

#+BEGIN_SRC sh 
  # Contains all executable targets 
  bin_PROGRAMS = app

  # Sources for the executable targets 
  app_SOURCES  = app.cpp 
#+END_SRC

File: clean.sh 
  + Helper bash script used for cleaning current directory.

#+BEGIN_SRC sh 
  #!/usr/bin/env sh 
  rm -v configure config.log config.status install-sh missing aclocal.m4 compile depcomp 
  rm -vrf autom4te.cache
  rm -v *.o *.bin *.so
  rm *~ # Remove temporary files 
#+END_SRC
*** Building Steps

 *STEP 1:* Performed by developer 

 + Create additional metadata files needed by _GNU autotools_

#+BEGIN_SRC sh 
  $ touch README NEWS AUTHORS ChangeLog # Set metadata files                                                │
#+END_SRC

 *STEP 2:* Performed by developer 

 + Run atuoreconf for generating ./configure shell script and addition files.
 + Run: $ autoreconf -i -v 

#+BEGIN_SRC sh 
  $ autoreconf -i -v 

  autoreconf: Entering directory `.'
  autoreconf: configure.ac: not using Gettext
  autoreconf: running: aclocal 
  autoreconf: configure.ac: tracing
  autoreconf: configure.ac: not using Libtool
  autoreconf: running: /usr/bin/autoconf
  autoreconf: configure.ac: not using Autoheader
  autoreconf: running: automake --add-missing --copy --no-force
  configure.ac:11: warning: unknown warning category 'extra'
  configure.ac:17: installing './compile'
  configure.ac:11: installing './install-sh'
  configure.ac:11: installing './missing'
  Makefile.am: installing './depcomp'
  autoreconf: Leaving directory `.'
#+END_SRC

 *STEP 3:* Performed by user

 + The following steps are performed by end-users or maintainers for
   installing the application in the system or in a local directory. 

 + Generate the Makefile by running the configuration script.

Run: $ ./configure  

#+BEGIN_SRC sh 
  $ ./configure 
  checking for a BSD-compatible install... /usr/bin/install -c
  checking whether build environment is sane... yes
  checking for a thread-safe mkdir -p... /usr/bin/mkdir -p
  checking for gawk... gawk

  ... ... ...   ... ... ...   ... ... ...   ... ... ... 
       # Suppress output for breviety purposes 
  ... ... ...   ... ... ...   ... ... ...   ... ... ... 

  checking dependency style of g++... gcc3
  checking that generated files are newer than configure... done
  configure: creating ./config.status
  config.status: creating Makefile
  config.status: executing depfiles commands
#+END_SRC

Run: $ ./configure CC=clang CXX=clang++ for using clang.

#+BEGIN_SRC sh 
 $ ./configure CC=clang CXX=clang++
#+END_SRC

 *STEP 4:* Performed by user

 + Run the makefile (GNU make)

Run: $ make 

#+BEGIN_SRC sh 
   $ make

   g++ -DPACKAGE_NAME=\"app\" -DPACKAGE_TARNAME=\"app\" -DPACKAGE_VERSION=\"0.1\"  \
       -DPACKAGE_STRING=\"app\ 0.1\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\"   \
        -DPACKAGE=\"app\" -DVERSION=\"0.1\" -I.     -g -O2 -MT app.o -MD -MP -MF   \
       .deps/app.Tpo -c -o app.o app.cpp \
       mv -f .deps/app.Tpo .deps/app.Po \
 
    g++  -g -O2   -o app app.o  
#+END_SRC

Run: $ make install 

#+BEGIN_SRC sh 
  $ make install
  make[1]: Entering directory '/home/archbox/projects/autools1'
   /usr/bin/mkdir -p '/usr/local/bin'
    /usr/bin/install -c app '/usr/local/bin'
  /usr/bin/install: cannot create regular file '/usr/local/bin/app': Permission denied
  make[1]: *** [Makefile:313: install-binPROGRAMS] Error 1
  make[1]: Leaving directory '/home/archbox/projects/autools1'
  make: *** [Makefile:615: install-am] Error 2

#+END_SRC

Run: $ make dist => Create a tarball distribution. 

#+BEGIN_SRC sh 
  $ make dist
  make  dist-gzip am__post_remove_distdir='@:'
  make[1]: Entering directory '/home/archbox/projects/autools1'
  if test -d "app-0.1"; then find "app-0.1" -type d ! -perm -200 -exec chmod u+w {} ... ... 
  test -d "app-0.1" || mkdir "app-0.1"

    .. ... ... ... ... ... ... 
  rm -rf "app-0.1" || { sleep 5 && rm -rf "app-0.1"; }; else :; fi
#+END_SRC

Check the tarball file: 

#+BEGIN_SRC sh 
      $ tar -tzvf app-0.1.tar.gz 
  drwxrwxr-x 1000/1000         0 2019-10-21 15:23 app-0.1/
  -rw-rw-r-- 1000/1000     42147 2019-10-21 15:22 app-0.1/aclocal.m4
  -rwxrwxr-x 1000/1000    154043 2019-10-21 15:22 app-0.1/configure
  -rw-rw-r-- 1000/1000       546 2019-10-21 15:01 app-0.1/configure.ac
  -rw-rw-r-- 1000/1000       101 2019-10-21 14:28 app-0.1/app.cpp
  -rwxr-xr-x 1000/1000     14676 2019-10-21 15:22 app-0.1/install-sh
  -rw-rw-r-- 1000/1000         0 2019-10-21 15:02 app-0.1/ChangeLog
  -rwxr-xr-x 1000/1000      6872 2019-10-21 15:22 app-0.1/missing
  -rwxr-xr-x 1000/1000     23566 2019-10-21 15:22 app-0.1/depcomp
  -rw-rw-r-- 1000/1000         0 2019-10-21 15:02 app-0.1/AUTHORS
  -rw-r--r-- 1000/1000     35147 2019-10-21 15:01 app-0.1/COPYING
  -rw-r--r-- 1000/1000     15756 2019-10-21 15:01 app-0.1/INSTALL
  -rwxr-xr-x 1000/1000      7381 2019-10-21 15:22 app-0.1/compile
  -rw-rw-r-- 1000/1000       117 2019-10-21 14:52 app-0.1/Makefile.am
  -rw-rw-r-- 1000/1000         0 2019-10-21 15:02 app-0.1/README
  -rw-rw-r-- 1000/1000         0 2019-10-21 15:02 app-0.1/NEWS
  -rw-rw-r-- 1000/1000     23477 2019-10-21 15:22 app-0.1/Makefile.in
#+END_SRC

 *STEP 5:* 

 + Test the application. 

#+BEGIN_SRC sh 
  # Check executable file 
  $ file app
  app: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter 
  /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=29f5b104ac648c3286ed616ea4cf4007a6b51ae2, 
  with debug_info, not stripped

  # Run native executable 
  $ ./app
  Hello world autotools
#+END_SRC

 *Build and install the application into a new location* 

Run configure script. 

#+BEGIN_SRC sh 
  # Build with clang and install at ~/opt/app-test 
  $ ./configure CC=clang CXX=clang++ --prefix=$HOME/opt/app-test
 
#+END_SRC

Run make and make install 

#+BEGIN_SRC sh 
  $ make install
  make[1]: Entering directory '/home/archbox/projects/autools1'
   /usr/bin/mkdir -p '/home/archbox/opt/app-test/bin'
    /usr/bin/install -c app '/home/archbox/opt/app-test/bin'
  make[1]: Nothing to be done for 'install-data-am'.
  make[1]: Leaving directory '/home/archbox/projects/autools1'
#+END_SRC

Test installation: 

#+BEGIN_SRC sh 
  $ tree /home/archbox/opt/app-test
  /home/archbox/opt/app-test
  └── bin
      └── app

  1 directory, 1 file
#+END_SRC

Run the application: 

#+BEGIN_SRC sh 
  $ /home/archbox/opt/app-test/bin/app 
  Hello world autotools
#+END_SRC
** Further Reading 

  + [[https://eklitzke.org/how-to-autotools][How To Use Autotools]] 

  + *GNU Autotools Book* - https://www.star.bnl.gov/~liuzx/autobook.html

  + [[https://elinux.org/images/4/43/Petazzoni.pdf][Embedded Linux Conference 2016 - GNU Autotools Tutorial]]

  + [[http://freesoftwaremagazine.com/articles/brief_introduction_to_gnu_autotools/][Chapter 1: A brief introduction to the GNU Autotools]]

  + [[https://stackoverflow.com/questions/10999549/how-do-i-create-a-configure-script][linux - How do I create a configure script? - Stack Overflow]]

  + [[https://developer.fedoraproject.org/tech/languages/c/autotools.html][Autotools — Fedora Developer Portal]]

  + [[http://thegreyblog.blogspot.com/2013/09/cc-project-built-with-gnu-build-system.html][C/C++ Project Built with GNU Build System (A.K.A. GNU Autotools): NetBeans vs. Eclipse CDT]]
* QMake Building System 
*** Overview 

QMake is a building system generator used by QT Framework and QT
Creator IDE, similar to CMake, which can generate Makefiles and
projects for Visual Studio IDE (MSBuild building system).

Features: 

  + QT Framework now provides official support to CMake, but QMake is
    still used in many old projects and libraries.

Benefits: 

  + For now, QMake still provides better support fro cross compilation
    and for mobile platforms, such as Android or iOS.

  + Multi-ABI cross-compilation support.

Problems: 

  + Not supported by other IDEs than QT Creator. So, it is not
    supported by Eclipse, Netbeans or Visual Studio.

  + Brittle building system => It does not support multiple targets or
    generating multiple executables in the same building script.

  + Hard to use with third-party libraries or libraries using CMake or
    other building systems. 

*** QMake project example 


Project Structure: 

#+BEGIN_SRC sh 
  $ cd /path/to/project-root/dir
  $ tree .
  .
  ├── app1
  │   ├── app1.cpp
  │   ├── app1.pro
  │   ├── dataset.cpp
  │   └── dataset.hpp
  ├── app2
  │   ├── app2.cpp
  │   └── app2.pro
  ├── apptest.pro
#+END_SRC

File: apptest.pro 

#+BEGIN_SRC conf 
  TEMPLATE = subdirs
  SUBDIRS = app1 app2
#+END_SRC

 *Target app1 - subproject* 

  + Target _app1_ is a console executable. 


File: app1/app1.pro

#+BEGIN_SRC sh 
  TEMPLATE = app
  CONFIG += console c++11
  CONFIG -= app_bundle
  CONFIG -= qt

  SOURCES += \
          dataset.cpp \
          app1.cpp

  HEADERS += \
      dataset.hpp
#+END_SRC

File: app1/app1.cpp 

#+BEGIN_SRC cpp 
  #include <iostream>
  #include "dataset.hpp"

  int main()
  {
      Dataset ds;
      ds.add_data(10.34);
      ds.add_data(100.23);
      ds.add_data(-100.0);

      std::cout << "Hello World!" << std::endl;
      std::cout << " ds[0] = " << ds.get_data(0) << std::endl;
      std::cout << " ds[1] = " << ds.get_data(0) << std::endl;
      std::cout << " ds[2] = " << ds.get_data(0) << std::endl;

      return 0;
  }
#+END_SRC

File: app1/dataset.hpp 

#+BEGIN_SRC cpp 
  #ifndef DATASET_HPP
  #define DATASET_HPP

  #include <cstddef>

  class Dataset{
      struct pimpl;
      pimpl* m_pimpl;
  public:
      Dataset();
      ~Dataset();
      Dataset(Dataset cosnt&) = delete;
      Dataset& operator=(Dataset const&) = delete;
      void   add_data(double x);
      double get_data(size_t idx) const;
  };

  #endif // DATASET_HPP
#+END_SRC

File: app1/dataset.cpp 

#+BEGIN_SRC cpp 
  #include "dataset.hpp"

  #include <memory>
  #include <vector>
  #include <iostream>

  struct Dataset::pimpl
  {
      std::vector<double> data;
  };


  Dataset::Dataset(): m_pimpl(new pimpl)
  {
      std::cout << " [INFO] Constructor called. OK" << std::endl;
  }

  Dataset::~Dataset(){
      delete m_pimpl;
  }

  void Dataset::add_data(double x)
  {
      m_pimpl->data.push_back(x);
  }

  double Dataset::get_data(size_t i) const
  {
      return m_pimpl->data[i];
  }
#+END_SRC

  *Target app2 - subproject*

  + Target _app2_ is a user interface QT Widgets executable which file
    name is app2_linux_x64.bin

File: app2/app2.pro 

#+BEGIN_SRC sh 
  QT       += core gui widgets
  TEMPLATE  = app
  CONFIG   += c++1z
  # CONFIG  += console c++1z
  # CONFIG  -= app_bundle

  # Change
  TARGET   = app2_linux_x64.bin
  SOURCES += app2.cpp 
#+END_SRC

File: app2/app2.cpp 

#+BEGIN_SRC cpp 
  #include <iostream>

  #include <QApplication>
  #include <QtWidgets>

  int main(int argc, char* argv[])
  {
      std::cout << " [INFO] Starting Application 2 OK" << std::endl;

      QApplication app(argc, argv);

      QPushButton button("Click me");
      button.setVisible(true);

      QObject::connect(&button, &QPushButton::clicked,
                       []{
                           std::cout << " [INFO] I Was clicked OK" << std::endl;
                       });

      return app.exec();
  }
#+END_SRC

 *Building and Running* 

STEP 1 - Create a ./build directory for separating the compilation
output from the source code. 

#+BEGIN_SRC sh 
  $ mkdir build && cd build
#+END_SRC

STEP 2 - Run QMake

#+BEGIN_SRC sh 
  $ qmake ../

  $ ls
  Makefile
#+END_SRC

STEP 3 - Run Makefile 

#+BEGIN_SRC sh 
  $ make

  $ tree .
  .
  ├── app1
  │   ├── app1
  │   ├── app1.o
  │   ├── dataset.o
  │   └── Makefile
  ├── app2
  │   ├── app2_linux_x64.bin
  │   ├── app2.o
  │   └── Makefile
  └── Makefile

  2 directories, 8 files
#+END_SRC

STEP 4 - Check executables 

#+BEGIN_SRC sh 
  # Run executable app1 
  #--------------------------------------
  $ app1/app1 
   [INFO] Constructor called. OK
  Hello World!
   ds[0] = 10.34
   ds[1] = 10.34
   ds[2] = 10.34

  # Run executable app2 
  #--------------------------------------
  $ app2/app2_linux_x64.bin 
   [INFO] Starting Application 2 OK
#+END_SRC

*** Further Reading 

Official Documentation 

   + *QMake Manual* - QT Company
     + <https://doc.qt.io/qt-5/qmake-manual.html> 

   + *QMake - Getting Started* - QT Company
     + <https://doc.qt.io/qt-5/qmake-tutorial.html>

   + *QMake Running* 
     + https://doc.qt.io/qt-5/qmake-running.html

   + *QMake Variables*
     + <https://doc.qt.io/qt-5/qmake-variable-reference.html>

General 

   + *Configuring QMake*
     + <https://doc.qt.io/qt-5/qmake-environment-reference.html>

   + KDAB - *Clang Tidy, part 2: Integrate qmake and other build systems using Bear*
     + <https://www.kdab.com/clang-tidy-part-2-integrate-qmake-and-other-build-systems-using-bear/>

   + KDAB - *Qt for Android better than ever before*
     + <https://www.kdab.com/qt-for-android-better-than-ever-before/>

   + *QMake for neophytes*
     + <https://www.develer.com/en/qmake-for-neophytes/>

   + *SUBDIRS for Fun and Profit*
     + <http://silmor.de/qtstuff.subdirs.php>

   + *C++ GUI Programming with Qt4: Building Qt Applications*
     + <http://www.informit.com/articles/article.aspx?p=1405563&seqNum=2>

   + *Building a Linux system for the STM32MP1: setting up a Qt5 application development environment*
     + <https://bootlin.com/blog/building-a-linux-system-for-the-stm32mp1-setting-up-a-qt5-application-development-environment/>

Questions: 

  + [[https://stackoverflow.com/questions/1538398/how-do-i-use-qmake-to-build-multiple-binaries-in-a-single-project/1538639][qt - How do I use qmake to build multiple binaries in a single project? - Stack Overflow]]

  + [[https://forum.qt.io/topic/15202/building-multiple-binaries-in-one-qt-project/4][Building multiple binaries in one qt project | Qt Forum]]

