export custom swift module - xcode

I've made a little module in Swift and I want to use it in other projects. Do I have to simply copy the name_of_module.a, name_of_module.swiftmodule and name_of_module.swiftdoc files in the folder of the new project?
Thanks

Swift packages and modules are used a bit differently than .frameworks did in Obj-C if that's what you've been using. Currently, modules are included via reference in your project's manifest file Package.swift.
This manifest file get called and dependencies' modules are used during .build (and by extension .debug).
The following is an example of a package.swift manifest file:
import PackageDescription
let package = Package(
name: "DeckOfPlayingCards",
targets: [],
dependencies: [
.Package(url: "https://github.com/apple/example-package-fisheryates.git",
majorVersion: 1),
.Package(url: "https://github.com/apple/example-package-playingcard.git",
majorVersion: 1),
]
)
Here the two dependencies (modules) are added to this project by a URL reference in git form. If you're familiar with URL format, you can create a URL pointing to an address on your local machine of your local module rather than on github like the example above.
If you're concerned with sub-dependencies or want to learn more, read Apple's Swift docs on this (https://swift.org/package-manager/#conceptual-overview)

Related

Is there a way to generate dSYMs for Swift Packages when Xcode archiving?

In the past when I've used Cocoapods to manage dependencies, archiving an app would put the frameworks in the dSYM folder of the archive. I would have one dSYM for the app, and one dSYM for each dependency. When using SPM, the archive dSYM folder only contains the app dSYM.
Is there a way to generate dSYMs for Swift Packages in the same way (or is my understanding wrong and this one dSYM contains everything)?
My configuration:
Xcode 13.2.1 (13C100)
OS 12.1 (21C52)
Debug Information Format = DWARF with dSYM File
Steps to reproduce:
Create a new Xcode project (macOS or iOS).
Check that Debug Information Format = DWARF with dSYM File
Add a dependency via SPM (https://github.com/hmlongco/Resolver).
Archive the project.
Open xxx.xcarchive/dSYMS
Notice only one dSYM for app but none for dependency.
It depends how your dependencies are linked into your app.
If you use Cocoapods with use_frameworks! all dependencies will be compiled as separate dynamic frameworks and will put into Frameworks folder inside your app and in this case XCode can generate dSYM files for each of them. But when you link your libraries statically the symbolication info is put into "YourApp.dSYM" file because libraries code is injected inside your app’s binary.
The same works with SPM. By default swift packages are compiled as static libraries so that its binaries will be inserted in your app's binary and all symbolication info will be inside "YourApp.dSYM" under __swift_ast section.
To make your package as dynamic library you should state it implicitly inside Package.swift file and after XCode can generate dSYM for it, e.g.:
let package = Package(
name: "MyDynamic",
products: [
.library(
name: "MyDynamic",
type: .dynamic,
targets: ["MyDynamic"]),
],
…
But if you want to link already static third party package dynamically you can make you own local dynamic package (wrapper) with needed static dependencies, for instance with Realm:
let package = Package(
name: "MyDynamic",
platforms: [
.iOS(.v12),
],
products: [
.library(
name: "MyDynamic",
type: .dynamic,
targets: ["MyDynamic"]),
],
dependencies: [
.package(name: "Realm", url: "https://github.com/realm/realm-swift.git", from: "10.28.1")
],
targets: [
.target(
name: "MyDynamic",
dependencies: [.product(name: "RealmSwift", package: "Realm")]),
.testTarget(
name: "MyDynamicTests",
dependencies: ["MyDynamic"]),
]
)
Next add it to your app (File > Add Packages… > Add local..) and then you can use Realm as usual inside your code because all MyDynamic dependencies are public to your app:
import RealmSwift
func load() {
let realm = try? Realm()
…
}
And “MyDynamic.framework.dSYM” will be generated and has all Realm symbolication info.

Getting 'no such module' error when importing a Swift Package Manager dependency

I'm running Xcode 11 Beta 4.
I'm using CocoaPods, and wanted to use one of my dependencies with Swift Package Manager as a static library instead of as a framework.
On a fresh project created with Xcode 11, the dependency can be imported successfully, but on my existing CocoaPods workspace, it does not.
I think it's likely related, but I'm also getting this link warning in Xcode:
directory not found for option '-L/Users/username/Library/Developer/Xcode/DerivedData/App-axanznliwntexmdfdskitsxlfypz/Build/Products/Release-iphoneos
I went to see if the directory exists after the warning is emitted, and it does.
I could not find any meaningful difference between the newly-created project and my old one, other than the existence of CocoaPods.
Would appreciate any pointers.
After adding a library (FASwiftUI in my case) through Swift Package Manager I had to add it to
Project Settings -> My Target ->
General -> Frameworks, Libraries, and Embedded Content
to be visible in the import statement.
I did not add any scripts for it to work.
Based on #AlexandreMorgado answer it seems like it is better to run this script in Build phases before Compile Sources. Then it works when archiving.
if [ -d "${SYMROOT}/Release${EFFECTIVE_PLATFORM_NAME}/" ] && [ "${SYMROOT}/Release${EFFECTIVE_PLATFORM_NAME}/" != "${SYMROOT}/${CONFIGURATION}${EFFECTIVE_PLATFORM_NAME}/" ]
then
cp -f -R "${SYMROOT}/Release${EFFECTIVE_PLATFORM_NAME}/" "${SYMROOT}/${CONFIGURATION}${EFFECTIVE_PLATFORM_NAME}/"
fi
Solution
let package = Package(
name: "PackageName",
dependencies: [
// YOU MUST ADD THE DEPENDENCY BOTH HERE [1] AND BELOW [2]
.package(url: "https://github.com/mattmaddux/FASwiftUI", from: "1.0.4")
],
targets: [
.target(
name: "PackageName",
/*[2]*/ dependencies: ["FASwiftUI"], // [2] <<<--------- Added here as well
]
)
Explanation
I'm developing a Swift package that must provide FontAwesome Icons to whoever imports it.
I was getting "No such module 'FASwiftUI'" in my SwiftUI preview canvas.
I solved it by adding "FASwiftUI" to BOTH the dependencies array of the package AS WELL AS to the dependencies array in the target itself.
Full Package.swift File
// swift-tools-version:5.3
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "PackageName",
platforms: [
.macOS(.v11),
.iOS(.v14)
],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "PackageName",
targets: ["PackageName"])
],
dependencies: [
// Dependencies declare other packages that this package depends on.
.package(url: "https://github.com/nalexn/ViewInspector", from: "0.8.1"),
.package(url: "https://github.com/mattmaddux/FASwiftUI", from: "1.0.4")
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "PackageName",
dependencies: ["FASwiftUI"], // <<<--------- Added this here
resources: [
.process("Assets")
]
),
.testTarget(
name: "PackageNameTests",
dependencies: ["PackageName", "ViewInspector"])
]
)
It turned out that Swift Package Manager implicitly depends on the project's Configuration names. I had them at live/qa instead of Release/Debug, and changing them back resolved the issue. Very odd, but I hope it saves you some trouble dear reader.
After a whole week fighting this issue, I developed a workaround using schemes and pre-actions.
I have a configuration called "Beta", so Xcode can't compile SPM dependencies. I realised Xcode compile SPM dependencies as Swift modules and add the files in Build/Products/Release-iphoneos folder in DeriverData.
So I created a scheme in Xcode and added this run script on build pre-actions:
cp -f -R "${SYMROOT}/Release${EFFECTIVE_PLATFORM_NAME}/" "${SYMROOT}/${CONFIGURATION}${EFFECTIVE_PLATFORM_NAME}/"
This script run before the build process, copying files and modules generated by Xcode on default Release-iphoneos folder to configuration folder, Beta-iphoneos, in my case.
After coping the content from Release-iphoneos to your $configuration$-iphoneos folder Xcode should correctly compile, build and run your project.
I just ran into a similar problem and discovered that my schemes referenced old configurations, configurations that no longer existed. Once I updated them to the correct configurations the build succeeded.
(I'm leaving this comment more than a year after the original post. It's possible that what I ran into is completely different from what was originally reported. Still, it took me quite a while to track the problem down, so I wanted to leave a note that might save others time.)
Clearing the derived data solved the issue in my case. I have Microsoft Azure Devops CI Pipeline, to clear the derived data I have to edit the Xcode build task and in the "Actions" field add this command: clean.
What worked for me: I removed my import WebMIDIKit line and added it again.
Based on #sliwinski.lukas's answer, in my case the ${CONFIGURATION} was outputting "Release", so it was just copying the Release folder itself which was no good. I simply hardcoded my configuration name, and flipped Release and MyConfiguration, and it worked. I put the following code right before "Compile Sources" in the "Build Phases" tab:
cp -f -R "${SYMROOT}/MyConfiguration${EFFECTIVE_PLATFORM_NAME}/" "${SYMROOT}/Release${EFFECTIVE_PLATFORM_NAME}/" || true
Also importantly, I had to add this in the project that used the SPM and not in the main app.
I just ran into a similar problem when running xcodebuild from the command line. I was passing CONFIGURATION_BUILD_DIR=build but found that it needs to be an absolute path: CONFIGURATION_BUILD_DIR=$(pwd)/build solved the problem.
Might I shed a bit more light on your plight...
I'm working on a fairly large iOS app (6680 files) whose result is composed of many frameworks and a mixed bag of podfiles, swift packages, legacy ObjC code (that still outnumbers newer Swift stuff).
Whenever we deal with swift packages, we need to wrap them in frameworks because it simplifies podfile & dependency resolutions when we have our remote (Jenkins) build system eat everything up to spew binaries for internal QA & ultimately, Enterprise & AppStore publishing.
Earlier today, I was dealing with one such swift package wrapped in a framework and all the issues listed above hit me square in the face.
After stashing, pushing usable code and then reapplying my stashed framework wrapper to the swift package, I used a different route than opening our project's workspace where a bunch of projects and targets are collected.
Opening the lone framework wrapper seems to have kicked XCode (13.3.1) into submission and at that point, the target settings "Frameworks, Libraries and Embeddable" section was actually able to display the swift package's "Foo" binary. Added it, and then everything was playing nice.
So, if you're still having problems, try simplifying the problem by opening smaller morsles if you can. Or start making these wrapper frameworks (if it's at all possible) so that you can actually manage smaller bites before integrating them on XC's platter.
For me, I go to Xcode -> File (The one on mac top bar) -> Packages -> Update to Latest Package Versions. This solved my problem.
In order to keep incremental builds working I had to specify the output files of "Fix SPM" build phase like so:

