Golang交叉编译中的那些坑

2023-11-09

最近两个月,一直在搞项目的国产化移植,把golang开发好的程序,运行在国产化平台上,操作系统基本都是基于Linux,但是CPU架构除了x86,还有ARM和MIPS,我们平时的Golang都是运行于x86 && x64 架构的CPU上,因此移植过程中遇到了好多坑,记录于此。

Golang交叉编译

交叉编译

在X64上的ubuntu 16.04系统上编译出其他平台的可执行程序

查看Golang支持的平台和版本

go tool dist list

此命令会列出所有go语言支持的操作系统和cpu架构

golang的交叉编译

其实go的交叉编译非常简单,只需要在编译前指定系统和CPU架构,基本不会有任何问题,编译出来讲文件拷贝到对应平台就能跑:

GOOS=linux GOARCH=arm64 go build xxx.go
# 有时候需要加上CGO_ENABLE=0
CGO_ENABLE=0 GOOS=linux GOARCH=arm64 go build xxx.go

go语言的交叉编译支持非常好,只要按照上述步骤基本不会出什么问题。坑,主要就坑在cgo!

采用cgo的交叉编译

使用cgo,就必须指定CGO_ENABLE=1。并且必须指定CC参数为对应架构的gcc的交叉编译器。
假设我们变异64位ARM平台的程序,就要提前下载aarch64版本的c++交叉编译工具

CGO_ENABLED=1 GOOS=linux GOARCH=arm64 CC=./aarch64-unknown-linux-gnueabi-5.4.0-2.23-4.4.6/bin/aarch64-unknown-linux-gnueabi-gcc go build xxx.go

如果调用的CGO调用的C程序中依赖各种库,那么这个编译过程会报错各种依赖的库not found ,各种基本的函数未定义。而且都是系统中最基本的库如libglibc、libgstream等。

解决方案是必须在编译时,加上链接库的参数,而链接的库必须交叉编译出的目标平台的系统库而不是当前系统的。

这个在下载交叉编译工具链的时候,一般都会附带,我这里放到系统根目录下,然后通过C++编译时链接库的语法将库链接进去:
主要是三个参数:-I , -isystem , -L, -l
下面命令是个例子,假设项目中用到了phnono、curl、protobuf等组件

CGO_ENABLED=1 GOOS=linux GOARCH=arm64 CC=./aarch64-unknown-linux-gnueabi-5.4.0-2.23-4.4.6/bin/aarch64-unknown-linux-gnueabi-gcc -Wall -std=c++11 -Llib -isystem/aarch64/usr/include -L/aarch64/lib -ldl -lpthread -Wl,-rpath-link,/aarch64/lib -L/aarch64/lib/aarch64-linux-gnu -L/aarch64/usr/lib -I/aarch64/usr/include -L/aarch64/usr/lib/aarch64-linux-gnu -ldl -lpthread -Wl,-rpath-link,/aarch64/usr/lib/aarch64-linux-gnu -lphonon -lcurl -lprotobuf go build xxx.go

到这一步,就基本解决了无法编译的坑。

平台差异的问题

在编译ARM版本的代码时,报错好几个系统调用找不到

  • undefined: syscall.Dup2
  • undefined: syscall.SYS_FORK

解决方案:对比golang源码实现:go/src/syscall/zsyscall_linux_amd64.gogo/src/syscall/zsyscall_linux_arm64.go,发现arm平台未实现Dup2但是提供了Dup3,参数略有差异,解决办法是修改调用的地方:

// - syscall.Dup2(oldfd, newfd) 修改为:
syscall.Dup3(oldfd,newfd,0)

而SYS_FORK的调用,查找之下发现golang的ARM实现根本没有实现fork的系统调用,没有SYS_FORK这个宏或替代品。
无奈只能修改项目代码,将fork的系统调用改为别的方式实现。

MIPS的大小端问题

报错:go.o: compiled for a big endian system and target is little endian
主要体现在大小端字节序的问题,这是我在交叉编译Mips版本发现的一个问题,仔细查看了我的编译命令发现:

CGO_ENABLED=1 GOOS=linux GOARCH=mips64 CC=./mips64el-unknown-linux-gnu-5.4.0-2.12-2.6.32/bin/mips64el-unknown-linux-gnu-gcc go build xxx.go

这里的命令中:CC指定的是mips64el的编译器,el代表小端字节序,而GOARCH=mips64这是大端字节序,前后不一致导致编译的报错,
解决方案:go和gcc保持统一、以目标平台为准(龙芯是小端字节序)

  • 将GOARCH指定为mips64le注意是le不是el
  • 最好加上LDFLAG=-EL
CGO_ENABLED=1 GOOS=linux GOARCH=mips64le CC=./mips64el-unknown-linux-gnu-5.4.0-2.12-2.6.32/bin/mips64el-unknown-linux-gnu-gcc LDFLAGS=-EL go build xxx.go

Tips

综上所述:

  • golang程序开发少用原生的系统调用syscall
  • 能用go解决的,尽可能不要用cgo
  • 如果有模块必须通过C/C++调用,推荐C++和golang分离,C++和Golang程序间使用socket等方式进行进程间通信
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Golang交叉编译中的那些坑 的相关文章

随机推荐

  • 使用代理同步Chromium代码的心得

    先参看 http www chromium org developers how tos build instructions windows 非常坑爹 谷歌获取chromium源码的方式又变了 从chromium39 0 2313 2之后
  • poj 2155 Matrix

    Problem poj org problem id 2155 vjudge net contest 146952 problem A Meaning 一个 N N 的矩阵 A 初始时全部值为 0 有两种操作 1 C x1 y1 x2 y2
  • 电机驱动板发烫严重怎么办?一份大厂PCB布局指南参考

    作者 Pete Millett Technical Marketing Engineer Monolithic Power Systems 翻译 Toffee Jia 来源 MPS 电机驱动 IC 传递大量电流的同时也耗散了大量电能 通常
  • java远程连接linux并发送命令,两种方案比较Jsch与ganymed-ssh2

    通过Jsch连接 step 1引入jar包
  • curl学习2

    代理 什么是代理 Merrian Webster的解释是 一个通过验证的用户扮演另一个用户 今天 代理已经被广泛的使用 许多公司提供网络代理服务器 允许员工的网络客户端访问 下载文件 代理服务器处理这些用户的请求 libcurl支持SOCK
  • 滑动穿透终极解决方案

    问题描述 滑动穿透 浮层上的触控会导致底层元素滑动 问题探究 1 给body加overflow hidden pc端可以锁scroll 移动端无效 pc端可以直接overflow hidden解决 2 给body加overflow hidd
  • 数据结构学习系列之单向链表的去重

    单向链表的去重 所谓的去重 就是去除单向链表中重复的数据结点 代码如下 示例代码 int del rep link list node t phead if NULL phead printf 入参为NULL 请检查 n return 1
  • 云计算通俗解释,什么叫云计算

    计算已经越来越为大众所熟知 那么云计算到底是什么呢 有没有云计算通俗解释呢 云计算是由分布式计算 并行处理 网格计算发展来的 是一种新兴的商业计算模型 目前 对于云计算的认识在不断的发展变化 云计算仍没有普遍一致的定义 云计算 Cloud
  • 【Java】HashMap原理-JDK1.7与JDK1.8的区别

    一 HashMap 扩容 JDK1 7 和JDK1 8 扩容原理相同 HashMap初始化大小为16 负载因子为0 75 每次当容量大于16 0 75 时 进行扩容 扩容为原来的两倍 也可以通过构造方法修改 但HashMap会自动将给定初始
  • 小鹅通面试回顾

    如果大家也在找面试笔试题目内容 可以看我的总结文章 正在更新之中 有没涉及到的内容 欢迎大家指出 附链接 数据库 C C HTML OS 计网面试准备 更新中 一面内容 最开始时讲述一下自己学校时曾做过的一些项目内容 之后我自己介绍时说对于
  • qt 登陆界面账号和密码的验证

    这几天一直研究怎么让界面账号和密码验证的问题 特别想用数据库 一直有QSQLlitdatabase cant find 的问题 找了很多方法没成功 要交课设 所以放弃用其他方法 用文件存吧 比较省事 但是有个更简单的办法 哈哈 先看 转到槽
  • 云象区块链解读区块链如何赋能贸易金融

    陀螺公开课 是定位于区块链行业的线上精品教育课程 以视频的形式传递行业思考 内容板块包括技术前沿 产业案例 领袖视野 学术思想 名人演讲等 通过邀请行业领域专家线上讲课 及开放高质量视频投稿 为用户提供优质的区块链学习内容 陀螺公开课第三期
  • nrm 安装后报错 --- 亲测有效

    发现问题 执行指令 npm i g nrm 安装后 nrm V 报错 报错内容如下 import process from node process SyntaxError Cannot use import statement outsi
  • 自学Unity游戏开发日记

    Unity游戏开发的启蒙老师是麦扣老师 在bilibili 讲的非常的棒 后悔没有早点发现麦扣老师 第一个案例游戏 Sunny Land 印象最深的问题 在按下空格进行跳跃时 跳不起来 或者说偶尔能跳起来 这是因为GetButtonDown
  • 虚拟机安装windows11

    前言 在日常工作中有的时候需要在虚拟环境里使用windows系统 因为在虚拟环境里不存在病毒传播或者搞坏C盘后数据丢失情况 所以在虚拟机里安装windows 是一个必备技能 根据生活 乱编的 下载 windows11地址 首先安装一个迅雷
  • 如何使用计算机做海报,用word做的海报步骤_word怎么设计海报

    5 用word做招聘海报 首先先打开wps软件或者是新建一个word文档 如果你想打印一张出租 出售之类的广告的话最好是打印横版的 因为这类的广告文字比较少 横向排版有帮于把文字的大小放到最大 点击页面布局 选择其中的纸张方向 在弹出的纸张
  • 数据库表结构设计方法

    author skate time 2011 02 12 数据库表结构设计方法 当我们设计一个数据库存储模式时 要仔细分析数据模式 不要一股脑的把所有的数据都放在一起 那样的话对系统的可用性 高效能 扩展性都会有严重的影响 当然你设计的系统
  • Python 深度学习实战:75个有关神经网络建模、强化学习与迁移学习的解决方案

    深度学习正在为广泛的行业带来革命性的变化 对于许多应用来说 深度学习通过做出更快和更准确的预测 证明其已经超越人类的预测 本书提供了自上而下和自下而上的方法来展示深度学习对不同领域现实问题的解决方案 这些应用程序包括计算机视觉 自然语言处理
  • 中医蜂疗新起点,新思路,新未来

    2021年10月22日 24日由世界中医药学会联合会蜂疗专业委员会 中国民族医药学会主办的蜂界年度盛会 第三届世界蜂疗大会暨世界中联蜂疗专业委员会换届大会暨第四届学术年会 中国民族医药学会蜂疗分会换届会议暨2021年学术年会在庄严的首都北京
  • Golang交叉编译中的那些坑

    最近两个月 一直在搞项目的国产化移植 把golang开发好的程序 运行在国产化平台上 操作系统基本都是基于Linux 但是CPU架构除了x86 还有ARM和MIPS 我们平时的Golang都是运行于x86 x64 架构的CPU上 因此移植过