Looping Through API Calls in a Makefile

Learn how to efficiently handle repetitive tasks in Makefiles by looping through API calls with parameter arrays. This guide demonstrates refactoring techniques to avoid command duplication and ensure smooth execution.

Looping Through API Calls in a Makefile

When working with Makefiles, you might encounter scenarios where you need to perform repetitive tasks, such as calling an API to list information from a server. Instead of duplicating code, it’s more efficient to extract a function and loop through an array of parameters. Let’s walk through an example and address a common issue that arises.

Initial Task

Consider the following task in a Makefile, which fetches data files for app1 and app2:

list.data.files:
	@echo "Data files for app1"
	@curl https://example.com/file/list?app=app1
	@echo "Data files for app2"
	@curl https://example.com/file/list?app=app2

Refactoring with a Function

To avoid code duplication, we can define a function and use an array to loop through the apps:

APPS = app1 app2

define list_data_files
	@echo "Data files for $(1)"
	@curl https://example.com/file/list?app=$(1)
endef

list.data.files:
	@$(foreach app,$(APPS),$(call list_data_files,$(app));)

Encountering Issues

However, running the above code results in an error:

/bin/sh: @echo: command not found
make: *** [list.data.files] Error 127

The first app executes correctly, but the second one fails. Further simplification to isolate the issue shows the same problem:

APPS = app1 app2

define list_data_files
	@echo "Data files for $(1)"
endef

list.data.files:
	@$(foreach app,$(APPS),$(call list_data_files,$(app));)

Output:

Data files for app1
/bin/sh: @echo: command not found
make: *** [list.data.files] Error 127

Removing the @ symbol before the command in the function leads to the same issue with curl:

APPS = app1 app2

define list_data_files
	@curl https://example.com/file/list?app=$(1)
endef

list.data.files:
	@$(foreach app,$(APPS),$(call list_data_files,$(app));)

Output:

...
/bin/sh: @curl: command not found
make: *** [list.data.files] Error 127

Solution

The solution is to remove the @ symbol before the commands in the function. Here’s the final, working Makefile:

APPS = app1 app2

define list_data_files
	echo "Data files for $(1)"
	curl https://example.com/file/list?app=$(1)
endef

list.data.files:
	@$(foreach app,$(APPS),$(call list_data_files,$(app));)

With this approach, the commands won't be printed when executed in the function, achieving the desired behavior without errors.