{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Application compilation\n",
    "\n",
    "- Compilation stages.\n",
    "- Static and shared libraries.\n",
    "- GNU make utility.\n",
    "- Environment variable settings.\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Compilation stages\n",
    "\n",
    "Suppose one needs to compile a single source C program, `code.c`, into an executable binary, `code.x`:\n",
    "```bash\n",
    "gcc -o code.x code.c\n",
    "```\n",
    "This implies the following implicit compilation steps that also can be done in 4 stages:\n",
    "\n",
    "| stage | name  | command | product \n",
    "|:-  |  :-  | :--  | -: \n",
    "|1\t|Preprocessing |gcc -E code.c -o code.i\t|#define, #ifdef, #include are processed \n",
    "|2\t|Compiling |gcc -S code.i -o  code.s\t|Assembly file, code.s \n",
    "|3\t|Asembling |gcc -c code.s -o  code.o\t|Creates object file in the machine language \n",
    "|4\t|Linking |gcc  code.o  -o  code.x\t|Code is linked with the other .o object files and libraries into an executable binary\n",
    "\n",
    "\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Compilation in stages (Exercise)\n",
    "\n",
    "Download `code.c`\n",
    "```bash\n",
    "wget http://linuxcourse.rutgers.edu/2024/html/lessons/application_compilation/downloads/code.c\n",
    "```\n",
    "Look at the content of the source file:\n",
    "```bash\n",
    "less code.c\n",
    "```\n",
    "Compile the source file in the four stages - Preprocessing, Compiling, Assembling, and Linking:\n",
    "```bash\n",
    "    gcc -E code.c -o  code.i\n",
    "    gcc -S code.i -o  code.s\n",
    "    gcc -c code.s -o  code.o\n",
    "    gcc    code.o -o  code.x -lm\n",
    "```\n",
    "Check the file type of the compilation products:\n",
    "```bash\n",
    "    file code.i\n",
    "    file code.s\n",
    "    file code.o\n",
    "    file code.x\n",
    "```\n",
    "Browse the content of the two ASCII files, `code.i` and `code.s`:\n",
    "```bash\n",
    "    less code.i\n",
    "    less code.s\n",
    "```\n",
    "Run the executable, code.x:\n",
    "```bash\n",
    "./code.x\n",
    "```\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Source code with multiple files\n",
    "\n",
    "If a source code consists of several files, the compilation procedure can be done either in one step:\n",
    "```bash\n",
    "gcc code.c extra_1.c extra_2.c extra_3.c -o code.x \n",
    "```\n",
    "or multiple steps with compiling into object files first:\n",
    "```bash\n",
    "    gcc -c code.c\n",
    "    gcc -c extra_1.c\n",
    "    gcc -c extra_2.c\n",
    "    gcc -c extra_3.c\n",
    "    gcc -o code.x code.o extra_1.o extra_2.o extra_3.o\n",
    "```\n",
    "\n",
    "The object files, however, can be collected into a library, for example:\n",
    "```bash \n",
    "    gcc -cr libextra.a extra_1.o extra_2.o extra_3.o\n",
    "```\n",
    "The library can be later linked with the code at compilation:\n",
    "```bash\n",
    "   gcc -o code.x code.c -lextra\n",
    "```\n",
    "This allows the library reuse and makes the code compilation cleaner.\n",
    "\n",
    "\n",
    "If the header files `*.h`, containing library prototypes, and the libraries `*.a` are located in the directories different from the source `*.c` files, their location needs to be specified as follows:\n",
    "```bash\n",
    "gcc  -o code.x code.c -I<path_to_include> -L<path_to_lib> -lextra\n",
    "```\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Static libraries\n",
    "\n",
    "A part of the code that can be compiled separately and linked with the other codes should be built as a library.\n",
    "\n",
    "![](img/staticlibs.jpg)\n",
    "\n",
    "Building a static library\n",
    "```bash\n",
    "    gcc -c extra_1.c\n",
    "    gcc -c extra_2.c\n",
    "    gcc -c extra_3.c\n",
    "    ar -cr libextra.a extra_1.o extra_2.o extra_3.o\n",
    "    ranlib libextra.a\n",
    "```\n",
    "to see the object files included in the library:\n",
    "```bash\n",
    "ar -t libextra.a\n",
    "```\n",
    "or \n",
    "```bash\n",
    "nm libextra.a\n",
    "```\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Static library content and compilation  (Exerecise)\n",
    "\n",
    "Get the list of modules included in the Math library, `libm.a`:\n",
    "```bash\n",
    "ar -t /usr/lib/x86_64-linux-gnu/libm-2.36.a\n",
    "```\n",
    "Btw, file `/usr/lib/x86_64-linux-gnu/libm.a` is a part of package `libc6-dev`. If the file is missing on your computer, install package `libc6-dev` by using command `apt-get install libc6-dev`.\n",
    "\n",
    "Compile code.c with the Math library statically:\n",
    "```bash\n",
    "gcc code.c -o code_stat.x -lm -static\n",
    "```\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Shared libraries\n",
    "\n",
    "Shared libraries, unlike static ones, are not compiled into the application binaris. They are loaded into the memory and linked with the application at a run time. Other running codes can use the loaded shared libraries.\n",
    "\n",
    "![](img/sharedlibs.jpg)\n",
    "\n",
    "Building a shared library\n",
    "```bash\n",
    "gcc -c -fPIC extra_1.c\n",
    "gcc -c -fPIC extra_2.c\n",
    "gcc -c -fPIC extra_3.c\n",
    "gcc -shared extra_1.o extra_2.o extra_3.o -o libextra.so\n",
    "```\n",
    "To compile the application with the library we would follow the step below:\n",
    "```bash\n",
    "gcc -o code.x code.c -L. -lextra\n",
    "```\n",
    "To see what the shared libraries the code needs, use `ldd` command\n",
    "```bash\n",
    "ldd code.x\n",
    "```\n",
    "If the library is not found, include it into `LD_LIBRARY_PATH` environment variable, for example:\n",
    "```bash\n",
    "export LD_LIBRARY_PATH=.\n",
    "```\n",
    "Alternatively the shared library path can be included into `/etc/ld.so.conf`. After `/etc/ld.so.conf` has been updated, we need to run command\n",
    "```bash\n",
    "/sbin/ldconfig -p\n",
    "```\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Compilation with a shared library (Exercise)\n",
    "\n",
    "Get the list of shared libraries required by command, ls:\n",
    "```bash\n",
    "ldd /bin/ls\n",
    "```\n",
    "Compile `code.c` with the Math shared library (default compilation):\n",
    "```bash\n",
    "gcc code.c -o code_shared.x -lm\n",
    "```\n",
    "Get the list of shared libraries required by `code_stat.x`, and `code_shared.x`:\n",
    "```bash\n",
    "ldd code_stat.x\n",
    "ldd code_shared.x\n",
    "```\n",
    "Compare the sizes of the executable files:\n",
    "```bash\n",
    "ls -lh  code_*.x\n",
    "```\n",
    "\n",
    "<hr>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Single code compilation and libraries (Exercise)\n",
    "\n",
    "By following the instructions below, download and compile a C code, \n",
    "[singe.c](https://linuxcourse.rutgers.edu/2024/html/lessons/application_compilation/downloads/single.c.html), \n",
    "that computes the scalar product of two vectors:\n",
    "![](img/formula_sc_product.png)\n",
    "```bash\n",
    "mkdir single_code\n",
    "cd single_code\n",
    "wget http://linuxcourse.rutgers.edu/2024/html/lessons/application_compilation/downloads/single.c\n",
    "gcc -o app.x single.c\n",
    "./app.x\n",
    "```\n",
    "When prompted for the input parameters, type in the dimension of the vectors and the value of their components, for example:\n",
    "\n",
    "```{admonition} ouput/input:\n",
    "    Vector dimension n=2\n",
    "    Input 2 coordinate x: 3 5\n",
    "    Input 2 coordinate y: 1 6\n",
    "```\n",
    "Compile the code with a static library.\n",
    "This time, the original `single.c` file has been devided into 3 separate modules: [`main.c`, `Scalar_Product.h`, and `Scalar_Product.c`](https://linuxcourse.rutgers.edu/2024/html/lessons/application_compilation/downloads/all_modules.html).\n",
    "Download the archive and untar it into a new directory:\n",
    "```bash\n",
    "cd\n",
    "wget http://linuxcourse.rutgers.edu/2024/html/lessons/application_compilation/downloads/source_code.tgz\n",
    "mkdir code_static\n",
    "cp source_code.tgz code_static\n",
    "cd code_static\n",
    "tar -zxvf source_code.tgz\n",
    "```\n",
    "Build the static library:\n",
    "```bash\n",
    "gcc -c Scalar_Product.c\n",
    "ar -cr libScalar_Product.a Scalar_Product.o\n",
    "ranlib libScalar_Product.a\n",
    "```\n",
    "Verify the content of library `libScalar_Product.a`:\n",
    "```bash\n",
    "ar -t libScalar_Product.a\n",
    "```\n",
    "Compile the main code and link with the library:\n",
    "```bash\n",
    "gcc -c main.c\n",
    "gcc -o app.x main.o -L. -lScalar_Product\n",
    "```\n",
    "Make sure the compiled code runs fine:\n",
    "```bash\n",
    "./app.x\n",
    "```\n",
    "Compile the code with a shared library.\n",
    "Create a new directory and untar the source code in it:\n",
    "```bash\n",
    "cd ..\n",
    "mkdir code_so\n",
    "cp source_code.tgz code_so\n",
    "cd code_so\n",
    "tar -zxvf source_code.tgz\n",
    "```\n",
    "Build the shared library:\n",
    "```bash\n",
    "gcc -fPIC -c Scalar_Product.c\n",
    "gcc -shared Scalar_Product.o -o libScalar_Product.so\n",
    "```\n",
    "Compile the main code and link with the shared library:\n",
    "```bash\n",
    "gcc -c main.c\n",
    "gcc -o apps.x main.o -L. -lScalar_Product\n",
    "```\n",
    "Verify that apps.x executable requires `libScalar_Product.so` library:\n",
    "```bash\n",
    "ldd apps.x\n",
    "```\n",
    "It should show that the shared library is not found, `libScalar_Product.so` => not found. Try running the code\n",
    "```bash\n",
    "./apps.x\n",
    "```\n",
    "It should fail to run.\n",
    "Set `LD_LIBRARY_PATH` environment variable to include the current working directory:\n",
    "```bash\n",
    "export LD_LIBRARY_PATH=./\n",
    "```\n",
    "Check if the loader finds the library and try running the code again:\n",
    "```\n",
    "ldd apps.x\n",
    "./apps.x\n",
    "```\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Software builders\n",
    "\n",
    "To automate software builds, tests, and installation there are specialized developer tools including:\n",
    "\n",
    "- Make\n",
    "- CMake\n",
    "- Bazel\n",
    "- Gradle\n",
    "- Ninja\n",
    "- Meson\n",
    "- npm\n",
    "- MS Visual Studio for linux\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## make and  Makefile\n",
    "\n",
    "Utility `make` is used for compilation and installation of a software with many source files.\n",
    "<br>\n",
    "        `make` keeps track with the dependencies and file access times tamps. Compilation is done in the correct order to meet prerequisites and satisfy the dependencies. If one or several source codes have been updated, only these and the files that depend on them would be recompiled by command make.\n",
    "        <br>\n",
    "`Makefile` syntax:\n",
    "![](img/Makefile.jpg)\n",
    "\n",
    "`Makefile` example:\n",
    "```{admonition} Makefile\n",
    "    app.x: main.o libScalar_Product.a\n",
    "            gcc -o app.x main.o -L. -lScalar_Product\n",
    "\n",
    "    main.o: main.c Scalar_Product.h\n",
    "            gcc -c main.c\n",
    "\n",
    "    Scalar_Product.o: Scalar_Product.c\n",
    "            gcc -c Scalar_Product.c\n",
    "\n",
    "    libScalar_Product.a: Scalar_Product.o\n",
    "            ar -cr libScalar_Product.a Scalar_Product.o\n",
    "            ranlib libScalar_Product.a\n",
    "```\n",
    "`Makefile` or `makefile` would be processed by running command `make`:\n",
    "```bash\n",
    "make\n",
    "```\n",
    "If the `Makefile` has different name, for example `Makefile1`, it can be processed as follows:\n",
    "```bash\n",
    "make -f Makefile1\n",
    "```\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Makefile with macros\n",
    "\n",
    "Parameters that appear in the `Makefile` multiple times or that need to be modified, depending on the environment, can be expressed through macronames.\n",
    "<br>\n",
    "`Makefile` with macros example:\n",
    "```{admonition} Makefile:\n",
    "    #First, we define the MACRONAMES:\n",
    "    SLIB = libScalar_Product.a\n",
    "    APP=app.x\n",
    "    CC = gcc\n",
    "    CFLAGS = -O3\n",
    "    LIBPATH = .\n",
    "\n",
    "    #Then we refer to them by $(MACRONAMES):\n",
    "    $(APP): main.o $(SLIB)\n",
    "            $(CC) $(CFLAGS) -o $(APP) main.o -L$(LIBPATH) -lScalar_Product\n",
    "\n",
    "    main.o: main.c Scalar_Product.h\n",
    "            $(CC) $(CFLAGS) -c main.c\n",
    "\n",
    "    Scalar_Product.o: Scalar_Product.c\n",
    "            $(CC) $(CFLAGS) -c Scalar_Product.c\n",
    "\n",
    "    $(SLIB): Scalar_Product.o\n",
    "            ar -cr $(SLIB) Scalar_Product.o\n",
    "            ranlib $(SLIB)\n",
    "```\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Makefile with phony targets\n",
    "\n",
    "When a target in a `Makefile` rather means just an action than a file, it is called a phony target.\n",
    "`Makefile` with phony targets (`clean`, `install`, and `uninstall`):\n",
    "\n",
    "```{admonition} Makefile:\n",
    "    SLIB = libScalar_Product.a\n",
    "    APP=app.x\n",
    "    CC = gcc\n",
    "    CFLAGS = -O3\n",
    "    LIBPATH = .\n",
    "    INSTPATH = /usr/local\n",
    "\n",
    "    $(APP): main.o $(SLIB)\n",
    "            $(CC) $(CFLAGS) -o $(APP) main.o -L$(LIBPATH) -lScalar_Product\n",
    "\n",
    "    main.o: main.c Scalar_Product.h\n",
    "            $(CC) $(CFLAGS) -c main.c\n",
    "\n",
    "    Scalar_Product.o: Scalar_Product.c\n",
    "            $(CC) $(CFLAGS) -c Scalar_Product.c\n",
    "\n",
    "    $(SLIB): Scalar_Product.o\n",
    "            ar -cr $(SLIB) Scalar_Product.o\n",
    "            ranlib $(SLIB)\n",
    "\n",
    "    clean:\n",
    "            -rm -f *.o *.a $(APP)\n",
    "\n",
    "    install:\n",
    "            @cp -p $(APP) $(INSTPATH)/bin ;\\\n",
    "            chown root:root $(INSTPATH)/bin/$(APP) ;\\\n",
    "            cp -p $(SLIB) $(INSTPATH)/lib ;\\\n",
    "            chown root:root $(INSTPATH)/lib/$(SLIB) ;\\\n",
    "            echo \"Install $(APP) and $(SLIB) into $(INSTPATH)\"\n",
    "    \n",
    "    uninstall:\n",
    "            -@rm -f $(INSTPATH)/bin/$(APP)\n",
    "            -@rm -f $(INSTPATH)/lib/$(SLIB)\n",
    "            @echo \"Removed $(APP) and $(SLIB) from $(INSTPATH)\"\n",
    "```\n",
    "\n",
    "Special symbols in the command prefixes mean:\n",
    "<br>\n",
    "`-` - don't quit on error. For example, -rm won't quit if there is no files to delete.\n",
    "<br>\n",
    "`@` - don't print the command itself.\n",
    "\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Makefile with target `all`\n",
    "\n",
    "Target `all` in a `Makefile` envokes a sequence of other targets.\n",
    "<br>\n",
    "Makefile with target `all`:\n",
    "```{admonition} Makefile:\n",
    "    SLIB = libScalar_Product.a\n",
    "    APP=app.x\n",
    "    CC = gcc\n",
    "    CFLAGS = -O3\n",
    "    LIBPATH = .\n",
    "    INSTPATH = /usr/local\n",
    "\n",
    "    all: $(APP) install clean\n",
    "\n",
    "    $(APP): main.o $(SLIB)\n",
    "            $(CC) $(CFLAGS) -o $(APP) main.o -L$(LIBPATH) -lScalar_Product\n",
    "\n",
    "    main.o: main.c Scalar_Product.h\n",
    "            $(CC) $(CFLAGS) -c main.c\n",
    "\n",
    "    Scalar_Product.o: Scalar_Product.c\n",
    "            $(CC) $(CFLAGS) -c Scalar_Product.c\n",
    "\n",
    "    $(SLIB): Scalar_Product.o\n",
    "            ar -cr $(SLIB) Scalar_Product.o\n",
    "            ranlib $(SLIB)\n",
    "\n",
    "    clean:\n",
    "            -rm -f *.o *.a $(APP)\n",
    "\n",
    "    install:\n",
    "            @cp -p $(APP) $(INSTPATH)/bin ;\\\n",
    "            chown root:root $(INSTPATH)/bin/$(APP) ;\\\n",
    "            cp -p $(SLIB) $(INSTPATH)/lib ;\\\n",
    "            chown root:root $(INSTPATH)/lib/$(SLIB) ;\\\n",
    "            echo \"Install $(APP) and $(SLIB) into $(INSTPATH)\"\n",
    "\n",
    "    uninstall:\n",
    "            -@rm -f $(INSTPATH)/bin/$(APP)\n",
    "            -@rm -f $(INSTPATH)/lib/$(SLIB)\n",
    "            @echo \"Removed $(APP) and $(SLIB) from $(INSTPATH)\"\n",
    "```\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Makefile with suffix rules\n",
    "\n",
    "When there is need to compile many `*.c` codes into `*.o` binaries, the suffix rule can be implemented to avoid many target lines in the `Makefile`.\n",
    "<br>\n",
    "`Makefile` with the suffix rule:\n",
    "\n",
    "```{admonition} Makefile\n",
    "    SLIB = libScalar_Product.a\n",
    "    APP=app.x\n",
    "    CC = gcc\n",
    "    CFLAGS = -O3\n",
    "    LIBPATH = .\n",
    "    INSTPATH = /usr/local\n",
    "\n",
    "\n",
    "    $(APP): main.o $(SLIB)\n",
    "            $(CC) $(CFLAGS) -o $@ main.o -L$(LIBPATH) -lScalar_Product\n",
    "\n",
    "    .c.o:\n",
    "            @echo \"Compiling\" $<\n",
    "            $(CC) -c $<\n",
    "\n",
    "    $(SLIB): Scalar_Product.o\n",
    "            ar -cr $@ $<\n",
    "            ranlib $@\n",
    "\n",
    "    clean:\n",
    "            -rm -f *.o *.a $(APP)\n",
    "\n",
    "    install:\n",
    "            @cp -p $(APP) $(INSTPATH)/bin ;\\\n",
    "            chown root:root $(INSTPATH)/bin/$(APP) ;\\\n",
    "            cp -p $(SLIB) $(INSTPATH)/lib ;\\\n",
    "            chown root:root $(INSTPATH)/lib/$(SLIB) ;\\\n",
    "            echo \"Install $(APP) and $(SLIB) into $(INSTPATH)\"\n",
    "\n",
    "    uninstall:\n",
    "            -@rm -f $(INSTPATH)/bin/$(APP)\n",
    "            -@rm -f $(INSTPATH)/lib/$(SLIB)\n",
    "            @echo \"Removed $(APP) and $(SLIB) from $(INSTPATH)\"\n",
    "```\n",
    "\n",
    "|Special symbol | Meaning  \n",
    "|:- | -: \n",
    "|`$@`\t| name of current target.\n",
    "|`$<`\t| name of current dependency.\n",
    "|`$*`\t| name of current dependency without extension.\n",
    "|`$?` | list of dependencies changed more recently than current target.\n",
    " \n",
    " \n",
    " <hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Makefile with suffix rules and object file dependencies\n",
    "\n",
    "The suffix rule discussed in the previous slide doesn't contain dependencies for the targets. Below, we include the dependencies for the object files.\n",
    "<br>\n",
    "`Makefile` with the suffix rule and object file dependencies\n",
    "```{admonition} Makefile:\n",
    "    SLIB = libScalar_Product.a\n",
    "    APP=app.x\n",
    "    CC = gcc\n",
    "    CFLAGS = -O3\n",
    "    LIBPATH = .\n",
    "    INSTPATH = /usr/local\n",
    "    OBJS = main.o\n",
    "\n",
    "    $(APP): main.o $(SLIB)\n",
    "            $(CC) $(CFLAGS) -o $@ main.o -L$(LIBPATH) -lScalar_Product\n",
    "\n",
    "    .c.o:\n",
    "            @echo \"Compiling\" $<\n",
    "            $(CC) -c $<\n",
    "\n",
    "    $(SLIB): Scalar_Product.o\n",
    "            ar -cr $@ $<\n",
    "            ranlib $@\n",
    "\n",
    "    $(OBJS): Scalar_Product.h\n",
    "\n",
    "    clean:\n",
    "        -rm -f *.o *.a $(APP)\n",
    "\n",
    "    install:\n",
    "            @cp -p $(APP) $(INSTPATH)/bin ;\\\n",
    "            chown root:root $(INSTPATH)/bin/$(APP) ;\\\n",
    "            cp -p $(SLIB) $(INSTPATH)/lib ;\\\n",
    "            chown root:root $(INSTPATH)/lib/$(SLIB) ;\\\n",
    "            echo \"Install $(APP) and $(SLIB) into $(INSTPATH)\"\n",
    "\n",
    "    uninstall:\n",
    "            -@rm -f $(INSTPATH)/bin/$(APP)\n",
    "            -@rm -f $(INSTPATH)/lib/$(SLIB)\n",
    "            @echo \"Removed $(APP) and $(SLIB) from $(INSTPATH)\"\n",
    "```\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Makefiles (Exercises)\n",
    "\n",
    "- Simple `Makefile`:\n",
    "Download `Makefile1` into directory `code_static`, created during the exercises with the static library compilation.\n",
    "```bash\n",
    "cd code_static\n",
    "rm *.o app.x *.a\n",
    "wget http://linuxcourse.rutgers.edu/2024/html/lessons/application_compilation/downloads/Makefile1\n",
    "```\n",
    "Check the content of the `Makefile`:\n",
    "```bash\n",
    "less Makefile1\n",
    "```\n",
    "Run make for compilation:\n",
    "```bash\n",
    "make -f Makefile1\n",
    "```\n",
    "Notice the sequence of the compilation steps. Run the command make again.\n",
    "Modify the time stamps of `main.c` then re-run make and notice the compilation steps made:\n",
    "```bash\n",
    "touch main.c\n",
    "make -f Makefile1\n",
    "```\n",
    "Modify the time stamps of `Scalar_Product.h` then re-run make and notice the compilation steps made:\n",
    "```bash\n",
    "touch Scalar_Product.h\n",
    "make -f Makefile1\n",
    "```\n",
    "Modify the time stamps of `Scalar_Product.c` then re-run make and notice the compilation steps made:\n",
    "```bash\n",
    "touch Scalar_Product.c\n",
    "make -f Makefile1\n",
    "```\n",
    "\n",
    "- Makefile containing macros, suffix rules, and phony targets. Download `Makefile6` into directory `code_static`:\n",
    "```bash\n",
    "wget http://linuxcourse.rutgers.edu/2024/html/lessons/application_compilation/downloads/Makefile6\n",
    "```\n",
    "See the content of `Makefile6`:\n",
    "```bash\n",
    "less Makefile6\n",
    "```\n",
    "Run the following command to remove the compiled files:\n",
    "```bash\n",
    "make -f Makefile6 clean\n",
    "```\n",
    "Verify there is no longer files `app.x`, `*.o`, and `libScalar_Product.a` in directory `code_static`.\n",
    "Run compilation:\n",
    "```bash\n",
    "make -f Makefile6\n",
    "```\n",
    "Install the compiled binary, `app.x` and the library, `libScalar_Product.a` into `/usr/local`:\n",
    "```bash\n",
    "sudo make -f Makefile6 install\n",
    "```\n",
    "Check if files `/usr/local/bin/app.x` and `/usr/local/lib/libScalar_Product.a` have been created.\n",
    "```bash\n",
    "ls -l /usr/local/bin\n",
    "ls -l /usr/local/lib\n",
    "```\n",
    "Remove the installed files:\n",
    "```bash\n",
    "sudo make -f Makefile6 uninstall\n",
    "```\n",
    "Verify taht the files have been removed:\n",
    "```bash\n",
    "ls -l /usr/local/bin\n",
    "ls -l /usr/local/lib\n",
    "```\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Multiple Makefiles. Software installation. (Exercises)\n",
    "\n",
    "Compilation and installation of software from its source code usually involves 4 steps: download and untar the archive, configuration, compilation, and installation. Multiple `Makefiles` may be involved if the software source is complex.\n",
    "\n",
    "- Download the tar archive and extract the files:\n",
    "```bash\n",
    "wget http://linuxcourse.rutgers.edu/2024/html/lessons/application_compilation/downloads/Project.tgz\n",
    "tar -zxvf Project.tgz\n",
    "```\n",
    "Check out the directory tree of `Project` and the files contained there:\n",
    "```bash\n",
    "apt-get install tree\n",
    "tree Project\n",
    "```\n",
    "You should notice two `Makefiles`: one in the root of directory `Project` and the other in subdirectory `src1`.\n",
    "\n",
    "- Configuration:\n",
    "```bash\n",
    "cd Project\n",
    "./configure\n",
    "```\n",
    "This sets the environment for the `Makefiles`.\n",
    "\n",
    "- Compilation:\n",
    "```bash\n",
    "make\n",
    "```\n",
    "- Installation:\n",
    "```bash\n",
    "sudo make install\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Makefiles in the project\n",
    "\n",
    "Command `make` above processes Makefile in directrory `Project`:\n",
    "\n",
    "```{admonition} Makefile:\n",
    "    SRC = src1\n",
    "\n",
    "    all:\n",
    "            (cd $(SRC); $(MAKE) )\n",
    "\n",
    "    clean:\n",
    "            (cd $(SRC); $(MAKE) clean )\n",
    "    \n",
    "    install:\n",
    "            (cd $(SRC); $(MAKE) install )\n",
    "\n",
    "    uninstall:\n",
    "            (cd $(SRC); $(MAKE) uninstall )\n",
    "\n",
    "```\n",
    "\n",
    "This Makefile contains phony targets, envoking make in subdirectory `src1`, which compiles the source codes, `*.c`, builds the library, the application binary and places them into subdirectories `lib` and `bin`.\n",
    "\n",
    "`Makefile` in directory `Project/src1`:\n",
    "```{admonition} Makefile:\n",
    "    SLIB = libScalar_Product.a\n",
    "    APP=app.x\n",
    "    CC = gcc\n",
    "    CFLAGS = -O3\n",
    "    LIBPATH = ../lib\n",
    "    INCPATH = ../include\n",
    "    BIN = ../bin\n",
    "    INSTPATH = /usr/local\n",
    "    OBJS = main.o\n",
    "\n",
    "    $(APP): main.o $(SLIB)\n",
    "        $(CC) $(CFLAGS) -o $@ main.o -L$(LIBPATH) -lScalar_Product\n",
    "        -cp $@ $(BIN)\n",
    "\n",
    "    .c.o:\n",
    "        @echo \"Compiling\" $<\n",
    "        $(CC) -c $< -I$(INCPATH)\n",
    "\n",
    "    $(SLIB): Scalar_Product.o\n",
    "        ar -cr $@ $<\n",
    "        ranlib $@\n",
    "        -cp $@ $(LIBPATH)\n",
    "\n",
    "    $(OBJS): $(INCPATH)/Scalar_Product.h\n",
    "\n",
    "    clean:\n",
    "        -rm -f *.o $(LIBPATH)/*.a *.a $(BIN)/$(APP) $(APP)\n",
    "\n",
    "    install:\n",
    "        @cp -p $(BIN)/$(APP) $(INSTPATH)/bin ;\\\n",
    "        chown root:root $(INSTPATH)/bin/$(APP) ;\\\n",
    "        cp -p $(LIBPATH)/$(SLIB) $(INSTPATH)/lib ;\\\n",
    "        chown root:root $(INSTPATH)/lib/$(SLIB) ;\\\n",
    "        echo \"Install $(APP) and $(SLIB) into $(INSTPATH)\"\n",
    "\n",
    "    uninstall:\n",
    "        -@rm -f $(INSTPATH)/bin/$(APP)\n",
    "        -@rm -f $(INSTPATH)/lib/$(SLIB)\n",
    "        @echo \"Removed $(APP) and $(SLIB) from $(INSTPATH)\"\n",
    "```\n",
    "After the compilation procedure completes, there will be binary, object files, sources, in the library in the subdirectoies of `Project`:\n",
    "```{admonition} tree:\n",
    "    Project\n",
    "    ├── bin\n",
    "    │   └── app.x\n",
    "    ├── configure\n",
    "    ├── include\n",
    "    │   └── Scalar_Product.h\n",
    "    ├── lib\n",
    "    │   └── libScalar_Product.a\n",
    "    ├── Makefile\n",
    "    ├── src1\n",
    "    │   ├── app.x\n",
    "    │   ├── libScalar_Product.a\n",
    "    │   ├── main.c\n",
    "    │   ├── main.o\n",
    "    │   ├── Makefile\n",
    "    │   ├── Scalar_Product.c\n",
    "    │   └── Scalar_Product.o\n",
    "    ├── src2\n",
    "    └── src3\n",
    "```\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Environment variables for executables and libraries\n",
    "\n",
    "- Executable `app.x` was installed in the convenbtional directory for binaries, `/usr/local/bin`.\n",
    "If it was installed, for example, in unconventional directory, say, `/usr/local/apps/bin`, then \n",
    "the directory needs to be added to the `PATH` environment variable:\n",
    "```bash\n",
    "export PATH=$PATH:/usr/local/apps/bin\n",
    "```\n",
    "\n",
    "- The installation also copies the library into /usr/local/lib. If shared object libraries are needed by an executable, they need to be either located in the conventional directories, or one should add the path to \n",
    " `LD_LIBRARY_PATH` environment variable:\n",
    " ```bash\n",
    " export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib\n",
    " ```\n",
    " Alternatively, the library path can be added in a new config file in directory `/etc/ld.so.conf.d`.\n",
    " \n",
    "- If compiled software contains brings MAN pages, the path to the pages should be added to environment variable MANPATH:\n",
    " ```bash\n",
    " export MANPATH=$MANPATH:/usr/local/man\n",
    " ```\n",
    " Alternatively, the new `man` pages can be added in file `/etc/manpath.config`.\n",
    " \n",
    " <hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## References on libraries and Makefiles\n",
    "\n",
    "[The textbook: Static libraries and Makefiles](http://linuxcourse.rutgers.edu/2024/html/documents/rute/node25.html#SECTION002530000000000000000)\n",
    "\n",
    "[The textbook: Shared libraries](http://linuxcourse.rutgers.edu/2024/html/documents/rute/node26.html#SECTION002610000000000000000)\n",
    "\n",
    "[Makefiles in Linux: An Overview](https://www.codeproject.com/Articles/31488/Makefiles-in-Linux-An-Overview)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
