当前位置:网站首页>Go新项目-编译项目的细节(4)
Go新项目-编译项目的细节(4)
2022-08-03 02:09:00 【编程圈小学生】
Go 语言是一门需要编译才能运行的编程语言,也就是说代码在运行之前需要通过编译器生成二进制机器码,包含二进制机器码的文件才能在目标机器上运行,下边就展开讲解下Go语言的编译的细节。
go build 编译时的附加参数
附加参数 | 备 注 |
---|---|
-v | 编译时显示包名 |
-p n | 开启并发编译,默认情况下该值为 CPU 逻辑核数 |
-a | 强制重新构建 |
-n | 打印编译时会用到的所有命令,但不真正执行 |
-x | 打印编译时会用到的所有命令 |
-race | 开启竞态检测 |
编译器:gc 和 gccgo
gc,全称Golang Compiler
go有两种不同的编译器,但是默认采用gc,这也会后边提到项目中运用了gccgo的编译错误的问题;
- Go 语言始终由 spec 说明书而不是实现定义。 Go 团队编写了两种实现该规范的不同编译器:gc 和 gccgo。具有两种不同的实现方式有助于确保规范的完整性和正确性:当编译器不同意时,我们会修复规范,并相应地更改一个或两个编译器。 Gc 是原始编译器,默认情况下 go 工具使用它。 Gccgo 是一种不同的实现方式,具有不同的侧重点,在这篇文章中,我们将对其进行更深入的研究。
- Gccgo 作为 GCC(GNU 编译器集合)的一部分进行分发。 GCC 支持不同语言的几种前端。 gccgo 是连接到 GCC 后端的 Go 前端。 Go 前端与 GCC 项目是分开的,旨在能够连接到其他编译器后端,但目前仅支持 GCC。
- 与 gc 相比,gccgo 编译代码的速度较慢,但支持更强大的优化,因此 gccgo 构建的受 CPU 约束的程序通常运行速度更快。多年来,在 GCC 中实现的所有优化都是可用的,包括内联,循环优化,向量化,指令调度等。尽管它并不总是能产生更好的代码,但在某些情况下,使用 gccgo 编译的程序可以运行 30%更快。
- gc 编译器仅支持最受欢迎的处理器:x86(32 位和 64 位)和 ARM。但是,Gccgo 支持 GCC 支持的所有处理器。并非所有这些处理器都经过了 gccgo 的全面测试,但是许多处理器都进行了测试,包括 x86(32 位和 64 位),SPARC,MIPS,PowerPC 甚至 Alpha。 Gccgo 还已经在 gc 编译器不支持的操作系统(尤其是 Solaris)上进行了测试。
- Gccgo 提供了标准的,完整的 Go 库。 Go 运行时的许多核心功能在 gccgo 和 gc 中都相同,包括 goroutine 调度程序,通道,内存分配器和垃圾收集器。 Gccgo 和 gc 编译器一样,支持拆分 goroutine 堆栈,但目前仅在 x86(32 位或 64 位)上,并且仅在使用 gold 链接器时(在其他处理器上,每个 goroutine 将具有较大的堆栈,以及一系列深层次的函数调用可能会运行到堆栈末尾并使程序崩溃)。
对比
- gc是Go语言原生的编译器,不需要安装,使用方便;而gccgo需要自已安装。
- gc编译速度比gccgo快。
- gc只支持一些主流的处理器,如x86、amd、ARM等。 而gccgo支持基本上所有的处理器。
- gccgo编译出的程序运行效率更高,因为gccgo比GC代码优化能力更强大。
- gccgo编译的代码可以更好的用于GDB。
- gccgo并不能支持编译所有的Golang版本,这个在使用时要注意。
编译的过程
Go 语言编译器的源代码在 src/cmd/compile 目录中,目录下的文件共同组成了 Go 语言的编译器,学过编译原理的人可能听说过编译器的前端和后端,
编译器的前端一般承担着词法分析、语法分析、类型检查和中间代码生成几部分工作,而编译器后端主要负责目标代码的生成和优化,也就是将中间代码翻译成目标机器能够运行的二进制机器码。
跨平台编译
Go 语言源代码的 src/cmd/compile/internal 目录中包含了很多机器码生成相关的包,不同类型的 CPU 分别使用了不同的包生成机器码,其中包括 amd64、arm、arm64、mips、mips64、ppc64、s390x、x86 和 wasm
下边列举一些常用的机器码生成的场景
windows编译linux
SET CGO_ENABLED=0 // 禁用CGO
SET GOOS=linux // 目标平台是linux
SET GOARCH=amd64 // 目标处理器架构是amd64
SET CGO_ENABLED=0 GOOS=linux GOARCH=amd64
go build custom.go //编译原名称
go build -o customLinux custom.go //编译自定义名称
GOOS=linux GOARCH=amd64 go build
同理linux下也可以用windows的exe
GOOS=windows GOARCH=amd64 go build
Mac 下编译 Linux 和 Windows平台 64位 可执行程序:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build
Linux 下编译 Mac 和 Windows 平台64位可执行程序:
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build
Windows下编译Mac平台64位可执行程序:
SET CGO_ENABLED=0
SET GOOS=darwin
SET GOARCH=amd64
go build
错误记录
上边提到go的两种编译方式:gc和gccgo,在项目过程有用到了go-sqlite3组件,并且还必须依赖cgo去编译生成;
当禁止cgo编译器时,出现这种错误:
Binary was compiled with 'CGO_ENABLED=0', go-sqlite3 requires cgo to work.
开启了gcc,直接go build ,还是报错:
/usr/local/go1.18/pkg/tool/linux_amd64/link: running gcc failed: exit status 1
推荐的解决方案
讨论细节:https://github.com/golang/go/issues/44703
源头:https://github.com/golang/go/issues/43996
rm -rf ~/.cache/go-build : this contained a few build artifacts
rm -rf ${MyProject}/{bin,pkg} : for the same reason
export CXXFLAGS="-stdlib=libstdc++" CC=/usr/bin/gcc CXX=/usr/bin/g++
当代码开启了cgo,以上解决不了的,再使用如下代码执行,适用于:Linux
1.Liunx需要安装gcc
yum install gcc
yum install gcc-c++ libstdc++-devel
yum install glibc-static.x86_64 -y
2.再进行编译操作(临时方案)
大概率是Linux版本过低
gcflags的参数
-N
: 禁止编译器优化-l
: 关闭内联 (inline)-c
int: 编译过程中的并发数,默认是1
# 为当前模块下的所有包关闭编译优化和内联
go build -v -gcflags="all=-N -l"
or
go build -v -gcflags="all=-N -l" -o customeLinux custom.go
go build -gcflags all="-N -l" *.go
单独介绍windows中gccgo编译问题
Windows下安装gcc
MinGW 的全称是:Minimalist GNU on Windows 。是将经典的开源 C语言 编译器 GCC 移植到了 Windows 平台下,并且包含了 Win32API ,因此可以将源代码编译为可在 Windows 中运行的可执行程序。
没有gcc的报错:
cgo: C compiler "gcc" not found: exec: "gcc": executable file not found in %PATH%
- 官网下载地址:https://www.mingw-w64.org/downloads/,直接安装免安装版,本机配置环境变量
- i686纯32位版供32位win系统使用
- x86_64是64位系统用的版本
- seh结尾是纯64位编译
- sjlj结尾是32 64两种编译,需加-m32或-m64参数
- posix通常用于跨平台,比win32兼容性好一些
- i686纯32位版供32位win系统使用
- 在桌面选择“计算机” --》右击选择“属性” --》进入“控制面板\所有控制面板项\系统”选项 --》选择左边的“高级系统设置” --》弹出的系统属性,选择“环境变量” --》在系统环境变量里,找到变量名为“Path” --》双击“Path”变量 --》在结尾追加“;D:\mingw64\bin”
- Windows版:https://github.com/niXman/mingw-builds-binaries/releases
- 验证调出cmd窗口:gcc -v
边栏推荐
- IDEA基本使用-创建和删除项目
- Topic Modeling of Short Texts: A Pseudo-Document View
- 怎么从零编写一个 v3 版本的 chrome 浏览器插件实现 CSDN 博客网站的暗黑和明亮主题切换?
- How does Excel compare if two columns of strings are the same?
- 五大靠谱的婚恋相亲APP详细特点缺点分析!
- leetcode:140. 单词拆分 II
- 【云原生】灰度发布、蓝绿发布、滚动发布、灰度发布解释
- 【云原生】阿里云ARMS业务实时监控
- mysql-installer安装教程(详细图文)
- LVS-NAT模式【案例实验】
猜你喜欢
随机推荐
通过kubernetes可视化界面(rancher)安装kibana
不想当Window的Dialog不是一个好Modal,弹窗翻身记...
QCheckBox、margin、border、pandding、QHoxLayout、QSplitter、QSpacerItem
PHICOMM(斐讯)N1盒子 - Armbian5.77(Debian 9)基本配置
leetcode:152. 乘积最大子数组
【Flink】如何生成 Flink 作业的交互式火焰图?
How does Excel compare if two columns of strings are the same?
leetcode:149. 直线上最多的点数
选中按钮上色
[Arduino] Reborn Arduino Monk (2)----Arduino Language
复杂多层布局的初级智能文本提示器
initramfs详解-----初识initramfs
MySQL-Explain详解
部门之间,互不信任正常吗?(你是否遇到过)
leetcode:139. 单词拆分
超级复杂可贴图布局的初级智能文本提示器
【UE4】搭建局域网内VR直播 UE4.27
leetcode:172. 阶乘后的零
JVM internal structure and various modules operation mechanism
简单的布局的初级智能文本提示器