TIL - Makefiles!

make command

  • make is used for building projects with multiple dependecies and many source/target files (mainly c++)
  • in order to build, we run, make <target>
  • it creates binaries based on definitions in the Makefile (perhaps in a bin directory)
  • sudo make install places the binaries in desired installation dir like /usr/bin /usr/local/bin (requires executable copying logic to be provided in the Makefile)
  • use "a.h" (colons) to add local headerfiles.
  • When rebuilding a project after changing certain source files. make determines the miniimum number of commands required to be ran from the Makefile, so that whole project doesn't get rebuilt everytime.

Makefiles

  • make reads the Makefile and determines the order and minimum number of commands to run to build the project
  • contains dependencies and rules
  • a simple example -
myproject: main.o dep1.o dep2.o     
    #project dependecy
    gcc -o myapp main.o dep1.o dep2.o

#dependency
main.o: main.c 1.h
    #rule (must be *tab* indented)      
    gcc -c main.c
dep1.o: dep1.c 1.h
    gcc -c dep1.c
dep2.o: dep2.c 1.h 2.h
    gcc -c dep2.c

Macros

Macros are like variables for build commands that help with adding flexibilty to build your projects on multiple targets.

# you can define a macro like so
CC=gcc
INSTDIR=/usr/local/bin

# and use them with $()
$(CC)
$(INSTDIR)

Default Macros

make provides some default macros are available to us and it is recommended to use them in the Makefile, so that builds on unique systems can be carried out with the correct tools.
These include

  • CC - the c compiler
  • CXX - the c++ compiler
  • JAVA_HOME - java runtime
  • PWD - current directory
    etc.
    Using default macros allows us to build using the tools available, whereas if we define the tools ourselves, the make command may fail.
  • you can use make -p get a list of all default macros

Nesting Makefiles

A large project may have a structure that is modular, with each module requiring its own makefile, so that the parent Makefile doesn't become unmaintainable.
For this purpose, we can invoke a make command from within a Makefile. This triggers the sub-make to build the submodule. It is important to use the MAKE macro for this purpose.
We can use the -C option to change into the subdirectory before running its Makefile.
ex -

myapp: main.c dep1.o
    $(GCC) $(CFLAGS) -o myapp main.c

module1:
    $(MAKE) -C module1
  • any variables/macros defined in the parent Makefile may also be exported to sub-make using export variable
  • any flags defined in parent Makefile are automatically added to the environment of the sub-make with the MAKEFLAGS macro.

References

#C++