How to combine .metal and .swift in the same package - swift

I created a MacOS command line app that defines and successfully calls a Metal kernel. I'm now trying to move this app's .metal and .swift logic into its own package so that it can used in other projects. I expected I would be able to create a Swift package, add my .metal and .swift logic and build/test it with no issues but this has not been the case.
In Xcode I created a new package (File->New->Package). After the package was created I tried to add a Metal file (right-click on sources -> New File). I opened the macOS tab in the window and tried to find a .metal template file but there was no result. I then just tried copy/pasting my .metal file into the sources and that worked but when I went to build I got an error
CompileSwiftSources normal x86_64 com.apple.xcode.tools.swift.compiler (in target '...' from project '...')
...
swiftc -incremental -module-name ...
...
Command CompileSwiftSources failed with a nonzero exit code
How can I add and build .metal files as part of my Xcode Swift package? I can't seem to find what I'm missing. I've found examples of packages on GitHub that have a combination of Metal and Swift in them and I managed to get this one (Metal in sources/other) to compile on my computer in Xcode.

Have you updated your Swift package file?
.metallib file (Bundle.module) is only available once you have specified your resources in the package manifest.
Package.swift:
.target(
name: "TargetName",
dependencies: [],
resources: [.process("ThePathToYour/Shader.metal")]
)

Related

Exporting Package.swift for Swift Package Manager from existing Xcode project

I'm working with Xcode 11.3 on macOS Catalina 10.15.6.
I have an existing Xcode project which builds an app for iOS. I am interested in reusing some of the classes in an interactive session with the swift command line interpreter. The classes I want to work with are Core Data classes which are autogenerated from an Xcode data model and also some classes I've written which work with the Core Data classes. The app has UI screens and makes use of UIKit but I'm not trying to use any of those classes; I'm hoping that I can either compile those classes and then not refer to them, or somehow tell Swift Package Manager to ignore those classes altogether.
What I think I would like to do is to export a Package.swift for the existing Xcode project, such that swift build at the command line would be able to compile all of the project classes, or, failing that, at least the non-UI classes, and then swift run --repl would be able to load the classes via import.
I see a menu item in Xcode to create a new Swift package, but not to export an existing project. Is there a way to export an existing project?
There are no a menu command or utility to convert application to a static library, dynamic framework or swift package since they are different types of projects with different settings etc.
If you want to export a part of your project as a swift package you should make next steps manually:
1. Create Package.swift file in the root of your project
import PackageDescription
let package = Package(
name: “MyLib”,
products: [
.library(name: "MyLib", targets: ["MyLib"])
],
targets: [
.target(name: "MyLib"),
],
...
)
2. Make folder with subfolder ./Sources/MyLib under the projects’s root.
By default swift package structure requires to put all your sources files under Sources/LibraryName folder but you can change it below.
NOTE: you can simplify first two steps by using swift package init and it creates Package.swift, Sources and Test folders etc.
3. Include source files
a) Move the needed files to share from their current locations to MyLib folder.
For instance:
./Classes/MyEntity.swift -> ./Sources/MyLib/MyEntity.swift
Also you have to update locations of the moved files in your Xcode project to leave it compilable.
b) Use path, sources and exclude to point needed source files to your package from their current locations:
.target(name: "MyLib", path: "Classes"),
NOTE: Don't forget to make your classes public to access to them after import your package:
public class MyEntity {
...
}
After all you will have two working projects - old XCode's one and new Swift package.
4. REPL
Now you can use command line interpreter with your swift package:
swift run --repl
import MyLib
let entity = MyEntity()
...

Package Loading: "Ignoring duplicate product" (SwiftPM)

I'm trying to build a Swift package using the Swift Package Manager.
However, when I open the package in Xcode and click Run, I get the following warning:
How can I resolve this?
This is an issue often encountered if you are attempting to build a library/framework but also have a main.swift file in your target's root directory, like so:
.
The presence of a main.swift file makes SwiftPM believe that you are attempting to build a command line tool, and thus complains about the unnecessary (duplicate in name) library produced.
This warning may be confusing as it does not occur in projects initialized with the dynamic framework template from Xcode, for iOS, macOS, tvOS or watchOS.
In my case it was because I had the same name in both the products section and the Package e.g.
let package = Package(
name: "Example",
products: [
.library(
name: "Example",
targets: ["Example"]),
],
)
This seems to be the default behavior of swift init for some reason. I removed the .library entry and the warning went away.

Error in Build After InAppPurchase Unity

