DEV Community

Cover image for Using a default Makefile
cerico
cerico

Posted on

Using a default Makefile

Setting up a default Makefile with wildcard rule

When setting up a new project, I like to have a default Makefile that I can use to run common tasks. This is a simple Makefile that I use to run common tasks. A project might have different ways of launching parts of the application, and standardising and centralising these commands is a good way of keeping things simple and consistent. It is also self-documenting, as the tldr target lists all the available targets by default. Lets take a look at my default Makefile, and then explore easily targets via a shell function.

tldr:
        @echo Available commands
        @echo ------------------
        @grep '^[[:alpha:]][^:[:space:]]*:' Makefile | cut -d ':' -f 1 | sort -u | sed 's/^/make /'
%:
        @$(MAKE) tldr
Enter fullscreen mode Exit fullscreen mode

As we can see, there are only two commands defined. The first is tldr, which lists all the available commands. The second is %, which is a wildcard that matches any command that is not defined. This is used to print the tldr command if an invalid command is entered.

The tldr rule prints out all the commands in the Makefile. It does this by using grep to find all the lines that start with a letter, followed by a colon. It then uses cut to extract the first field, which is the command name. It then uses sort to sort the commands, and finally uses sed to add the make command to the start of each line. The output looks like this:

☁  brew@kelso:projects/making  ➜ make tldr
Available commands
------------------
make tldr
Enter fullscreen mode Exit fullscreen mode

As there is only one rule defined, the wildcard rule is used to print the tldr command. Same thing happens if you enter an invalid command, instead of erroring out, it prints the tldr command.

☁  brew@kelso:projects/making  ➜ make nonsense
Available commands
------------------
make tldr
Enter fullscreen mode Exit fullscreen mode

Using the addmake function to create or add to the Makefile

addmake () {
  if [[ ! -f Makefile ]];
    then
    cp ~/.zsh/templates/Makefile .
  fi
  if [[ ! $1 ]];
    then
    make tldr
    return
  fi
  local target=$1 || read "target?Enter target: "
  if [[ -e $target ]]
    then
    echo "Error: A file or directory named '$target' already exists." && return 1
  fi
  if grep -q "^$target:" Makefile
    then
    echo "Error: Target '$target' already exists in the Makefile." && return 1
  fi
  [[ -n $2 ]] && local recipe=$2 || read "recipe?Enter recipe: "
  echo "$target:\n\t$recipe" >> Makefile
  echo "\nSuccess: Target '$target' added to Makefile\n"
  make tldr
}
Enter fullscreen mode Exit fullscreen mode

Lets run through the function. First, we check if a Makefile exists in the current directory. If it doesn't, we copy the default Makefile shown above, which is stored in ~/.zsh/templates/Makefile.

Next, we check if the first argument is empty. If it is, we run make to print the tldr command, listing available commands, and then exit.

If we run the addmake function with one argument, it will create a new target with the argument and then prompt us for the corresponding recipe. If we run it with two arguments, it will create a new target with the first argument and the recipe with the second argument, before running the tldr target to list all the available commands, including the newly added target.

It also checks to make sure the target doesn't have the same name as a file or directory at the top level of the project, which make doesn't seem to like. It also checks to make sure the target doesn't already exist in the Makefile.

Lets take a look at the function in action.

☁  brew@kelso:projects/making ➜ addmake
Available commands
------------------
make tldr
Enter fullscreen mode Exit fullscreen mode
☁  brew@kelso:projects/making  ➜ addmake hello "@echo hello world"

Success: Target 'hello' added to Makefile

Available commands
------------------
make hello
make tldr
Enter fullscreen mode Exit fullscreen mode
☁  brew@kelso:projects/making  ➜ addmake goodbye
Enter recipe: "@echo see you in the next episode"

Success: Target 'goodbye' added to Makefile

Available commands
------------------
make goodbye
make hello
make tldr
Enter fullscreen mode Exit fullscreen mode
☁  brew@kels:projects/making ➜ addmake hello
Error: Target 'hello' already exists in the Makefile.
Enter fullscreen mode Exit fullscreen mode
☁  brew@kels:projects/making ➜ addmake images
Error: A file or directory named 'images' already exists.
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
cavo789 profile image
Christophe Avonture

Hello. In case of interest, I'm using a help target (like your tldr) but giving more info on screen : avonture.be/blog/makefile-help.

I'm using blocks to split set of commands like the ones for the application, for the database,...