GO語言的優勢:可直接編譯成機器碼,不依賴其他庫,glibc的版本有一定要求,部署就是扔一個文件上去就完成了。靜態類型語言,但是有動態語言的感覺,靜態類型的語言就是可以在編譯的時候檢查出來隱藏的大多數問題,動態語言的感覺就是有很多的包可以使用,寫起來的效率很高。語言層面支持并發,這個就是Go最大的特色,天生的支持并發,我曾經說過一句話,天生的基因和整容是有區別的,大家一樣美麗,但是你喜歡整容的還是天生基因的美麗呢?Go就是基因里面支持的并發,可以充分的利用多核,很容易的使用并發。內置runtime,支持垃圾回收,這屬于動態語言的特性之一吧,雖然目前來說GC不算完美,但是足以應付我們所能遇到的大多數情況,特別是Go1.1之后的GC。簡單易學,Go語言的作者都有C的基因,那么Go自然而然就有了C的基因,那么Go關鍵字是25個,但是表達能力很強大,幾乎支持大多數你在其他語言見過的特性:繼承、重載、對象等。豐富的標準庫,Go目前已經內置了大量的庫,特別是網絡庫非常強大,我最愛的也是這部分。內置強大的工具,Go語言里面內置了很多工具鏈,最好的應該是gofmt工具,自動化格式化代碼,能夠讓團隊review變得如此的簡單,代碼格式一模一樣,想不一樣都很困難。跨平臺編譯,如果你寫的Go代碼不包含cgo,那么就可以做到window系統編譯linux的應用,如何做到的呢?Go引用了plan9的代碼,這就是不依賴系統的信息。Go語言這么多的優勢,你還不想學嗎?我記得當時我看的是黑馬程序員的視頻,我對他們視頻的印象就是通俗易懂,就是好!
成都創新互聯主營浙江網站建設的網絡公司,主營網站建設方案,app軟件定制開發,浙江h5小程序開發搭建,浙江網站營銷推廣歡迎浙江等地區企業咨詢
Cgo 使得Go程序能夠調用C代碼. cgo讀入一個用特別的格式寫的Go語言源文件, 輸出Go和C程序, 使得C程序能打包到Go語言的程序包中.
舉例說明一下. 下面是一個Go語言包, 包含了兩個函數 -- Random 和 Seed -- 是C語言庫中random和srandom函數的馬甲.
package rand
/*
#include stdlib.h
*/ import "C" func Random() int { return int(C.random()) } func Seed(i int) { C.srandom(C.uint(i)) }
我們來看一下這里都有什么內容. 開始是一個包的導入語句.
rand包導入了"C"包, 但你會發現在Go的標準庫里沒有這個包. 那是因為C是一個"偽包", 一個為cgo引入的特殊的包名, 它是C命名空間的一個引用.
rand 包包含4個到C包的引用: 調用 C.random和C.srandom, 類型轉換 C.uint(i)還有引用語句.
Random函數調用libc中的random函數, 然后回返結果. 在C中, random返回一個C類型的長整形值, cgo把它輪換為C.long. 這個值必需轉換成Go的類型, 才能在Go程序中使用. 使用一個常見的Go類型轉換:
func Random() int { return int(C.random()) }
這是一個等價的函數, 使用了一個臨時變量來進行類型轉換:
func Random() int { var r C.long = C.random() return int(r) }
Seed函數則相反. 它接受一個Go語言的int類型, 轉換成C語言的unsigned int類型, 然后傳遞給C的srandom函數.
func Seed(i int) { C.srandom(C.uint(i)) }
需要注意的是, cgo中的unsigned int類型寫為C.uint; cgo的文檔中有完整的類型列表.
這個例子中還有一個細節我們沒有說到, 那就是導入語句上面的注釋.
/*
#include stdlib.h
*/ import "C"
Cgo可以識別這個注釋, 并在編譯C語言程序的時候將它當作一個頭文件來處理. 在這個例子中, 它只是一個include語句, 然而其實它可以是使用有效的C語言代碼. 這個注釋必需緊靠在import "C"這個語句的上面, 不能有空行, 就像是文檔注釋一樣.
Strings and things
與Go語言不同, C語言中沒有顯式的字符串類型. 字符串在C語言中是一個以0結尾的字符數組.
Go和C語言中的字符串轉換是通過C.CString, C.GoString,和C.GoStringN這些函數進行的. 這些轉換將得到字符串類型的一個副本.
下一個例子是實現一個Print函數, 它使用C標準庫中的fputs函數把一個字符串寫到標準輸出上:
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程序中進行的內存分配是不能被Go語言的內存管理器感知的. 當你使用C.CString創建一個C字符串時(或者其它類型的C語言內存分配), 你必需記得在使用完后用C.free來釋放它.
調用C.CString將返回一個指向字符數組開始處的指錯, 所以在函數退出前我們把它轉換成一個unsafe.Pointer(Go中與C的void 等價的東西), 使用C.free來釋放分配的內存. 一個慣用法是在分配內存后緊跟一個defer(特別是當這段代碼比較復雜的時候), 這樣我們就有了下面這個Print函數:
func Print(s string) { cs := C.CString(s) defer C.free(unsafe.Pointer(cs)) C.fputs(cs, (*C.FILE)(C.stdout)) }
構建 cgo 包
如果你使用goinstall, 構建cgo包就比較容易了, 只要調用像平常一樣使用goinstall命令, 它就能自動識別這個特殊的import "C", 然后自動使用cgo來編譯這些文件.
如果你想使用Go的Makefiles來構建, 那在CGOFILES變量中列出那些要用cgo處理的文件, 就像GOFILES變量包含一般的Go源文件一樣.
rand包的Makefile可以寫成下面這樣:
include $(GOROOT)/src/Make.inc
TARG=goblog/rand
CGOFILES=\ rand.go\ include $(GOROOT)/src/Make.pkg
然后輸入gomake開始構建.
更多 cgo 的資源
cgo的文檔中包含了關于C偽包的更多詳細的說明, 以及構建過程. Go代碼樹中的cgo的例子給出了更多更高級的用法.
一個簡單而又符合Go慣用法的基于cgo的包是Russ Cox寫的gosqlite. 而Go語言的網站上也列出了更多的的cgo包.
最后, 如果你對于cgo的內部是怎么運作這個事情感到好奇的話, 去看看運行時包的cgocall.c文件的注釋吧.
直接嵌入c源代碼到go代碼里面
package main
/*
#include stdio.h
void myhello(int i) {
printf("Hello C: %d\n", i);
}
*/
import "C"
import "fmt"
func main() {
C.myhello(C.int(12))
fmt.Println("Hello Go");
}
需要注意的是C代碼必須放在注釋里面
import "C"語句和前面的C代碼之間不能有空行
運行結果
$ go build main.go ./main
Hello C: 12
Hello Go
分開c代碼到單獨文件
嵌在一起代碼結構不是很好看,很多人包括我,還是喜歡把兩個分開,放在不同的文件里面,顯得干凈,go源文件里面是go的源代碼,c源文件里面是c的源代碼。
$ ls
hello.c hello.h main.go
$ cat hello.h
void hello(int);
$ cat hello.c
#include stdio.h
void hello(int i) {
printf("Hello C: %d\n", i);
}
$ cat main.go
package main
// #include "hello.h"
import "C"
import "fmt"
func main() {
C.hello(C.int(12))
fmt.Println("Hello Go");
}
編譯運行
$ go build ./main
Hello C: 12
Hello Go
編譯成庫文件
如果c文件比較多,最好還是能夠編譯成一個獨立的庫文件,然后go來調用庫。
$ find mylib main
mylib
mylib/hello.h
mylib/hello.c
main
main/main.go
編譯庫文件
$ cd mylib
# gcc -fPIC -shared -o libhello.so hello.c
編譯go程序
$ cd main
$ cat main.go
package main
// #cgo CFLAGS: -I../mylib
// #cgo LDFLAGS: -L../mylib -lhello
// #include "hello.h"
import "C"
import "fmt"
func main() {
C.hello(C.int(12))
fmt.Println("Hello Go");
}
$ go build main.go
運行
$ export LD_LIBRARY_PATH=../mylib
$ ./main
Hello C: 12
Hello Go
在我們的例子中,庫文件是編譯成動態庫的,main程序鏈接的時候也是采用的動態庫
$ ldd main
linux-vdso.so.1 = (0x00007fffc7968000)
libhello.so = ../mylib/libhello.so (0x00007f513684c000)
libpthread.so.0 = /lib64/libpthread.so.0 (0x00007f5136614000)
libc.so.6 = /lib64/libc.so.6 (0x00007f5136253000)
/lib64/ld-linux-x86-64.so.2 (0x000055d819227000)
理論上講也是可以編譯成整個一靜態鏈接的可執行程序,由于我的機器上缺少靜態鏈接的系統庫,比如libc.a,所以只能編譯成動態鏈接。
TinyGo是一個為微控制器、WebAssembly(Wasm)和命令行工具等小型場景設計的Go語言編譯器。TinyGo重用了Go語言工具和LLVM使用的庫,以編譯用Go語言編寫的程序。目前,該項目在GitHub上已經積累了10.1k的Star。
如下為一個示例程序,當運行在任何支持的帶板載LED的主板上時,則會點亮內置LED。
上述程序可以在單片機、Adafruit ItsyBitsy M0微控制器或任何支持的帶內置LED的板上進行編譯和不需要修改的運行,只要設置正確的TinyGo編譯器目標即可。例如,設置如下目標可以編譯和點亮 單片機。
項目概述
TinyGo項目旨在將Go語言引入到具有單進程或核心的微控制器和小系統。TinyGo類似于emgo,但主要的區別在于作者想要保留Go內存模型。另一個區別在于TinyGo在內部使用LLVM,因而可以獲得更小更高效的代碼以及更高的靈活性。
創建TinyGo項目的初衷是,如果Python可以在微控制器上運行,Go語言當然也應該能夠在更低級微設備上運行。
支持設備
你可以為微控制器、WebAssembly和Linux編譯TinyGo程序。目前,TinyGo支持以下85種微處理器板。
更多技術細節請參閱原項目。
當前名稱:go語言編譯動態庫 golang 編譯成動態庫
本文路徑:http://vcdvsql.cn/article14/hpjode.html
成都網站建設公司_創新互聯,為您提供網站建設、虛擬主機、外貿網站建設、App設計、響應式網站、關鍵詞優化
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