Lorenzo's Blog About me

How to prevent your Mac from sleeping in a Makefile

On - Reading Time: 2 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! 🥰

Comments