Showing posts with label Golang. Show all posts
Showing posts with label Golang. Show all posts

Thursday, November 25, 2021

[xgo] The first phase of hacking xgo

 xgo is a great Go CGO cross compiler that can help users to build the application written in Golang to multi-platforms at the same time. 

For more information in details, please check out these URLs:

https://github.com/karalabe/xgo
https://www.jianshu.com/p/a6047d3f976e

But, without any further study, we probably cannot understand how it works well. So here I just give some information about it. I will use my Github repository as the example:

# Install xgo
go get github.com/karalabe/xgo
$ git clone https://github.com/teyenliu/win-shared-example
$ cd win-shared-example

# Use xgo to cross-compile to windows/amd64
xgo -targets windows/amd64 github.com/teyenliu/win-shared-example


Then, we finish the cross-compilation for my application
And actually, xgo, this tool, is based on its prebuilt docker image: "karalabe/xgo-latest" to complete the cross-compilation task. We can check the dockerhub for it as well: https://hub.docker.com/r/karalabe/xgo-latest/builds

So, we can directly run this Docker Image to cross-compile my application based on my case as follows:

$ docker run --rm -v /home/liudanny/git/xgo:/build \
-v /home/liudanny/.xgo-cache:/deps-cache:ro \
-e REPO_REMOTE= \
-e REPO_BRANCH= \
-e PACK= \
-e DEPS= \
-e ARGS= \
-e OUT= \
-e FLAG_V=false \
-e FLAG_X=false \
-e FLAG_RACE=false \
-e FLAG_TAGS= \
-e FLAG_LDFLAGS= \
-e FLAG_BUILDMODE=default \
-e TARGETS=windows/amd64 \
-e EXT_GOPATH= \
karalabe/xgo-latest \
github.com/teyenliu/win-shared-example


Furthermore, we can directly run xgo's build.sh to cross-compile my application in the host instead of in in the container:

$ sudo su
# set Golang path
export PATH=$PATH:/usr/local/go/bin
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin

# rm /deps in advance
rm -rf /deps

# run build.sh
env GO111MODULE=off \
env REPO_REMOTE= \
env REPO_BRANCH= \
env PACK= \
env DEPS= \
env ARGS= \
env OUT= \
env FLAG_V=false \
env FLAG_X=false \
env FLAG_RACE=false \
env FLAG_TAGS= \
env FLAG_LDFLAGS= \
env FLAG_BUILDMODE=default \
env TARGETS=windows/amd64 \
env EXT_GOPATH= \
env BUILD_DEPS=/home/liudanny/git/xgo/docker/base/build_deps.sh \
env BOOTSTRAP_REPO=/home/liudanny/git/xgo/docker/base/bootstrap_repo.sh \
env BOOTSTRAP_PURE=/home/liudanny/git/xgo/docker/base/bootstrap_pure.sh \
env BOOTSTRAP=/home/liudanny/git/xgo/docker/base/bootstrap.sh \
env PATH=/usr/local/go/bin:$PATH \
./build.sh github.com/teyenliu/win-shared-example

Reference:
Golang 交叉编译
Golang交叉编译各个平台的二进制文件
Fyne Cross Compile


The following commands are not succesful to work for cross-compilation
$ CGO_ENABLED=1 CXX="x86_64-w64-mingw32-g++" CXX_FOR_TARGET="x86_64-w64-mingw32-g++" CC="x86_64-w64-mingw32-gcc" CC_FOR_TARGET="x86_64-w64-mingw32-gcc" GOOS=windows GOARCH=amd64 \
go build -ldflags -v -x -installsuffix cgo -o example.exe main.go

$ GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc go build -ldflags -v -x -installsuffix cgo -o example.exe main.go


Friday, November 19, 2021

[Golang] Golang with Cgo 動態連結(dynamic linking) 與 靜態連結(static linking)函式庫範例與筆記 in Windows environment

This post is focusd on how to do dynamic/static linking using Golang with cgo on Windows environment. If you want to see it on Linux environment, please check out another post: 

[Golang] Golang with Cgo 動態連結(dynamic linking) 函式庫範例與筆記 in Linux environment

First of all, thanks to someone who had posted several useful articles describing how to do dynamic linking and static linking using Golang(Go) with Cgo in Windows environment as follows:

P.S: For using this example on Linux environment, you should deal with the build process for the static and dynamic libraries.

在 Windows 環境建置動態連結函式庫 (Dynamic-link library),使用 MinGW gcc/g++ 以及 CodeBlock

Go with Cgo 靜態連結 (static linking) 函式庫建置範例與筆記
Go with Cgo 動態連結 (dynamic linking) 函式庫建置範例與筆記

Thursday, October 28, 2021

[Golang] The example function of converting Struct or Map data to Map[string]interface{} Type

    I recently encountered a use case that I need to convert my struct or map value to the type of map[string]interface{}. After surveying and studying for a while, I figure out how to deal with this kind of task and the way to do it.

    The following function ConvertStructToMap()  is the example of converting Struct or Map data to Map[string]interface{} Type. It receives the argument as interface type and uses reflect function to check the receiver type is correct and what we want. But, it has a constrain, which if you give a map, and Map's key type must be string.

