Random stuff on Make

I decided to learn make to have a better understanding on some tasks I’ve been assigned recently on my job. Comes up I’ll also become some kind of release manager which means I’ll be responsible for the the daily creation of some Empire product. This crazy machinery already works with GNU Make, so here we go:

From Managing Projects with GNU Make, 3rd Edition:

  • When no parameters are passed to make, the first target will be run.
  • Make uses tabs for command indentation. Each command MUST begin with a tab character.
    • Commands are passed to a subshell for execution.
  • Blank lines will be ignored.
  • As for prerequisites they can be:
    • Other targets (PHONY targets)
    • Filenames
    • Names of system libraries:
      • -l<NAME> will search for libNAME.so or libNAME.a
  • For debugging use: make –just-print or -n. This will only display commands it would execute.
  • Makefile names are: makefile, Makefile or GNUMakefile.
  • Placing a ‘@’ before a command will result in not echoing the command, just the output of it.
  • Placing a ‘-‘ before a command indicates that errors in the command should be ignored by make.
  • Placing a ‘+’ before a command forces that particular command even if the “–just-print” option was provided.
  • ‘@’, ‘+’ and ‘-‘ are called command modifiers.
  • Makefiles are structured top-down, but commands are executed bottom-up.
  • Makefile should be in the same directory the command is being executed.
  • ‘all’ target come first, ‘clean’ targets come last in the Makefile.
  • We can add more than one target in a line:
    target1 target2 target3 : prerequisite1 prerequisite2
            command
    1
            command
    2
            command3
  • Comments begin with the ‘#’ character, they can be indented.
  • Long lines can be continued using the ‘\’ character.
  • Type of rules (The most important ones):
    • Explicit rules Target will be updated if it is out of date with respect to any of its prerequisites.
      • Examples:
        • # More than one target in the same line
          vpath.o variable.o: make.h config.h getopt.h gettext.h dep.h
          vpath.o: make.h config.h getopt.h gettext.h dep.h
          variable.o: make.h config.h getopt.h gettext.h dep.h
        • # Breaking long lines for readability
          vpath.o: vpath.c make.h config.h getopt.h gettext.h dep.h
          vpath.o: filedef.h hash.h job.h commands.h variable.h vpath.h
        • # Make sure lexer.c is created before vpath.c is compiled.
          vpath.o: lexer.c
          ...
          # Compile vpath.c with special flags.
          vpath.o: vpath.c
                  $(COMPILE.c) $(RULE_FLAGS) $(OUTPUT_OPTION) $<
          ...
          # Include dependencies generated by a program.
          include auto-generated-dependencies.d
    • Pattern rules Use wildcards instead of explicit filenames. This allows make to apply the rule any time a target file matching the pattern needs to be updated.
  • Uses a set of wildcards identical to Bourne shell’s: ~, *, ?, […] and [^…]
    • Tilde is used to represent the user’s home directory.
    • Good use of wildcards:
      prog: *.c
              $(CC) -o $@ $^
    • Bad use of wildcards:
      # If there are no *.o files in the directory (clean)
      # directory, this translates into : constants.h
      *.o: constants.h
  • When the pattern appears as a target or prerequisite, the expansion is performed by Make itself.
  • When the pattern appears in a command, the expansion is performed by the subshell.
  • Targets that do not represent files are known as PHONY targets.
    clean:
            rm -f *.o lexer.c
  • To avoid confusion between phony targets and targets that are actual files with the same name, Make has an special target called .PHONY:
    .PHONY: all
    all: bash bashbug
    .PHONY: clean
    clean:
            rm -f *.o lexer.c
  • PHONY targets can also be thought of as shell scripts embedded in a makefile:
    # df PHONY target can be used in other PHONY targets
    .PHONY: make-documentation
    make-documentation: df
            javadoc ...
    
    .PHONY: df
    df:
            df -k . | awk 'NR =  = 2 { printf( "%d available\n", $$4 ) }'
  • PHONY targets are always out of date.
  • PHONY targets can be useful to determine the actual progress of the execution:
    $(Program): build_msg $(OBJECTS) $(BUILTINS_DEP) $(LIBDEP)
            $(RM) $@
            $(CC) $(LDFLAGS) -o $(Program) $(OBJECTS) $(LIBS)
            ls -l $(Program)
            size $(Program)
    
    .PHONY: build_msg
    build_msg:
            @printf "#\n# Building $(Program)\n#\n"
  • By convention there are a set of  more or less standard phony targets that many makefiles include:
    Target Function
    all Perform all tasks to build the application
    install Create an installation of the application from the compiled binaries
    clean Delete the binary files generated from sources
    distclean Delete all the generated files that were not in the original source distribution
    TAGS Create a tags table for use by editors
    info Create GNU info files from their Texinfo sources
    check Run any tests associated with this application
  • ctags and etags
  • Rules whose target is an empty file is sometimes referred as a cookie.
  • Automatic variable $? – defined to be the set of prerequisites that are newer than the target. (Files that have changed)
  • Empty files are often used for their timestamp. Used to mark the last time a particular event has taken place.
  • Variables:
    • Variable names must be surrounded by $( ) or ${ }.
      • Some people use $( ) for function call and ${ } for variable reference.
    • Variables are case sensitive.
    • Trailing spaces are not removed
    • Variables that appear only in the makefile are all lowercase.
    • A single variable character variable name does not require the parentheses.
    • Variables can contain almost any text, and variable names can contain most characters including punctuation.
    • Automatic variables:
      • $@ – The filename representing the target.
      • $% – The filename element of an archive member specification.
      • $< – The filename of the first prerequisite.
      • $? The names of all prerequisites that are newer than the target, separated by spaces.
      • $^ – The filenames of all the prerequisites, separated by spaces. This list has duplicate filenames removed.
      • $+ – Similar to $^ but includes duplicated filenames.
      • $* – The stem of the target filename. Stem is typically a file without its suffix.
      • Example:
        count_words: count_words.o counter.o lexer.o -lfl
                gcc $^ -o $@
        
        count_words.o: count_words.c
                gcc -c $<
    • Variable types:
      • Simply expanded variables:
        MAKE_DEPEND := $(CC) -M
      • Recursively expanded variable:
        MAKE_DEPEND = $(CC) -M
        ...
        # Some time later
        CC = gcc
    • Conditional assignment:
      # Put all generated files in the directory $(PROJECT_DIR)/out.
      # Assigns a value only if OUTPUT_DIR has no value
      OUTPUT_DIR ?= $(PROJECT_DIR)/out
  • Macros
    • If a ‘@’ is placed before the macro reference, the whole macro will be hidden.
    • Example:
      define create-jar
       @echo Creating $@...
       $(RM) $(TMP_JAR_DIR)
       $(MKDIR) $(TMP_JAR_DIR)
       $(CP) -r $^ $(TMP_JAR_DIR)
       cd $(TMP_JAR_DIR) && $(JAR) $(JARFLAGS) $@ .
       $(JAR) -ufm $@ $(MANIFEST)
       $(RM) $(TMP_JAR_DIR)
      endef
      $(UI_JAR): $(UI_CLASSES)
              $(create-jar)
    • Rules of immediate and deferred expansion.
      Definition Expansion of a Expansion of b
      a = b Immediate Deferred
      a ?= b Immediate Deferred
      a := b Immediate Immediate
      a += b Immediate Deferred or immediate
      define a Immediate Deferred
      b...

      b...

      b

      ... endef

    • Standard make variables
      • MAKE_VERSION – Version number of Make
      • CURDIR – Sames as the value in the PWD environment variable
      • MAKEFILE_LIST – List of each file make has read
      • MAKECMDGOALS – List of all the targets specified on the command line for the current execution
      • .VARIABLES – Names of all the variables defined in makefiles read so far.
  • Conditional and include processing.
    • # COMSPEC is defined only on Windows.
      ifdef COMSPEC
        PATH_SEP := ;
        EXE_EXT  := .exe
      else
        PATH_SEP := :
        EXE_EXT  :=
      endif
    • libGui.a: $(gui_objects)
              $(AR) $(ARFLAGS) $@ $<
          ifdef RANLIB
              $(RANLIB) $@
          endif
    • ifeq "$(strip $(OPTIONS))" "-d"
        COMPILATION_FLAGS += -DDEBUG
      endif
  • Functions
    • Looks much like a variable reference, but includes one or more parameters separated by commas.
    • Example:
      define parent
        echo "parent has two parameters: $1, $2"
        $(call child,$1)
      endef
      
      define child
        echo "child has one parameter: $1"
        echo "but child can also see parent's second parameter: $2!"
      endef
      
      scoping_issue:
              @$(call parent,one,two)
    • Patterns can be used as arguments to functions.
    • Make has a lot of built-in functions:
      • String processing
      • Miscellaneous
      • File name
      • Flow control
      • Less important miscellaneous functions
    • Passing parameters
      • # $(call process-xml,project-prefix,file-name)
        define process-xml
          $($1_LIB)/xmlto -o $($1_BIN)/xml/$2 $($1_SRC)/xml/$2
        endef
      • release: MAKING_RELEASE = 1
        release: libraries executables
        ...
        $(foo_lib):
                $(call build-library,$^)
        ...
        # $(call build-library, file-list)
        define build-library
          $(AR) $(ARFLAGS) $@           \
            $(if $(MAKING_RELEASE),     \
              $(filter-out debug/%,$1), \
              $1)
        endef
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s