banner
raye~

Raye's Journey

且趁闲身未老,尽放我、些子疏狂。
medium
tg_channel
twitter
github
email
nintendo switch
playstation
steam_profiles

Learn to use Makefile to manage projects

Group 4

I always thought Makefile was exclusive to C++ projects, and seeing this file made me quite overwhelmed, as it inevitably requires executing a bunch of make commands to wait for compilation and linking.

However, I recently learned that the make command isn't as mysterious as it seems; on the contrary, it can effectively organize various commands, environment variables, shell commands, etc., that will be used in development projects.

In addition, one major benefit of Makefile is that it can configure some automated pre-steps, such as pip install for Python projects, npm install for Node projects, and so on.

Finally, Makefile can also depend on local files; if a file hasn't been updated, the corresponding tasks won't be executed, somewhat similar to local CI.

Next, let's get acquainted with the simple writing and examples of Makefile.

Basic Syntax of Makefile#

.PHONY#

Since the original intention of Makefile is to monitor whether local files have been updated and then trigger a series of actions, pure shell command execution needs to use .PHONY (phony) to achieve this. For example:

dev:
	@echo "Hello, world!"
.PHONY: dev

Dependencies#

Makefile operates in steps, and each step will have its prerequisite tasks. The general syntax is:

target1 [target2 ...]: [pre-req1 pre-req2 pre-req3 ...]
    [recipes
    ...]

A simple example would be if we want to execute a local preview of a next.js project, its prerequisite must be that the corresponding dependencies are already installed, so we can write:

dev: node_modules ## Start local service
	@./node_modules/.bin/next dev
.PHONY: dev

node_modules: package.json
	@yarn install

This forms a sequence of dependent execution:

  1. Executing make dev will check the prerequisite node_modules (note that this is a step name).
  2. The node_modules step depends on package.json, meaning it will first execute yarn install, and only if package.json is updated will it execute again.

From the above simple example, we can see that Makefile allows us to manage some common development steps clearly and orderly, avoiding "tragedies" such as modifying package.json but forgetting to execute yarn install.

Help Documentation#

In the above example, comments can be written using ##.

At this point, if we add the following segment to the Makefile:

help: ## Show this help
	@echo "\nSpecify a command. The choices are:\n"
	@grep -E '^[0-9a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "  \033[0;36m%-12s\033[m %s\n", $$1, $$2}'
	@echo ""
.PHONY: help

It can automatically generate comments, meaning that entering make help will automatically print the help documentation. Isn't that amazing? hh

Simple Example: Using Makefile to Manage Your Hugo Blog#

Hugo has a few simple commands for managing blogs, such as starting the server, generating static site files, etc. We can put them all in a Makefile:

all: help ## Default opens help documentation

serve: ## Start server
	@echo "Starting Hugo server..."
	hugo server

build: ## Build site
	@echo "Building the site..."
	hugo 

clean: ## Clean generated files
	@echo "Cleaning up the public directory..."
	rm -rf public/

help: ## Show this help
	@echo "\nSpecify a command. The choices are:\n"
	@grep -E '^[0-9a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "  \033[0;36m%-12s\033[m %s\n", $$1, $$2}'
	@echo ""

.PHONY: all serve build clean help

The default command all simply displays the help documentation, and the generation of help documentation can be automatically completed by writing clear comments. Now, entering the make command yields the following effect:

$:~/develop$ make

Specify a command. The choices are:

  all          Default opens help documentation
  serve        Start server
  build        Build site
  clean        Clean generated files
  help         Show this help

Of course, this is just the simplest demonstration; you can also add corresponding dependency files and integrate operations like new post as needed.

Step by Step Using Makefile to Manage Python Projects#

Simple Version#

First, let's assume our Python project entry is app.py, so our final target is:

run: ## Remember to add comments, which can automatically generate help documentation
  python app.py
.PHONY run ## Since there are no dependency files, we need to use .PHONY

Next, Python certainly has prerequisite dependencies that need to be installed, which are generally listed in requirements.txt, so we have:

setup: requirements.txt
    pip install -r requirements.txt

Of course, we would generally also add a clean command, so we have:

clean:
    rm -rf __pycache__

Advanced Version#

Since everyone's local Python environment variables are different, this can also be solved using Docker, but Python itself provides a more lightweight solution called venv, so we can:

python3 -m venv venv

-m venv means using the venv command to create a virtual environment located in the venv directory.

At this point, installing dependencies can use:

./venv/bin/pip install -r requirements.txt

Because pip is located in the ./venv/bin/ directory.

So we get the Makefile:

venv/bin/activate: requirements.txt
 python3 -m venv venv
 ./venv/bin/pip install -r requirements.txt

However, writing ./venv/bin/ every time can be cumbersome, so we can simplify it using a variable.

That is, declare a variable VENV with a default value of the venv directory, but you can also modify it through command-line arguments.

The way to reference the variable is $(VENV), which can be understood as a simple string replacement. Thus, the Makefile can be modified to:

VENV = venv
PYTHON = $(VENV)/bin/python3
PIP = $(VENV)/bin/pip

run: $(VENV)/bin/activate
 $(PYTHON) app.py
.PHONY run

$(VENV)/bin/activate: requirements.txt
 python3 -m venv $(VENV)
 $(PIP) install -r requirements.txt

clean:
 rm -rf __pycache__
 rm -rf $(VENV)
.PHONY clean

Simple Summary#

With GPT, Makefile can completely be handled by GPT. One can have a simple understanding of its syntax and be able to comprehend it, so I only listed the simplest syntax and corresponding examples.

I must say that with AI, such tasks no longer require developers to worry. From another perspective, what used to seem troublesome and not worth understanding often has many unexpected benefits.

Specifically regarding Makefile, it can be treated as a series of command encapsulations and steps that are cumbersome to record manually, and it can even be used as a README file.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.