在Linux中快速编译带图标的windows程序

一. 引言

以前做的一个项目有个需求, 需要在Linux系统上的服务后端根据前端配置动态编译出能在Windows平台运行的程序, 并且能支持程序带图标, 虽然使用Go语言能够方便的编译跨平台运行的代码, 但编译带资源图标的Windows可执行程序还未尝试过, 本篇文章对这部分内容做一个实践尝试。

二. 准备工作

如果要单独完成这项任务, 需要准备以下几样"配菜":

1.rsrc程序, 开源项目, 地址: https://github.com/akavel/rsrc

2.一份模拟在Windows平台运行的源码, 当被自动编译后, 能看到运行效果。

3.一份图标文件, 文件后缀为.ico。

4.一份模拟服务后端功能的程序, 该程序负责编译出最终带图标的Windows程序。

下面将依次介绍这四样"配菜"的调制方法:

2.1 rsrc程序

rsrc程序是一个开源专门负责将ico资源文件写入Windows PE可执行程序的工具, 该工具使用Go语言开发, 能够支持将rsrc代码编译成支持不同平台的可执行程序, 支持的系统包括: Darwin、Linux(amd64)、Windows(386)、Windows(amd64)。

rsrc程序的参数在实际使用过程中主要有三个:

1.-arch 该参数将指定嵌入资源后的程序运行的CPU架构, 为了向下同时兼容32位和64位系统, 这里一般设置的参数为:"-arch 386"。

2.-ico 该参数执行传入的图标文件保存的全路径。

3.-o 该参数是一个输出参数, 将输出一个.res或者.syso的资源文件, 如果不指定资源文件的名字, rsrc将默认输出一个名为:rsrc_windows_{arch}.syso的文件, 在我们实际应用中, 将输出格式为: .syso的文件。

2.2 模拟Windows程序

模拟Windows程序, 这里为了能看到运行的实际效果, 将在Go代码中嵌入Windows的对话框元素, 双击执行后将弹出一个对话框, 表示程序运行成功。以下是模拟Windows程序的Go源码:

package main
​
import (
    "syscall"
    "unsafe"
)
​
var (
    user32, _     = syscall.LoadLibrary("user32.dll")
    messageBox, _ = syscall.GetProcAddress(user32, "MessageBoxW")
)
​
func IntPtr(n int) uintptr {
    return uintptr(n)
}
​
func StrPtr(s string) uintptr {
    return uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(s)))
}
​
func ShowMessage(title, text string) {
    user32 := syscall.NewLazyDLL("user32.dll")
    MessageBoxW := user32.NewProc("MessageBoxW")
    MessageBoxW.Call(IntPtr(0), StrPtr(text), StrPtr(title), IntPtr(0))
}
​
func main() {
    defer syscall.FreeLibrary(user32)
    ShowMessage("成功消息!", "Hello!")
}
这段代码运行成功后, 将弹出一个成功的对话框。

2.3 图标文件

图标文件准备标准的ico格式文件即可, 以下是我的图标文件:

在Linux中快速编译带图标的windows程序_第1张图片

2.4 模拟服务后端程序

模拟服务后端程序主要负责利用rsrc将资源文件编译成.syso格式,并利用go build完成最终的二进程程序编译, 完整代码如下:`

package main
​
import (
  "fmt"
  "os/exec"
)
​
const (
  hIconPath     = "/home/gocompile/icon/Folder.ico" // 图标文件路径
  ProgramName   = "gocompile"                       // 编译完成最终程序名称
  compileOutput = "./output/gocompile.exe"          // 编译之后最终的输出目录
)
​
func CompileProgram() {
  cmd := "./rsrc -arch 386 -ico " + hIconPath + " -o " + ProgramName + ".syso" + " && " +
    "CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -o " + compileOutput
  _, err := exec.Command("bash", "-c", cmd).Output()
  if err != nil {
    fmt.Println(err.Error())
    return
  }
}
​
func main() {
  CompileProgram()
}

利用以下命令将模拟服务后端程序编译成能在Linux系统上运行的程序:

CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o gocontrol

将编译完成的gocontrol程序上传到Linux服务器, 准备完成最终的跨平台程序编译。

三. 交叉编译

在Linux服务器上建立工作目录:/home/gocompile, 在目录下新建code和icon两个目录, 将本地的所有图标文件上传到icon文件夹下;将

编译完成的gocontrol、模拟Windows程序源码、rsrc程序上传到code 目录下, 如图:

编辑/etc/profile, 在最后加上路径:export PATH=$PATH:/home/gocompile/code,如图 :

在Linux中快速编译带图标的windows程序_第2张图片

执行: source /etc/profile

进入code目录, 给予gocontrol和rsrc可执行权限, ./gocontrol运行程序, 如果没有错误产生,将在output目录中生成名为gocompile.exe程序,如图:

四. 结果验证

将output中的gocompile.exe程序拷贝到WIndows系统上,可以看到已经生成了带图标的程序,如图:

在Linux中快速编译带图标的windows程序_第3张图片

双击执行该程序, 可以看到已经执行成功:

在Linux中快速编译带图标的windows程序_第4张图片

五. 总结

这里主要利用了rsrc开源库将图标资源写入可执行程序, 利用Go语言的跨平台特性方便的在Linux系统上生成了在WIndows系统中执行的程序。

你可能感兴趣的:(工作项目经验,后端)