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

Golang交叉编译

交叉编译

在X64上的ubuntu 16.04系统上编译出其他平台的可执行程序, 查看Golang支持的平台和版本:

go tool dist list

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

aix/ppc64

android/386

android/amd64

android/arm

android/arm64

darwin/amd64

darwin/arm64

dragonfly/amd64

freebsd/386

freebsd/amd64

freebsd/arm

freebsd/arm64

illumos/amd64

js/wasm

linux/386

linux/amd64

linux/arm

linux/arm64

linux/mips

linux/mips64

linux/mips64le

linux/mipsle

linux/ppc64

linux/ppc64le

linux/riscv64

linux/s390x

netbsd/386

netbsd/amd64

netbsd/arm

netbsd/arm64

openbsd/386

openbsd/amd64

openbsd/arm

openbsd/arm64

plan9/386

plan9/amd64

plan9/arm

solaris/amd64

windows/386

windows/amd64

windows/arm

其实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_ENABLED=0 关闭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.go和go/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=-ELCGO_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

总结经验:

1. golang程序开发少用原生的系统调用syscall

2. 能用go解决的,尽可能不要用cgo

3. 如果有模块必须通过C/C++调用,推荐C++和golang分离,C++和Golang程序间使用socket等方式进行进程间通信

字符大小端aix linux,Go交叉编译的那些事相关推荐

  1. 字符大小端aix linux,long, unsigned long不是跨平台的(慎用)

    项目中用到long.long long等字段,遇到一些问题.先说得到的一些结论: 大小端:Windows.Linux是小端,AIX是大端. sizeof(指针类型)=程序位数/8. long.unsi ...

  2. Linux账户标识R=400是什么意思_带你阅读linux内核源码:通俗讲解编译器、交叉编译器和大小端...

    欢迎关注"技术简说",持续分享linux内核和驱动开发干货. 本文内容包括: 编译器和交叉编译器的介绍 交叉编译器的命名规则 如何交叉编译C代码 大端.小端的通俗讲解 如何判断你的 ...

  3. linux大端小端命令,linux的大小端、网络字节序问题

    linux的大小端.网络字节序问题 总结:1.80X86使用小端法,网络字节序使用大端法. 2.二进制的网络编程中,传送数据,最好以unsigned char, unsigned short, uns ...

  4. Linux内核判断大小端,linux kernel 如何处理大小端

    暂时在用MPC8309,不太清楚大小端内核是什么时候给转的. 今天看了关于readl和writel具体实现的文章 今天就主要来分析下readl/writel如何实现高效的数据swap和寄存器读写.我们 ...

  5. Linux大小端转换实现

    实现 #include <byteswap.h> #include <stdint.h>/*** @brief 8字节类型的字节序转化*/ template<class ...

  6. linux中判断平台是大端或小端的方法,判断机器大小端的方法

    以前就简单据说过电脑的大小端之分,还有经过程序来判断你的电脑是大端仍是小端.今天在学习网络的时候又接触了大小端,这里就再给你们详细的介绍一下电脑的大小端.node 首先,介绍一下什么是大端什么是小端. ...

  7. Linux一句命令之判断大小端序

    笔者在开发Linux应用程序时,由于判断大小端序的问题,使用的方法是用C语言判断,方法是可以判断得到系统是什么端序,但是太麻烦了.笔者是比较懒的人,不想写那么多代码,想一句命令就解决端序判断的问题. ...

  8. Linux系统的大小端模式

    大端模式 所谓的大端模式,是指数据的低位(就是权值较小的后面那几位)保存在内存的高地址中,而数据的高位,保存在内存的低地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数 ...

  9. linux查看编译器的大小端,Linux系统大小端判断

    大端模式 大端模式,是指数据的低位保存在内存的高地址中,而数据的高位保存在内存的低地址中. 小端模式 小端模式,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中. 判断程序 文件: ...

最新文章

  1. 怎么定义图像的质量?如何评价图像的质量?
  2. 继承CListCtrl,然后重载OnLButtonUP消息,发现变成双击才触发???
  3. etcd 集群故障(数据变成只读)
  4. 本质矩阵svd分解_SVD推荐系统
  5. java验证码识别--2
  6. 理论基础 —— 队列
  7. 基于JAVA+SpringMVC+Mybatis+MYSQL的实验室设备管理系统
  8. DELL Latitude E5400 装了PC DOS 7.1系统启动不了
  9. 阿里Sentinel支持Spring Cloud Gateway的实现
  10. 腾讯云学生服务器分享
  11. python scipy 密度函数 分位数 累计函数计算p值 卡方检验 t检验 F检验 假设检验 AB实验 显著性检验
  12. 人脸识别(1)---人脸识别长篇研究
  13. android 图标删除不了,手机程序卸载之后桌面上残留的图标删除不掉
  14. 物联网毕设(基于STM32的蓝牙检测心率+步数+手机APP)
  15. Python——pyqt5的计算器(源码+打包)
  16. selenium 批量下载qq邮箱附件
  17. (二)安全计算-Threat Modelling威胁建模
  18. React Native开发之——Webstorm开发RN配置
  19. 壹角硬币是错版币,也是残币,有收藏价值吗?
  20. shell exec命令

热门文章

  1. Uniform Distribution均匀分布
  2. 洛谷 P1074 靶形数独 Label:search 不会
  3. Odoo链接magento纪实
  4. 框架会使程序员变笨吗?
  5. 思科华为基础命令对照表
  6. 【自然框架】元数据的数据库结构的详细说明和示例(三):项目与数据库字段的关联...
  7. 用DirectX Audio和DirectShow播放声音和音乐(3)
  8. 分析器错误信息: 未能加载类型命名空间.类...
  9. 028-进阶(网络编程)
  10. [NOIp2013] 货车运输