Golang交叉编译中的那些坑_Three_dog的博客-程序员宝宝

技术标签: Golang  跨平台  golang  go  交叉编译  国产化  

最近两个月,一直在搞项目的国产化移植,把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等方式进行进程间通信
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Three_dog/article/details/94640507

智能推荐

非法入侵竟然如此简单 黑客表演令人愕然(图)_edison20的博客-程序员宝宝

  【日经BP社报道】在Networld+Interop会期间,除了将举办展览会以外还将举行Work Shop活动。此次最抢风光的是题为“Hacking Exposed(黑客行为曝光)”的Work Shop。会场准备的约200个席位基本满座。当在屏幕上出现劫持目标电脑的情形时,全场发出阵阵震惊和叹息。  在这一Work Shop中,实际演示了网络非法入侵者(黑客,Cracker)通过什么顺

如何写优雅的代码(序)——自语_norains的博客-程序员宝宝

//========================================================================//TITLE://    如何写优雅的代码(序)——自语//AUTHOR://    norains//DATE://    Thursday  16-July-2009//Environment://    WINCE5.0 + VS2005//=

【Mysql】创建某个用户只能访问指定的数据库_UniverseLin的博客-程序员宝宝

转载链接: Mysql中使某个用户只能访问指定的数据库.感谢该博主的说明。使用navicat 1)使用root用户新建连接 2)新建MySQL用户 3)点击权限,选择添加权限,出现MySQL中已存在的数据库列表,选择你要为该新建用户开放的数据库,此处选择“test”数据库,选择一些必要的权限信息,确定 4)查看新建用户对数据库的操作权限,如下图 5)很重要的一点,别忘记保存! 6)然后新建连接,输入用户名和密码,打开连接,则新建的那个用户只能看到为他分配的那个数据库 2.命令行实现

DataSource配置详解_zhu473105308的博客-程序员宝宝

10         100         20         60         10      但由于预缓存的statements属于单个connection而不是整个连接池。  所以设置这个参数需要考虑到多方面的因素。     如果maxStatements与maxStatementsPerConnec

数据结构-线性结构-单链表_suxiaorui的博客-程序员宝宝

单链表的读取在线性表的顺序存储结构中,我们要知道任意一个元素的存储位置是很容易的,但是在单链表中,实现获取第i个元素的数据操作GetElem,就需要点想法。思路:声明一个结点 p 指向链表第一个结点,初始化 j 从1开始 当 j < i 时,就遍历链表,让p的指针向后移动,不断指向下一个结点,j 累加1 若到链表末尾p为空,则说明第 i 个元素不存在 否则查找成功,返回结...

matlab 反走样,如何在python中使用Matlab的imresize_邦成为寄卖连锁的博客-程序员宝宝

对我来说,scipy.misc.imresize函数有点奇怪。首先,当我指定您提供给这个图像上的scipy.misc.imresize调用的示例2D图像时,会发生这种情况,比例为1.0。理想情况下,它应该给你相同的图像,但我们得到的是(在IPython中):In [35]: from scipy.misc import imresizeIn [36]: import numpy as npIn [...

随便推点

oracle数据库安装后如何建立自己的数据库_sunyllove的博客-程序员宝宝_安装完oracle后怎么创建数据库

oracle数据库安装后如何建立自己的数据库 (2012-05-27 15:49:50)转载▼标签: 数据库 oracle 创建表 杂谈       最近,有个人找自己做oracle方面的东西,自己之前搞过数据库,但是没有搞过oracle数据库,有点担心,但是,之后研究了一下

Android开发中java.lang.RuntimeException: Unable to start activity ComponentInfo问题_嗯哼丶苏苏的博客-程序员宝宝

今天学着写了个底部导航栏滑动切换页面,主要是使用Fragment+ViewPager,项目可编译,但是运行就会报错停止,错误提示如下:手机程序中则是:通过查看错误信息发现报错是MainActivity中的 setContentView(R.layout.activity_main); 但是MainActivity并没有报错,查看R.layout.activity_main布局文件也...

Linux下查看文件和文件夹大小_sunxiaopengsun的博客-程序员宝宝_linux 查看文件夹大小命令

1 Linux下查看文件和文件夹大小2 删除系统日志等场景:在sts中执行自动部署时候maven提示No space left on device错误,后来经检查发现是磁盘空间满了,用下面的方法分析发现tomcat下面的logs目录占用了很大的空间,删除多余的日志问题解决!回到顶部1 Linux下查看文件和文件夹大小当磁盘大小超过标准时会有报警提示,这时如果掌握df和du命令是非常明智的选择。 d...

深入理解Consul注册中心机制_雪中的记忆的博客-程序员宝宝_consul注册中心

所有Consul Server节点参与Raft协议,共同组成`Peer Set`。`Peer set `理解为参与日志复制所有成员的集合。所有Consul Client节点把请求转发给Consul Server节点。这种设计主要原因是,随着更多Consul节点成员的加入到`Peer Set`中。 `quorum` 的大小也会增加。`quorum` 理解为多数派。对于N个Consul Server节点成员,`quorum`要求至少有(N/2)+1成员。 ...

linux内核license,GitHub - ldcm/linux-kernel-exploits: linux-kernel-exploits Linux平台提权漏洞集合..._weixin_39757739的博客-程序员宝宝

CVE–2018–18955  [map_write() in kernel/user_namespace.c allows privilege escalation](Linux kernel 4.15.x through 4.19.x before 4.19.2)CVE–2018–1000001  [glibc](glibc <= 2.26)CVE-2017-1000367  [Sudo...

css圆形背景_CSS背景重复:圆形_culuo8053的博客-程序员宝宝

css圆形背景The CSS spec is full of gems that sneak their way past most of us web designers and developers. Stuff like :focus-within, prefers-reduced-motion, and prefers-color-scheme suddenly make their wa...