Use swift package manager on existing xcode project
Asked Answered
C

3

27

im new to the swift and xcode world, so i'm having a problem trying to integrate a package to my project.

I want to add Alamofire dependency, with the following commands:

Inside my root project folder:

swift init

this creates the Package.swift file, i add the dependency inside, run then:

swift build

Everything seems to be ok, but im my project when i try to import my library:

import Alamofire

I get an error, it says that the module is not recognized. So my question here is, what is the correct steps to integrate Package Manager and a dependency on a existing project without crashing everything.

UPDATE:

swift build

outputs:

Resolved version: 4.3.0
Compile Swift Module 'Alamofire' (17 sources)
Compile Swift Module 'Sample' (1 sources)

And my Package.swift is:

import PackageDescription

let package = Package(
    name: "Sample",
    dependencies: [
        .Package(url: "https://github.com/Alamofire/Alamofire.git", majorVersion: 4)
    ]
)
Chigetai answered 27/1, 2017 at 18:33 Comment(7)
Try building it once and see if the error goes away.Mortar
can you please add your Package.swift file to you questionFitted
I've just added my Package.swift code, and i ran again the swift build command, seems to be correct, but the import doesn't work.Naif
Maybe you should edit your file under Source/ directory.Bret
Swift Package Manager is still in its infancy, you should use CocoaPods for now.Labana
swift package init i guessKarolekarolina
Definitely use only Carthage for now. And pray for a fast iOS -> SPM path :OVolcanism
B
15

Swift Package Manager is a standalone tool which allows managing dependencies and building projects without Xcode. It can generate Xcode projects for you with swift package generate-xcodeproj.

However, at the moment, Swift Package Manager only has support for building projects for macOS and Linux platforms. The only way to build projects for iOS, tvOS and watchOS is using Xcode, which includes the SDKs needed for these platforms.

There are ways to use Swift Packages Manager to manage dependencies for iOS/tvOS/watchOS, but it is not easy and requires manual work. If you are interested, take a look at https://github.com/j-channings/swift-package-manager-ios

Other than that, I'd recommend using Carthage or CocoaPods.

Update for Xcode 11

Swift Package Manager is now integrated into Xcode 11. You can add your package by going to "File" then "Swift Packages" then "Add Package Dependency..." Paste the repository's URL into the field above then click "next". Xcode will walk you through the rest of the steps. You can learn more at this WWDC talk.

Backlog answered 10/8, 2018 at 17:24 Comment(4)
here's another article on the topic ralfebert.de/ios-examples/xcode/…Volcanism
and click HERE stackoverflow.com/questions/47373001/…Volcanism
So, there's no overt Package.swift file when you use the Swift Package manager with an iOS project?Fiann
@ChrisPrince, there is, but it is hidden and maintained by Xcode behind the scenes. Once packages are resolved, you will want to add Packages.resolved to your source control repository.Backlog
A
23

If you're using an Xcode project, you don't need (and shouldn't use) a Package.swift, just click the plus icon in Swift Packages in Xcode, and add the GitHub URL of the Swift Package, and the library will also be added to your target automatically (follow the GIF below, or click Add icon in image here):

Extra info

  • Inconsistency problem: You can't maintain both an Xcode project and a Swift.package for the same targets. They do not synchronize, and will become inconsistent, so depending on which tools, you'll get different builds: confusing. You used to be able to create a xcodeproj based on Package.swift using swift package generate-xcodeproj, but this is deprecated. Changes you make to this Xcodeproj didn't get reflected in the original Package.swift).
  • xcodebuild vs. swift build: Conveniently, if there is no xcodeproj in the same directory as your Package.swift, xcodebuild will auto-generate schemes for you to use, so you don't have to use swift build. For example, run xcodebuild -list to see the list of schemes generated from your Package.swift file, then use one of these schemes. Unconveniently, there isn't a way/ config to make xcodebuild use Package.swift.
Akron answered 29/5, 2021 at 12:52 Comment(0)
B
15

Swift Package Manager is a standalone tool which allows managing dependencies and building projects without Xcode. It can generate Xcode projects for you with swift package generate-xcodeproj.

However, at the moment, Swift Package Manager only has support for building projects for macOS and Linux platforms. The only way to build projects for iOS, tvOS and watchOS is using Xcode, which includes the SDKs needed for these platforms.

There are ways to use Swift Packages Manager to manage dependencies for iOS/tvOS/watchOS, but it is not easy and requires manual work. If you are interested, take a look at https://github.com/j-channings/swift-package-manager-ios

Other than that, I'd recommend using Carthage or CocoaPods.

Update for Xcode 11

Swift Package Manager is now integrated into Xcode 11. You can add your package by going to "File" then "Swift Packages" then "Add Package Dependency..." Paste the repository's URL into the field above then click "next". Xcode will walk you through the rest of the steps. You can learn more at this WWDC talk.

Backlog answered 10/8, 2018 at 17:24 Comment(4)
here's another article on the topic ralfebert.de/ios-examples/xcode/…Volcanism
and click HERE stackoverflow.com/questions/47373001/…Volcanism
So, there's no overt Package.swift file when you use the Swift Package manager with an iOS project?Fiann
@ChrisPrince, there is, but it is hidden and maintained by Xcode behind the scenes. Once packages are resolved, you will want to add Packages.resolved to your source control repository.Backlog
W
1

Swift Package Manager(SPM)

[iOS Dependency manager]

Consume: [SPM manage dependency]

Produce: If you are developing library/module(modularisation) you should take care of supporting it

Package.swift - manifest file.

  • It is a hardcoded name.
  • Should be placed on the same level or higher, in other cases:
target '<target_name>' in package '<package_name>' is outside the package root

Package.swift example

// 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: "PackageName1",

    //Supported platforms
    platforms: [
        .iOS(.v11)
    ],
    
    //Product list - executable binary
    products: [
        .library(
            name: "LibraryName1",
            targets: ["TargetName1"]),
    ],

    //Additional SPM dependencies declaration(packages) which are used in targets
    dependencies: [

        //Local package path
        .package(name: "PackageName2", path: "../Feature1")

        //Local package URL
        .package(name: "PackageName2", url: "file:///some_local_path", .branch("master"))

        //Remote package URL
        .package(name: "PackageName2", url: "https://github.com/user/repo", .branch("master")),
    ],

    targets: [
        //Source code location. implicitly `Sources/<target_name>`(Sources/TargetName1) or explicitly `path:`
        .target(
            name: "TargetName1",
            dependencies: [
                //using dependencies from package.targets and package.dependencies

                //package.targets
                "LibraryName2"

                //package.dependencies
                .product(name: "PM2LibraryName1", package: "PackageName2")
            ]),
            path: "Sources/TargetName1"
    ]
)

