Lorenzo's Blog About me

How to prevent your Mac from sleeping in a Makefile

On - Reading Time: 1 Minutes,

Often I find myself using third-party software like Caffeine or Amphetamine to keep my Mac awake while running some specific commands. Sometimes it is because I am running backups. Sometimes it is because I am compiling something. I found out that macOS comes pre-installed with caffeinete command… this post is about how to integrate it in your Makefile so that running any command there will prevent your Mac from sleeping!

The command: caffeinate

This command comes pre-installed in any mac ๐Ÿคฏ This makes my life way easier because I would not have to brew anything. This is how I am going to use it:

caffeinate -i ${COMMAND}

This will prevent the system from sleeping while the ${COMMAND} runs.

I prefer to allow the display to sleep so that I can save some energy. I am using the -i flag to prevent the system from idle sleeping, while I could also use -d to prevent the display from sleeping. You can get more options from a quick check in the manual (man caffeinate).

Using it with Make

When writing a Makefile, I usually writhe commands directly. Like so:

%.out:
	command $*
	other-command $*

What we could do to prevent sleep or hibernation is to use caffeinate before every command, like so:

%.out:
	caffeinate -i command $*
	caffeinate -i other-command $*

But this might not be good-looking… and the senior gods of the DRY religion might cause your next live demo to fail! To make it better, I decided to use SHELL variable so that every command will be passed to caffeinate and bash. It will look something like this:

SHELL := caffeinate -i bash

%.out:
	command $*
	other-command $*

Sadly, this Makefile will not be portable, as caffeinate is available on macOS but not necessarily everywhere. So here is a simple condition to check if the binary is available and then overwrite the default shell used by Make:

# Prevent the system from idle sleeping, only on macOS
ifeq ($(shell uname -s),Darwin)
SHELL := caffeinate -i bash
endif

%.out:
	command $*
	other-command $*

There is a catch, though: caffeinate on macOS works differently than the package available here, and that might cause issues as the flags are different. ๐Ÿค” Therefore, instead of checking if caffeinate command is available like this:

ifneq (,$(shell which caffeinate))

I have decided to check if the kernel/OS is Darwin/macOS. There is space for improvements here to support different GNU/Linux distros.

I have implemented this in my Ansible Playbooks, as I was always finding myself struggling with having to restart commands just because I forgot to prevent my Mac from sleeping. Now I got it fixed with just three lines of code! ๐Ÿฅฐ