Welcome back. In this video, we'll be introducing the concepts to design your own makefiles. In the last video, you learned make and build generation tools can help speed up your development process and instill better process into building projects. Automating the build process is just like writing software. In some cases, you will use shell scripts or other scripting languages to run a series of commands to generate needed executable files. These commands will of course be a mixture of our GCC commands to produce executables. In our case, you will be writing a makefile that stores all of the necessary configurations, flags, and commands in order to generate our build in other non-source files. Nick has provided a makefile which has many software language characteristics. You can version control your makefile and you can update your bill process over time as our source code changes. This allows us to record in our repo history exactly what we built with our software projects at any particular command. You should not store your output files in the repository because you will have all you need to create them, the source file and the akmefile. Adding the output files into version control just adds excess bloat to your repository and is unneeded. Make is given directions on what to compile via one or more makefiles. To create a makefile, you just need to create a textfile and save it as makefile. You could give your makefile any name as long as you pass the file into make. However, there are set defaults that make looks for such as the name makefile. Each makefile may consistently set up build rules or build targets that generate output files. These rules and output house typically require other files such as dependencies like object files or header files, for our final output executable to be built. Each target contains a special syntax. The target name is provided first followed by a colon and then a prerequisite list. You can think of the target name as our output file like objects or executables. Prerequisite files are target files that must exist before the current target can be executed. Dependency lists can be written manually or auto generated by make. Following the target prerequisites is a recipe or a set of commands that will executed in order to produce this target file. The commandlets that are run are the same as the commands you ran from the command line. These include things like GCC to compile and linking or other standard CLI utilities. Putting this altogether, we an tell make to generate a target file by giving make the target name. Make will then search through a given or a default makefile looking for a matching target name. It then checks if the prerequisites exist and generates them if not and then it executes the recipe. Makefiles have their own syntax similar to other software languages. But with the purpose of providing the necessary directions for compilation. Make does not execute the full makefile nor does it execute every line from top to bottom. However it has very similar characteristics to the C programming you have experience with. Makefiles can have comments and they start with a number sign. Write as many comments as you like and document what your makefile does at the top. You can include other makefiles with the include command and the included files can contain all the same characteristics. If your lines get too long, you can use the backwards slash to make your makefile more readable, this is line continuation. You can create variables to make your makefile more readable and portable by reusing the same variable names instead of retyping all the contents. You can define many rules with many command recipes. In each command in the recipe must start with a tab. Finally, targets can be used by other rules. There are more advanced features of make that we will get into. But with this small set of conventions, we can highly automate our build process, so that it is simple to use and provides consistent results. Variables are very important for our use in writing makefiles, as they allow us to remove a lot of duplicated code. There are different types of variables and different ways to get data assigned to them. Two types that we will use are recursively expanded variables and simply expanded variables. Recursively expanded variables get data signed to and substituted into a statement, whenever the variable is referenced. Simply expanded variables get data signed only once at the time of definition. These can be useful for gathering some information about the current system you are compiling on. Perhaps to make your makefile dynamic in selecting native versus cross compiler applications. Given how we were compiling with lots of flags, often reused and identical for each individual file we compiled, we could substitute all of that written code here with a variable. Here, we have defined a variable called CFLAGS, and it will hold our regularly occurring compile flags for GCC. For every target that we need to compile an object file for, we can simply list the CFLAG variables in the recipe commands. We can get even more dynamic by using variables that contain other variables which highly automates our makefile, providing a mechanism to make it more portable. You can actually create variables that point to your source files and include paths. This allows us to make even more generic rules for compiling based on these variables. Let's call one INCLUDE= which could reference every include directory. Let's call another one SRCS= which can list all of our source files. These can be extended to our object files, we're we can have a variable called objects which lists all of our object files for easy reference. Now you can combine what we have used so far and we can begin to make targets very flexible, readable, and portable. We can define a makefile rule for a particular target by listing every single command, flags, and prerequisites for every particular target. Alternatively, we can create rules that utilize variables and simply the build rule. Given how long a compile command can be, you can group options into different variables and reuse them in other places. Taking this further, makefiles have special variables called automatic variables. Automatic variables can be used to reduce the amount of typing for a particular rule. Automatic variables are only useful within a recipe, as they have a scope. Here, we have two automatic variables, one with with the dollar $^, and another one with $@. These mean the target and pre-requisite list, and you can use these instead of retyping those long statements. With this basic introduction to makefiles, we can create highly automated build systems that produce binaries very consistently with the use of make. Next, we will look at some more advanced features.