初玩Makefile与Go项目中Makefile的简单使用

简介: 初玩Makefile与Go项目中Makefile的简单使用

1 回顾程序的编译和链接流程

1.1 一个C语言源文件变为可执行程序的过程

简单来讲,源代码文件一般由程序员使用高级计算机语言(C、Go、Java、C++等)进行编写,不同的语言有不同的文件后缀名,但是他们的共同点就是他们都是程序的源文件,这些文件(一个或多个)需要进行编译和链接后生成可直接运行的程序,才能真正的被运行。

当然有些编程语言并没有这种机制,这种语言一般为解释执行型的语言,比如Java,以及解析型的脚本语言,比如Python。拥有这种机制的语言一般为编译性语言,比如经典的C语言。

1.2 程序源文件如何编译和链接

那么问题来了,程序的源文件是如何编译和链接的呢?

我们那最经典的C语言举例子,其实上图针对C语言的编译过程描述的并不是很全面,只是一个大概的过程,C语言较为完整的编译过程是C源文件->(预编译)->中间文件->(编译)->中间文件->(链接)->可执行文件并且其中还依赖了众多的库文件。

1.3 源代码编译为程序的必要条件—编译器

以上并不是重点,我们都知道C语言是具有很好的移植性,并且能够在绝大多数操作系统下进行编译,可谓是一次编写,处处编译,但是任何语言都是由编译器的,不同操作系统下C语言源文件编译成的可执行文件不同(比如在Windows下编译成xx.exe,而在Linux下编译成xx.sh或xx,所以我们可以逆向推导出,C语言的编译器在不同的操作系统中具有不同的种类,但是所有的编译器种类都要符合一个特点的规范,如下:

  • C语言规范:ANSI C
    ANSI C是由美国国家标准协会(ANSI)及国际标准化组织(ISO)推出的关于C语言的标准。ANSI C 主要标准化了现存的实现, 同时增加了一些来自 C++ 的内容 (主要是函数原型) 并支持多国字符集 (包括备受争议的三字符序列)。 ANSI C 标准同时规定了 C 运行期库例程的标准。
  • 流行的C语言编译器有以下几种:
  • GNU Compiler Collection 或称 GCC
  • Microsoft C 或称 MS C
  • Borland Turbo C 或称 Turbo C
1.4 小结

通过以上内容我们知道了一个main.c程序是如何变为可执行程序的简单过程,这个过程看起来可以说并不简单,但是为什么我们测试程序的时候完全无感知呢?

答案就是——IDE(Integrated Development Environment ),中文名称:集成开发环境,正是因为有IDE我们才不需要每次启动程序时都进行重复流程的操作,而是他已经帮我们搞好了一套流程用来对源代码进行编译和运行。

所以本文的重点——Makefile也是如此,因为我们的项目代码最终都是要放到服务器上去运行的,但是服务器上并没有我们个人电脑上存在非常好用的IDE,最大的原因就是耗费服务器的资源,因此我们使用Makefile来进行对程序的自动化编译,下面步入正题。

2 Makefile快速入门

2.1 核心语法
target ... : prerequisites ...
    command
    ...
    ...

解释

  • target
    可以是一个object file(目标文件),也可以是一个执行文件,还可以是一个标签(label)。对于标签这种特性,在后续的“伪目标”章节中会有叙述。
  • prerequisites
    生成该target所依赖的文件和/或target
  • command
    该target要执行的命令(任意的shell命令)
2.2 编译和运行单个源代码文件实战
2.2.1 Linux下gcc环境检测
gcc -v

2.2.2 编写main.c源代码文件
#include<stdio.h>
  
int main(){
   printf("Hello Makefile ~\n");
   return 0;
}
2.2.3 编写Makefile文件
main: main.o
        gcc -o main main.o
main.o: main.c
        gcc -c main.c
clean:
        rm main.o

注意

Makefile命令的开头一定要使用Tab键而不是空格键,否则就会报错。

2.2.4 运行Makefile

自定义运行:

2.2.5 Makefile中使用shell命令

我们也可以在Makefile中使用shell命令,举个例子:

hello:
        echo Hello Makefile
        @echo Hello Makefile Too
        @ls -al

运行结果:

由此我们知道了,在shell命令前加@的不会输出命令的本身,反之则输出命令的本身。

3 Go项目中Makefile的简单使用

3.1 伪目标和变量
3.1.1 伪目标

最早先的一个例子中,我们提到过一个“clean”的目标,这是一个“伪目标”,

clean:
    rm *.o temp

更为稳健的做法是:

.PHONY : clean
clean :
    - rm *.o temp

前面说过, .PHONY 表示 clean 是一个“伪目标”。而在 rm 命令前面加了一个小减号的意思就是,也许某些文件出现问题,但不要管,继续做后面的事。当然, clean 的规则不要放在文件的开头,不然,这就会变成make的默认目标,相信谁也不愿意这样。不成文的规矩是——“clean从来都是放在文件的最后”。

.PHONY : all 声明了“all”这个目标为“伪目标”。(注:这里的显式“.PHONY : all” 不写的话一般情况也可以正确的执行,这样make可通过隐式规则推导出, “all” 是一个伪目标,执行make不会生成“all”文件,而执行后面的多个目标。建议:显式写出是一个好习惯。)

小结:因为伪目标总是会被执行,所以其依赖总是会被决议。通过这种方式,可以达到同时执行所有依赖项的目的。

3.1.2 变量的使用

(1)变量的声明:

变量在声明时需要给予初值,而在使用时,需要给在变量名前加上 $ 符号,但最好用小括号 () 或是大括号 {} 把变量给包括起来。如果你要使用真实的 $ 字符,那么你需要用 $$ 来表示。

(2)演示

hello.txt

Hello~

Makefile

i=10
txt=./hello.txt
run:
        @echo $(i)
        @cat $(txt)

执行

(3)扩展

变量的命名字可以包含字符、数字,下划线(可以是数字开头),但不应该含有 :#= 或是空字符(空格、回车等)。变量是大小写敏感的,“foo”、“Foo”和“FOO”是三个不同的变量名。传统的Makefile的变量名是全大写的命名方式,但我推荐使用大小写搭配的变量名,如:MakeFlags。这样可以避免和系统的变量冲突,而发生意外的事情。

3.2 Go项目的常用命令

为什么要说一下Go中的常用命令呢,因为Go项目中Makefile的使用较为简单,大多都是对Go命令的一些执行操作,因此我们首先要熟知Go语言中的常用命令,才能更好的编写Makefile。

  • Go一般命令:
  • build: 编译包和依赖。
  • clean: 移除当前源码包里面编译生成的文件。
  • doc: 显示包或者符号的文档。
  • env: 打印go的环境信息,查看GOPATH,GOROOT环境变量都可以使用该命令查看。
  • bug: 启动错误报告。
  • fix: 运行go tool fix。
  • fmt: 运行gofmt进行格式化。
  • generate: 从processing source生成go文件。
  • get: 下载并安装包和依赖。
  • install: 编译并安装包和依赖。
  • list: 列出包。
  • run: 编译并运行go程序。
  • test: 自动读取源码目录下面名为*_test.go的文件,生成并运行测试用的可执行文件。
  • tool: 运行go提供的工具。
  • version: 显示当前环境安装go的版本。
  • vet: 运行go tool vet。
  • Go mod命令:
  • go mod init [项目名称]:初始化工程项目。
  • go mod graph:输入工程当前所有的依赖。
  • go mod download: 使用此命令来下载指定的模块到本地。
  • go mod tidy:就是把不需要的依赖给删除掉。
  • go mod verify:验证mod里依赖是否正确,同时也会验证go源代码其它依赖的内容。
  • go mod why:可以展示及指定依赖关系。比如代码中有个依赖包,但是并不知道这个包的依赖关系,这时候就可以使用这个命令查看。
3.3 使用实践

项目目录:

Makefile文件内容:

.PHONY:tidy
tidy:
   go mod tidy
.PHONY:build
build:
   go build ./cmd/main.go
.PHONY:run
run:
   @./main

执行:

4 总结

Makefile文件是在项目构建这非常重要的一环,最初认识它是在GitHub上的开源项目中,发现每个项目都有一个Makefile,而且语法看不懂,于是就专门抽时间学习一下,当然由于本人初次学习,本文涵盖的知识点有限,更详细的学习请看 【这篇文章】,在本文这如有错误和不足,感谢读者指出!

参考链接:

https://github.com/seisman/how-to-write-makefile

https://seisman.github.io/how-to-write-makefile/

https://www.cnblogs.com/songgj/p/13167251.html

相关文章
|
4月前
|
JSON 运维 Go
Go 项目配置文件的定义和读取
Go 项目配置文件的定义和读取
|
1月前
|
Go API 数据库
Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
本文介绍了 Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
106 4
|
1月前
|
存储 JSON Go
如何在 Go 项目中隐藏敏感信息,比如避免暴露用户密码?
在Go语言开发中,用户信息管理常涉及敏感数据如密码的处理。为防止这些数据暴露给客户端,本文介绍了三种方法:使用JSON标签忽略字段、自定义序列化逻辑、使用数据传输对象(DTO),以确保用户数据的安全性。通过这些方法,可以有效控制数据输出,避免敏感信息泄露。
36 1
|
1月前
|
中间件 Go API
Go语言中几种流行的Web框架,如Beego、Gin和Echo,分析了它们的特点、性能及适用场景,并讨论了如何根据项目需求、性能要求、团队经验和社区支持等因素选择最合适的框架
本文概述了Go语言中几种流行的Web框架,如Beego、Gin和Echo,分析了它们的特点、性能及适用场景,并讨论了如何根据项目需求、性能要求、团队经验和社区支持等因素选择最合适的框架。
92 1
|
2月前
|
SQL 关系型数据库 MySQL
Go语言项目高效对接SQL数据库:实践技巧与方法
在Go语言项目中,与SQL数据库进行对接是一项基础且重要的任务
92 11
|
2月前
|
Go
使用go语言将A助手加入项目中
使用go语言将A助手加入项目中
27 2
|
2月前
|
存储 Kubernetes Go
Go语言项目组织架构
Go语言项目组织架构
|
22天前
|
存储 Go 索引
go语言中数组和切片
go语言中数组和切片
36 7
|
22天前
|
Go 开发工具
百炼-千问模型通过openai接口构建assistant 等 go语言
由于阿里百炼平台通义千问大模型没有完善的go语言兼容openapi示例,并且官方答复assistant是不兼容openapi sdk的。 实际使用中发现是能够支持的,所以自己写了一个demo test示例,给大家做一个参考。
|
22天前
|
程序员 Go
go语言中结构体(Struct)
go语言中结构体(Struct)
97 71