Skip to content
torarnvPublic

About

Qt for Swift

Resources

Stars

17 stars

Watchers

1 watching

Forks

Repository files navigation

Qt for Swift

Use Qt from Swift. This package exposes every installed Qt 6 module to Swift so you can import QtCore, import QtWidgets, or import QtQuick and call Qt's C++ APIs directly from Swift code.

Requirements

Swift 6.4 or later

Shipped with Xcode, or installed via swiftly.

Important

This project heavily exercises the Swift C++ interoperability machinery and experimentalCGen build tool feature, and you may hit sharp corners. If possible, use a nightly Swift toolchain, to ensure the smoothest ride.

Qt 6.8 or later

Installed from the Qt Online Installer, system package manager (Homebrew, apt, etc), or your own local build.

Tip

If Qt has been installed outside of the system pkg-config location you can point the build to it via swift build --pkg-config-path <…> or by opening Xcode with a custom PKG_CONFIG_PATH set: open --env PKG_CONFIG_PATH=<…> -a Xcode

Platforms

The package has been tested on macOS and Linux

Installation

Swift Package Manager

Add the package to the dependencies in your Package.swift:

dependencies: [
    .package(url: "https://github.com/torarnv/qt-swift.git", branch: "main")
]

Then depend on the Qt modules you need, and turn on C++ interoperability in every target that imports Qt:

.executableTarget(
    name: "MyApp",
    dependencies: [
        .product(name: "QtWidgets", package: "qt-swift")
    ],
    swiftSettings: [
        .interoperabilityMode(.Cxx),
        .enableExperimentalFeature("ImportCxxMembersLazily")
    ]
)

Xcode project

Choose File → Add Package Dependencies, enter https://github.com/torarnv/qt-swift.git, and add the Qt modules you need to your app target.

Then turn on the same Swift settings as above, using a configuration file. Choose File → New → File from Template, pick Configuration Settings File, and name it Qt.xcconfig:

SWIFT_OBJC_INTEROP_MODE = objcxx
OTHER_SWIFT_FLAGS = $(inherited) -enable-experimental-feature ImportCxxMembersLazily

Select the project in the navigator, open the Info tab, and under Configurations set Qt as the configuration file of your app target, for both Debug and Release.

Features

Applications

Conform your @main type to QtApplication. The package creates the Qt application object, calls your init() to set up the UI, and then runs the event loop until the application quits.

import QtWidgets

@main
struct HelloWidgets: QtApplication {
    init() {
        // ...
    }
}

Strings

QString and Swift String convert in both directions, and QString accepts string literals and interpolation:

window.setTitle("Hello 🌍 from Qt \(QLibraryInfo.version())")
print(window.title())

Known Issues

  • swift build runs the module generator plugin on every target in Qt, regardless of which products the application depends on (swift-package-manager#10590)
    • The module generator tool itself is not run, but the plugin invocations alone add about 6 seconds to every build (even clean incremental ones)
    • To work around this, limit the products reported by the Qt for Swift package to those you depend on, via QT_SWIFT_MODULES="QtQuick" swift build
    • This is not an issue in Xcode, where the build plan prunes unused products before running build tool plugins
  • Swift's C++ importer eagerly imports members, resulting in import cycles
    • For Swift 6.5 the default has been changed to import members lazily
    • Ealier toolchains need to explicitly set .enableExperimentalFeature("ImportCxxMembersLazily")
  • Swift 6.4 does not import constructors with optional arguments in reference types (swift#92685)
    • These are very common in Qt, due to the default parent of e.g. QObject(QObject *parent = nullptr)
    • The fix is in Swift main snapshots, so please use a recent snapshot if possible
  • Swift 6.4 cannot upcast a derived reference type to its base class, e.g. QWidget to QObject (swift#80231)
    • This makes APIs taking a base class pointer unreachable from a subclass-typed value
    • The fix is in Swift main snapshots, so please use a recent snapshot if possible
    • As a workaround for 6.4 you can use unsafeBitCast(widget, to: QObject.self) for the primary base
  • Swift 6.4 can crash the compiler when calling an inherited method with an unnamed parameter, e.g. quickView.setTitle("...")
    • The fix is in Swift main snapshots, so please use a recent snapshot if possible
    • As a workaround for 6.4 you can call the method on the base type, e.g. unsafeBitCast(quickView, to: QWindow.self).setTitle("Hello")

Examples

The Examples directory holds small projects you can build and run:

  • HelloCore prints the Qt version
  • HelloWidgets shows a window using Qt Widgets
  • HelloQuick shows a Qt Quick scene

License

Qt for Swift is available under the terms of the GNU Lesser General Public License v3 (LGPL-3.0-only), or under a commercial Qt license. See the LICENSES directory for the full texts.

About

Qt for Swift

Resources

Stars

17 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages