GO語言包估計能直接調(diào)用我沒試
創(chuàng)新互聯(lián)是由多位在大型網(wǎng)絡(luò)公司、廣告設(shè)計公司的優(yōu)秀設(shè)計人員和策劃人員組成的一個具有豐富經(jīng)驗的團(tuán)隊,其中包括網(wǎng)站策劃、網(wǎng)頁美工、網(wǎng)站程序員、網(wǎng)頁設(shè)計師、平面廣告設(shè)計師、網(wǎng)絡(luò)營銷人員及形象策劃。承接:成都做網(wǎng)站、成都網(wǎng)站建設(shè)、網(wǎng)站改版、網(wǎng)頁設(shè)計制作、網(wǎng)站建設(shè)與維護(hù)、網(wǎng)絡(luò)推廣、數(shù)據(jù)庫開發(fā),以高性價比制作企業(yè)網(wǎng)站、行業(yè)門戶平臺等全方位的服務(wù)。
編譯DLL庫絕調(diào)用或者直接直接用系統(tǒng)命令調(diào)用編譯完執(zhí)行程序
因為Java是以沙箱機(jī)制運(yùn)行的,進(jìn)程間隔離,要想用Java寫外掛也不是完全不可以,只是先得用C/C++編寫注入程序(通常是動態(tài)鏈接庫),然后用JNI方式編寫其Java擴(kuò)展。
至于Go語言,不太了解。但是外掛主要是指ABI層次的,和語言無關(guān),只要一種語言的調(diào)用約定符合你要注入的程序的調(diào)用約定(以Windows為例就是WindowsAPI)都可以的(Java就是和C語言的調(diào)用約定不同所以不能直接寫外掛)。
關(guān)于注入的技巧,可以中搜這個文章
Three
Ways
to
Inject
Your
Code
into
Another
Process
或中文《注入代碼的
3
種方法》
Cgo 使得Go程序能夠調(diào)用C代碼. cgo讀入一個用特別的格式寫的Go語言源文件, 輸出Go和C程序, 使得C程序能打包到Go語言的程序包中.
舉例說明一下. 下面是一個Go語言包, 包含了兩個函數(shù) -- Random 和 Seed -- 是C語言庫中random和srandom函數(shù)的馬甲.
package rand
/*
#include stdlib.h
*/ import "C" func Random() int { return int(C.random()) } func Seed(i int) { C.srandom(C.uint(i)) }
我們來看一下這里都有什么內(nèi)容. 開始是一個包的導(dǎo)入語句.
rand包導(dǎo)入了"C"包, 但你會發(fā)現(xiàn)在Go的標(biāo)準(zhǔn)庫里沒有這個包. 那是因為C是一個"偽包", 一個為cgo引入的特殊的包名, 它是C命名空間的一個引用.
rand 包包含4個到C包的引用: 調(diào)用 C.random和C.srandom, 類型轉(zhuǎn)換 C.uint(i)還有引用語句.
Random函數(shù)調(diào)用libc中的random函數(shù), 然后回返結(jié)果. 在C中, random返回一個C類型的長整形值, cgo把它輪換為C.long. 這個值必需轉(zhuǎn)換成Go的類型, 才能在Go程序中使用. 使用一個常見的Go類型轉(zhuǎn)換:
func Random() int { return int(C.random()) }
這是一個等價的函數(shù), 使用了一個臨時變量來進(jìn)行類型轉(zhuǎn)換:
func Random() int { var r C.long = C.random() return int(r) }
Seed函數(shù)則相反. 它接受一個Go語言的int類型, 轉(zhuǎn)換成C語言的unsigned int類型, 然后傳遞給C的srandom函數(shù).
func Seed(i int) { C.srandom(C.uint(i)) }
需要注意的是, cgo中的unsigned int類型寫為C.uint; cgo的文檔中有完整的類型列表.
這個例子中還有一個細(xì)節(jié)我們沒有說到, 那就是導(dǎo)入語句上面的注釋.
/*
#include stdlib.h
*/ import "C"
Cgo可以識別這個注釋, 并在編譯C語言程序的時候?qū)⑺?dāng)作一個頭文件來處理. 在這個例子中, 它只是一個include語句, 然而其實(shí)它可以是使用有效的C語言代碼. 這個注釋必需緊靠在import "C"這個語句的上面, 不能有空行, 就像是文檔注釋一樣.
Strings and things
與Go語言不同, C語言中沒有顯式的字符串類型. 字符串在C語言中是一個以0結(jié)尾的字符數(shù)組.
Go和C語言中的字符串轉(zhuǎn)換是通過C.CString, C.GoString,和C.GoStringN這些函數(shù)進(jìn)行的. 這些轉(zhuǎn)換將得到字符串類型的一個副本.
下一個例子是實(shí)現(xiàn)一個Print函數(shù), 它使用C標(biāo)準(zhǔn)庫中的fputs函數(shù)把一個字符串寫到標(biāo)準(zhǔn)輸出上:
package print // #include stdio.h // #include stdlib.h import "C" import "unsafe" func Print(s string) { cs := C.CString(s) C.fputs(cs, (*C.FILE)(C.stdout)) C.free(unsafe.Pointer(cs)) }
在C程序中進(jìn)行的內(nèi)存分配是不能被Go語言的內(nèi)存管理器感知的. 當(dāng)你使用C.CString創(chuàng)建一個C字符串時(或者其它類型的C語言內(nèi)存分配), 你必需記得在使用完后用C.free來釋放它.
調(diào)用C.CString將返回一個指向字符數(shù)組開始處的指錯, 所以在函數(shù)退出前我們把它轉(zhuǎn)換成一個unsafe.Pointer(Go中與C的void 等價的東西), 使用C.free來釋放分配的內(nèi)存. 一個慣用法是在分配內(nèi)存后緊跟一個defer(特別是當(dāng)這段代碼比較復(fù)雜的時候), 這樣我們就有了下面這個Print函數(shù):
func Print(s string) { cs := C.CString(s) defer C.free(unsafe.Pointer(cs)) C.fputs(cs, (*C.FILE)(C.stdout)) }
構(gòu)建 cgo 包
如果你使用goinstall, 構(gòu)建cgo包就比較容易了, 只要調(diào)用像平常一樣使用goinstall命令, 它就能自動識別這個特殊的import "C", 然后自動使用cgo來編譯這些文件.
如果你想使用Go的Makefiles來構(gòu)建, 那在CGOFILES變量中列出那些要用cgo處理的文件, 就像GOFILES變量包含一般的Go源文件一樣.
rand包的Makefile可以寫成下面這樣:
include $(GOROOT)/src/Make.inc
TARG=goblog/rand
CGOFILES=\ rand.go\ include $(GOROOT)/src/Make.pkg
然后輸入gomake開始構(gòu)建.
更多 cgo 的資源
cgo的文檔中包含了關(guān)于C偽包的更多詳細(xì)的說明, 以及構(gòu)建過程. Go代碼樹中的cgo的例子給出了更多更高級的用法.
一個簡單而又符合Go慣用法的基于cgo的包是Russ Cox寫的gosqlite. 而Go語言的網(wǎng)站上也列出了更多的的cgo包.
最后, 如果你對于cgo的內(nèi)部是怎么運(yùn)作這個事情感到好奇的話, 去看看運(yùn)行時包的cgocall.c文件的注釋吧.
由于我們的 Dockerfile 使用多階段構(gòu)建,
由于 alpine 鏡像非常小,只有 5 mb 左右,但是由于客戶那邊強(qiáng)制要使用紅帽的基礎(chǔ)鏡像,所以在第二階段修改成紅帽的鏡像,最終打成的鏡像運(yùn)行的時候會提示 No such file or directory 。
這個問題的原因在于第一階段構(gòu)建的環(huán)境和第二階段的運(yùn)行的環(huán)境不一致,很多時候以為都是 Linux 環(huán)境,怎么可能不一致呢,但是由于 Linux 的各個發(fā)行版都有自己定制化的部分,就譬如 alpine 分支,他的 C 語言動態(tài)鏈接庫使用的是 musl,而像 centos 用的都是 glibc,他們都是 c 語言的標(biāo)準(zhǔn)庫,用來調(diào)用操作系統(tǒng)的庫。
上面說的是一方面原因,但是不是這個問題的最具體的原因。
go build 打包出來的二進(jìn)制文件還寫一個非常重要的信息 interpreter 。
我將二進(jìn)制文件從容器內(nèi) copy 出來通過 file 查看
可以看到二進(jìn)制的文件上有些一個解釋器的地址,這個文件地址是寫死在二進(jìn)制文件上的,后面我啟動一個 centos 容器。
果然報了同樣的一個錯誤。
Linux 如何啟動一個二進(jìn)制文件可以參考一下參考文檔,就是通過這個解釋器出發(fā)將程序調(diào)入內(nèi)存。