miqt

repository·master·Indexed 20 days ago

https://github.com/mappu/miqt

Go bindings for the Qt framework (5.15 and 6.4+) using CGO for building native cross-platform GUI applications. The project includes a suite of tools: genbindings for regenerating bindings via Clang AST, miqt-docker for managing cross-compiler environments, miqt-lupdate for translation file generation, miqt-rcc for Qt resource packs, and miqt-uic for compiling Qt Designer .ui files into Go code.

Tokens
14.6K
Snippets
44
Records
64
Agent score
73%

What's inside miqt

  1. Overview of MIQT

    master

    MIQT provides MIT-licensed Qt bindings for Go using CGO. It is a straightforward binding of the Qt 5.15 and Qt 6.4+ APIs.

    Key Features:

    • Supports subclassing.
    • Includes implementations for uic, rcc, and lupdate.
    • Comprehensive coverage for many Qt modules including QtCore, QtGui, QtWidgets, Qt SQL, QtMultimedia, QtWebEngine, QML, and more.

    Prerequisites: You must have a working Qt C++ development toolchain installed on your system to use these bindings.

  2. Use MIQT Extras for third-party Qt library bindings

    master
    The qt-extras directory provides bindings to third-party Qt libraries that are not part of the core MIQT package. Currently, this includes support for ScintillaEdit, which is licensed under the MIT license. Use these extras when your application requires specialized Qt components like advanced text editors provided by Scintilla.
  3. Understand MIQT Restricted Extras licensing

    master

    The qt-restricted-extras directory provides bindings to Qt libraries that carry more restrictive licenses than the standard permissive or LGPL licenses used elsewhere in MIQT. Developers must evaluate their project's licensing requirements before using these specific bindings.

    Supported restricted libraries include:

    • QScintilla: Licensed under GPL or Commercial licenses.
    • Qt Charts: Licensed under GPLv3 or Commercial licenses.
  4. License information for MIQT

    master

    The MIQT Go bindings are licensed under the MIT license.

    Important: While the bindings themselves are MIT-licensed, you must also comply with your specific Qt license obligations when using them.

  5. Supported syntax for string extraction in miqt-lupdate

    master

    The miqt-lupdate tool parses Go files to find translation contexts. It currently only supports raw string and integer parameter types within valid syntax structures. Common patterns include:

    • QCoreApplication_Translate("Context", "String")
    • WidgetName_Tr("String") (e.g., QPushButton_Tr")
    // Supported pattern 1
    l := NewQLabel3(QCoreApplication_Translate("Context", "My string to translate"))
    
    // Supported pattern 2
    p := NewQPushButton3(QPushButton_Tr("My string to translate"))
  6. How the MIQT Go API differs from Qt C++

    master

    While most functions are implemented 1:1 with the official Qt C++ API, there are key differences in how types, memory, and events are handled in Go:

    Container Types

    Qt containers are projected as native Go types:

    • QByteArray $\rightarrow$ []byte
    • QString $\rightarrow$ string (Must be UTF-8 to avoid corruption)
    • QList<T> / QVector<T> $\rightarrow$ []T
    • QMap<K,V> / QHash<K,V> $\rightarrow$ map[K]V (Note: Iteration order will differ from Qt's QMap)

    Memory Management

    When Qt returns a C++ object by value (e.g., QSize), MIQT may move it to the heap and represent it as a pointer in Go. A Go finalizer is automatically added to handle deletion.

    Events and Signals

    • Signals: The C++ connect(source, signal, target, slot) is projected as targetObject.onSourceSignal(func()...).
    • Virtual Methods: You can override virtual methods (like PaintEvent) using the same pattern. The callback receives super() as the first argument to call the base class implementation.

    Class Pointers and Inheritance

    • Inheritance: Qt classes are projected as Go embedded structs. To pass a subclass to a function expecting a base class, use the base class field (e.g., myLabel.QWidget).
    • Shadowing: If a subclass adds an overload, the base class version is shadowed. Access it via the base class field (e.g., myQMenu.QWidget.AddAction(QAction*)).
    • Pointer Equality: Because MIQT pointers wrap Go structs, direct comparison like QTabWidget.CurrentWidget() == MyTab will fail. Instead, compare raw pointers using .UnsafePointer(): QTabWidget.CurrentWidget().UnsafePointer() == MyTab.UnsafePointer()

    Multithreading

    MIQT automatically calls runtime.LockOSThread() when qt.NewQApplication is first called to bind the Go runtime to the Qt main thread. When accessing Qt objects from other goroutines, use (qt6/mainthread).Wait() or Start() to ensure execution on the main thread.

  7. How genbindings works

    master

    The genbindings program is used to regenerate the Qt bindings through a two-pass architecture:

    Pass 1: AST Extraction and Transformation

    1. Scanning: Scans input directories for header files.
    2. Clang AST Generation: Runs clang --ast-dump=json to generate a JSON AST for each header. Results are cached in ./cachedir to speed up subsequent runs.
    3. Filtering: Strips Clang AST nodes included from other files to focus only on the header's own definitions.
    4. IR Conversion: Converts the Clang AST into an internal intermediate representation (IR).
    5. Transformation: Applies transformations to the IR.
    6. Global State Collection: Caches and collects global state for all known class names, enum names, and typedefs.

    Pass 2: Code Emission

    1. CABI Emission: For each IR AST, it emits a "CABI" (C-style ABI) C++/H pair. This projects Qt into plain C, allowing the header to be used with extern c.
    2. Go Binding Emission: Emits Go binding files that use CGO to call into the CABI bindings.
  8. Build MIQT on Windows using miqt-docker

    master

    The easiest way to build for Windows is using the miqt-docker tool, which provides pre-configured environments for various Qt and linking configurations.

    1. Install the tool:
      go install github.com/mappu/miqt/cmd/miqt-docker@latest
    2. Run the desired build command:
      • Qt 5 Dynamic: miqt-docker win32-qt5-dynamic -windows-build
      • Qt 5 Static: miqt-docker win32-qt5-static -windows-build --tags=windowsqtstatic
      • Qt 6 Static: miqt-docker win64-qt6-static -windows-build --tags=windowsqtstatic
    go install github.com/mappu/miqt/cmd/miqt-docker@latest
    miqt-docker win64-qt6-static -windows-build --tags=windowsqtstatic
  9. Build MIQT for Android

    master

    MIQT supports Android compilation via miqt-docker, which handles the bridging between Java, C++, and Go.

    1. Install the tool:
      go install github.com/mappu/miqt/cmd/miqt-docker
    2. Run the Android build:
      miqt-docker android-qt5 -android-build # For Qt 5
      # OR
      miqt-docker android-qt6 -android-build # For Qt 6
      This generates an .apk in the current directory with a default manifest, icon, and keystore. You can customize these files for subsequent builds.
    go install github.com/mappu/miqt/cmd/miqt-docker
    miqt-docker android-qt6 -android-build
  10. Build MIQT on Windows (MSYS2)

    master

    Using MSYS2 provides a managed way to install Go, C++ toolchains, and Qt via pacman.

    Dynamic Linking (UCRT64)

    1. Install toolchains and Qt:
      pacman -S mingw-w64-ucrt-x86_64-{go,gcc,pkg-config}
      # For Qt 5:
      pacman -S mingw-w64-ucrt-x86_64-qt5-base
      # For Qt 6:
      pacman -S mingw-w64-ucrt-x86_64-qt6-base
    2. Build:
      go build -ldflags "-s -w -H windowsgui"

    Static Linking (UCRT64, Qt 5 only)

    1. Install static Qt:
      pacman -S mingw-w64-ucrt-x86_64-qt5-static
    2. Configure environment for static linking:
      • Set PKG_CONFIG_PATH to the static pkgconfig directory.
      • Set CGO_LDFLAGS with the necessary paths to static libraries (e.g., -lqwindows, -lQt5FontDatabaseSupport, etc.).
      • Copy libzstd.a and libz.a to the static Qt library directory so pkg-config can find them.
    3. Build:
      go build -ldflags "-s -w -H windowsgui" --tags=windowsqtstatic
    # MSYS2 Dynamic Example
    pacman -S mingw-w64-ucrt-x86_64-{go,gcc,pkg-config}
    pacman -S mingw-w64-ucrt-x86_64-qt6-base
    go build -ldflags "-s -w -H windowsgui"
  11. Use pkg-config to bind third-party C++ libraries

    master

    MIQT relies on pkg-config to locate the C++ libraries it needs to bind. While Qt libraries typically provide their own .pc definitions, third-party libraries may not.

    Instead of using global environment variables like CGO_CFLAGS or CGO_LDFLAGS (which can cause conflicts when using multiple libraries), the recommended approach is to create a custom .pc file for your library and point pkg-config to it using the PKG_CONFIG_PATH environment variable.

    Both CGO and the genbindings tool respect the PKG_CONFIG_PATH variable.

    # Create a MyLibrary.pc file
    # Then run build with the path to the directory containing your .pc file
    PKG_CONFIG_PATH=/path/to/dir/ go build
  12. Build MIQT on macOS

    master

    Using Homebrew (Dynamic Linking)

    1. Install dependencies:
      xcode-select --install
      brew install golang pkg-config qt@5
    2. Build:
      go build -ldflags '-s -w'
      Note: If pkg-config errors occur, ensure you have applied the environment variables suggested by the brew install pkg-config output.

    Using Docker (Cross-compilation)

    1. Build the cross-compilation container (from the docker/ directory):
      docker build -t miqt/osxcross:latest -f macos-cross-x86_64-sdk14.5-go1.19-qt5.15-dynamic.Dockerfile .
    2. Run the build:
      docker run --rm -v $(pwd):/src -w /src miqt/osxcross:latest go build -ldflags '-s -w'
    3. Copy necessary Qt LGPL libraries and plugin files to the output.
    # macOS Homebrew Dynamic Build
    xcode-select --install
    brew install golang pkg-config qt@5
    go build -ldflags '-s -w'