stackotter / swift-cross-ui

A cross-platform declarative UI framework, inspired by SwiftUI.
https://stackotter.github.io/swift-cross-ui/documentation/swiftcrossui/
MIT License
652 stars 36 forks source link

Make all products/targets visible to consumers. #76

Closed furby-tm closed 7 months ago

furby-tm commented 8 months ago

The Problem

error: target GtkBackend does not exist in package swift-cross-ui.

The way to prevent this error from happening is for consuming users to implement something like the following to reference swift-cross-ui in their own Package.swift manifests in a way that doesn't break a user's existing SwiftPM package:

public static func pkgDeps() -> [Package.Dependency]
{
  #if os(Linux) || os(Android) || os(OpenBSD) || os(FreeBSD) || os(Windows) || os(Cygwin)
    [
      .package(url: "https://github.com/stackotter/swift-cross-ui", revision: "dd09e61")
    ]
  #else
    []
  #endif
}

public static func backend() -> [Target.Dependency]
{
  #if os(Linux) || os(Android) || os(OpenBSD) || os(FreeBSD) || os(Windows) || os(Cygwin)
    [
      .product(name: "SwiftCrossUI", package: "swift-cross-ui", condition: .when(platforms: [.linux, .windows])),
      .product(name: "GtkBackend", package: "swift-cross-ui", condition: .when(platforms: [.linux, .windows])),
    ]
  #else
    []
  #endif
}

The Solution

Use Case

Now in my own SwiftPM project I can do the following without inducing the error noted above:

  // maintaining the "standard" method of adding SwiftPM dependencies
  // to an existing SwiftPM project is what is demonstrated here.

  ...
  dependencies: [
    .package(url: "https://github.com/furby-tm/swift-cross-ui", revision: "a26353e")
  ],
  targets: [
    .executableTarget(
      name: "MyReallyEpicCrossPlatformApp",
      dependencies: [
        .product(name: "SwiftCrossUI", package: "swift-cross-ui", condition: .when(platforms: [.linux, .windows])),
        .product(name: "GtkBackend", package: "swift-cross-ui", condition: .when(platforms: [.linux, .windows])),
      ]
    ),
  ]

Potential Drawback

You will now have to preprocess all backend-dependent Swift code in swift-cross-ui if you wish to be able to build the whole package (swift build) (now that specifying a specific target is a prerequisite (swift build --target GtkBackend)) like the following:

// for any file that uses anything from 'Gtk'.
#if canImport(Gtk)
  import Gtk

  // many lines of swift code.
  // many lines of swift code.
  // many lines of swift code.
  // many lines of swift code.
#endif /* canImport(Gtk) */

However, it appears that supporting swift build to "target" the whole package was not something that was working anyway from the latest SPI build results, so this drawback seems unsubstantial.

stackotter commented 7 months ago

I've just pushed some changes that I've had locally for a little while and I believe that they fix the same issue (although possibly slightly differently). I ended up implementing a SwiftPM plugin that checks the system dependencies so that instead of the disgusting couldn't build Objective C module CGtk error or whatever SwiftPM spits out, you get something saying that you need to install gtk to use the GtkBackend (and similarly for other backends). Feel free to open an issue if the changes don't fix the issue that you were trying to fix!

stackotter commented 7 months ago

Hmm, annoyingly the plugin seems to run for QtBackend even if you're only using the GtkBackend and vice versa 😭 I'll remove it for now even though the errors you get are terrible:

warning: couldn't find pc file for Qt5Widgets
Building for debugging...
/Users/stackotter/Desktop/Projects/Swift/SwiftCrossUI/.build/checkouts/qlift/Sources/CQlift/qlift-dispatchToQThread.cpp:8:10: fatal error: 'QTimer' file not found
#include <QTimer>
         ^~~~~~~~
1 error generated.