// ConvertStructToMap()
func ConvertStructToMap(message interface{}) (map[string]interface{}, error) {
msg := reflect.ValueOf(message)
msgtype := msg.Type()

// support Struct
if msgtype.Kind() == reflect.Struct {
// message should be tagged by "codec" or "msg"
kv := make(map[string]interface{})
fields := msgtype.NumField()
for i := 0; i < fields; i++ {
field := msgtype.Field(i)
name := field.Name
if n1 := field.Tag.Get("json"); n1 != "" {
name = n1
} else if n2 := field.Tag.Get("msg"); n2 != "" {
name = n2
}
kv[name] = msg.FieldByIndex(field.Index).Interface()
}
return kv, nil
}
// support map[string]interface{} or map[string]string
if msgtype.Kind() != reflect.Map {
return nil, errors.New("message must be a map")
} else if msgtype.Key().Kind() != reflect.String {
return nil, errors.New("map keys must be strings")
}

// Get the interface{}'s current value
kv := make(map[string]interface{})
for _, k := range msg.MapKeys() {
kv[k.String()] = msg.MapIndex(k).Interface()
}
return kv, nil
}

func main() {
fmt.Println("Hello, playground")
structData := struct { Name string `json:"JsonName"` 
                       Score int `msg:"MsgScore"`} { 
                       "john smith", 30, }
kv, err := ConvertStructToMap( structData )
if err != nil {
    fmt.Println(err)
}
fmt.Println(kv)
}

How to use it? Here we go! You can try it on the Go Playground:
https://play.golang.org/p/TLKBIbSxIQj

or just take a look at the sample as follows:

// The way to use ConvertStructToMap()
func main() {
structData := struct { Name string `json:"JsonName"` 
                       Score int `msg:"MsgScore"`} { 
                       "john smith", 30, }
kv, err := ConvertStructToMap( structData )
if err != nil {
    fmt.Println(err)
}
fmt.Println(kv)
        mapData := make(map[string]int)
        mapData["Score1"] = 100
        mapData["Score2"] = 60
        kv, err = ConvertStructToMap( mapData )
        if err != nil {
    fmt.Println(err)
}
fmt.Println(kv)
}


Run Result==>

map[JsonName:john smith MsgScore:30]
map[Score1:100 Score2:60]



Thursday, September 16, 2021

Golang 設定與常用指令說明

 Golang設定

加入下列於 ~/.profile
#Golang path
export PATH=$PATH:/usr/local/go/bin
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin


常用的指令與使用說明
初始化 Module
這個會在資料夾底下產生一個初始的 go.mod 檔案
go mod init <module>
  • 在 build go 專案的時候,會根據 module name 的最後一路路徑 myproject 當作輸出檔名,會產生 myproject.exe 的檔案
  • 在 import 自己專案 package 的路徑的時候,github.com/mileslin/myproject 是根目錄,例如我新增一個 pg1 的 package ,則我在 import 的時候要輸入 import "github.com/mileslin/myproject/pg1"。

取得套件
go get -u github.com/gorilla/mux (-u 是說明,取得套件的時候不要從 cache 取得

#go get 的時候指定版本
go get github.com/gorilla/mux@v1.6.1
除了會新增一個 go.sum 檔案之外呢, go.mod 也會記錄你下載的套件,如下範例
module github.com/mileslin/myproject
go 1.13
require github.com/gorilla/mux v1.7.3 // indirect
// indirect 的意思是說,此套件還沒被用到。 所以只要在程式碼中使用此到件,並且 build 專案後,// indirect 就會消失
最後提一下,下載的套件會被放在 GOPATH/pkg/mod 底下。 (可以使用 go env 指令查看 GOPATH 路徑)

列出套件與套件版本
go list 取得可以使用的套件列表
$ go list all 會列出所有套件,包含 GOROOT 套件
$ go list -m all 只列出 module 列出的套件(包含自己的 package)
$ go list -m -versions github.com/gorilla/mux 列出此套件的所有版本

檢查套件使用情形
列出使套件在哪裡有被用到
$ go mod why github.com/gorilla/mux

Module download
這個會將 go.mod 定義的 library 都下載下來,但基本上 go build, go test 也會自動下載 library 並新增到 go.mod 上,
並會產出 go.sum 來確保 library 是否有更新。可以說能達到一樣的效果
go mod download

如果你忘了 import ,則會出現以下的錯誤
// github.com/streadway/amqp
go build -o ./bin/rabbitmq ./cmd
# rabbitmq/cmd
cmd/main.go:16:15: undefined: amqp
cmd/main.go:41:4: undefined: amqp

Module tidy
移除在 go.mod 不需要的 library
go mod tidy


go test
go test -timeout 30s ./probe/endpoint/... -run "TestSpyNoProcesses|TestSpyWithProcesses"
go test -timeout 30s ./probe/endpoint/...
go test -v -run=TestNewWithAssert ./example18-write-testing-and-doc/...