使用 Makefile 简化您的项目

2025-06-10

使用 Makefile 简化您的项目

make是我们项目任务精简工具之一。事实证明,它尤其适用于简化开发流程、使用自定义 CLI(例如子命令)重复执行日常任务,以及帮助新团队成员顺利入职

有了Makefile中的一系列规则,您就可以快速启动并运行,保持流程的合理性,并为团队中的每个人节省时间和精力。我们将从基础知识入手,讲解一些可以用 Makefile 实现的有趣功能。

这个等式由两部分组成:一部分是makeCLI 工具,另一部分是 Makefile 。其基本功能是从 Makefile 中make读取规则并执行。我今天要展示的只是 Makefilemake功能的一小部分。

编写 Makefile

YAML如果您以前曾使用过文件,那么您会觉得编写 Makefile 非常轻松。

规则剖析

每个都Makefile包含以下结构的规则:

target: dependencies
    recipe
Enter fullscreen mode Exit fullscreen mode
  • target:target 可以是可执行文件、对象,或者仅仅是我们想要执行的操作的名称。我们将使用纯规则的占位符名称作为 target。请注意名称,因为它应该与我们想要执行的操作相呼应,而不会造成任何混淆。
  • 依赖项:依赖项是需要执行的规则,以使当前规则起作用。
  • Recipe:Recipe 是 的核心Makefile,它代表了我们想要使用名称执行的操作target。请确保tab在每一行 Recipe 的开头都添加一个字符(就像 YAML 一样)。您也可以tab使用变量将字符替换为您想要的任何内容.RECIPEPREFIX

接下来我们将研究一些如何使用的示例Makefile。这些示例将基于设置开发环境。

基本规则

一个基本规则是,你只需要添加一些别名,这很简单。

假设你有一个Python项目,想把它交给一个新的团队成员。你该如何简化这个设置过程呢?或许可以这样理解。


#用于评论。

@符号用于禁用将配方打印到标准输出的功能。请在配方开头
不使用符号进行测试。@

:=是扩展运算符,可防止使用具有相同变量名的后续值。

SHELL变量决定了执行配方的默认 shell。

SHELL :=/bin/bash

.PHONY: format check

venv: # setup a virtual environment
    @python3 -m venv venv

setup: # install dev dependencies
    @pip install -e .[dev]
    @echo -e "\nInstalling pre-commit hook..."
    @pre-commit install

format: # format code using black
    @black .

check: # check for formatting using black
    @black --check --diff -v .

test: # run pytest
    @pytest -vvv
Enter fullscreen mode Exit fullscreen mode

您可以对现有项目做类似的事情。

现在要启动并运行,您需要做的就是:

$ make venv 

$ . venv/bin/activate 

$ make setup

$ make format 

# and so on
Enter fullscreen mode Exit fullscreen mode

具有依赖关系的规则

参照上面的例子,假设我们希望check每次运行format目标时都打印出目标的输出。那么如何创建这个依赖关系呢?很简单,我们只需要更新format目标,使其看起来像这样:

format: check # run the formatter on files.
 @black .
Enter fullscreen mode Exit fullscreen mode

check我们在目标的右侧添加了依赖项,就像在解剖规则部分中所展示的那样。

变量

如果我们有一些需要重复使用的命令,也可以定义变量。在本例中,我们将以管理命令为例Django

变量通常全部大写,用于:=将变量名赋值。变量可以使用$()${}语法访问。

DJANGO_MANAGE := python manage.py
run: 
 @${DJANGO_MANAGE} runserver

show: 
 @${DJANGO_MANAGE} showmigrations

migrate: 
 @${DJANGO_MANAGE} migrate
Enter fullscreen mode Exit fullscreen mode

您的SHELL 环境变量也会转换为 Makefile 环境变量,因此您可以在创建规则时直接使用它们。

例子:

在我们的 shell 中,我们可以导出一个名为的环境变量INFO

$ export INFO="Run make help to show all the available rules."
Enter fullscreen mode Exit fullscreen mode

现在我们可以在 Makefile 中将其作为任何变量来引用。

info: # show project info
    @echo ${INFO}
Enter fullscreen mode Exit fullscreen mode

默认目标

如果你只是make在命令行上运行,什么也不会发生。但是我们可以通过使用.DEFAULTGOAL特殊变量并指定我们想要默认运行的目标来改变这种情况。

.DEFAULT_GOAL := run
Enter fullscreen mode Exit fullscreen mode

现在,下次运行时make它将Django默认运行服务器。

自我记录

现在,我们有很多目标,Makefile并且我们也将这个组合称为一个自定义的迷你 CLI 应用。如果我们能有一个类似于真实 CLI 应用的帮助命令,那不是很棒吗?不用多说,感谢Victoria Drake博客,我们有了实现这个功能的脚本。

