第一章:Golang跨平台编译的核心原理与环境准备
Go 语言的跨平台编译能力源于其静态链接与目标平台抽象的设计哲学。编译器在构建阶段将运行时、标准库及依赖全部静态链接进可执行文件,不依赖外部动态库;同时通过 GOOS 和 GOARCH 环境变量控制目标操作系统与架构的代码生成逻辑,无需虚拟机或运行时解释器介入。
Go 工具链的跨平台支持机制
Go 源码中内置了对主流平台(如 linux/amd64、darwin/arm64、windows/386)的完整支持。go build 命令通过交叉编译(cross-compilation)直接产出目标平台原生二进制,无需安装对应平台的 SDK 或模拟器。该能力由 Go 的自举编译器和平台特定的汇编器、链接器协同实现。
必备环境配置步骤
确保已安装 Go(建议 v1.19+),并验证基础环境:
# 检查 Go 版本与默认构建环境
go version
go env GOOS GOARCH # 输出通常为当前主机系统(如 linux amd64)
# 设置目标平台变量后编译(示例:构建 macOS ARM64 可执行文件)
GOOS=darwin GOARCH=arm64 go build -o myapp-darwin-arm64 main.go
# 构建 Windows 64 位程序(注意:Windows 下需添加 .exe 后缀)
GOOS=windows GOARCH=amd64 go build -o myapp.exe main.go
⚠️ 注意:
CGO_ENABLED=0是推荐的跨平台编译开关,可禁用 C 语言互操作,避免因目标平台缺失 libc 而失败。若项目未使用 cgo,强制设为可提升兼容性与构建稳定性。
常见目标平台组合参考
| GOOS | GOARCH | 典型用途 |
|---|---|---|
| linux | amd64 | 主流服务器部署 |
| darwin | arm64 | Apple Silicon Mac 应用 |
| windows | 386 | 32 位 Windows 兼容程序 |
| linux | arm64 | 树莓派、ARM 云服务器 |
验证交叉编译结果
使用 file 命令检查输出二进制的目标平台属性:
file myapp-darwin-arm64
# 输出应包含 "Mach-O 64-bit executable arm64" 字样
所有跨平台构建均在宿主机器上完成,无需 Docker 或虚拟机——这是 Go 区别于 JVM 或 .NET 的关键轻量优势。
第二章:多平台交叉编译实战模板
2.1 GOOS/GOARCH环境变量的底层机制与组合映射表
Go 编译器在构建阶段通过 GOOS 和 GOARCH 环境变量决定目标平台的运行时行为与指令集生成策略。
构建时决策链
# 查看当前默认组合
go env GOOS GOARCH
# 显式交叉编译示例
GOOS=linux GOARCH=arm64 go build -o app-linux-arm64 .
该命令触发 cmd/compile/internal/sys 中的 Arch 和 OS 初始化,绑定到 buildcfg 全局配置对象;GOARCH=arm64 触发 archARM64 实例加载,含寄存器布局、调用约定及 ABI 特性。
支持组合片段(部分)
| GOOS | GOARCH | 说明 |
|---|---|---|
| linux | amd64 | 默认组合,支持 CGO |
| darwin | arm64 | Apple Silicon 原生支持 |
| windows | 386 | 32位 Windows 兼容模式 |
构建流程示意
graph TD
A[读取 GOOS/GOARCH] --> B[匹配 arch/OS 表]
B --> C[初始化 Target 结构体]
C --> D[生成对应汇编器/链接器后端]
2.2 Windows/macOS/Linux三端二进制一键构建脚本编写
为统一跨平台构建流程,采用 Bash + PowerShell 混合策略,主入口为 build.sh,自动识别宿主系统并调度对应逻辑。
核心构建逻辑分支
#!/usr/bin/env bash
case "$(uname -s)" in
Linux) TARGET="linux-amd64" ; BUILD_CMD="go build -o dist/app-$TARGET ." ;;
Darwin) TARGET="darwin-amd64" ; BUILD_CMD="go build -o dist/app-$TARGET ." ;;
MSYS*|MINGW*) TARGET="windows-amd64"; BUILD_CMD="go build -o dist/app-$TARGET.exe ." ;;
esac
eval "$BUILD_CMD"
该脚本通过 uname -s 精准判别内核类型,避免依赖 $OSTYPE 的模糊匹配;eval 动态执行构建命令,兼顾可读性与灵活性;输出路径按平台规范命名,便于 CI/CD 后续归档。
构建目标对照表
| 平台 | 输出文件名 | Go GOOS/GOARCH |
|---|---|---|
| Linux | app-linux-amd64 |
linux/amd64 |
| macOS | app-darwin-amd64 |
darwin/amd64 |
| Windows | app-windows-amd64.exe |
windows/amd64 |
跨平台兼容要点
- 使用
sh而非bash特有语法确保 POSIX 兼容 - Windows 下通过 Git Bash 或 MSYS2 提供 Unix-like 环境支持
- 所有路径使用正斜杠
/,Go 工具链自动适配
2.3 ARM64架构(含Apple Silicon与树莓派)编译适配要点
ARM64(AArch64)指令集在Apple Silicon(M1/M2/M3)与树莓派(RPi 4/5,CM4/CM5)上虽同属64位,但微架构差异显著:Apple采用高性能自研核心(Firestorm/Icestorm),而树莓派依赖Cortex-A72/A76/A78,缓存策略、内存一致性模型及SIMD扩展支持各不相同。
编译器标志关键差异
-march=armv8-a+crypto+simd:基础兼容,但Apple Silicon需追加+sve2(部分新芯片支持),树莓派则不支持SVE;-mtune=native在 macOS 上触发 Apple-specific 优化(如-mcpu=apple-a14隐式启用),而在 RPi 上应显式指定-mtune=cortex-a76。
典型交叉编译配置表
| 平台 | 推荐 --host |
关键 CFLAGS | 注意事项 |
|---|---|---|---|
| macOS (Apple Silicon) | aarch64-apple-darwin |
-O2 -mcpu=apple-m1 |
必须启用 -fPIE -isysroot |
| Raspberry Pi OS | aarch64-linux-gnu |
-O2 -mcpu=cortex-a76+simd |
避免 -march=armv8.4-a(RPi 4 不支持) |
# Apple Silicon 本地构建示例(使用 clang)
clang -target arm64-apple-macos13.0 \
-mcpu=apple-m1 \
-O3 -flto=thin \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk \
-o app main.c
此命令显式绑定目标 SDK 与 CPU 微架构:-target 确保 ABI 兼容性;-mcpu=apple-m1 启用 M1 特有指令(如 AMX 预取提示);-isysroot 指向正确系统头文件路径,避免误用 x86_64 头定义;-flto=thin 利用 Apple LLVM 的 ThinLTO 实现跨函数内联优化。
架构适配决策流
graph TD
A[源码是否含内联汇编] --> B{是否平台专用?}
B -->|是| C[分离 asm 文件: apple.s / rpi.s]
B -->|否| D[统一 C 实现 + 条件编译]
C --> E[编译时通过 -DAPPLE_SILICON 或 -DRPI_TARGET 选择]
D --> F[__builtin_cpu_is\(\"apple\"\\) 运行时分发]
2.4 CGO_ENABLED=0与动态链接库依赖的权衡实践
Go 编译时默认启用 CGO(CGO_ENABLED=1),以支持调用 C 库(如 libc、openssl)。但设为 可生成纯静态二进制,彻底消除运行时对系统动态库(如 libpthread.so, libc.so.6)的依赖。
静态编译 vs 动态依赖对比
| 维度 | CGO_ENABLED=0 |
CGO_ENABLED=1(默认) |
|---|---|---|
| 二进制大小 | 较小(无 C 运行时嵌入) | 较大(含部分 cgo 运行时) |
| 运行环境兼容性 | ✅ 极高(glibc 版本无关) | ❌ 依赖宿主机 glibc 版本 |
| 网络 DNS 解析 | 仅支持 netgo(纯 Go 实现) |
支持 cgo(可调用 getaddrinfo) |
# 关闭 CGO 后强制使用纯 Go DNS 解析
CGO_ENABLED=0 go build -ldflags="-s -w" -o app .
此命令禁用所有 C 交互,
-ldflags="-s -w"剥离调试符号并减小体积;但若代码中显式调用os/user.Lookup或net/http的某些 TLS 接口,可能因缺失cgo导致解析失败或回退到受限模式。
权衡决策流程
graph TD
A[是否需调用 C 库?] -->|否| B[设 CGO_ENABLED=0]
A -->|是| C[评估目标环境 glibc 兼容性]
C -->|不可控/老旧| D[交叉编译 + 容器内构建]
C -->|可控| E[保留 CGO_ENABLED=1 + 静态链接 libc]
关键约束:CGO_ENABLED=0 下 os/exec 仍可用,但 syscall.Exec 等底层接口受限;DNS 行为可通过 GODEBUG=netdns=go 显式锁定。
2.5 静态链接与libc兼容性问题诊断与修复
静态链接二进制在跨环境部署时,常因 libc 版本不匹配导致 symbol not found 或 segmentation fault。
常见症状识别
- 运行时报错:
./app: /lib64/libc.so.6: version 'GLIBC_2.34' not found ldd ./app显示not a dynamic executable(确认为静态链接)readelf -V ./app | grep GLIBC暴露所依赖的符号版本
兼容性诊断工具链
# 检查目标系统支持的最高glibc版本
getconf GNU_LIBC_VERSION # 输出:glibc 2.31
# 提取静态二进制中嵌入的符号版本需求
objdump -T ./app | grep '@@GLIBC_' | sort -u
此命令解析动态符号表(即使静态链接,部分符号仍保留版本标签),
@@GLIBC_2.28表示该符号需 glibc ≥2.28;若目标系统仅含 2.27,则必然失败。
修复策略对比
| 方案 | 适用场景 | 风险 |
|---|---|---|
用 musl-gcc 重新静态编译 |
容器/嵌入式环境 | 无 glibc 依赖,但部分 pthread/NSS 功能受限 |
| 降级构建机 libc(如 Ubuntu 20.04) | 企业内网统一基线 | 构建环境维护成本高 |
动态链接 + LD_LIBRARY_PATH 托管 |
混合部署 | 失去静态部署优势 |
graph TD
A[发现运行失败] --> B{ldd ./app ?}
B -->|not a dynamic executable| C[确认静态链接]
C --> D[readelf -V ./app]
D --> E[比对目标系统 getconf GNU_LIBC_VERSION]
E --> F[选择 musl 编译 或 降级构建环境]
第三章:符号剥离与体积优化技术
3.1 -ldflags=”-s -w”的汇编级作用原理与反汇编验证
-s 剥离符号表,-w 禁用 DWARF 调试信息——二者共同消除二进制中所有调试元数据,直接作用于链接器(go link)的 ELF 构建阶段。
符号表剥离效果对比
# 编译带调试信息的二进制
go build -o main.debug main.go
# 编译精简版
go build -ldflags="-s -w" -o main.strip main.go
执行后,readelf -S main.debug 显示 .symtab 和 .debug_* 节区存在;而 main.strip 中二者完全消失,仅保留 .text、.rodata 等运行必需节区。
反汇编验证关键差异
| 项目 | -s -w 启用 |
默认编译 |
|---|---|---|
.symtab |
❌ 不存在 | ✅ 包含函数/变量符号 |
.debug_line |
❌ 被移除 | ✅ 支持源码行映射 |
objdump -d |
仅显示地址+机器码 | 可关联源码注释 |
链接器行为流程
graph TD
A[Go compiler: .o object files] --> B[go link with -ldflags]
B --> C{Flags parsed}
C -->|"-s"| D[Drop .symtab/.strtab]
C -->|"-w"| E[Skip DWARF emission]
D & E --> F[Final stripped ELF binary]
3.2 UPX压缩的适用边界与Go二进制安全风险评估
UPX 对 Go 编译生成的静态链接二进制文件支持有限,因其依赖 .got, .plt 等 ELF 结构,而 Go 1.16+ 默认禁用 CGO_ENABLED=0 时无传统 PLT 表,导致 UPX 解压失败或运行时崩溃。
典型失败场景复现
# 尝试压缩标准 Go 二进制(Go 1.22, linux/amd64)
$ go build -o server main.go
$ upx --best server
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2023
UPX 4.2.1 Markus Oberhumer, Laszlo Molnar & John Reiser Jan 23rd 2023
upx: server: NotPackedException: not packed (no UPX signature)
逻辑分析:UPX 无法识别 Go 的自定义 ELF 节布局(如
.go.buildinfo、.noptrdata),且 Go 运行时依赖精确的虚拟地址偏移,压缩后重定位易破坏runtime·findfunc查找链。
安全风险维度对比
| 风险类型 | UPX 压缩后影响 | Go 原生二进制 |
|---|---|---|
| 反调试难度 | ⬆️(入口点混淆) | ⬇️(清晰入口) |
| 符号剥离完整性 | ❌(UPX 不处理 Go 符号表) | ✅(-ldflags="-s -w") |
| 内存解压载荷检测 | ⬆️(EDR 易捕获 mmap+PROT_WRITE+PROT_EXEC) |
⬇️(静态加载) |
graph TD
A[Go源码] --> B[go build -ldflags=-s]
B --> C{UPX 压缩?}
C -->|否| D[纯净静态二进制]
C -->|是| E[解压 stub 注入内存]
E --> F[触发 mmap+PROT_EXEC]
F --> G[EDR/AV 实时告警]
3.3 自定义buildid与debug信息定向剥离策略
在嵌入式与安全敏感场景中,构建标识(buildid)需脱离默认编译器生成逻辑,同时精准控制调试符号的保留/剥离边界。
构建ID注入示例
# 在链接阶段注入自定义buildid(SHA256摘要+Git短哈希)
gcc -Wl,--build-id=0x$(git rev-parse --short HEAD | xxd -p -c 16) \
-o firmware.elf main.o
--build-id=参数强制覆盖默认GNU build-id;xxd -p -c 16将7位Git哈希转为16字节十六进制,确保符合ELF build-id格式要求。
debug信息剥离策略对比
| 策略 | 保留段 | 剥离命令 |
|---|---|---|
| 最小化调试 | .debug_line, .symtab |
objcopy --strip-unneeded |
| 符号级可控剥离 | 仅.debug_info |
objcopy --strip-debug --keep-section=.debug_line |
剥离流程示意
graph TD
A[原始ELF] --> B{是否启用DEBUG_MODE?}
B -->|是| C[保留.debug_line/.debug_abbrev]
B -->|否| D[strip --strip-all]
C --> E[生成release-with-trace.elf]
D --> F[生成final.bin]
第四章:CI/CD流水线集成与自动化发布
4.1 GitHub Actions多平台并发编译工作流设计
核心设计原则
采用矩阵策略(strategy: { matrix })触发跨平台并行执行,避免平台耦合与重复配置。
关键 YAML 片段
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-22.04, macos-14, windows-2022]
arch: [x64, arm64]
steps:
- uses: actions/checkout@v4
- name: Setup toolchain
run: |
case ${{ runner.os }} in
Linux) sudo apt-get update && sudo apt-get install -y cmake ;;
macOS) brew install cmake ;;
Windows) choco install cmake --force ;;
esac
逻辑分析:
matrix.os与matrix.arch组合生成 6 个独立 job 实例;runs-on动态绑定运行环境;case分支按 OS 差异化安装 CMake,确保构建工具一致性。
并发性能对比
| 平台组合 | 单任务耗时 | 并发总耗时 | 加速比 |
|---|---|---|---|
| Ubuntu x64 | 4.2 min | — | — |
| 全平台 6 任务 | — | 5.1 min | ≈5.8× |
构建状态协调
graph TD
A[Trigger push/tag] --> B[Matrix job dispatch]
B --> C[各平台独立 checkout + build]
C --> D{全部成功?}
D -->|Yes| E[上传统一 artifact]
D -->|No| F[失败 job 标记并中断]
4.2 GitLab CI中ARM64模拟器(QEMU)的高效配置
在多架构持续集成中,ARM64原生构建节点稀缺,QEMU用户态模拟成为关键桥梁。GitLab Runner需启用docker+machine或docker执行器并预装QEMU静态二进制。
安装与注册QEMU binfmt
# 注册ARM64模拟器(仅需在Runner宿主机执行一次)
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
该命令将QEMU-arm64-static注册为Linux binfmt_misc处理器,使内核自动调用其解释ARM64 ELF文件;--reset确保覆盖旧配置,-p yes启用持久化注册。
.gitlab-ci.yml核心配置
build-arm64:
image: docker:stable
services:
- docker:dind
script:
- docker build --platform linux/arm64 -t $CI_REGISTRY_IMAGE:arm64 .
--platform参数强制Docker BuildKit使用ARM64目标架构,依赖底层QEMU透明支持。
| 组件 | 版本要求 | 说明 |
|---|---|---|
| qemu-user-static | ≥6.2.0 | 提供稳定的ARM64 syscall翻译 |
| Docker Engine | ≥20.10 | 需启用BuildKit |
graph TD A[CI Job触发] –> B[Kernel检测ARM64 ELF] B –> C{binfmt已注册?} C –>|是| D[调用qemu-arm64-static] C –>|否| E[执行失败] D –> F[正常运行ARM64容器]
4.3 语义化版本自动打标与制品归档(Artifacts)最佳实践
核心原则
- 制品(Artifacts)必须与 Git 提交精确绑定,禁止手动打标;
- 版本号严格遵循
MAJOR.MINOR.PATCH规则,由提交消息前缀(如feat:、fix:、BREAKING CHANGE)自动推导; - 所有构建产物须附带完整元数据(SHA、环境、时间戳、依赖树快照)。
自动化流水线示例(GitHub Actions)
# .github/workflows/release.yml
- name: Semantic Release
uses: cycjimmy/semantic-release-action@v4
with:
semantic_version: 21.0.7 # 兼容 conventional-changelog
branch: main
dry_run: ${{ github.event_name == 'pull_request' }}
逻辑分析:该 Action 解析
conventional-commits格式提交(如feat(api): add timeout config),调用@semantic-release/npm等插件生成版本号,并自动推送 Git tag 与 npm 包。dry_run避免 PR 中误触发发布。
制品归档关键字段
| 字段 | 示例 | 说明 |
|---|---|---|
artifactId |
web-ui-v2.3.1-8a3f5c2.tgz |
包含语义版本 + 提交短哈希,确保可追溯 |
metadata.json |
{ "gitRef": "v2.3.1", "buildTime": "2024-06-15T08:22:14Z", "depsHash": "sha256:abc123..." } |
归档时内嵌,供审计与回滚验证 |
graph TD
A[Git Push to main] --> B{Conventional Commit?}
B -->|Yes| C[Calculate next version]
B -->|No| D[Fail build]
C --> E[Tag commit vX.Y.Z]
E --> F[Build & sign artifact]
F --> G[Upload to Nexus + S3 with metadata]
4.4 跨平台校验脚本:sha256sum + file + ldd/readelf自动化验证
在混合架构(x86_64/ARM64)CI/CD流水线中,需确保二进制文件完整性、格式一致性与动态依赖兼容性。
校验维度与工具分工
sha256sum:验证传输后哈希一致性file:识别ELF架构、位宽与ABI类型ldd(Linux)或readelf -d(跨平台无依赖场景):解析动态链接器与共享库需求
自动化校验脚本(核心片段)
#!/bin/bash
BIN="$1"
sha256sum "$BIN" | awk '{print $1}' # 输出纯哈希值,供CI比对
file "$BIN" # 检查是否为"ELF 64-bit LSB pie executable, x86-64"
if command -v ldd >/dev/null; then
ldd "$BIN" | grep -E 'not found|=> /' # 快速捕获缺失或路径异常库
else
readelf -d "$BIN" 2>/dev/null | grep 'NEEDED\|INTERP' # ARM交叉环境回退方案
fi
逻辑说明:脚本优先调用
ldd获取运行时依赖图;若不可用(如容器无glibc),则用readelf -d提取DT_NEEDED条目,规避环境限制。file输出直接用于断言目标平台匹配性。
多平台校验结果对照表
| 工具 | Linux x86_64 | Linux ARM64 | macOS (Mach-O) |
|---|---|---|---|
sha256sum |
✅ | ✅ | ❌(用shasum -a 256) |
file |
✅ | ✅ | ✅ |
ldd |
✅ | ❌ | ❌ |
graph TD
A[输入二进制] --> B{OS/Arch?}
B -->|Linux| C[sha256sum → hash]
B -->|Linux| D[file → arch/abi]
B -->|Linux glibc| E[ldd → deps]
B -->|Linux musl/ARM| F[readelf -d → NEEDED]
第五章:golang编程之旅免费下载
获取官方资源的正确路径
Go 官方网站(https://go.dev/dl/)提供全平台二进制安装包,包括 Linux(.tar.gz)、macOS(.pkg 和 .tar.gz)、Windows(.msi 和 .zip)。建议优先选择与系统架构匹配的最新稳定版(如 go1.22.5.linux-amd64.tar.gz),避免使用第三方镜像站未经校验的打包版本。执行以下命令可验证下载完整性:
curl -O https://go.dev/dl/go1.22.5.linux-amd64.tar.gz
sha256sum go1.22.5.linux-amd64.tar.gz
# 对比官网发布的 SHA256 值:a7f3b8e...(共64位十六进制字符)
镜像加速与可信替代源
国内开发者常因网络延迟导致 curl 超时。清华大学开源软件镜像站提供同步更新的 Go 下载服务,URL 为 https://mirrors.tuna.tsinghua.edu.cn/golang/。该镜像每小时自动同步一次,且经 GPG 签名验证。以下脚本可自动化完成下载、校验与解压:
MIRROR="https://mirrors.tuna.tsinghua.edu.cn/golang"
VERSION="go1.22.5.linux-amd64.tar.gz"
curl -L "${MIRROR}/${VERSION}" -o /tmp/go.tar.gz
curl -L "${MIRROR}/${VERSION}.sha256" -o /tmp/go.tar.gz.sha256
sha256sum -c /tmp/go.tar.gz.sha256
sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf /tmp/go.tar.gz
免费电子书与实战文档组合包
《Go 语言设计与实现》《Go 语言高级编程》《Concurrency in Go》三本经典书籍均以 CC BY-NC-ND 4.0 协议开源,可合法下载 PDF 版本。下表汇总其获取方式与核心价值:
| 书名 | GitHub 仓库 | 关键章节 | 适用场景 |
|---|---|---|---|
| Go 语言设计与实现 | https://github.com/changkun/go-under-the-hood | 内存分配器、GC 实现、调度器源码解析 | 深度理解 runtime 行为 |
| Go 语言高级编程 | https://github.com/chai2010/advanced-go-programming-book | Plugin 动态加载、eBPF 集成、WASM 编译 | 构建云原生扩展能力 |
| Concurrency in Go | https://github.com/karlseguin/concurrency-in-go | Context 取消传播、errgroup 并发控制、pipeline 模式 | 高并发服务稳定性保障 |
离线开发环境一键构建
使用 go install golang.org/x/tools/cmd/goimports@latest 后,配合 VS Code 的 gopls 插件,可实现保存即格式化、自动导入、实时类型推导。以下 mermaid 流程图描述了从下载到启用 lint 工具链的完整链路:
flowchart LR
A[下载 go1.22.5] --> B[配置 GOROOT/GOPATH]
B --> C[运行 go env -w GO111MODULE=on]
C --> D[执行 go install github.com/mgechev/revive@v1.3.4]
D --> E[VS Code 设置 “gopls” → “analyses” 启用 unused]
E --> F[新建 main.go 并触发保存]
社区驱动的持续更新机制
Go 官方每六个月发布一个新主版本(偶数月份),所有旧版本至少维护 12 个月。通过 go version -m your_binary 可追溯编译时使用的 Go 版本;利用 go tool dist list 可枚举当前支持的所有 OS/ARCH 组合,确保交叉编译目标兼容性。在 CI 流水线中嵌入如下检查逻辑,能提前拦截不兼容依赖:
if ! go version | grep -q "go1\.2[0-9]\."; then
echo "ERROR: Requires Go 1.20+"
exit 1
fi
实战案例:从零部署 HTTP 服务并打包为静态二进制
创建 server.go 文件后,仅需两条命令即可生成无外部依赖的可执行文件:
go mod init example.com/httpserver
go build -ldflags="-s -w" -o httpserver .
该二进制可在任意相同架构的 Linux 发行版中直接运行,无需安装 Go 运行时。使用 file httpserver 可确认其为 ELF 64-bit LSB executable, x86-64,而 ldd httpserver 输出 not a dynamic executable,证明静态链接成功。