golang modules and local packages

I'm trying to understand how to organize my golang project using go1.11 modules. I tried several options, but none of them worked.
I have some code in the main package under the application folder and a local package that the main package uses.
$GOPATH
+ src
+ application/
+ main/
+ main.go
+ otherFileUnderMainPackage.go
+ aLocalPackage/
+ someCode.go
+ someCode_test.go
+ someMoreCode.go
+ someMoreCode_test.go
Files in the main package, imports ../aLocalPackage. When I compile by go build main/*.go it's working.
Then, I ran go mod init application: V.0.9.9 and got the go.mod file, but the build always fails. I always get error about not finding the local package: build application:V0.9.9/main: cannot find module for path _/.../src/application/aLocalPackage. I also tried to place the local package right under src/, place it under main/ etc. but none of these methods worked for me.
What is the way to use modules and local packages?
Thanks.
Relative import paths are not supported in module mode. You will need to update your import statements to use a full (absolute) import path.
You should also choose a module name other than application. Your module path should generally begin with a URL prefix that you control — either your own domain name, or a unique path such as github.com/$USER/$REPO.
I had some problems working with local packages myself.
There are two tricks to make it work:
you run "go build" in the package directory
This compiles the package and places it in the build cache.
This link about code organisation in go explains more.
You can identify where the cache is using:
>go env GOCACHE
/home/<user>/.cache/go-build
Import using a path relative to the project
I puzzled loads over what the correct import path was and finally discovered that go doc or go list will tell you.
>go doc
package docs // import "tools/src/hello/docs"
>go list
tools/src/hello/docs
For example. I have a hello world API project and was using swaggo to generate documentation which it does in a docs sub-directory.
To use it I add an import:
_ "tools/src/hello/docs"
For my case the _ is important as docs is not used directly but we its init() function to be invoked.
Now in hello/main.go I can add "tools/src/hello/docs" and it will import the correct package.
The path is relative to the location of go.mod if you have one.
I have tools/ here as I have a go.mod declaring "modules tools".
Modules are a different kettle of fish - see https://github.com/golang/go/wiki/Modules.
Recent versions of go (1.11 and later) can create a go.mod file which you may use to fix the version of a module that is used and avoid go's crazy default behaviour of just downloading the latest version of any package you import.
I have written a blogpost on how to start your first Go project using modules.
https://marcofranssen.nl/start-on-your-first-golang-project/
In general it boils down to just create a new folder somewhere on your system (doesn't have to be in GOPATH).
mkdir my-project
cd my-project
go mod init github.com/you-user/my-project
This will create the go.mod file. Now you can simply create your project layout and start building whatever you like.
Maybe one of my other blogs can inspire you a bit more on how to do things.
https://marcofranssen.nl/categories/software-development/golang/

ModuleMap: How can I set a relative path for the umbrella header?

I am working with the Swift Package Manager. I have a project which I can successfully build via "swift build". I have created an Xcode project via "swift package generate-xcodeproj". When I open the project in Xcode it builds successfully.
The Xcode project includes two modules A and B.
Module A has the following map:
module ModuleA {
umbrella header "/Users/Robert/Temp/MyProject/Sources/ModuleA/include/ModuleA.h"
link "ModuleA"
export *
}
Module B depends upon A and has the following import:
import ModuleA
So far so good; everything builds successfully. Now I want to change the module map so that it uses a relative path, such as:
module ModuleA {
umbrella header "ModuleA.h"
link "ModuleA"
export *
}
However, when I do that I cannot get Module B to build: Error - Umbrella header 'ModuleA.h' not found. I have tried everything that I can think of in Build Settings -> Search Paths -> Header Search Paths and User Header Search Paths. I've found similar issues online, here and elsewhere, and have tried what I read but so far no go.
This has reached the hair pulling stage. Any advice will be much appreciated!
My guess is you're modifying the generated modulemap. Create a modulemap file at /Users/Robert/Temp/MyProject/Sources/ModuleA/include/module.modulemap containing:
module ModuleA {
umbrella header "ModuleA.h"
link "ModuleA"
export *
}
Run $ swift package clean to remove the old generated modulemap in .build directory and $ swift build to confirm that the custom modulemap works.
Then delete the generated Xcode project and re-generate it.

Building my own NativeScript app made of TypeScript and using external Telerik modules

I am building a simple NativeScript app, and am trying to do it using a TypeScript base code.
I am using Sublime Text 3 under OSX.
I realized by looking at the demo apps that the tns_modules matches the NativeScript repository so I added it to my app/ folder as a Git submodule, and then compiled it (npm i && grunt). Is that the wrong way to integrate these modules?
I then realized that I could not just run a tns emulate android of my app made of .ts files: I had to compile them too. So I set up a Grunt task to do so, but it was not easy to handle the dependencies. I ended up with this Gruntfile.coffee in app/:
module.exports = (grunt) ->
grunt.loadNpmTasks 'grunt-typescript'
grunt.config 'typescript',
build:
src: [
'**/*.ts'
'!*_modules/**'
]
options:
references: [
'tns_modules/bin/dist/definitions/**/*.d.ts'
]
target: 'es5'
sourceMap: false
declaration: false
module: 'commonjs'
noResolve: true
And it works with simple code, e.g. I'm able to extend a module like Observable by writing:
import observable = require("data/observable");
class Activities extends observable.Observable {
//...
}
I then compile with grunt (the .js files are created along with the .ts ones) and run with tns emulate android (with Genymotion emulator).
Is it the right architecture for my development? When I use Telerik Platform, the compilation process is hidden so I'm not sure I'm doing it right.
And now I'm trying to use Telerik's side-bar module directly in a page's XML file, the way they do it:
<Page xmlns="http://www.nativescript.org/tns.xsd" loaded="pageLoaded" xmlns:tsb="./tns_modules/bin/dist/apps/TelerikNEXT/TelerikUI/side-bar">
<tsb:SideBar title="MyApp">
...
But I get this error:
E/TNS.Native( 2456): TypeError: Cannot read property 'android' of undefined
E/TNS.Native( 2456): File: "/data/data/org.nativescript.scmobile/files/app/./tns_modules/bin/dist/apps/TelerikNEXT/TelerikUI/side-bar, line: 39, column: 39
Which corresponds to:
this._android = new com.telerik.android.primitives.widget.sidedrawer.RadSideDrawer(this._context);
Any idea how I should include these modules? Note that I'm new to mobile dev.
The sidebar, which they're using in the example, is a (payed) controller from Telerik.
As such, it needs to be downloaded and added with tns library add {ios|android} /path/to/the/sidebar.
This command will read project.properties file from the specified shared library folder and will add a reference to it in your project. If in turn the shared library has references to other projects then these projects will be included recursively. As a result, this will create a new folder lib which is sibling to already existing app and platforms.
http://docs.nativescript.org/runtimes/android/external-libs/resource-libs

Resources