在現(xiàn)代計(jì)算機(jī)系統(tǒng)中,X86和ARM64是兩種常見的處理器架構(gòu)。為了滿足不同架構(gòu)的需求,Docker鏡像也需要支持雙架構(gòu)編包形式。本文將介紹Docker鏡像雙架構(gòu)編包統(tǒng)一的實(shí)踐
? ? 一、Docker鏡像編包
? ??在Docker鏡像中,通常使用多階段構(gòu)建來實(shí)現(xiàn)。在第一階段,構(gòu)建出對(duì)應(yīng)架構(gòu)服務(wù)的二進(jìn)制文件;在第二階段,運(yùn)行對(duì)應(yīng)架構(gòu)的二進(jìn)制文件,下面是兩個(gè)基于Debian的Dockerfile文件示例,分別用于構(gòu)建X86架構(gòu)和ARM64架構(gòu)的Docker鏡像:
1.X86架構(gòu)的Dockerfile文件示例:
FROM debian:latest AS builder
RUN apt-get update && apt-get install -y build-essential
WORKDIR /app
COPY . .
RUN make
FROM debian:latest
WORKDIR /app
COPY --from=builder /app/app /app
CMD ["/app/app/install.sh"]
CMD ["/app/app/build.sh"]
復(fù)制
?2.ARM64架構(gòu)的Dockerfile文件示例:
FROM arm64v8/debian:latest AS builder
RUN apt-get update && apt-get install -y build-essential
WORKDIR /app
COPY . .
RUN make
FROM arm64v8/debian:latest
WORKDIR /app
COPY --from=builder /app/app /app
CMD ["/app/app/install_arm.sh"]
CMD ["/app/app/build_arm.sh"]
復(fù)制
? ? ? 這兩個(gè)Dockerfile文件的主要區(qū)別在于基礎(chǔ)鏡像的選擇和FROM語句中的架構(gòu)標(biāo)識(shí)符。X86架構(gòu)的Dockerfile文件使用了debian:latest作為基礎(chǔ)鏡像,而ARM64架構(gòu)的Dockerfile文件使用了arm64v8/debian:latest作為基礎(chǔ)鏡像。此外,ARM64架構(gòu)的Dockerfile文件在FROM語句中使用了arm64v8標(biāo)識(shí)符,以指定ARM64架構(gòu)。最后,CMD執(zhí)行的安裝腳本也不一樣,應(yīng)該是不同的環(huán)境需要不同的安裝腳本。
? ? 為了方便在雙架構(gòu)環(huán)境下部署Docker服務(wù),可以編寫一個(gè)bash腳本,以執(zhí)行docker build命令的形式來調(diào)用上面兩種Dockerfile文件的運(yùn)行。下面是兩個(gè)示例bash腳本:
1.X86的bash腳本
#!/bin/bash
docker build -t myapp:x86 -f Dockerfile.x86 .
docker manifest create myapp:latest myapp:x86
docker manifest push myapp:latest
復(fù)制
2.Arm64的bash腳本
#!/bin/bash
docker build -t myapp:arm64 -f Dockerfile.arm64 .
docker manifest create myapp:latest myapp:arm64
docker manifest push myapp:latest
復(fù)制
? ? ? 這個(gè)bash腳本中,首先使用docker build命令分別構(gòu)建X86架構(gòu)和ARM64架構(gòu)的Docker鏡像,并分別打上myapp:x86和myapp:arm64的標(biāo)簽。然后,使用docker manifest create命令創(chuàng)建一個(gè)名為myapp:latest的manifest文件,并將myapp:x86和myapp:arm64的標(biāo)簽添加到manifest文件中。最后,使用docker manifest push命令將manifest文件推送到Docker Hub上,以便在不同架構(gòu)的計(jì)算機(jī)系統(tǒng)上使用myapp:latest標(biāo)簽來獲取Docker鏡像。
具體流程大概是這樣:
? ? 二、Docker鏡像多架構(gòu)編包統(tǒng)一
從上面的流程圖中,可以看到,編譯雙架構(gòu)的鏡像基本上需要兩套完全獨(dú)立的腳本,這顯然會(huì)增加代碼量和維護(hù)成本,那么有沒有可以統(tǒng)一多架構(gòu)編包的腳本和流程內(nèi)?答案是顯然的,下面就以上面的流程為例,生成一套多架構(gòu)統(tǒng)一的編譯腳本集。
1.合并build_docker.sh腳本
首先是編鏡像的啟動(dòng)腳本build_docker.sh,這里之所以有兩個(gè)腳本,是因?yàn)橐獔?zhí)行不同的dockerfile,事實(shí)上,可以通過傳入?yún)?shù)的形式,來動(dòng)態(tài)決定執(zhí)行不同的dockersfile,比如下面這個(gè)示例:
#!/bin/bash
# 獲取傳入的架構(gòu)參數(shù)
ARCH=$1
# 根據(jù)不同的架構(gòu)參數(shù),構(gòu)建不同的Dockerfile文件
case $ARCH in
"x86_64")
DOCKERFILE="Dockerfile.x86_64"
;;
"armv7l")
DOCKERFILE="Dockerfile.armv7l"
;;
"aarch64")
DOCKERFILE="Dockerfile.aarch64"
;;
*)
echo "Unsupported architecture: $ARCH"
exit 1
;;
esac
# 構(gòu)建Docker鏡像
docker build -t myimage:$ARCH -f $DOCKERFILE .
復(fù)制
?當(dāng)然,如果業(yè)務(wù)本身已經(jīng)有很多參數(shù)了,問了避免混淆和命令層級(jí)的一致性,也可以使用opt的別名進(jìn)行,比如:
#!/bin/bash
# 默認(rèn)架構(gòu)為x86_64
ARCH="x86_64"
# 處理命令行參數(shù)
while getopts "a:" opt; do
case $opt in
a)
ARCH=$OPTARG
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
exit 1
;;
esac
done
# 根據(jù)不同的架構(gòu)參數(shù),構(gòu)建不同的Dockerfile文件
case $ARCH in
"x86_64")
DOCKERFILE="Dockerfile.x86_64"
;;
"armv7l")
DOCKERFILE="Dockerfile.armv7l"
;;
"aarch64")
DOCKERFILE="Dockerfile.aarch64"
;;
*)
echo "Unsupported architecture: $ARCH"
exit 1
;;
esac
# 構(gòu)建Docker鏡像
docker build -t myimage:$ARCH -f $DOCKERFILE .
復(fù)制
?這里有個(gè)優(yōu)雅的點(diǎn):如果沒有指定-a選項(xiàng),則默認(rèn)使用x86_64架構(gòu),方便與已有編譯腳本的融合和兼容。如果傳入的架構(gòu)參數(shù)不支持,腳本會(huì)輸出錯(cuò)誤信息并退出。
當(dāng)然,業(yè)務(wù)需要可能是一次編譯多個(gè)架構(gòu),那還需要對(duì)這個(gè)腳本再更新一下:
#!/bin/bash
# 默認(rèn)架構(gòu)為x86_64
ARCHS=("x86_64")
# 處理命令行參數(shù)
while getopts "a:" opt; do
case $opt in
a)
ARCHS+=("$OPTARG")
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
exit 1
;;
esac
done
# 如果有兩個(gè)以上的架構(gòu)參數(shù),則同時(shí)構(gòu)建多個(gè)Docker鏡像
if [ ${#ARCHS[@]} -ge 2 ]; then
# 構(gòu)建Docker鏡像
docker buildx build --platform "${ARCHS[@]/#/--platform }" -t myimage .
else
# 只有一個(gè)架構(gòu)參數(shù),則按照之前的方式構(gòu)建Docker鏡像
ARCH=${ARCHS[0]}
# 根據(jù)不同的架構(gòu)參數(shù),構(gòu)建不同的Dockerfile文件
case $ARCH in
"x86_64")
DOCKERFILE="Dockerfile.x86_64"
;;
"armv7l")
DOCKERFILE="Dockerfile.armv7l"
;;
"aarch64")
DOCKERFILE="Dockerfile.aarch64"
;;
*)
echo "Unsupported architecture: $ARCH"
exit 1
;;
esac
# 構(gòu)建Docker鏡像
docker build -t myimage:$ARCH -f $DOCKERFILE .
fi
復(fù)制
這里涉及到--platform的使用,對(duì)應(yīng)的dockerfile為:
FROM --platform=$BUILDPLATFORM golang:1.14 as builder
復(fù)制
事實(shí)上,還有其他的dockerfile命令可以用
架構(gòu)相關(guān)變量
Dockerfile
支持如下架構(gòu)相關(guān)的變量
TARGETPLATFORM
構(gòu)建鏡像的目標(biāo)平臺(tái),例如 linux/amd64
, linux/arm/v7
, windows/amd64
。
TARGETOS
TARGETPLATFORM
的 OS 類型,例如 linux
, windows
TARGETARCH
TARGETPLATFORM
的架構(gòu)類型,例如 amd64
, arm
TARGETVARIANT
TARGETPLATFORM
的變種,該變量可能為空,例如 v7
BUILDPLATFORM
構(gòu)建鏡像主機(jī)平臺(tái),例如 linux/amd64
BUILDOS
BUILDPLATFORM
的 OS 類型,例如 linux
BUILDARCH
BUILDPLATFORM
的架構(gòu)類型,例如 amd64
BUILDVARIANT
BUILDPLATFORM
的變種,該變量可能為空,例如 v7
那么通過這三種方式,做到了build_docker.sh腳本的統(tǒng)一
即
2.合并dockerfile文件
剛才,主要解決了build_docker.sh的合并統(tǒng)一,現(xiàn)在還要解決dockfile文件的一致的問題
在剛才的build_docker腳本中使用
docker build
或者
docker buildx build
--platform
的命令運(yùn)行dockerfile文件
這里由于dockerfile文件需要根據(jù)不同的架構(gòu)進(jìn)行編包,內(nèi)容不同,所以寫了兩個(gè)文件dockerfile.x86和dockerfile.arm
如果可以將架構(gòu)信息傳遞到dockerfile中,則可以將這兩個(gè)文件合二為一
這里主要的執(zhí)行命令為:
docker build --build-arg ARCH=x86_64 -t myimage:x86_64 .
復(fù)制
對(duì)應(yīng)的dockerfile文件為:
# 構(gòu)建參數(shù)
ARG ARCH
# 根據(jù)不同的架構(gòu),選擇不同的基礎(chǔ)鏡像
FROM ${ARCH}/debian:latest
# 安裝必要的軟件包
RUN apt-get update && apt-get install -y gcc g++ make && rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY . .
RUN make
FROM ${ARCH}/debian:latest
WORKDIR /app
COPY --from=builder /app/app /app
CMD ["/app/app/install.sh"]
CMD ["/app/app/build.sh"]
復(fù)制
當(dāng)然這里只是做了個(gè)樣例,實(shí)際上除了FROM里面還有一些安裝腳本需要選擇,這里就需要用到了IF ELSE命令
?修改上面的腳本如下:
# 構(gòu)建參數(shù)
ARG ARCH
# 根據(jù)不同的架構(gòu),選擇不同的基礎(chǔ)鏡像
FROM ${ARCH}/debian:latest
# 安裝必要的軟件包
RUN apt-get update && apt-get install -y gcc g++ make && rm -rf /var/lib/apt/lists/*
# 復(fù)制應(yīng)用程序源代碼
COPY app /app
# 根據(jù)不同的架構(gòu),選擇不同的應(yīng)用程序目錄
RUN if [ "$ARCH" = "x86_64" ]; then \
cp -r /app/install_x86.sh /app/install.sh; \
elif [ "$ARCH" = "arm64v8" ]; then \
cp -r /app/install_arm.sh /app/install.sh; \
else \
echo "Unsupported architecture: $ARCH"; \
exit 1; \
fi
# 運(yùn)行安裝程序
CMD ["/app/install.sh"]
復(fù)制
?通過上面的方法,基本上實(shí)現(xiàn)了一個(gè)dockerfile文件的多架構(gòu)鏡像編譯
那么情況變成了這個(gè)樣子:
離成功又進(jìn)了一步
3.合并安裝依賴腳本(install.sh)
和上面類似,通過變量傳入進(jìn)行修改
#!/bin/bash
# 構(gòu)建參數(shù)
ARCH=$1
# 安裝不同的環(huán)境依賴
if [ "$ARCH" = "x86_64" ]; then
apt-get update && apt-get install -y gcc g++ make
elif [ "$ARCH" = "arm64v8" ]; then
apt-get update && apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu make
else
echo "Unsupported architecture: $ARCH"
exit 1
fi
# 下載并編譯golang程序
wget https://example.com/myapp.tar.gz
tar -xzf myapp.tar.gz
cd myapp
GOOS=linux GOARCH=$ARCH go build -o myapp
# 運(yùn)行g(shù)olang程序
./myapp
復(fù)制
當(dāng)然,一般來說依賴安裝會(huì)稍微復(fù)雜一些,有些涉及的是ARm和非ARM的版本問題,有的是版本號(hào)的升級(jí)和降級(jí),除了上文額if和else之外,還可以使用sed –i命令進(jìn)行個(gè)性化修改,比如安裝腳本是這樣的:
#!/bin/bash
# 安裝x86架構(gòu)的環(huán)境依賴
apt-get update && apt-get install -y gcc g++ make libssl-dev
# 下載并編譯golang程序
wget https://example.com/myapp.tar.gz
tar -xzf myapp.tar.gz
cd myapp
GOOS=linux GOARCH=amd64 go build -o myapp
# 運(yùn)行g(shù)olang程序
./myapp
復(fù)制
那外部調(diào)用腳本可以用下面的方式進(jìn)行調(diào)整
#!/bin/bash
# 修改install.sh中的環(huán)境依賴
sed -i 's/apt-get install -y gcc g++ make libssl-dev/apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu make libssl-dev/g' install.sh
# 調(diào)用安裝腳本
./install.sh
復(fù)制
當(dāng)然sed -i是比較靈活的修改方式,需要注意可維護(hù)性,不然,可能出現(xiàn)改一個(gè)腳本,導(dǎo)致一堆腳本不可用
當(dāng)然,看到這里,可能有個(gè)疑問,dockerfile的多架構(gòu)適配是不是也可以用sed -i的方法,而不用ARG的傳參?
這里筆者也比較了下兩者的不同
最后,這里的建議是把基本的安裝依賴作為基礎(chǔ)鏡像單獨(dú)存儲(chǔ),這樣可以避免在多個(gè)業(yè)務(wù)鏡像中重復(fù)編譯
大概是這樣:
? 三、golang多架構(gòu)編譯
1.Golang多系統(tǒng)多架構(gòu)編譯
在Golang中,我們可以通過不同的文件后綴來實(shí)現(xiàn)多架構(gòu)編譯。這是因?yàn)镚olang的編譯器可以根據(jù)文件后綴來判斷需要編譯的架構(gòu)類型。首先,讓我們來了解一下不同的文件后綴代表的含義。在Golang中,文件后綴通常由兩部分組成,分別是操作系統(tǒng)(GOOS)和架構(gòu)(GOARCH)。例如,文件名為“hello_windows_amd64.exe”,其中“windows”代表操作系統(tǒng)為Windows,“amd64”代表架構(gòu)為64位的x86架構(gòu)。
下面是一個(gè)基本的Golang多系統(tǒng)多架構(gòu)編譯示例:
package main
import "fmt"
func main() {
fmt.Println("Hello, world!")
}
復(fù)制
?在Linux操作系統(tǒng)下,可以使用以下命令編譯該程序:
$ go build -o hello_windows_amd64.exe
復(fù)制
?在ARM處理器架構(gòu)下,可以使用以下命令編譯該程序:
go build -o hello_linux_amd64
復(fù)制
這個(gè)方法在很多的ARM的信創(chuàng)適配上比較常用
以github上比較常見的日志庫為例:
適配時(shí)報(bào)了這個(gè)錯(cuò)誤
因?yàn)槭褂昧薉up2這個(gè)方法報(bào)錯(cuò),dup2是dup命令的一種,還有dup和dup3命令,三者的區(qū)別如下
dup(int filedes)函數(shù)返回一個(gè)可用的與filedes共享文件表項(xiàng)的最小描述符
dup2(int filedes,int filedes2)是使用一個(gè)描述符filedes2去指向filedes文件表項(xiàng)(也是共享)
dup3(int oldfd, int newfd, int flags)和dup2相似,不同在于,可以通過指定flags為O_CLOEXEC強(qiáng)制置位新文件描述符的 close-on-exec 標(biāo)志
事實(shí)上,三個(gè)方法除了功能上的差異外,在平臺(tái)適配上也有些不同:
Darwin(MacOS)的X86架構(gòu)支持: Dup2
Linux的X86架構(gòu)支持: ? ?Dup2、Dup3
Linux的arm架構(gòu)支持: Dup3
所以進(jìn)行適配時(shí),可以根據(jù)不同的平臺(tái)編譯不同的文件分別定義對(duì)應(yīng)的方法實(shí)現(xiàn),比如:
2.CGo多系統(tǒng)多架構(gòu)編譯
CGO是Go語言中用于與C語言進(jìn)行交互的工具,它可以讓我們?cè)贕o語言中調(diào)用C語言的函數(shù)和使用C語言的庫。在進(jìn)行CGO編譯時(shí),我們需要考慮多系統(tǒng)多架構(gòu)的問題,以確保我們的程序可以在不同的操作系統(tǒng)和架構(gòu)中正常運(yùn)行。
下面是一些CGO多系統(tǒng)多架構(gòu)編譯的方法:
2.1?使用CGO_ENABLED環(huán)境變量
使用CGO_ENABLED環(huán)境變量。CGO_ENABLED環(huán)境變量可以用來控制CGO是否啟用。在進(jìn)行多系統(tǒng)多架構(gòu)編譯時(shí),我們可以設(shè)置CGO_ENABLED環(huán)境變量為0,這樣就可以禁用CGO,從而避免在不同的操作系統(tǒng)和架構(gòu)中出現(xiàn)問題。
下面是一個(gè)具體的例子,假設(shè)我們需要編譯一個(gè)使用了libcurl庫的Go程序,并且需要在Linux和Windows操作系統(tǒng)中分別編譯出x86和x64架構(gòu)的程序。我們可以使用以下命令來進(jìn)行編譯:
CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -o myprogram-linux-amd64 main.go
CGO_ENABLED=1 GOOS=linux GOARCH=386 go build -o myprogram-linux-386 main.go
CGO_ENABLED=1 GOOS=windows GOARCH=amd64 go build -o myprogram-windows-amd64.exe main.go
CGO_ENABLED=1 GOOS=windows GOARCH=386 go build -o myprogram-windows-386.exe main.go
復(fù)制
這個(gè)命令會(huì)分別編譯出Linux和Windows操作系統(tǒng)中的x86和x64架構(gòu)的程序
2.2 使用交叉編譯工具
使用交叉編譯工具。交叉編譯工具可以讓我們?cè)谝慌_(tái)機(jī)器上編譯出多個(gè)不同操作系統(tǒng)和架構(gòu)的程序。在進(jìn)行CGO編譯時(shí),我們可以使用交叉編譯工具來編譯出多個(gè)不同操作系統(tǒng)和架構(gòu)的程序,從而確保我們的程序可以在不同的操作系統(tǒng)和架構(gòu)中正常運(yùn)行。
下面是一個(gè)詳細(xì)的cgo交叉編譯的例子,假設(shè)我們需要編譯一個(gè)使用了libcurl庫的Go程序,并且需要在Linux和Windows操作系統(tǒng)中分別編譯出x86和x64架構(gòu)的程序。
安裝交叉編譯工具 首先,我們需要安裝交叉編譯工具。在Ubuntu系統(tǒng)中,我們可以使用以下命令來安裝交叉編譯工具:
sudo apt-get install gcc-arm-linux-gnueabihf
sudo apt-get install gcc-mingw-w64-x86-64
復(fù)制
?這個(gè)命令會(huì)安裝arm-linux-gnueabihf和mingw-w64-x86-64交叉編譯工具,分別用于編譯ARM和Windows x64架構(gòu)的程序。
編寫Go程序 接下來,我們需要編寫一個(gè)使用了libcurl庫的Go程序。假設(shè)我們的程序代碼如下:
package main
// #cgo LDFLAGS: -lcurl
// #include <curl/curl.h>
import "C"
import (
"fmt"
"unsafe"
)
func main() {
curl := C.curl_easy_init()
if curl == nil {
fmt.Println("Failed to initialize curl")
return
}
defer C.curl_easy_cleanup(curl)
url := C.CString("https://www.example.com")
defer C.free(unsafe.Pointer(url))
C.curl_easy_setopt(curl, C.CURLOPT_URL, url)
res := C.curl_easy_perform(curl)
if res != C.CURLE_OK {
fmt.Println("Failed to perform curl request")
return
}
fmt.Println("Curl request succeeded")
}
復(fù)制
?這個(gè)程序使用了libcurl庫來發(fā)送HTTP請(qǐng)求。在程序中,我們使用了CGO LDFLAGS關(guān)鍵字來鏈接libcurl庫,并使用了C語言的頭文件來調(diào)用libcurl庫的函數(shù)。
編譯ARM架構(gòu)的程序 接下來,我們需要編譯ARM架構(gòu)的程序。我們可以使用以下命令來編譯ARM架構(gòu)的程序:
CGO_ENABLED=1 GOOS=linux GOARCH=arm GOARM=7 CC=arm-linux-gnueabihf-gcc go build -o myprogram-arm main.go
復(fù)制
這個(gè)命令會(huì)使用arm-linux-gnueabihf-gcc交叉編譯工具來編譯ARM架構(gòu)的程序,并使用CGO LDFLAGS關(guān)鍵字來鏈接libcurl庫。其中,GOOS=linux表示編譯Linux操作系統(tǒng)的程序,GOARCH=arm表示編譯ARM架構(gòu)的程序,GOARM=7表示編譯ARMv7架構(gòu)的程序。
編譯Windows x64架構(gòu)的程序 最后,我們需要編譯Windows x64架構(gòu)的程序。我們可以使用以下命令來編譯Windows x64架構(gòu)的程序:
CGO_ENABLED=1 GOOS=windows GOARCH=amd64 CC=x86_64-w64-mingw32-gcc go build -o myprogram-windows.exe main.go
復(fù)制
?這個(gè)命令會(huì)使用x86_64-w64-mingw32-gcc交叉編譯工具來編譯Windows x64架構(gòu)的程序,并使用CGO LDFLAGS關(guān)鍵字來鏈接libcurl庫。其中,GOOS=windows表示編譯Windows操作系統(tǒng)的程序,GOARCH=amd64表示編譯x64架構(gòu)的程序。
這里還有一個(gè)比較好的例子:
如何使用 docker buildx 構(gòu)建跨平臺(tái) Go 鏡像
2.3 使用CGO LDFLAGS等關(guān)鍵字
使用CGO LDFLAGS等關(guān)鍵字。在進(jìn)行CGO編譯時(shí),我們可以使用CGO LDFLAGS等關(guān)鍵字來指定需要鏈接的庫和編譯選項(xiàng)。這些關(guān)鍵字可以讓我們?cè)诓煌牟僮飨到y(tǒng)和架構(gòu)中使用不同的鏈接庫和編譯選項(xiàng),從而確保我們的程序可以在不同的操作系統(tǒng)和架構(gòu)中正常運(yùn)行。
#cgo指令符是用于在Go語言中調(diào)用C語言函數(shù)和庫的關(guān)鍵字。它可以讓我們?cè)贕o語言中使用C語言的函數(shù)和庫,從而擴(kuò)展Go語言的功能。在進(jìn)行cgo多架構(gòu)編譯時(shí),我們可以使用#cgo指令符來指定不同操作系統(tǒng)和架構(gòu)下的編譯選項(xiàng)。
下面是一些#cgo指令符在cgo多架構(gòu)編譯中的使用方法:
#cgo CFLAGS #cgo CFLAGS指令符可以用來指定C語言編譯器的編譯選項(xiàng)。在進(jìn)行多架構(gòu)編譯時(shí),我們可以使用#cgo CFLAGS指令符來指定不同操作系統(tǒng)和架構(gòu)下的編譯選項(xiàng)。例如,我們可以使用以下指令符來指定ARM架構(gòu)下的編譯選項(xiàng):
#cgo CFLAGS: -march=armv7-a -mfpu=neon
復(fù)制
這個(gè)指令符會(huì)在ARM架構(gòu)下使用-march=armv7-a和-mfpu=neon編譯選項(xiàng)來編譯C語言代碼。
#cgo LDFLAGS #cgo LDFLAGS指令符可以用來指定鏈接器的選項(xiàng)。在進(jìn)行多架構(gòu)編譯時(shí),我們可以使用#cgo LDFLAGS指令符來指定不同操作系統(tǒng)和架構(gòu)下的鏈接選項(xiàng)。例如,我們可以使用以下指令符來指定Windows x64架構(gòu)下的鏈接選項(xiàng):
#cgo LDFLAGS: -L/usr/local/lib -lcurl
復(fù)制
?這個(gè)指令符會(huì)在Windows x64架構(gòu)下使用-L/usr/local/lib和-lcurl鏈接選項(xiàng)來鏈接libcurl庫。
#cgo windows #cgo windows指令符可以用來指定Windows操作系統(tǒng)下的編譯選項(xiàng)。在進(jìn)行多架構(gòu)編譯時(shí),我們可以使用#cgo windows指令符來指定不同操作系統(tǒng)下的編譯選項(xiàng)。例如,我們可以使用以下指令符來指定Windows操作系統(tǒng)下的編譯選項(xiàng):
#cgo windows CFLAGS: -D_WIN32_WINNT=0x0601
復(fù)制
?這個(gè)指令符會(huì)在Windows操作系統(tǒng)下使用-D_WIN32_WINNT=0x0601編譯選項(xiàng)來編譯C語言代碼
#cgo linux
#cgo windows指令符可以用來指定Linux操作系統(tǒng)下的編譯選項(xiàng)。在進(jìn)行多架構(gòu)編譯時(shí),我們可以使用#cgo linux指令符來指定不同操作系統(tǒng)下的編譯選項(xiàng)。例如,我們可以使用以下指令符來指定Linux操作系統(tǒng)下的編譯選項(xiàng):
#cgo linux CFLAGS: -D_GNU_SOURCE
復(fù)制
?這個(gè)指令符會(huì)在Linux操作系統(tǒng)下使用-D_GNU_SOURCE編譯選項(xiàng)來編譯C語言代碼。
#cgo darwin #cgo darwin指令符可以用來指定macOS操作系統(tǒng)下的編譯選項(xiàng)。在進(jìn)行多架構(gòu)編譯時(shí),我們可以使用#cgo darwin指令符來指定不同操作系統(tǒng)下的編譯選項(xiàng)。例如,我們可以使用以下指令符來指定macOS操作系統(tǒng)下的編譯選項(xiàng):
#cgo darwin CFLAGS: -mmacosx-version-min=10.10
復(fù)制
?這個(gè)指令符會(huì)在macOS操作系統(tǒng)下使用-mmacosx-version-min=10.10編譯選項(xiàng)來編譯C語言代碼。
#cgo linux,arm64 和 #cgo linux,amd64
#cgo linux,amd64 LDFLAGS: /lib/linux/liba.a
#cgo linux,arm64 LDFLAGS: /lib/linux/liba_arm.a
復(fù)制
?等價(jià)于
#cgo linux,!arm64 LDFLAGS: /lib/linux/liba.a
#cgo linux,!amd64 LDFLAGS: /lib/linux/liba_arm.a
復(fù)制
通過上面兩個(gè)代碼層級(jí)的編譯一致性,可以得到在編譯階段也可以做到合并統(tǒng)一
這時(shí)流程圖變成了這樣的
文章來源:http://www.zghlxwxcb.cn/news/detail-464882.html
完美!文章來源地址http://www.zghlxwxcb.cn/news/detail-464882.html
到了這里,關(guān)于【保姆級(jí)教程】Docker服務(wù)在雙架構(gòu)(X86和ARM)編譯統(tǒng)一實(shí)踐的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!