How to add a Package.swift into a CommandLine projects? - swift

I currently have a XCodeProj but want to use the Package.swift file to add dependencies for other libraries.
This project currently generates a binary as a target file, then the binary file takes in arguments and runs some things based on the arguments. The main reason to use the Package.swift is for me to use the argparser using Vapor (not the base ArgumentParser because you have to do the swift run..) or other argument parser libraries.
How can I correctly add the Package.swift file to the XCodeProj? Or how can I add packages to this XCodeProj?

Related

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

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")]
)

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()
...

Is it possible to run a swift file in terminal, including a Swift Package?

Let's say I have a swift package located at examplefolder/mypackage/ and a swift file examplefolder/file.swift. Can I include the package mypackage somehow, when I run the swift file with
swift examplefolder/file.swift
, like I could include it in another package by adding
.package(url: "examplefolder/mypackage", .branch("master"))
to the Package.swift file?

How to import library into swift code used in CLI?

What I want to do
I want to try to get son file through API by swift library on CLI.
I am using the library, Alamofire, but I can't understand how to import swift library.
Maybe some tasks are needed before import (building? linking?) but I can't find how to document...
Could you teach me how to do it?
Problem
$ swift getAPI.swift
getAPI.swift:1:8: error: no such module 'Alamofire'
import Alamofire
^
Sourcecode
import Alamofire
func getArticles(){
Alamofire.request(.GET, "https://qiita.com/api/v2/items")
.responseJSON { response in
print(response.result.value )
}
}
getArticles()
This should help with running one-off scripts and when using the Swift REPL. However, for building simple tools for the command line, I would recommend using the Swift Package Manager since it takes care of the linking and dependency management for you.
To link your script code to the Alamofire library, the swift compiler has to know where to the library is located. By default it searches /Library/Frameworks, but we can supply options to tell it where else to look. Checking swift --help, we see the following options (among many others).
USAGE: swift [options] <inputs>
OPTIONS:
-F <value> Add directory to framework search path
-I <value> Add directory to the import search path
-L <value> Add directory to library link search path
The directory you supply must to contain the compiled binaries of the libraries you want to import.
To import .swiftmodule binaries, use -I
To import .framework binaries, use -F
For linking to libraries like libsqlite3.0.dylib, use -L
I think Carthage and CocoaPods will build frameworks, whereas the Swift Package Manager will build .swiftmodules. All three should put the binaries in very predictable locations. Different kinds of binaries may all be in the same and that's okay.
Putting it all together, if you build with SPM, your invocation might look like this:
$ swift -I .build/debug/
But if you manage dependencies with Carthage, it might look something like this:
$ swift -F ./Carthage/Build/iOS
For further reading, I found these resources useful:
krakendev.io/blog/scripting-in-swift
realm.io/news/swift-scripting/
Update: The Swift package manager can now take care of this for you as well! If you're writing a script as a package and include a bunch of dependencies, like Alamofire, you can now test them out in the REPL. Just cd into your package directory and launch it using swift run --repl. See the swift.org blog for more details.

SwiftPM: How to setup Swift module.map referring to two connected C libraries

I'm trying to build a Swift Package Manager system package (a module.modulemap)
making available two system C libraries where one includes the other.
That is, one (say libcurl) is a base module and the other C library is including
that (like so: #include "libcurl.h"). On the regular C side this works, because
the makefiles pass in proper -I flags and all is good (and I could presumably
do the same in SPM, but I'd like to avoid extra flags to SPM).
So what I came up with is this module map:
module CBase [system] {
header "/usr/include/curl.h"
link "curl"
export *
}
module CMyLib [system] {
use CBase
header "/usr/include/mylib.h"
link "mylib"
export *
}
I got importing CBase in a Swift package working fine.
But when I try to import CMyLib, the compiler complains:
error: 'curl.h' file not found
Which is kinda understandable because the compiler doesn't know where to look
(though I assumed that use CBase would help).
Is there a way to get this to work w/o having to add -Xcc -I flags to the
build process?
Update 1: To a degree this is covered in
Swift SR-145
and
SE-0063: SwiftPM System Module Search Paths.
The recommendation is to use the Package.swift pkgConfig setting. This seems to work OK for my specific setup. However, it is a chicken and egg if there is no .pc file. I tried embedding an own .pc file in the package, but the system package directory isn't added to the PKG_CONFIG_PATH (and hence won't be considered during the compilation of a dependent module). So the question stands: how to accomplish that in an environment where there libs are installed, but w/o a .pc file (just header and lib).