Docker for windows でfyneを使ってwindowsアプリ用の環境構築

# 初めに
bokkuruといいます。
今回はgolangの勉強用にGUI用のパッケージのfyneを使ってみるための環境構築を行います。wsl2上のdockerで開発を行い、動作はメインosであるwindows上で実行を目指します。
ブラウザ上でのHello Worldの表示まで行います。
筆者がgolang初心者なのでgolangに関する初歩的なミスが多いですが許して下さい。

# 前提環境
OS : windows 10
wsl2のos : Ubuntu
docker : Docker desktop for windows
Fyne : https://github.com/fyne-io/fyne
golang : https://golang.org/
editor : VS code (Remote-Containers)

方針
dockerのlinux上でコンパイルしてwindows向けのファイルを作りたい

# Dockerの起動
```DockerFile:Dockerfile
FROM golang:1.16.8
RUN apt update
RUN apt install -y git
RUN go get fyne.io/fyne/v2
```
このファイルを元にコンテナを作成しました。
golangを最新にするとgo getコマンドが使用できなくなっているそうでgo installに代わるようですが、怖いのでgo getが使える1.16.8にしています。

# goの記述
FyneのGithubの
https://github.com/fyne-io/fyne
に書かれているHello用のコードをコピーしました。

```Helloworld.go
package main

import (
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/widget"
)

func main() {
	a := app.New()
	w := a.NewWindow("Hello")

	hello := widget.NewLabel("Hello Fyne!")
	w.SetContent(container.NewVBox(
		hello,
		widget.NewButton("Hi!", func() {
			hello.SetText("Welcome :)")
		}),
	))

	w.ShowAndRun()
}
```
ディレクトリ構成は

```
$GOPATH
├ bin
├ pkg
└ src
   └ test
       └ Helloworld.go
```

# コンパイル成功までのバグと対処
## go.modの作成
取り敢えずこれをwindowsで作れるようにコンパイルするべく

```:Terminal
# GOOS=windows go build -o hello.exe test/Helloworld.go
```
を実行します。
go buildでは最初に<環境変数名>=<値>で記載するとgo envにある環境変数を上書きして実行できるようで、この場合はGOOS=windowsでコンパイル先OSをwindowsに書き換えています。

しかしエラーとして

```:Terminal
# go.mod file not found in current directory or any parent directory; see 'go help modules0'
```
が表示されました。

どうやらgolangではgo.modが必要らしいので調べると、go.modでモジュール名やそのモジュールに必要なパッケージを管理しているらしいです。
そこでsrc下で以下のコマンドを行います。

```:Terminal
# go mod init fyne/test
```
これにより以下のファイルが作られます。

```:go.mod
module fyne/test

go 1.16
```
またgo mod tidyをやれと言われるのでそちらも行うと

```:go.mod
module fyne/test

go 1.16

require fyne.io/fyne/v2 v2.1.0
```
に代わりgo.sumが作られます。これによって必要なパッケージが自動でgo.modに記載されるそうです。すごい便利。

## クロスコンパイルにおけるcコンパイラの設定
これで行けるかと思い先ほどのコンパイルを行うと

```:Terminal
package command-line-arguments
        imports fyne.io/fyne/app
        imports fyne.io/fyne/internal/driver/glfw
        imports fyne.io/fyne/internal/painter/gl
        imports github.com/go-gl/gl/v3.2-core/gl: build constraints exclude all Go files in /go/pkg/mod/github.com/go-gl/gl@v0.0.0-20190320180904-bf2b1f2f34d7/v3.2-core/gl
package command-line-arguments
        imports fyne.io/fyne/app
        imports fyne.io/fyne/internal/driver/glfw
        imports github.com/go-gl/glfw/v3.3/glfw: build constraints exclude all Go files in /go/pkg/mod/github.com/go-gl/glfw/v3.3/glfw@v0.0.0-20200625191551-73d3c3675aa3
```
のエラーが起きます。

これが最大の謎だったのですが。https://qiita.com/acnaman/items/28a45a31864952fb7bad この方の記事を見る限りクロスコンパイルする場合はそのos用のcコンパイラが必要のようです。今回はwindowsなのでmingw-w64をインストールします。

```:Terminal
# apt install mingw-w64
```

その上で環境変数であるCCにそのコンパイラ情報を渡してCGO_ENABLED=1にする必要があるようです。以上からbuild用のコードが以下に変わります。

```:Terminal
# GOOS=windows CC=x86_64-w64-mingw32-gcc CGO_ENABLED=1 go build -o hello.exe test/Helloworld.go
```

## X11のインストール
これで行けると思いきやまだエラーが起きます。

```
fatal error: X11/Xlib.h: No such file or directory 
```
どうやらX11のパッケージが必要なようです。これはX window systemのことでGUIパッケージを使うならGUI用の開発ツールが必要なのは当然ということでインストールしてはエラーをはいてそしたら必要なのをまたインストールを繰り返しました。結局実行したコードは

```
apt install -y libx11-dev
apt install -y libxcursor-dev
apt install -y libxrandr-dev
apt install -y libxinerama-dev 
apt install -y libxi-dev
apt install -y libgl1-mesa-dev
apt install -y libxxf86vm-dev
```
となります。
これによって必要なX11用の開発ツールをインストールできました。
後で知りましたが。

```:Terminal
# apt install -y xorg-dev libgl1-mesa-dev
```
で一括でインストールできるっぽいです。

これでコンパイルするとhello.exeができるのでwindowsに移して実行すると...
![fyne_hello.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1331313/482ccdee-751e-15e6-0e7c-44ef9aa9173c.png)

動きました !

# まとめ
色々書きましたが、以下のdockerを作って。go.modの作成やgoファイルの作成コンパイルすればいけるっぽいです。

```:Dockerfile
FROM golang:1.16.8
RUN apt update
RUN apt install -y git
RUN cd $GOPATH
RUN apt install -y xorg-dev libgl1-mesa-dev mingw-w64 
RUN mkdir test
RUN go env -w CGO_ENABLED=1
```

恐らくlinux用に書くならgccも必要だと思います。

# 終わりに
golangの学習のためにfyneを使ってようと思い環境構築を行いました。
クロスコンパイルの仕様とか参考になれば幸いです。