goversioninfo

repository·master·Indexed 21 days ago

https://github.com/josephspurrier/goversioninfo

A tool for Go developers to generate Microsoft Windows version information, application icons, and manifests. It produces .syso files that are automatically embedded into Windows executables during the Go build process. The tool supports configuration via versioninfo.json or CLI flags, provides automatic architecture detection based on GOARCH, and can synchronize numeric FixedFileInfo with StringFileInfo version strings.

Tokens
9K
Snippets
25
Records
28
Agent score
74%

What's inside goversioninfo

  1. How architecture detection works

    master

    The -64 and -arm flags default based on the GOARCH environment variable (falling back to the host architecture if GOARCH is not set).

    This allows go generate to automatically produce a resource file matching your target architecture without needing to pass the flags explicitly. You can still override these defaults by passing the flags manually on the command line.

  2. How version synchronization works between FixedFileInfo and StringFileInfo

    master

    The versioninfo.json configuration contains both FixedFileInfo (structured numeric components: Major, Minor, Patch, Build) and StringFileInfo (free-form strings).

    When Build() is called, the tool synchronizes them:

    • If FixedFileInfo is set but StringFileInfo is empty, the string is generated (e.g., "2.0.0.0").
    • If StringFileInfo has a parseable version string but FixedFileInfo is all zeros, the numeric fields are populated from the string.
    • If both are set, neither is modified (a warning is logged if they do not match).
    • If a StringFileInfo version string cannot be parsed, a warning is logged.

    Because of this, you only need to specify version information in one place (e.g., just FixedFileInfo).

    {
      "FixedFileInfo": {
        "FileVersion": {
          "Major": 2,
          "Minor": 0,
          "Patch": 0,
          "Build": 0
        },
        "ProductVersion": {
          "Major": 2,
          "Minor": 0,
          "Patch": 0,
          "Build": 0
        }
      }
    }
  3. Use goversioninfo in your Go project

    master

    To embed Windows version information, icons, and manifests into your Go executable, follow these steps:

    1. Prepare Configuration: Copy testdata/resource/versioninfo.json into your working directory and modify it with your desired settings.
    2. Add Generate Directive: Add a //go:generate directive to your Go source code. The -icon and -manifest flags are optional.
    3. Generate and Build: Run go generate followed by go build. This creates a .syso file in the same directory as your source code, which Go will automatically embed during the build process.

    Example directive:

    //go:generate goversioninfo -icon=testdata/resource/icon.ico -manifest=testdata/resource/goversioninfo.exe.manifest
  4. VSVarFileInfo and VSVar: Translation information

    master

    The VSVarFileInfo and VSVar structs handle the translation information (Language ID and Code Page) required by Windows to identify which string table to use for a specific locale.

    • VSVarFileInfo: A container for the translation collection.
    • VSVar: Holds the actual translation key and the uint32 value representing the language/charset identifiers.
    type VSVarFileInfo struct {
    	WLength      uint16
    	WValueLength uint16
    	WType        uint16
    	SzKey        []byte
    	Padding      []byte
    	Value        VSVar
    }
    
    type VSVar struct {
    	WLength      uint16
    	WValueLength uint16
    	WType        uint16
    	SzKey        []byte
    	Padding      []byte
    	Value        uint32
    }
  5. VSStringFileInfo and VSStringTable: String-based versioning

    master

    Windows version resources use a hierarchical structure to store text-based version information (like FileVersion or ProductName).

    1. VSStringFileInfo: The top-level container for string information. It contains a single VSStringTable in this package.
    2. VSStringTable: A collection of VSString entries.
    3. VSString: The actual key-value pair (e.g., Key: FileVersion, Value: 1.0.0.0).

    These structures use WType to indicate the data type (0 for binary, 1 for text) and include padding to ensure 32-bit boundary alignment.

    type VSStringFileInfo struct {
    	WLength      uint16
    	WValueLength uint16
    	WType        uint16
    	SzKey        []byte
    	Padding      []byte
    	Children     VSStringTable
    }
    
    type VSStringTable struct {
    	WLength      uint16
    	WValueLength uint16
    	WType        uint16
    	SzKey        []byte
    	Padding      []byte
    	Children     []VSString
    }
    
    type VSString struct {
    	WLength      uint16
    	WValueLength uint16
    	WType        uint16
    	SzKey        []byte
    	Padding      []byte
    	Value        []byte
    }
  6. Configure application icons and window title bar icons

    master

    By default, Windows uses the system default icon for the window title bar. To set a custom icon, goversioninfo embeds an icon resource with the IDI_APPLICATION resource ID (32512).

    • IconPath: Sets the main application icon. If ApplicationIconPath is not set, this is also used for the window title bar.
    • ApplicationIconPath: Sets a specific icon for the window title bar. If unset, it defaults to IconPath.

    If neither is set, no application icon is embedded.

    You can configure this in versioninfo.json or via CLI flags.

    {
        "IconPath": "icons/main.ico",
        "ApplicationIconPath": "icons/small.ico"
    }
  7. Note on Unicode characters in versioninfo.json

    master

    The versioninfo.json file must be saved as UTF-8.

    If the file is saved using a different encoding (like Windows-1252), non-ASCII characters such as the copyright symbol © will appear as ? or in the compiled executable's file properties. This happens because Go reads the JSON as UTF-8 and replaces invalid bytes with the Unicode replacement character (U+FFFD).

    Solutions:

    1. Save versioninfo.json as UTF-8 in your text editor.
    2. Use the JSON escape sequence (e.g., \u00a9 for ©) instead of the literal character.
  8. Reference: goversioninfo command-line flags

    master

    Complete list of flags available for the goversioninfo CLI:

    FlagDescription
    -charset=0charset ID
    -comment=""StringFileInfo.Comments
    -company=""StringFileInfo.CompanyName
    -copyright=""StringFileInfo.LegalCopyright
    -description=""StringFileInfo.FileDescription
    -example=falsedump out an example versioninfo.json to stdout
    -file-version=""StringFileInfo.FileVersion
    -icon=""icon file name(s), separated by commas
    -application-icon=""icon file for IDI_APPLICATION (window title bar); defaults to -icon if unset
    -internal-name=""StringFileInfo.InternalName
    -manifest=""manifest file name
    -skip-versioninfo=falseskip version info reading on true, allows setting just icon
    -o="resource.syso"output file name
    -gofile=""Go output file name (optional) - generates a Go file to access version information internally
    -gofilepackage="main"Go output package name (optional, requires parameter: 'gofile')
    -platform-specific=falseoutput i386 and amd64 named resource.syso, ignores -o
    -original-name=""StringFileInfo.OriginalFilename
    -private-build=""StringFileInfo.PrivateBuild
    -product-name=""StringFileInfo.ProductName
    -product-version=""StringFileInfo.ProductVersion
    -special-build=""StringFileInfo.SpecialBuild
    -trademark=""StringFileInfo.LegalTrademarks
    -translation=0translation ID
    -64:falsegenerate 64-bit binaries on true
    -arm:falsegenerate ARM binaries on true
    -ver-major=-1FileVersion.Major
    -ver-minor=-1FileVersion.Minor
    -ver-patch=-1FileVersion.Patch
    -ver-build=-1FileVersion.Build
    -product-ver-major=-1ProductVersion.Major
    -product-ver-minor=-1ProductVersion.Minor
    -product-ver-patch=-1ProductVersion.Patch
    -product-ver-build=-1ProductVersion.Build
  9. Generate version info resources with RunCLI()

    master

    The RunCLI function is the primary entrypoint for generating version info resource files (.syso) and Go source files based on a provided CLIConfig. It performs the following steps:

    1. Parses JSON: Reads the configuration from ConfigFile (or stdin if set to -) and parses it into a VersionInfo object.
    2. Applies Overrides: Applies any non-empty fields from CLIConfig (such as CompanyName, FileVersion, or IconPath) to the VersionInfo object.
    3. Version Synchronization: If PropagateVerStrings is true, it synchronizes the numeric FixedFileInfo version fields with the string-based StringFileInfo.FileVersion and StringFileInfo.ProductVersion fields.
    4. Builds Resources: Executes the build and walk processes to prepare the resource data.
    5. Writes Go Files: If GoFile is specified, it writes the version information to that Go file using the specified GoFilePackage.
    6. Writes SYSO Files: Generates one or more .syso files. If PlatformSpecific is true, it generates files for multiple architectures (386, amd64, arm, arm64). Otherwise, it generates a single file for the detected architecture.
    cfg := goversioninfo.NewCLIConfig()
    cfg.ConfigFile = "versioninfo.json"
    cfg.OutputFile = "resource.syso"
    cfg.GoFile = "version.go"
    cfg.GoFilePackage = "main"
    
    err := goversioninfo.RunCLI(cfg)
    if err != nil {
    	panic(err)
    }
  10. Generate a Go file containing version info

    master

    Use WriteGo to generate a Go source file that embeds the version information as a raw string literal. This allows your application to access its own version metadata at runtime by unmarshaling the embedded data.

    Parameters:

    • filename: The destination path for the generated .go file.
    • packageName: The package name to be used in the generated file (defaults to "main" if empty).
    err := vi.WriteGo("version_data.go", "myapp/version")
    if err != nil {
    	// handle error
    }