Observations for Swift dependency

  • [SWIFT_MODULE_NAME, PRODUCT_NAME, EXECUTABLE_NAME] == package.targets.target.name
  • package.products.library.name is used only for Xcode representation
  • Library is used[About]
  • When target has a dependency on another target source code will be included into single library with a kind of explicit multi module from .modulemap[About] and access can be thought
import Module1
import Module2
  • Swift library converts into single .o format[About] file and .swiftmodule[About]
  • Swift library exposes .modulemap umbrella.h[About] for exposing module for Objective-C consumer thought @import SomeModule;
- You are able to work with `Package.swift` in Xcode if double click on it
.swiftpm/xcode with .xcworkspace will be generated 
- When you work with `Package.swift` you are able to check it, just save this file
- When you work with `Package.swift` you should specify schema and device(platform)
- When you build `Package.swift` 
  - library and .swiftmodule is located:
<path_to_derived_data>/DerivedData/<folder_name_where_Package.swift_located>-<randomizer>/Build/Products/<platform>
//e.g.
/Users/alex/Library/Developer/Xcode/DerivedData/someFolder-ccivqbbjujxuvdcxtuydyqfeepfx/Build/Products/Debug-iphonesimulator
  - .modulemap and umbrella.header is located:
<path_to_derived_data>/DerivedData/<folder_name_where_Package.swift_located>-<randomizer>/Build/Intermediates.noindex/<project_name>.build/<platform>/<target_name>.build/<.modulemap> and plus /Objects-normal/<arch>/<tarhet_name-Swift.h>

- When you build consumer with `Package.swift` results files will be located:
<path_to_derived_data>/DerivedData/<target_name>-<randomizer>/Build/Products/<platform>

- When you work with consumer of `Package.swift` SPM clones it into
<path_to_derived_data>/DerivedData/<target_name>-<randomizer>/SourcePackages/checkouts

package.products.library.targets

You are able to specify several targets. It means that it is possible to use several modules from single executable binary(a kind of umbrella library)

producer:
package.products.library.targets: ["TargetName1", "TargetName2"]

consumer: 
1. adds single library
2. several imports

import TargetName1
import TargetName2

package.targets.target.dependencies

If your target has dependency. You will have the same effect - Umbrella library.

1.Add another target from the same package

For example Explicit Dependency[About] is used. Important: use the same names(module and SPM target). If you don't set dependency at package.targets.target.dependencies you get next error

Undefined symbol

2.Add product from another package. All targets from the other package will be exposed

2.1 Local package path

You can not use on consumer side. But it allows you to debut it at least

package <package_name_1> is required using a revision-based requirement and it depends on local package <package_name_2>, which is not supported

2.2 Local package URL

Don't use space( ) in path or you get

The URL file:///hello world/some_local_path is invalid

If you don't specify // swift-tools-version:<version> you get:

package at '<some_path>' is using Swift tools version 3.1.0 which is no longer supported; consider using '// swift-tools-version:5.3' to specify the current tools version

*Do not forget commit your changes and update[About] before testing it

Waxman answered 1/4, 2021 at 19:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.