Go語言編譯時為exe新增圖示和屬性資訊的方法

烟熏牛肉干發表於2024-06-26

在使用Go語言開發應用程式時,有個非常方便的地方就是編譯得到的可執行檔案可以不依賴任何動態連結庫、並且不需要任何執行環境即可執行,本文給大家介紹Go編譯時為exe新增圖示和屬性資訊的方法,需要的朋友可以參考下

    1,安裝go-winres命令
    2,建立配置模板
    3,修改配置
        (1) 圖示指定
        (2) 軟體清單
        (3) 後設資料資訊
        (4) 簡易winres.json模板
    4,編譯資源
    5,編譯Go程式

在使用Go語言開發應用程式時,有個非常方便的地方就是編譯得到的可執行檔案可以不依賴任何動態連結庫、並且不需要任何執行環境即可執行,這一點Java就沒那麼方便了。
不過在Windows上編譯得到的exe檔案,預設是不帶圖示和任何屬性資訊的,那麼怎麼才能讓我們編譯得到的可執行檔案帶上圖示和屬性資訊呢?
事實上,藉助go-winres這款命令列工具即可很方便地實現。

1,安裝go-winres命令

執行下列命令即可安裝go-winres命令到電腦中:

go install github.com/tc-hib/go-winres@latest

2,建立配置模板

我們首先需要一個配置檔案來指定我們的圖示檔案和屬性資訊,然後將它們編譯得到資原始檔,最後將資原始檔和Go原始碼一起編譯即可得到帶有圖示的可執行檔案了!
我們可以先生成一個配置模板,然後進行修改即可,執行下列命令:

go-winres init

然後在當前目錄下,你會發現多了個winres目錄,其中winres.json就是配置檔案,而兩個png檔案則是它自帶的圖示檔案:

3,修改配置

使用文字編輯器開啟winres.json檔案,其中有一些初始內容:

其中的大致結構我們不需要修改,基本上就是修改指定其中部分欄位值即可。
下面,我們來單獨看一下每個部分。
(1) 圖示指定
我們來看看圖示部分,宣告在json檔案中的RT_GROUP_ICON屬性中:

"RT_GROUP_ICON": {
    "APP": {
        "0000": [
            "icon.png",
            "icon16.png"
        ]
    }
}

上述APP表示一組圖示,其中還有一個0000,表示語言,不過這兩個屬性名稱都不需要怎麼動,重點是看0000這個屬性,它是一個陣列,而很顯然陣列中記錄著一組圖示,在其中可以指定不同解析度的圖示。在這裡指定的圖示就會被應用到最終編譯的可執行檔案上去。
圖示檔案可以就是png檔案,將它和winres.json放在同一目錄下,然後在這個0000陣列中指定圖示檔名即可。
假設我現在需要自定義圖示,並且只需要一個檔案,那麼我可以先刪除裡面自帶的兩個png檔案,然後把我的圖示放在和winres.json同級目錄下:

然後修改圖示部分配置如下:

"RT_GROUP_ICON": {
    "APP": {
        "0000": [
            "my-icon.png"
        ]
    }
}

這樣,圖示就指定完成了!
需要注意的是,圖片檔案尺寸不能大於256 x 256!
(2) 軟體清單
軟體清單部分宣告在RT_MANIFEST屬性中:

"RT_MANIFEST": {
    "#1": {
        "0409": {
            "identity": {
                "name": "",
                "version": ""
            },
            "description": "",
            "minimum-os": "win7",
            "execution-level": "as invoker",
            "ui-access": false,
            "auto-elevate": false,
            "dpi-awareness": "system",
            "disable-theming": false,
            "disable-window-filtering": false,
            "high-resolution-scrolling-aware": false,
            "ultra-high-resolution-scrolling-aware": false,
            "long-path-aware": false,
            "printer-driver-isolation": false,
            "gdi-scaling": false,
            "segment-heap": false,
            "use-common-controls-v6": false
        }
    }
}

上述並非所有屬性都需要填寫和修改,這裡將重要的部分講解一下:

    description 檔案的描述資訊
    minimum-os 最低要求作業系統,可以是以下值:
        "vista"
        "win7"
        "win8"
        "win8.1"
        "win10"
    execution-level 應用程式所需的許可權,可以是:
        "as invoker" 不需要任何許可權
        "highest" 使用當前使用者的可用最高許可權
        "administrator" 強制要求管理員許可權才能執行

對於identify屬性,普通應用程式建議留空即可,也可以將其刪除。
(3) 後設資料資訊
這部分定義在RT_VERSION屬性中:

