linux 编译c_含有CGO代码的项目如何实现跨平台编译
目前小菜刀的项目中需要用到SQLite数据库,https://github.com/mattn/go-sqlite3支持database/sql接口,采用Go的标准接口有利于项目后续扩展,因此选择了该驱动。但是,它是基于CGO实现的,所以跨平台编译会比较麻烦,小菜刀总结了一些经验,特分享给读者朋友们。
什么是跨平台编译?
简单地说, 就是在一个平台上生成另一个平台上的可执行代码。这里需要注意的是,所谓平台,实际上包含两个概念:体系架构(Architecture)、操作系统 (Operating System)。同一个体系架构可以运行不同的操作系统;同样,同一个操作系统也可以在不同的体系架构上运行。
我们知道Go语言是支持跨平台编译的,在之前的文章《Go交叉编译》中有详细介绍过怎么操作。Go实现跨平台编译的思想其实很简单:通过保存可以生成最终机器码的多份翻译代码,在编译时根据 GOARCH=xxx
和GOOS=xxx
参数(对应体系架构和操作系统)进行初始化设置,最终调用对应平台编写的特定方法来生成机器码,从而实现跨平台编译。
CGO编译存在的问题
有一点需要注意:Go所谓的跨平台编译只是针对Go代码部分,它是Go的交叉编译器(cross-compiler toolchains)。当我们使用了CGO时,要想实现跨平台编译,同时需要让C/C++代码也支持跨平台。
1package main 2 3/* 4#include 5 6void printint(int v) { 7 printf("printint: %d\n", v); 8} 9*/10import "C"1112func main() {13 v := 4214 C.printint(C.int(v))15}
小菜刀的开发机器:amd64架构,darwin系统。目标编译平台:amd64架构,linux系统。现想将上述含有CGO的代码编译为目标平台的可执行文件。
1$ GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -o main main.go
通过以上命令,得到编译错误如下:
1/usr/local/go/pkg/tool/darwin_amd64/link: running clang failed: exit status 12ld: warning: ignoring file /var/folders/xk/gn46n46d503dsztbc6_9qb2h0000gn/T/go-link-220081766/go.o, building for macOS-x86_64 but attempting to link with file built for unknown-unsupported file format ( 0x7F 0x45 0x4C 0x46 0x02 0x01 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 )3Undefined symbols for architecture x86_64:4 "_main", referenced from:5 implicit entry/start for main executable6ld: symbol(s) not found for architecture x86_647clang: error: linker command failed with exit code 1 (use -v to see invocation)
可以看到,由于CGO的存在,跨平台编译失败。那该如何解决呢?
其实思路可以很简单:和Go一样,当我们拥有目标平台的C/C++代码翻译系统后,自然就能够编译为目标平台的可执行文件。
Mac下的可行方案
下载linux编译工具链
1brew install FiloSottile/musl-cross/musl-cross
或者windows编译工具链
1brew install mingw-w64
以linux编译工具链为例。在下载完毕后,/usr/local/bin下会存在以下对应平台C/C++编译器
1x86_64-linux-musl-addr2line x86_64-linux-musl-elfedit x86_64-linux-musl-gcov x86_64-linux-musl-objcopy2x86_64-linux-musl-ar x86_64-linux-musl-g++ x86_64-linux-musl-gcov-dump x86_64-linux-musl-objdump3x86_64-linux-musl-as x86_64-linux-musl-gcc x86_64-linux-musl-gcov-tool x86_64-linux-musl-ranlib4x86_64-linux-musl-c++ x86_64-linux-musl-gcc-9.2.0 x86_64-linux-musl-gprof x86_64-linux-musl-readelf5x86_64-linux-musl-c++filt x86_64-linux-musl-gcc-ar x86_64-linux-musl-ld x86_64-linux-musl-size6x86_64-linux-musl-cc x86_64-linux-musl-gcc-nm x86_64-linux-musl-ld.bfd x86_64-linux-musl-strings7x86_64-linux-musl-cpp x86_64-linux-musl-gcc-ranlib x86_64-linux-musl-nm x86_64-linux-musl-strip
上述指定下载命令只下载了x86_64体系下的编译器,但其实并不止这些。可通过brew info musl-cross
命令进行查看。
1$ brew info musl-cross 2filosottile/musl-cross/musl-cross: stable 0.9.9 (bottled), HEAD 3Linux cross compilers based on musl libc 4https://github.com/richfelker/musl-cross-make 5/usr/local/Cellar/musl-cross/0.9.9 (1,851 files, 245.8MB) * 6 Poured from bottle on 2020-11-16 at 17:09:31 7From: https://github.com/filosottile/homebrew-musl-cross/blob/master/musl-cross.rb 8==> Dependencies 9Build: gnu-sed ✔, make ✔10==> Options11--with-aarch6412 Build cross-compilers targeting arm-linux-muslaarch6413--with-arm14 Build cross-compilers targeting arm-linux-musleabi15--with-arm-hf16 Build cross-compilers targeting arm-linux-musleabihf17--with-i48618 Build cross-compilers targeting i486-linux-musl19--with-mips20 Build cross-compilers targeting mips-linux-musl21--with-mips6422 Build cross-compilers targeting mips64-linux-musl23--with-mips64el24 Build cross-compilers targeting mips64el-linux-musl25--with-mipsel26 Build cross-compilers targeting mipsel-linux-musl27--without-x86_6428 Do not build cross-compilers targeting x86_64-linux-musl29--HEAD30 Install HEAD version
此时,通过指定C/C++编译器为/usr/local/bin/x86_64-linux-musl-gcc
,替换默认的C/C++编译器(本机编译,可通过go env CC
查看),即可完成含有CGO的Go代码交叉编译任务。
1$ GOOS=linux CC="/usr/local/bin/x86_64-linux-musl-gcc" GOARCH=amd64 CGO_ENABLED=1 go build -ldflags "-linkmode external -extldflags -static" main.go
最终,在本机mac系统上就编译得到了amd64 linux平台的可执行文件。
Docker解决方案
在小菜刀通过上述方式完成cgo的跨平台编译之余,找到了另外一种可行方案:基于Docker容器的xgo打包工具。
它的实现也很简单:将多平台所需要的Go工具链,C/C++交叉编译器和头文件/库都组装到Docker容器中(因此,在镜像拉取时,会下载大量的依赖资源),再借助xgo打包工具实现跨平台编译。
Docker安装(省略)
拉取镜像
1docker pull karalabe/xgo-latest
打包工具安装
1go get github.com/karalabe/xgo
轻量级的命令包装器,它的作用就是简化复杂的Docker命令。
跨平台编译
指定要编译的导入路径即可,其余工作由xgo完成。在本例中,代码位置位于$GOPATH/src/workspace/example/cgoDemo2/
1xgo $GOPATH/src/workspace/example/cgoDemo2/
编译之后,本目录下会存在以下各平台可执行文件
1$ ls -al 2total 44960 3drwxr-xr-x 23 slp staff 736 Nov 17 11:43 . 4drwxr-xr-x 39 slp staff 1248 Nov 16 17:59 .. 5-rwxr-xr-x 1 slp staff 1761872 Nov 17 11:42 cgoDemo2-android-16-386 6drwxr-xr-x 5 slp staff 160 Nov 17 11:42 cgoDemo2-android-16-aar 7-rwxr-xr-x 1 slp staff 1778464 Nov 17 11:42 cgoDemo2-android-16-arm 8-rwxr-xr-x 1 slp staff 902436 Nov 17 11:43 cgoDemo2-darwin-10.6-386 9-rwxr-xr-x 1 slp staff 1053816 Nov 17 11:43 cgoDemo2-darwin-10.6-amd6410-rwxr-xr-x 1 slp staff 1065232 Nov 17 11:43 cgoDemo2-ios-5.0-arm6411-rwxr-xr-x 1 slp staff 978016 Nov 17 11:43 cgoDemo2-ios-5.0-armv712drwxrwxrwx 3 slp staff 96 Nov 17 11:43 cgoDemo2-ios-5.0-framework13-rwxr-xr-x 1 slp staff 1084208 Nov 17 11:42 cgoDemo2-linux-38614-rwxr-xr-x 1 slp staff 1226072 Nov 17 11:42 cgoDemo2-linux-amd6415-rwxr-xr-x 1 slp staff 1093728 Nov 17 11:42 cgoDemo2-linux-arm-516-rwxr-xr-x 1 slp staff 1074348 Nov 17 11:43 cgoDemo2-linux-arm-617-rwxr-xr-x 1 slp staff 1073800 Nov 17 11:43 cgoDemo2-linux-arm-718-rwxr-xr-x 1 slp staff 1196520 Nov 17 11:43 cgoDemo2-linux-arm6419-rwxr-xr-x 1 slp staff 1152088 Nov 17 11:43 cgoDemo2-linux-mips20-rwxr-xr-x 1 slp staff 1274272 Nov 17 11:43 cgoDemo2-linux-mips6421-rwxr-xr-x 1 slp staff 1271464 Nov 17 11:43 cgoDemo2-linux-mips64le22-rwxr-xr-x 1 slp staff 1148892 Nov 17 11:43 cgoDemo2-linux-mipsle23-rwxr-xr-x 1 slp staff 1712214 Nov 17 11:43 cgoDemo2-windows-4.0-386.exe24-rwxr-xr-x 1 slp staff 2115121 Nov 17 11:43 cgoDemo2-windows-4.0-amd64.exe25-rw-r--r-- 1 slp staff 157 Nov 16 16:51 main.go
默认情况下,xgo会尝试编译Go运行时所支持的所有平台。如果我们只想构建特定的几个目标系统,可以使用逗号分隔的--targets
选项控制,例如--targets=windows/amd64,linux/amd64
代表编译目标仅包括amd64架构的windows和linux平台。
1$ xgo --targets=windows/amd64,linux/amd64 $GOPATH/src/workspace/example/cgoDemo2/
目前支持的平台列表如下
操作系统:
android
,darwin
,ios
,linux
,windows
架构:
386
,amd64
,arm-5
,arm-6
,arm-7
,arm64
,mips
,mipsle
,mips64
,mips64le
xgo提供了比较灵活的编译方案,通过$ xgo -h
查看选项信息,更多详情可点击文末的xgo链接。
参考链接[easy windows and linux cross-compilers for macOS] https://blog.filippo.io/easy-windows-and-linux-cross-compilers-for-macos/[musl-cross-make] https://github.com/richfelker/musl-cross-make[homebrew-musl-cross] https://github.com/FiloSottile/homebrew-musl-cross[xgo] https://github.com/karalabe/xgo
往期推荐
- 一个Golang版丝滑的可视化库
- 切片传递的隐藏危机
- 一文读懂channel设计
- Go是如何设计Map的
linux 编译c_含有CGO代码的项目如何实现跨平台编译相关推荐
- vs release编译出现 “不安全代码只会在使用 /unsafe 编译的情况下出现“的解决方法
原因是:在编译的代码里面有不安全类型unsafe方法或类! 解决方法:将项目的"可编译不安全代码"属性设置为true就可以了,方法如下:项目属性对话框->配置属性->生 ...
- Java 在线运行编译【运行 Java 代码工具推荐】
JJava 在线运行编译,是一款可在线编程编辑器,在编辑器上输入Java代码,点击运行,可在线编译运行Java,Java代码在线运行调试,Java在线编译,可快速在线测试您的Java代码,在线编译Ja ...
- Android跨平台编译 —— BOOST
2019独角兽企业重金招聘Python工程师标准>>> 前言 android studio在2.2开始已经全面接入了cmake,用来编译jni代码.所以我们的跨平台编译同样需要与时俱 ...
- 一份简单的在 Linux下编译及调试 C 代码的指南
摘要: 一份简单的在 Linux下编译及调试 C 代码的指南 对于Linux下的C程序员来说,几乎天天都会和Linux打交道.但在很多人的眼中,Linux是一个易用性极差.靠命令驱动的操作系统,根本无 ...
- Linux 下编译及调试 C 代码的简易指南
对于Linux下的C程序员来说,几乎天天都会和Linux打交道.但在很多人的眼中,Linux是一个易用性极差.靠命令驱动的操作系统,根本无法与有着友好用户界面的Windows相比.确实是这样的,即使大 ...
- 关于Linux开源项目基础组件make编译流程
关于Linux开源项目基础组件make编译流程 非常多Linux开源项目都会用到编译出可运行文件的make.这个是有一套流程的. 首先,GNU构建系统:https://en.wikipedia. ...
- C++项目中编译部分C的代码
在C++项目中如果真能编译部分C的代码,那么一定会用到一下语句 #ifdef __cplusplus extern "C" { #endif /*...*/ #ifdef __cp ...
- 基于Linux下的即时通讯聊天室项目(全代码 有注释 可直接运行)
基于Linux下的即时通讯聊天室项目 一.序言 二.具体功能 三.系统客户要求 四.具体代码 1.服务器代码 2.客户端代码 一.序言 最近在写一个基于Linux下的聊天工具 它适合于局域网内所有人进 ...
- linux编译c++11的代码
C++11,(即ISO/IEC 14882:2011),是目前的C++编程语言的最新正式标准.它取代了第二版标准(第一版公开于1998年,第二版于2003年更新,分别通称C++98以及C++03,两者 ...
最新文章
- python面试常见问题-常见Python面试题
- dram和nand哪个难生产_DRAM与NAND差别这么大,存储之争都争啥
- Oracle中删除用户和表空间的常见问题(比如:ORA-01940无法删除当前已连接用户的解决方案)
- python开发上位机软件-UR机器人通信--上位机通信(python)
- 透彻解析云原生在数字化转型中的应用实践,PaaS功不可没
- 中upload依赖包_upload-labs writeup
- 2019-0405视觉SLAM的学习第四讲
- 带新手玩转MVC——不讲道理就是干(下)
- android文件操作和SDCard卡操作
- c语言程序设计必备单词,C语言编程必背单词版.docx
- 阿里 Lindorm 数据库联手 Hightopo ,开启工业物联超融合存储模式
- 过去式加ed的发音_动词过去式加ed后发音
- spss多元线性回归散点图_SPSS19.0实战之多元线性回归分析
- 2019 年终总结,168 篇,已归类!
- lda主题模型python实现篇_主题模型TopicModel:通过gensim实现LDA
- 知名IT企业面试题整理(八)--合并
- 海康、华为、中兴、联影...找工作记录
- 【2016-2017】陪伴是最长情的告白
- RPGMaker MV 插件基础04:插件指令与脚本
- SICP-Notes-Lecture 21 SQL I