cgo静态编译不能用glibc,用musl
Golang 的一个动态链接依赖问题
upx 是一个压缩二进制的工具,如上图,经过压缩之后,这些 binary 的体积都减少了 46%。
静态链接 CGO 的依赖
如果使用 glibc 的是,是不能静态链接的:
root@f88271a666f9:/workspace# go build -ldflags "-linkmode external -extldflags '-static'" ./cmd/spex
# git.garena.com/shopee/platform/spex/cmd/spex
/usr/bin/ld: /go/pkg/mod/github.com/confluentinc/confluent-kafka-go@v1.5.2/kafka/librdkafka/librdkafka_glibc_linux.a(rddl.o): in function `rd_dl_open':
(.text+0x1d): warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/bin/ld: /tmp/go-link-883441031/000004.o: in function `_cgo_26061493d47f_C2func_getaddrinfo':
/tmp/go-build/cgo-gcc-prolog:58: warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
因为 glibc 依赖了 libnss ,libnss 支持不同的 provider,必须被 dynamic link.所以这里只有使用 musl 替换 glibc 了。librdkafka 和 golang 的封装 confluent-kafka-go 都支持 musl 构建。只要在构建的时候指定 --tags musl 即可。alpine 是基于 musl 的发行版,这里直接使用 alpine Linux 进行构建。然后指定使用外部 ld,指定 flags 使用 -static,编译出来的 binary 就完全是静态链接的了。编译过程如下:$ docker run -it -v $(pwd):/workspace -v /Users/xintao.lai/.netrc:/root/.netrc golang:alpine3.14
/go $ cd /workspace/
/workspace $ apk add git alpine-sdk
fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/community/x86_64/APKINDEX.tar.gz
(1/37) Installing fakeroot (1.25.3-r3)
(2/37) Installing openssl (1.1.1l-r0)
(3/37) Installing libattr (2.5.1-r0)
(4/37) Installing attr (2.5.1-r0)
(5/37) Installing libacl (2.2.53-r0)
(6/37) Installing tar (1.34-r0)
(7/37) Installing pkgconf (1.7.4-r0)
...
/workspace $ go build -ldflags "-linkmode external -extldflags '-static'" -tags musl ./cmd/spex
/workspace $ ldd spex
/lib/ld-musl-x86_64.so.1: spex: Not a valid dynamic program
$ docker run -it -v $(pwd):/workspace -v /Users/xintao.lai/.netrc:/root/.netrc golang:alpine3.14
/go $ cd /workspace/
/workspace $ apk add git alpine-sdk
fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/community/x86_64/APKINDEX.tar.gz
(1/37) Installing fakeroot (1.25.3-r3)
(2/37) Installing openssl (1.1.1l-r0)
(3/37) Installing libattr (2.5.1-r0)
(4/37) Installing attr (2.5.1-r0)
(5/37) Installing libacl (2.2.53-r0)
(6/37) Installing tar (1.34-r0)
(7/37) Installing pkgconf (1.7.4-r0)
...
/workspace $ go build -ldflags "-linkmode external -extldflags '-static'" -tags musl ./cmd/spex
/workspace $ ldd spex
/lib/ld-musl-x86_64.so.1: spex: Not a valid dynamic program
静态编译 CGO 的依赖可以参考这篇教程:Using CGO bindings under Alpine, CentOS and Ubuntu 和这个例子:go-static-linking.
shadowmint/go-static-linking
https://github.com/shadowmint/go-static-linking
Go语言涉及CGO的交叉编译(跨平台编译)解决办法
在实际开发中,我们往往要使用交叉编译[1]来实现跨平台部署,这两天查阅资料,发现之所以TensorFlow跨平台编译失败,是因为使用了cgo来调用TensorFlow C。今天我们就来深入了解下,怎么处理带CGO的交叉编译。
在没有CGO调用的情况下,交叉编译只需带上三个参数便可以实现
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build
或者加上可选参数
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags ‘-s -w --extldflags “-static -fpic”’ main.go
CGO_ENABLED 这个参数默认为1,开启CGO。需要指定为0来关闭,因为CGO不支持交叉编译。
GOOS 和 GOARCH 用来指定要构建的平台为Linux
可选参数-ldflags 是编译选项:
-s -w 去掉调试信息,可以减小构建后文件体积,
–extldflags “-static -fpic” 完全静态编译[2],这样编译生成的文件就可以任意放到指定平台下运行,而不需要运行环境配置。
显然对于带CGO的交叉编译,CGO_ENABLED必须开启。这也就需要辅助编译器来帮我们实现交叉编译了。
如果你是mac平台,可以用这个工具 FiloSottile/musl-cross/musl-cross 直接通过brew安装就可以使用
brew install FiloSottile/musl-cross/musl-cross
安装成功后,有多种编译器可以帮我们实现交叉编译,使用时只需在编译对应参数下指定就可以了。
FiloSottile/musl-cross/musl-cross
CGO_ENABLED=1 GOOS=linux GOARCH=amd64 CC=x86_64-linux-musl-gcc CGO_LDFLAGS=“-static” go build -a -v
通过CC=x86_64-linux-musl-gcc 来指定GCC编译器。而CGO_LDFLAGS="-static"来指定CGO部分的编译为静态编译。
这样就可以实现带CGO的交叉编译啦。如果你是其他平台,也可以通过跨平台编译的工具musl 下载对应平台工具,这里有支持多平台实现工具。下载解压,将解压好的目录下 bin 文件路径,放到PATH环境变量中就可以啦。
brew install FiloSottile/musl-cross/musl-cross
安装过程中出现如下问题:
Error: An exception occurred within a child process: NoMethodError: undefined method `path’ for nil:NilClass Did you mean? paths
解决方案
使用命令brew update-reset升级Homebrew即可[1]
References
[1] https://discourse.brew.sh/t/homebrew-installation-fail/7439
再次安装brew install FiloSottile/musl-cross/musl-cross
提示如下:
lizhongsu@lizhongdeMBP ~ % brew install FiloSottile/musl-cross/musl-cross
==> Downloading https://ghcr.io/v2/homebrew/portable-ruby/portable-ruby/blobs/sha256:b065e5e3783954f3e65d8d3a6377ca51649bfcfa21b356b0dd70490f74c6bd86
##################################################################################################################################################################################################### 100.0%
==> Pouring portable-ruby-2.6.3_2.yosemite.bottle.tar.gz
Error:homebrew-core is a shallow clone.
To `brew update`, first run:git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core fetch --unshallow
This command may take a few minutes to run due to the large size of the repository.
This restriction has been made on GitHub's request because updating shallow
clones is an extremely expensive operation due to the tree layout and traffic of
Homebrew/homebrew-core and Homebrew/homebrew-cask. We don't do this for you
automatically to avoid repeatedly performing an expensive unshallow operation in
CI systems (which should instead be fixed to not use shallow clones). Sorry for
the inconvenience!
==> Installing musl-cross from filosottile/musl-cross
==> Downloading https://f001.backblazeb2.com/file/filippo-public/musl-cross-0.9.9_1.catalina.bottle.tar.gz
######################################################################## 100.0%
==> Pouring musl-cross-0.9.9_1.catalina.bottle.tar.gz
🍺 /usr/local/Cellar/musl-cross/0.9.9_1: 1,851 files, 246.3MB
==> `brew cleanup` has not been run in 30 days, running now...
Removing: /Users/lizhongsu/Library/Caches/Homebrew/autoconf--2.69.catalina.bottle.4.tar.gz... (871.6KB)
Removing: /Users/lizhongsu/Library/Caches/Homebrew/automake--1.16.2.catalina.bottle.tar.gz... (948.7KB)
Removing: /Users/lizhongsu/Library/Logs/Homebrew/autoconf... (64B)
Removing: /Users/lizhongsu/Library/Logs/Homebrew/automake... (64B)
Removing: /Users/lizhongsu/Library/Logs/Homebrew/telnet... (64B)
Pruned 2 symbolic links from /usr/local
有一个错误提示:
Error:
homebrew-core is a shallow clone.
To brew update, first run:
git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core fetch --unshallow
This command may take a few minutes to run due to the large size of the repository.
This restriction has been made on GitHub’s request because updating shallow
clones is an extremely expensive operation due to the tree layout and traffic of
Homebrew/homebrew-core and Homebrew/homebrew-cask. We don’t do this for you
automatically to avoid repeatedly performing an expensive unshallow operation in
CI systems (which should instead be fixed to not use shallow clones). Sorry for
the inconvenience!
暂时没有进行根据提示进行处理,尝试编译,成功!
执行命令
CGO_ENABLED=1 GOOS=linux GOARCH=amd64 CC=x86_64-linux-musl-gcc CGO_LDFLAGS=“-static” go build -a -v
成功交叉编译完成Go在linux下可运行文件。
相关文章:
cgo静态编译不能用glibc,用musl
Golang 的一个动态链接依赖问题 upx 是一个压缩二进制的工具,如上图,经过压缩之后,这些 binary 的体积都减少了 46%。 静态链接 CGO 的依赖 如果使用 glibc 的是,是不能静态链接的: rootf88271a666f9:/workspace# g…...
力扣解法汇总1124. 表现良好的最长时间段
目录链接: 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目: https://github.com/September26/java-algorithms 原题链接:力扣 描述: 给你一份工作时间表 hours,上面记录着某一位员工每天的工作小时数。…...

12- 降维算法 (PCA降维/LDA分类/NMF) (数据处理)
数据降维就是一种对高维度特征数据预处理方法。降维是将高维度的数据保留下最重要的一些特征,去除噪声和不重要的特征,从而实现提升数据处理速度的目的。PCA算法有两种实现方法: 基于特征值分解协方差矩阵实现PCA算法基于SVD分解协方差矩阵实…...
QT+ OpenGL学习
文章目录QT OpenGLQOpenGLWidget:不需要GLFWQOpenGLFunction_X_X_Core:不需要GLAD你好,三角形顶点输入顶点着色器片段着色器链接着色器本节代码元素缓冲对象EBOQT交互GLSLGLSL支持的类型输入输出Uniform纹理纹理单元纹理环绕纹理过滤多级渐远纹理QT OpenGL 本篇完整…...

C语言(字符串输入)
目录 一.gets和puts组合 二.fgets()和fputs() 三.fgets()函数返回 四.fgets读取满问题 五.修改fgets函数,自动用\0替换\n 一.gets和puts组合 Gets()读取整行输入,知道遇到换行符,然后丢弃换行符,存储其余字符,并在这些字符的…...
背包问题求方案数(AcWing)(JAVA)
有 N件物品和一个容量是 V 的背包。每件物品只能使用一次。 第 i 件物品的体积是 vi,价值是 wi。 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 输出 最优选法的方案数。注意答案可能很大,请输出答…...

一篇文章带你读懂HashMap
HashMap是面试中经常问到的一个知识点,也是判断一个候选人基础是否扎实的标准之一。可见HashMap的掌握是多重要。 一、HashMap源码分析 1、构造函数 让我们先从构造函数说起,HashMap有四个构造方法,别慌 1.1 HashMap() // 1.无参构造方法、// 构造一…...
Java如何进行优雅的判空——Optional类的灵活应用
0 引言 在Java Web项目开发中,经常令人头疼的NPE问题(NullPointerException)——空指针,例如我们在调用equal()方法时,就经常会出现NPE问题: String str null; str.equals("fsfs");…...
Fluent Python 笔记 第 12 章 继承的优缺点
重点是说明对 Python 而言尤为重要的两个细节: 子类化内置类型的缺点多重继承和方法解析顺序 12.1 子类化内置类型很麻烦 内置类型(使用 C 语言编写)不会调用用户定义的类覆盖的特殊方法。 不要子类化内置类型,用户自己定义的类应 该继承 collections 模块(http…...
Go语言读取解析yml文件,快速转换yml到go struct
YAML (YAML Aint a Markup Language)是一种标记语言,通常以.yml为后缀的文件,是一种直观的能够被计算机程序识别的数据序列化格式,并且容易被人类阅读,容易和脚本语言交互的,可以被支持YAML库的不同的编程语言程序导入…...
第二十六章 java并发常见知识内容(ThreadLocal 详解)
JAVA重要知识点带着疑问看ThreadLocalGC 之后 key 是否为 null?ThreadLocalMap Hash 算法ThreadLocalMap Hash 冲突ThreadLocalMap.set()方法ThreadLocalMap过期 key 的探测式清理流程ThreadLocalMap扩容机制ThreadLocalMap.get()详解ThreadLocalMap过期 key 的启发…...
人类的第一语言是什么
其实机器智能始终存在一个争议 没有人类的肢体和感受器无法理解和感同身受 这不用想是自然,但是可以通过虚拟数据进行模拟,深度学习便是 深度学习是模拟简单输入输出的最好选择,但不是开放性的学习 没有智能交互的智能永远不是智能 就像狼孩一…...

jsp(全部知识点)
👌 棒棒有言:也许我一直照着别人的方向飞,可是这次,我想要用我的方式飞翔一次!人生,既要淡,又要有味。凡事不必太在意,一切随缘,缘深多聚聚,缘浅随它去。凡事…...

测试开发面试基础题
1.对测试开发的理解 测试开发首先离不开测试,而软件测试是指,在规定的条件下对程序进行操作,以发现程序错误,衡量软件质量,并对其是否能满足设计要求进行评估的过程。 而且,现在不仅仅是通过手工测试来发…...

C++——多态|虚函数|重写|虚表
文章目录1. 多态的概念1.1 概念2. 多态的定义及实现2.1多态的构成条件2.2 虚函数2.3虚函数的重写虚函数重写的三个例外:2.4 普通调用和多态调用:2.5 C11 override 和 final2.6 重载、虚函数的覆盖(重写)、隐藏(重定义)的对比3. 抽象类(有关纯虚函数)3.1 …...

IPV4地址详解
文章目录IPV4地址分类编址划分子网无分类编制CIDR路由聚合应用规划(子网划分的细节)定长的子网掩码FLSM变长的子网掩码VLSMIPV4地址 IPV4地址就是给因特网(Internet)上的每一台主机(或路由器)的每一个接口…...

(一)初识Streamlit(附安装)
本入门指南介绍Streamlit的工作原理、如何在您首选的操作系统上安装Streamlit,以及如何创建第一个Streamlit应用程序! 1 安装 1.1 先决条件 Python 3.7 – Python 3.11 **注:我这里使用的是anaconda的虚拟环境,用pycharm编写代…...
【新】华为OD机试 - 斗地主 2(Python)| 刷完获取OD招聘渠道
斗地主 2 题目描述 在斗地主扑克牌游戏中,扑克牌由小到大的顺序为3 4 5 6 7 8 9 10 J Q K A 2 玩家可以出的扑克牌阵型有,单张,对子,顺子,飞机,炸弹等 其中顺子的出牌规则为,由至少 5 张由小到大连续递增的扑克牌组成 且不能包含2 例如:{3,4,5,6,7}、{3,4,5,6,7,8,9,1…...

秒杀项目之消息推送
目录一、创建消费者二、创建订单链路配置2.1 定义RabbitMQ配置类2.2 创建RabbitmqOrderConfig配置类三、如何实现RabbitMQ重复投递机制3.1 开启发送者消息确认模式3.2 消费发送确认3.2.1 创建ConfirmCallBack确认模式3.2.2 创建ReturnCallBack退回模式3.3 创建生产者3.4 创建消…...

【重磅】IEEE33配电网两阶段鲁棒优化调度CCG
目录 1 前言 2基本内容 2.1 配网两阶段鲁棒模型 2.2 求解步骤 3部分程序 4程序结果 5程序链接 1 前言 鲁棒优化是电力系统研究的热点,而两阶段鲁棒和分布鲁棒研究就成为各类期刊(sci/ei/核心)的宠儿,最简单的思路是通过改…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...

自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...

【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...
【FTP】ftp文件传输会丢包吗?批量几百个文件传输,有一些文件没有传输完整,如何解决?
FTP(File Transfer Protocol)本身是一个基于 TCP 的协议,理论上不会丢包。但 FTP 文件传输过程中仍可能出现文件不完整、丢失或损坏的情况,主要原因包括: ✅ 一、FTP传输可能“丢包”或文件不完整的原因 原因描述网络…...

实战设计模式之模板方法模式
概述 模板方法模式定义了一个操作中的算法骨架,并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下,重新定义算法中的某些步骤。简单来说,就是在一个方法中定义了要执行的步骤顺序或算法框架,但允许子类…...