• Home
  • Health
  • Software
  • Blog
  • bash

    Makefiles

    Make was created for compiled languages like C and C++, but people still use them for this day for doing stuff, often random bash commands.


    Makefiles usually define variables and run Targets, which look like this:

    # This is a file named makefile
    
    target: [dependencies]
            <command>
            <command 2>
            ...
    


    They're supposed to use tabs, not spaces. Some have made it work with spaces, but it's usually tabs.


    They have parameters sometimes:

    # makefile example 2
    
    CC = gcc
    FILES = in_one.c in_two.c
    # This line is an example of an optional param:
    OUT_EXE ?= out_executable
    
    build: $(FILES)
            $(CC) -o $(OUT_EXE) $(FILES) $(environment) $(tags)
    

    If I run `make build OUT_EXE="test.exe"` it will output to test.exe

    If I run `make build` it will output to out_executable


    Be careful with changing variables, because `=` and `?=` can use the end result, rather than the value at the time.

    e.g.

    testvar = abcd
    setme = $(testvar)
    testvar = efgh
    
    # setme is now equal to efgh
    # you can use := to prevent this:
    
    testvar2 = abcd
    setme2 := $(testvar)   # <-- Key difference
    testvar2 = efgh
    
    # setme2 is now equal to abcd
    

    I think the above is mainly used when appending text to a variable.


    You can append, but it will just create a variable if it doesn't already exist:

    # makefile example 3
    
    VARIABLE += value
    
    # another example:
    
    grep_command = "ggrep" #GNU grep example, being run on a Mac
    arguments := "-I --exclude-dir=node_modules"
    
    arguments += "--exclude=yarn.lock"
    


    You can use conditionals:

    # makefile example 4
    
    args := "--exclude-dir=node_modules"
    
    # Using a wildcard function to verify file exists
    ifneq ("",$(wildcard ./yarn.lock))
         args += "--exclude=yarn.lock"
    endif
    
    ifeq ("test","test")
         testvar = happened
    endif
    
    some_target:
            echo $(args)
            echo $(testvar)
    


    This checks OS version and processor:

    UNAME_S := $(shell uname -s)
    
    ifeq ($(UNAME_S),Linux)
        CCFLAGS += -D LINUX
    endif
    ifeq ($(UNAME_S),Darwin)
        CCFLAGS += -D OSX
    endif
    
    UNAME_P := $(shell uname -p)
    ifeq ($(UNAME_P),x86_64)
        CCFLAGS += -D AMD64
    endif
    ifneq ($(filter %86,$(UNAME_P)),)
        CCFLAGS += -D IA32
    endif
    ifneq ($(filter arm%,$(UNAME_P)),)
        CCFLAGS += -D ARM
    endif
    
    ifeq ("test","test")
            testvar = happened
    endif
    
    some_target:
            @echo $(UNAME_S)
            @echo $(UNAME_P)