CommandInvokationFailure: Unable to merge android manifests. See the Console for more details.
C:/Program Files/Java/jdk1.8.0_161\bin\java.exe -Xmx2048M -Dcom.android.sdkmanager.toolsdir="C:/Users/Sabasoft Developer/Downloads/tools_r25.2.3-windows\tools" -Dfile.encoding=UTF8 -jar "D:\Unity\Editor\Data\PlaybackEngines\AndroidPlayer/Tools\sdktools.jar" -
stderr[
]
stdout[
Warning: [Temp\StagingArea\AndroidManifest-main.xml:12, D:\unity projects\Pizza maker\Temp\StagingArea\android-libraries\GooglePlay\AndroidManifest.xml:3] Main manifest has but library uses targetSdkVersion='24'
]
exit code: 1
Update Java SdK
Update Android SdK
Check target in menifest file and Unity editor. Both should be same.
Remove duplicate .jar under plugins folder if there are any.
You are using a library somewhere in your code (possibly something for GooglePlay?). The library has a manifest.xml file that is likely located in a folder called plugin or one of its subfolders.
The manifest is the file used by android to describe the app: how it starts, what permissions it has, and so on.
Any android project in unity will include a default manifest.xml file. This file is edited by unity with some info relative to you game (the name, and the target version, are part of it).
Now, the libraries you include in your project might need different options and values in the manifest, so Unity libraries for android usually come with another manifest.xml file. This will will be automatically merged with the default one by unity at build time.
Usually, it goes well, the additional line in the manifest from the library get added to the default manifest.
But in your case, there is a conflict between these manifests. The target version is specified both in the library and in your project. So unity can't resolve it.
To fix this, use a target version for your project that is the same or higher than the one of the library. Edit your target version under player settings

How to generate a framework from a SwiftPM-generated XCode project?

I used SwiftPM to set up an XCode project for a framework; based on
// swift-tools-version:4.0
import PackageDescription
let package = Package(
name: "MyThing",
products: [
.library(
name: "MyThing",
targets: ["MyThing"]),
],
dependencies: [
],
targets: [
.target(
name: "MyThing",
dependencies: [])
)
I ran swift package generate-xcodeproj and then pod install (based on a Podfile whose content shouldn't matter). I obtain MyThing.xcworkspace.
Now I figured that
xcodebuild -workspace MyThing.xcworkspace -scheme MyThing clean build
should create the .framework -- but it doesn't, only a binary file appears. I suspect some automatism is at work here since the source folder contains a file named main.swift, among others.
What do I have to do to get the framework built?
I need to script the whole process, to please no manual workarounds.
As of Swift 4.0 swift package generate-xcodeproj doesn't automatically generate schemes for all targets, but still makes those targets accessible from Xcode.
If creating a new scheme manually once is acceptable, you can do so and add your framework target as a scheme build target.
Otherwise, new schemes can be created programmatically with libraries like xcodeswift/xcproj, which allow you to parse a newly generated Xcode project and generate a new scheme with its XCSharedData class.
After that new framework scheme is created you can run the build with xcodebuild -workspace MyThing.xcworkspace -scheme MyThingFramework clean build.
Mixing script files and framework code in one target seems to confuse SwiftPM. Moving main.swift out of the source folder clears up things.
Scheme MyThing-Package creates all build products as specified in Package.swift, including the framework.
If you want to have the script files in the same XCode Workspace (for editing convenience), put them in their own target. You can even create an executable product (which won't create anything useful since an executable can't link to dynamic frameworks).

Swift Package Manager - How to use it

I have a project that I want to use this package in my app. I googled and follow the instructions:
//in Terminal
? mkdir SGLMath
? cd SGLMath
? swift package init --type executable
Then I open the package.swift file and change to this:
// swift-tools-version:3.1
import PackageDescription
let package = Package(
name: "SGLMath",
dependencies: [
.Package(url: "https://github.com/SwiftGL/Math.git", majorVersion: 1)
]
)
then Terminal:
? swift package fetch
Then I got this error:
error: the package has an unsupported layout, unexpected source
file(s) found:
/Users/xuanxi/SGLMath/.build/checkouts/Math.git-9167533630816302265/Tests/EqualWithAccuracy.swift,
/Users/xuanxi/SGLMath/.build/checkouts/Math.git-9167533630816302265/Tests/FunctionsTests.swift,
/Users/xuanxi/SGLMath/.build/checkouts/Math.git-9167533630816302265/Tests/Matrix2x2Tests.swift,
/Users/xuanxi/SGLMath/.build/checkouts/Math.git-9167533630816302265/Tests/Matrix3x3Tests.swift,
/Users/xuanxi/SGLMath/.build/checkouts/Math.git-9167533630816302265/Tests/Matrix4x4Tests.swift,
/Users/xuanxi/SGLMath/.build/checkouts/Math.git-9167533630816302265/Tests/SwizzleTests.swift,
/Users/xuanxi/SGLMath/.build/checkouts/Math.git-9167533630816302265/Tests/Vector2Tests.swift,
/Users/xuanxi/SGLMath/.build/checkouts/Math.git-9167533630816302265/Tests/Vector4Tests.swift,
/Users/xuanxi/SGLMath/.build/checkouts/Math.git-9167533630816302265/Tests/glmMatrixTests.swift
fix: move the file(s) inside a module
How can I resolve this?
What if I want to add this package into my existing Xcode project?
The project https://github.com/SwiftGL/Math.git does not have the correct Swift Package Manager format. The files in Tests directory should be in a directory with name: the module name + "Tests" ending appended, in this case SGLMathTests. You can fork the project and fix it or ask the author to fix it.
To use the project with Xcode, once you fix it:
a. Run swift package generate-xcodeproj. It will generate an Xcode project with the package.
b. Create an Xcode workspace and add to it your existing Xcode project and the generated project in the previous step. Add the framework with the package from the generated project to your existing Xcode project as a dependency. This should work.