"RT_VERSION": {
    "#1": {
        "0000": {
            "fixed": {
                "file_version": "0.0.0.0",
                "product_version": "0.0.0.0"
            },
            "info": {
                "0409": {
                    "Comments": "",
                    "CompanyName": "",
                    "FileDescription": "",
                    "FileVersion": "",
                    "InternalName": "",
                    "LegalCopyright": "",
                    "LegalTrademarks": "",
                    "OriginalFilename": "",
                    "PrivateBuild": "",
                    "ProductName": "",
                    "ProductVersion": "",
                    "SpecialBuild": ""
                }
            }
        }
    }
}

這裡也並非所有屬性都需要填寫和修改,這裡將重要的部分講解一下:

    fixed 屬性中的兩個屬性,主要是宣告檔案版本和程式版本,按照x.y.z.w的格式自己填寫即可
    info 主要是屬性資訊,其中0409是英語的語言程式碼,表示在英文環境下顯示其中的屬性,在info中可以定義多個語言環境下的屬性資訊,具體大家可以檢視官方專案示例,在其中:
        CompanyName 公司名稱
        FileDescription 檔案描述
        FileVersion 檔案版本
        ProductVersion 程式版本
        LegalCopyright 版權資訊
        OriginalFilename 原始檔名
        ProductName 程式名稱

(4) 簡易winres.json模板
可見上述有許多屬性是我們大多數時候不需要進行設定的,可以刪除,因此這裡我提供一個模板,大家可以複製作為自己的winres.json檔案使用:

{
    "RT_GROUP_ICON": {
        "APP": {
            "0000": [
                "my-icon.png"
            ]
        }
    },
    "RT_MANIFEST": {
        "#1": {
            "2052": {
                "description": "我的Go示例程式",
                "minimum-os": "win7",
                "execution-level": "highest",
                "ui-access": false,
                "auto-elevate": false,
                "dpi-awareness": "system",
                "disable-theming": false,
                "disable-window-filtering": false,
                "high-resolution-scrolling-aware": false,
                "ultra-high-resolution-scrolling-aware": false,
                "long-path-aware": false,
                "printer-driver-isolation": false,
                "gdi-scaling": false,
                "segment-heap": false,
                "use-common-controls-v6": false
            }
        }
    },
    "RT_VERSION": {
        "#1": {
            "0000": {
                "fixed": {
                    "file_version": "1.0.0.0"
                },
                "info": {
                    "2052": {
                        "CompanyName": "公司名稱",
                        "FileDescription": "我的Golang示例程式",
                        "LegalCopyright": "© 版權",
                        "OriginalFilename": "demo.exe",
                        "ProductName": "Go示例",
                        "ProductVersion": "1.0.0.0"
                    }
                }
            }
        }
    }
}

大家修改其中資訊為自己的即可。

4,編譯資源

在winres資料夾所在目錄下執行命令

go-winres make

此時你會發現多了這幾個syso檔案,這就是編譯得到的資源:

需要注意的是,上述命令的執行路徑是在winres資料夾所在目錄下,而不是winres資料夾裡面。
當然,你也可以使用--in引數指定json檔案位置,如果你的執行路徑不在winres資料夾的所在目錄下的話:

# 指定json配置檔案在上一級目錄的res目錄中
go-winres make --in "../res/winres.json"

還可以使用--out引數指定輸出的資原始檔位置,具體大家可以透過命令go-winres make --help檢視幫助。

5,編譯Go程式

首先確保上述編譯得到的兩個syso資原始檔和Go語言模組配置go.mod在同級目錄下:

然後像平時一樣,在go.mod所在目錄下執行構建命令即可:

go build -ldflags "-w -s"

這樣,我們得到的可執行檔案就有圖示和屬性資訊了!


上述命令中,ldflags引數指定的是去除除錯和符號資訊以減小構建產物檔案大小,這個引數可以省略。
可見我們編譯得到的資原始檔都有著類似_windows_amd64這樣的字尾,這個字尾是用於go build命令連結資源時,根據架構判斷連結哪個資源用的,例如當我們編譯64位程式時,go build就會自動尋找名為xxx_windows_amd64.syso的資原始檔進行連結,同樣地如果是編譯為32位程式,則是尋找名為xxx_windows_386.syso的資原始檔,因此syso資原始檔的檔名必須是xxx_windows_amd64.syso這樣的形式,不可以修改其字尾。
與此同時,在進行go build時,go.mod檔案必須要和syso檔案在同一目錄下,如果沒有go.mod檔案,那主程式檔案(被編譯的)就需要和syso檔案在同一目錄下。

相關文章