Makefile相關語法學習-基礎語法 使用 Makefile 自動化編譯和部署-學習原理與流程

Published on Wednesday, February 15, 2023

Makefile

Makefile主要應用在Linux與Mac環境之中,通常在大型專案之中用來編譯C或C++,因為Makefile能夠判斷在一個專案中有哪些依賴的檔案需要重新編譯,哪些檔案可以忽略不再編譯

此外Make命令在Linux個發布版本與Mac都有內建,所以Make在距離第一版發布多年之後還是廣泛的被開發者使用

本文章的範例將使用play with docker建立的Linux環境,詳細可參考Docker Certified Associate(DCA)認證考試學習-準備環境

文章內容參考自makefile-cookbook

首先建立我們的測試環境,並建立以下檔案

mkdir hello-world && cd $_
vi Makefile

在 Makefile 輸入以下內容

hello:
	echo "Hello, World"

最後在終端機輸入make命令

[node1] (local) root@192.168.0.18 ~/hello-world
$ make
echo "Hello, World"
Hello, World

Makefile Syntax

首先我們先了解一下Makefile的語法:

targets: prerequisites
	command
	command
	command
  • targets 就像是dotnet中Method的名稱,它的作用範圍內可以包含多個命令,輸入完名稱之後需要使用: 隔開
  • command 為運作的命令,注意這邊在輸入命令需要用一個TAB開頭,不可以用空格
  • prerequisites 為前置需求,在運作這個target之前要先運作,指定的target

以上就是make的最基礎語法,首先先看一下先前Makefile的內容:
第一行hello:為targets
第二行 echo "Hello, World"command
此範例沒有前置需求

那麼我們可以更進一步修改Makefile的內容

hello: hello-second
	echo "Hello, World"
hello-second:
	echo "Hello, World second"

這邊我建立了一個新的target hello-second,並且在target hello新增一個之前的前置需求,要求在運行hello之前需要先執行hello-second

[node1] (local) root@192.168.0.18 ~/hello-world
$ make
echo "Hello, World second"
Hello, World second
echo "Hello, World"
Hello, World

Makefile Sample

接下來看另一個範例,這邊會將docker的範例程式clone下來,再透過Makefile將流程整合在一起 程式來自docker範例程式github

新增或修改Makefile添加以下內容

all: docker-run clean

docker-run: docker-build
	docker run --name myhello hello-world
docker-build: file-copy
	docker build -t hello-world .
file-copy: git-pull
	cp hello-world/amd64/hello-world/hello .
git-pull: 
	git clone https://github.com/docker-library/hello-world

clean:
	rm -rf hello*

這邊如果有多個targets,一般都是使用all作為預設執行的target

再新增一個Dockerfile添加以下內容

vi Dockerfile
FROM scratch
COPY hello /
CMD ["/hello"]

最後在終端機輸入make

[node1] (local) root@192.168.0.28 ~
$ make
git clone https://github.com/docker-library/hello-world
Cloning into 'hello-world'...
remote: Enumerating objects: 755, done.
remote: Counting objects: 100% (97/97), done.
remote: Compressing objects: 100% (59/59), done.
remote: Total 755 (delta 33), reused 79 (delta 22), pack-reused 658
Receiving objects: 100% (755/755), 574.50 KiB | 3.23 MiB/s, done.
Resolving deltas: 100% (313/313), done.
cp hello-world/amd64/hello-world/hello .
docker build -t hello-world .
Sending build context to Docker daemon  889.9kB
Step 1/3 : FROM scratch
 ---> 
Step 2/3 : COPY hello /
 ---> 22851d3f8c16
Step 3/3 : CMD ["/hello"]
 ---> Running in 2a147ee248d2
Removing intermediate container 2a147ee248d2
 ---> 37873ba92f23
Successfully built 37873ba92f23
Successfully tagged hello-world:latest
docker run --name myhello hello-world

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

rm -rf hello*

Summary

從今天的測試中可以得知,Makefile除了可以編譯大型程式之外,也可以拿來做一些基礎的流程控制
有了Makefile之後,可以省下一些力氣背不同的指令,像在此處只需要記住一個指令make即可完成許多事
而且只要專案有提供Makefile,都可以快速執行作者想要提供給我們的功能,非常方便。