The Lost Art of Makefile: A Guide for iOS Developers

Photo by Markus Spiske / Unsplash

In the world of iOS development, we often find ourselves relying on Xcode and Swift for most of our tasks. However, there's a powerful tool that's been around for decades and can greatly simplify our development process: the Makefile.

A Makefile is a file containing a set of directives used with the make build automation tool. It's a way to automate and document the steps you take to build your projects. In this blog post, we'll walk through a Makefile designed to set up a development environment for an iOS project.

The Makefile

Here's the Makefile we'll be discussing:

all: check_brew check_asdf check_ruby_plugin check_ruby_version check_bundler install_dependencies

	@if ! command -v brew &> /dev/null; then \
		echo "Error: brew is not installed. Please install brew first."; \
		exit 1; \
	else \
		echo "brew is already installed"; \

	@if ! command -v asdf &> /dev/null; then \
		echo "asdf is not installed, installing now..."; \
		brew install asdf; \
	else \
		echo "asdf is already installed"; \

	@if ! asdf plugin-list | grep -q ruby; then \
		echo "asdf ruby plugin is not installed, installing now..."; \
		asdf plugin-add ruby; \
	else \
		echo "asdf ruby plugin is already installed"; \

	@RUBY_VERSION=$$(grep ruby .tool-versions | cut -d ' ' -f2); \
	if ! asdf list ruby | grep -q $$RUBY_VERSION; then \
		echo "Ruby version $$RUBY_VERSION is not installed, installing now..."; \
		asdf install ruby $$RUBY_VERSION; \
	else \
		echo "Ruby version $$RUBY_VERSION is already installed"; \

	@if ! gem list bundler -i > /dev/null; then \
		echo "bundler is not installed, installing now..."; \
		gem install bundler; \
	else \
		echo "bundler is already installed"; \

	@echo "Installing gems in root folder..."; \
	bundle install;

Understanding the Makefile

Let's break down what's happening in this Makefile.

The all Target

The all target is the default target. This means that when you run make without specifying a target, make will execute the all target. In this case, all depends on several other targets: check_brew, check_asdf, check_ruby_plugin, check_ruby_version, check_bundler, and install_dependencies. This means that make will execute these targets in order.

The check_brew Target

The check_brew target checks if Homebrew (a package manager for macOS) is installed. If it's not, it prints an error message and exits. If it is, it prints a confirmation message. This is a good example of how you can use Makefile to check for necessary dependencies and install them if needed.

The check_asdf, check_ruby_plugin, check_ruby_version and check_bundler Targets

These targets make sure all required environments and dependencies are installed, in the correct order. If something is missing, Makefile will install it.

The install_dependencies Target

Finally, the install_dependencies target installs the necessary Ruby gems using Bundler. This is the place you can use to install cocoa pods and use Fastlane to install development certificates. Everything that needs to be done to set up workspace.


Makefiles can be a powerful tool for automating and documenting your build process. They can help ensure that all developers on a team are using the same environment and dependencies, which can help prevent the dreaded "it works on my machine" problem. So next time you're setting up a project, consider using a Makefile. It might just make your life a little easier.

Artur Gruchała

Artur Gruchała

I started learning iOS development when Swift was introduced. Since then I've tried Xamarin, Flutter, and React Native. Nothing is better than native code:)