只需创建一个help目标并将其指定为.DEFAULT_GOAL。这样,我们在目标上写的所有评论都会转换成一条有用的帮助信息。

.DEFAULT_GOAL := help 
help: # Show this help
 @egrep -h '\s#\s' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?# "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
Enter fullscreen mode Exit fullscreen mode

包含其他 Makefile

我们可以根据 Makefile 执行的任务将其分离出来,并将include它们放入主目录中Makefile。我们通常分别Makefile管理环境变量DockerKubernetes。这样就可以将所有从项目设置到部署的任务都转移到 Makefile 中。

我将展示每个文件的简短示例,仅举一个例子:

注意:由于 make 在 shell 的新实例上运行每个配方,我们可以使用?=含义来延迟评估变量,它们仅在单个 shell 实例引用时才被初始化。

Makefile
由其他 Makefile 组成的根 makefile。

SHELL :=/bin/bash
APP_ROOT := $(PWD)
TMP_PATH := $(APP_ROOT)/.tmp
VENV_PATH := $(APP_ROOT)/.venv

export ENVIRONMENT_OVERRIDE_PATH ?= $(APP_ROOT)/env/Makefile.override

-include $(ENVIRONMENT_OVERRIDE_PATH)
include $(APP_ROOT)/targets/Makefile.docker
include $(APP_ROOT)/targets/Makefile.k8s
Enter fullscreen mode Exit fullscreen mode

环境变量
Makefile.override
Makefile 仅包含必要的环境变量。

STAGE ?= <stage>
SERVICE_NAME ?= <service-name>
AKS_RESOURCE_GROUP ?= <resource-group>
AKS_CLUSTER_NAME ?= <cluster-name>
REGISTRY_URL ?= <registry-url>
AZ_ACR_REPO_NAME ?= <repo-name>
Enter fullscreen mode Exit fullscreen mode

Docker
Makefile.docker
包含 docker 规则的 Makefile。

export GIT_COMMIT ?= $(shell cut -c-8 <<< `git rev-parse HEAD`)
export BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD)

export DOCKER_BUILD_FLAGS ?= --no-cache
export DOCKER_BUILD_PATH ?= $(APP_ROOT)
export DOCKER_FILE ?= $(APP_ROOT)/Dockerfile

export TARGET_IMAGE ?= $(REGISTRY_URL)/$(AZ_ACR_REPO_NAME)/$(SERVICE_NAME)
export TARGET_IMAGE_LATEST ?= $(TARGET_IMAGE):$(BRANCH)-$(GIT_COMMIT)

acr-docker-login:
    az acr login --name $(AZ_ACR_REPO_NAME)

docker-build:
    docker build $(DOCKER_BUILD_FLAGS) -t $(SERVICE_NAME) -f $(DOCKER_FILE) $(DOCKER_BUILD_PATH)

docker-tag:
    docker tag $(SERVICE_NAME) $(TARGET_IMAGE_LATEST)

docker-push: acr-docker-login
    docker push $(TARGET_IMAGE_LATEST)
Enter fullscreen mode Exit fullscreen mode

Kubernetes

Makefile.k8s
包含 Kubernetes 规则的 Makefile。

export OVERLAY_PATH ?= $(APP_ROOT)/k8s/overlays/$(STAGE)/

define kustomize-image-edit
    cd $(OVERLAY_PATH) && kustomize edit set image api=$(1) && \
    cd $(APP_ROOT)
endef

kubectl-apply:
    kustomize build $(OVERLAY_PATH)
    kustomize build $(OVERLAY_PATH) | kubectl apply -f -

update-kubeconfig:
    az aks get-credentials --resource-group $(AKS_RESOURCE_GROUP) --name $(AKS_CLUSTER_NAME)

aks-deploy: update-kubeconfig
    $(call kustomize-image-edit,$(TARGET_IMAGE_LATEST))
    make kubectl-apply

aks-delete: update-kubeconfig
    kubectl delete namespace $(STAGE)-api

kustomize-edit:
    $(call kustomize-image-edit,$(TARGET_IMAGE_LATEST))

Enter fullscreen mode Exit fullscreen mode

现在我们已经编排了所有这些 Makefile,如果您要使用 Makefile 做很多事情,那么跟踪所有规则会更容易,并且使用 Makefile 会更合理。

结论

因此,通过使用,Makefile我们可以简化项目中的许多冗余任务,而不必记住冗长而多样的命令。

它提高了整个团队的工作效率;通过更简单的项目设置和将冗余任务外包给Makefile直观的目标名称,让开发人员专注于手头更重要的任务。

鏂囩珷鏉ユ簮锛�https://dev.to/yankee/streamline-projects-using-makefile-28fe
PREV
关于微软新编程语言 Bosque,你需要知道的一切
NEXT
Git Worktree 实用指南