Hi Daniel, Thanks for the reply. Sorry I wasn't clear - by removal I actually meant remove pkgConfig from the Package, and introduce it in a custom build configuration (associated with a Target). I think pkgConfig and custom build configurations may fit nicely together. And you are absolutely right this is probably best suited for a follow on to the current manifest API redesign. Let's discuss that later and once again thank you for your quick reply.
Regards, Jens > On 28 Feb 2017, at 17.05, Daniel Dunbar <daniel_dun...@apple.com> wrote: > > >> On Feb 28, 2017, at 12:28 AM, Jens Nerup <j...@makecph.com >> <mailto:j...@makecph.com>> wrote: >> >> Hello Daniel, >> >> In general I’m really happy with the changes in the proposal and especially >> after you have incorporated the comments from David (Thanks David). In the >> proposal it is stated that the exclude section may be eliminated as soon as >> we have custom layouts. My question is: would pkgConfig be a candidate for >> removal as soon as we have support for custom build configurations? > > I don't think so, I don't think custom build configurations will be a > replacement for the pkgConfig functionality, which is trying to gather > settings from *outside* the package. > > I agree with the sentiment that it is an awkward thing to have the system > module map package initializer, but unfortunately I think we may have to live > with it for the time being. We have briefly discussed making it be a target > not a package thing, and perhaps the move to using `.target()` should > actually encourage us to do that, but that is probably something best done as > a follow on to the manifest API redesign (as with exclude) given its limited > scope. > > - Daniel > >> >> Regards, >> >> Jens >> >>> On 28 Feb 2017, at 01.50, Daniel Dunbar via swift-build-dev >>> <swift-build-...@swift.org <mailto:swift-build-...@swift.org>> wrote: >>> >>> Hi David, >>> >>> We discussed the leading-dot & capitalization issue today again... this was >>> already something we weren't really happy about, but had chosen to live >>> with (using the "identity" rule to determine what was a type and what >>> wasn't). However, as we talked it over more we: >>> 1. Felt that for the product types, using .library vs .Library would be >>> reasonable and consistent with a user model of thinking of these like enums >>> (even though they won't actually be in practice, we will use factory >>> functions on Product to make the dot work and keep the space extensible). >>> 2. Realized that using .target would be a useful change to make now if we >>> ever ended up needing to make the Targets array polymorphic (not something >>> we plan to do now, but it never hurts to have it be extensible). >>> so we decided to go ahead and revise to a model where we use leading-dot + >>> lowercase for everything (except Package), including reverting >>> SystemPackageProvider to the `.brew(...)` style syntax. >>> >>> Thanks for the feedback! >>> - Daniel >>> >>>> On Feb 27, 2017, at 2:21 AM, Ankit Aggarwal via swift-build-dev >>>> <swift-build-...@swift.org <mailto:swift-build-...@swift.org>> wrote: >>>> >>>> Hi David, >>>> >>>> Thanks for the feedback! Comments inline: >>>> >>>> >>>> On Sun, Feb 26, 2017 at 5:08 AM, David Hart via swift-build-dev >>>> <swift-build-...@swift.org <mailto:swift-build-...@swift.org>> wrote: >>>> Was looking forward to this :) here are my comments: >>>> >>>> On 25 Feb 2017, at 01:35, Rick Ballard via swift-evolution >>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote: >>>> >>>>> Hi all, >>>>> >>>>> Ankit, Daniel, Anders, Boris and I have a draft proposal in progress for >>>>> a Package.swift manifest API redesign for the Package Manager. We'll >>>>> welcome comments or discussion at this time. My hope is that we can get >>>>> this polished up and ready for evolution within the next week or so, but >>>>> we'll see how the conversation goes! >>>>> >>>>> You can see the proposal in progress at >>>>> https://github.com/aciidb0mb3r/swift-evolution/blob/manifest-api-redesign/proposals/xxxx-package-manager-manifest-api-redesign.md >>>>> >>>>> <https://github.com/aciidb0mb3r/swift-evolution/blob/manifest-api-redesign/proposals/xxxx-package-manager-manifest-api-redesign.md>. >>>>> I'm also including the current version inline in this email. >>>>> >>>>> Thanks, >>>>> >>>>> - Rick >>>>> >>>>> # Package Manager Manifest API Redesign >>>>> >>>>> * Proposal: [SE-XXXX](xxxx-package-manager-manifest-api-redesign.md >>>>> <http://xxxx-package-manager-manifest-api-redesign.md/>) >>>>> * Author: [Ankit Aggarwal](https://github.com/aciidb0mb3r >>>>> <https://github.com/aciidb0mb3r>) >>>>> * Review Manager: TBD >>>>> * Status: **Discussion** >>>>> >>>>> ## Introduction >>>>> >>>>> This is a proposal for redesigning the `Package.swift` manifest APIs >>>>> provided >>>>> by Swift Package Manager. >>>>> This proposal only redesigns the existing public APIs and does not add any >>>>> new functionality; any API to be added for new functionality will happen >>>>> in >>>>> separate proposals. >>>>> >>>>> ## Motivation >>>>> >>>>> The `Package.swift` manifest APIs were designed prior to the [API Design >>>>> Guidelines] (https://swift.org/documentation/api-design-guidelines/ >>>>> <https://swift.org/documentation/api-design-guidelines/>), and their >>>>> design was not reviewed by the evolution process. Additionally, there are >>>>> several small areas which can be cleaned up to make the overall API more >>>>> "Swifty". >>>>> >>>>> We would like to redesign these APIs as necessary to provide clean, >>>>> conventions-compliant APIs that we can rely on in the future. Because we >>>>> anticipate that the user community for the Swift Package Manager will grow >>>>> considerably in Swift 4, we would like to make these changes now, before >>>>> more packages are created using the old API. >>>>> >>>>> ## Proposed solution >>>>> >>>>> Note: Access modifier is omitted from the diffs and examples for brevity. >>>>> The >>>>> access modifier is `public` for all APIs unless specified. >>>>> >>>>> * Remove `successor()` and `predecessor()` from `Version`. >>>>> >>>>> These methods neither have well defined semantics nor are used a lot >>>>> (internally or publicly). For e.g., the current implementation of >>>>> `successor()` always just increases the patch version. >>>>> >>>>> >>>>> <details> >>>>> <summary>View diff</summary> >>>>> <p> >>>>> ```diff >>>>> struct Version { >>>>> - func successor() -> Version >>>>> >>>>> - func predecessor() -> Version >>>>> } >>>>> ``` >>>>> </p></details> >>>>> >>>>> * Make all properties of `Package` and `Target` mutable. >>>>> >>>>> Currently, `Package` has three immutable and four mutable properties, >>>>> and >>>>> `Target` has one immutable and one mutable property. We propose to >>>>> make all >>>>> properties mutable to allow complex customization on the package object >>>>> after initial declaration. >>>>> >>>>> <details> >>>>> <summary>View diff and example</summary> >>>>> <p> >>>>> >>>>> Diff: >>>>> ```diff >>>>> final class Target { >>>>> - let name: String >>>>> + var name: String >>>>> } >>>>> >>>>> final class Package { >>>>> - let name: String >>>>> + var name: String >>>>> >>>>> - let pkgConfig: String? >>>>> + var pkgConfig: String? >>>>> >>>>> - let providers: [SystemPackageProvider]? >>>>> + var providers: [SystemPackageProvider]? >>>>> } >>>>> ``` >>>>> >>>>> Example: >>>>> ```swift >>>>> let package = Package( >>>>> name: "FooPackage", >>>>> targets: [ >>>>> Target(name: "Foo", dependencies: ["Bar"]), >>>>> ] >>>>> ) >>>>> >>>>> #if os(Linux) >>>>> package.targets[0].dependencies = ["BarLinux"] >>>>> #endif >>>>> ``` >>>>> </p></details> >>>>> >>>>> * Change `Target.Dependency` enum cases to lowerCamelCase. >>>>> >>>>> According to API design guidelines, everything other than types should >>>>> be in lowerCamelCase. >>>>> >>>>> <details> >>>>> <summary>View diff and example</summary> >>>>> <p> >>>>> >>>>> Diff: >>>>> ```diff >>>>> enum Dependency { >>>>> - case Target(name: String) >>>>> + case target(name: String) >>>>> >>>>> - case Product(name: String, package: String?) >>>>> + case product(name: String, package: String?) >>>>> >>>>> - case ByName(name: String) >>>>> + case byName(name: String) >>>>> } >>>>> ``` >>>>> >>>>> Example: >>>>> ```diff >>>>> let package = Package( >>>>> name: "FooPackage", >>>>> targets: [ >>>>> Target( >>>>> name: "Foo", >>>>> dependencies: [ >>>>> - .Target(name: "Bar"), >>>>> + .target(name: "Bar"), >>>>> >>>>> - .Product(name: "SwiftyJSON", package: "SwiftyJSON"), >>>>> + .product(name: "SwiftyJSON", package: "SwiftyJSON"), >>>>> ] >>>>> ), >>>>> ] >>>>> ) >>>>> ``` >>>>> </p></details> >>>>> >>>>> * Add default parameter to the enum case `Target.Dependency.product`. >>>>> >>>>> The associated value `package` in the (enum) case `product`, is an >>>>> optional >>>>> `String`. It should have the default value `nil` so clients don't need >>>>> to >>>>> write it if they prefer using explicit enum cases but don't want to >>>>> specify >>>>> the package name i.e. it should be possible to write `.product(name: >>>>> "Foo")` instead of `.product(name: "Foo", package: nil)`. >>>>> >>>>> If >>>>> >>>>> [SE-0155](https://github.com/apple/swift-evolution/blob/master/proposals/0155-normalize-enum-case-representation.md >>>>> >>>>> <https://github.com/apple/swift-evolution/blob/master/proposals/0155-normalize-enum-case-representation.md>) >>>>> is accepted, we can directly add a default value. Otherwise, we will >>>>> use a >>>>> static factory method to provide default value for `package`. >>>>> >>>>> * Upgrade `SystemPackageProvider` enum to a struct. >>>>> >>>>> This enum allows SwiftPM System Packages to emit hints in case of build >>>>> failures due to absence of a system package. Currently, only one system >>>>> package per system packager can be specified. We propose to allow >>>>> specifying multiple system packages by replacing the enum with this >>>>> struct: >>>>> >>>>> ```swift >>>>> public struct SystemPackageProvider { >>>>> enum PackageManager { >>>>> case apt >>>>> case brew >>>>> } >>>>> >>>>> /// The system package manager. >>>>> let packageManager: PackageManager >>>>> >>>>> /// The array of system packages. >>>>> let packages: [String] >>>>> >>>>> init(_ packageManager: PackageManager, packages: [String]) >>>>> } >>>>> ``` >>>>> >>>>> <details> >>>>> <summary>View diff and example</summary> >>>>> <p> >>>>> >>>>> Diff: >>>>> ```diff >>>>> -enum SystemPackageProvider { >>>>> - case Brew(String) >>>>> - case Apt(String) >>>>> -} >>>>> >>>>> +struct SystemPackageProvider { >>>>> + enum PackageManager { >>>>> + case apt >>>>> + case brew >>>>> + } >>>>> + >>>>> + /// The system package manager. >>>>> + let packageManager: PackageManager >>>>> + >>>>> + /// The array of system packages. >>>>> + let packages: [String] >>>>> + >>>>> + init(_ packageManager: PackageManager, packages: [String]) >>>>> +} >>>>> ``` >>>>> >>>>> Example: >>>>> >>>>> ```diff >>>>> let package = Package( >>>>> name: "Copenssl", >>>>> pkgConfig: "openssl", >>>>> providers: [ >>>>> - .Brew("openssl"), >>>>> + SystemPackageProvider(.brew, packages: ["openssl"]), >>>>> >>>>> - .Apt("openssl-dev"), >>>>> + SystemPackageProvider(.apt, packages: ["openssl", >>>>> "libssl-dev"]), >>>>> ] >>>>> ) >>>>> ``` >>>>> </p></details> >>>> >>>> Why not keep the enum and change the associated type to a String array? >>>> >>>> >>>> True, we could do that but we'd be repeating that information in every >>>> SystemPackager we add. Converting to a struct makes it easier to scale. >>>> >>>>> * Remove implicit target dependency rule for test targets. >>>>> >>>>> There is an implicit test target dependency rule: a test target >>>>> "FooTests" >>>>> implicity depends on a target "Foo", if "Foo" exists and "FooTests" >>>>> doesn't >>>>> explicitly declare any dependency. We propose to remove this rule >>>>> because: >>>>> >>>>> 1. It is a non obvious "magic" rule that has to be learned. >>>>> 2. It is not possible for "FooTests" to remove dependency on "Foo" >>>>> while >>>>> having no other (target) dependency. >>>>> 3. It makes real dependencies less discoverable. >>>>> 4. It may cause issues when we get support for mechanically editing >>>>> target >>>>> dependencies. >>>>> >>>>> * Introduce an "identity rule" to determine if an API should use an >>>>> initializer >>>>> or a factory method: >>>> >>>> Could you explain this rule in more detail. What is an identity in this >>>> case? I'm confused. >>>> >>>> >>>> This is similar to the rule we use to decide if something should be a >>>> struct or a class. If you're forming a concrete object, that would be an >>>> identity. Consider these two examples: >>>> >>>> 1. Target and its dependencies: >>>> >>>> Target(name: "Foo", dependencies: [.target(name: "Bar")]) >>>> >>>> Here the target Foo is being constructed, so an initializer is used. The >>>> target Bar is being referred in Foo's dependencies so that uses a factory >>>> method. >>>> >>>> 2. Product and product dependencies in targets: >>>> >>>> When constructing the product, the initializer should be used: >>>> .Library(name: "FooLib", targets: ["Foo", "Utility"]) >>>> >>>> And while referring to the product, like in target dependency, factory >>>> method should be used: >>>> Target(name: "Foo", dependencies: [.product(name: "FooLib")]) >>>> >>>>> Under this rule, an entity having an identity, will use a type >>>>> initializer >>>>> and everything else will use factory methods. `Package`, `Target` and >>>>> `Product` are identities. However, a product referenced in a target >>>>> dependency is not an identity. >>>>> >>>>> This means the `Product` enum should be converted into an identity. We >>>>> propose to introduce a `Product` class with two subclasses: >>>>> `Executable` >>>>> and `Library`. These subclasses will be nested inside `Product` class >>>>> instead of being a top level declaration in the module. The major >>>>> advantage of nesting is that we get a namespace for products and it is >>>>> easy >>>>> to find all the supported products when the product types grows to a >>>>> large >>>>> number. A downside of nesting is that the product initializers will >>>>> have to >>>>> used with the dot notation (e.g.: `.Executable(name: "tool", targets: >>>>> ["tool"])`) which is a little awkward because we expect factory >>>>> methods to >>>>> use the dots. >>>>> >>>>> They will be defined as follow: >>>>> >>>>> ```swift >>>>> /// Represents a product. >>>>> class Product { >>>>> >>>>> /// The name of the product. >>>>> let name: String >>>>> >>>>> /// The names of the targets in this product. >>>>> let targets: [String] >>>>> >>>>> private init(name: String, targets: [String]) { >>>>> self.name <http://self.name/> = name >>>>> self.targets = targets >>>>> } >>>>> >>>>> /// Represents an executable product. >>>>> final class Executable: Product { >>>>> >>>>> /// Creates an executable product with given name and targets. >>>>> override init(name: String, targets: [String]) >>>>> } >>>>> >>>>> /// Represents a library product. >>>>> final class Library: Product { >>>>> /// The type of library product. >>>>> enum LibraryType: String { >>>>> case `static` >>>>> case `dynamic` >>>>> } >>>>> >>>>> /// The type of the library. >>>>> /// >>>>> /// If the type is unspecified, package manager will >>>>> automatically choose a type. >>>>> let type: LibraryType? >>>>> >>>>> /// Creates a library product. >>>>> init(name: String, type: LibraryType? = nil, targets: [String]) >>>>> } >>>>> } >>>>> ``` >>>>> >>>>> <details> >>>>> <summary>View example</summary> >>>>> <p> >>>>> >>>>> Example: >>>>> >>>>> ```swift >>>>> let package = Package( >>>>> name: "Foo", >>>>> target: [ >>>>> Target(name: "Foo", dependencies: ["Utility"]), >>>>> Target(name: "tool", dependencies: ["Foo"]), >>>>> ], >>>>> products: [ >>>>> .Executable(name: "tool", targets: ["tool"]), >>>>> .Library(name: "Foo", targets: ["Foo"]), >>>>> .Library(name: "FooDy", type: .dynamic, targets: ["Foo"]), >>>>> ] >>>>> ) >>>>> ``` >>>>> </p></details> >>>> >>>> This API looks very weird: the leading dog is usually used for enum cases >>>> and static members. Using it with a type means that the capitalization >>>> looks very out of place. >>>> >>>> >>>> Yes, as mentioned in the proposal we think the dot and capitalization >>>> following it looks out of place here but we really think that the products >>>> should be under a namespace because the types supported product might grow >>>> to a substantial number in future. Adding namespace using nesting solves >>>> this issue nicely. >>>> >>>> Another advantage would be getting free autocomplete support for products >>>> in IDEs or text editors which supports SourceKit. Right now there is none >>>> which supports autocomplete for the manifest file but since SourceKit is >>>> cross platform, it should be possible to create a plugin in future. >>>> >>>>> * Special syntax for version initializers. >>>>> >>>>> A simplified summary of what is commonly supported in other package >>>>> managers: >>>>> >>>>> | Package Manager | x-ranges | tilde (`~` or `~>`) | caret >>>>> (`^`) | >>>>> >>>>> |-----------------|---------------|-------------------------|---------------| >>>>> | npm | Supported | Allows patch-level changes if a >>>>> minor version is specified on the comparator. Allows minor-level changes >>>>> if not. | patch and minor updates | >>>>> | Cargo | Supported | Same as above | Same as >>>>> above | >>>>> | CocoaPods | Not supported | Same as above | Not >>>>> supported | >>>>> | Carthage | Not supported | patch and minor updates | Not >>>>> supported | >>>>> >>>>> Some general observations: >>>>> >>>>> * Every package manager we looked at for this supports the tilde `~` >>>>> operator in some form. >>>>> * The widely accepted suggestion on how to constrain your versions is >>>>> "use >>>>> `~>`, it does the right thing". >>>>> * It's not clear to us why this has so much traction as "the right >>>>> thing", as it can >>>>> prevent upgrades that should be compatible (one minor version to >>>>> next minor version). >>>>> * Most users may not really understand `~`, and just use it per >>>>> recommendations. >>>>> See e.g. how Google created a [6-minute instructional >>>>> video](https://www.youtube.com/watch?v=x4ARXyovvPc >>>>> <https://www.youtube.com/watch?v=x4ARXyovvPc>) >>>>> about this operator for CocoaPods. >>>>> * A lot of people even explicitly set a single exact version simply >>>>> because >>>>> they don't know better. This leads to "dependency hell" >>>>> (unresolvable dependencies >>>>> due to conflicting requirements for a package in the dependency >>>>> graph). >>>>> * The Swift Package Manager will probably have many novice users, >>>>> because it >>>>> comes built-in to Swift. >>>>> * We think caret `^` has the right behaviour most of the time. That >>>>> is, you >>>>> should be able to specify a minimum version, and you should be >>>>> willing to let >>>>> your package use anything after that up to the next major version. >>>>> This policy >>>>> works if packages correctly follow semantic versioning, and it >>>>> prevents "dependency >>>>> hell" by expressing permissive constraints. >>>>> * We also think caret `^` is syntactically non-obvious, and we'd >>>>> prefer a syntax >>>>> that doesn't require reading a manual for novices to understand, >>>>> even if that >>>>> means we break with the syntactic convention established by the >>>>> other package managers which >>>>> support caret `^`. >>>>> * We'd like a convenient syntax for caret `^`, but to still support >>>>> the use >>>>> case that tilde `~` is used for; but tilde `~` (or a single exact >>>>> version) should >>>>> be less convenient than caret `^`, to encourge permissive dependency >>>>> constraints. >>>>> >>>>> What we propose: >>>>> >>>>> * We will introduce a factory method which takes a lower bound version >>>>> and >>>>> forms a range that goes upto the next major version (i.e. caret). >>>>> >>>>> ```swift >>>>> // 1.0.0 ..< 2.0.0 >>>>> .package(url: "/SwiftyJSON", from: "1.0.0"), >>>>> >>>>> // 1.2.0 ..< 2.0.0 >>>>> .package(url: "/SwiftyJSON", from: "1.2.0"), >>>>> >>>>> // 1.5.8 ..< 2.0.0 >>>>> .package(url: "/SwiftyJSON", from: "1.5.8"), >>>>> ``` >>>>> >>>>> * We will introduce a factory method which takes >>>>> `VersionSetSpecifier`, to >>>>> conveniently specify common ranges. >>>>> >>>>> `VersionSetSpecifier` is an enum defined as follows: >>>>> >>>>> ```swift >>>>> enum VersionSetSpecifier { >>>>> case exact(Version) >>>>> case range(Range<Version>) >>>>> >>>>> /// Creates a specifier for an exact version. >>>>> static func only(_ version: Version) -> VersionSetSpecifier >>>>> >>>>> /// Creates a specified for a range starting at the given lower >>>>> bound >>>>> /// and going upto next major version. >>>>> static func uptoNextMajor(_ version: Version) -> >>>>> VersionSetSpecifier >>>>> >>>>> /// Creates a specified for a range starting at the given lower >>>>> bound >>>>> /// and going upto next minor version. >>>>> static func uptoNextMinor(_ version: Version) -> >>>>> VersionSetSpecifier >>>>> } >>>>> ``` >>>>> >>>>> Examples: >>>>> >>>>> ```swift >>>>> // 1.5.8 ..< 2.0.0 >>>>> .package(url: "/SwiftyJSON", .uptoNextMajor("1.5.8")), >>>>> >>>>> // 1.5.8 ..< 1.6.0 >>>>> .package(url: "/SwiftyJSON", .uptoNextMinor("1.5.8")), >>>>> >>>>> // 1.5.8 >>>>> .package(url: "/SwiftyJSON", .only("1.5.8")), >>>>> ``` >>>>> >>>>> * This will also give us ability to add more complex features in >>>>> future: >>>>> >>>>> Examples: >>>>>> Note that we're not actually proposing these as part of this proposal. >>>>> >>>>> ```swift >>>>> .package(url: "/SwiftyJSON", >>>>> .uptoNextMajor("1.5.8").excluding("1.6.4")), >>>>> >>>>> .package(url: "/SwiftyJSON", .only("1.5.8", "1.6.3")), >>>>> >>>>> ``` >>>>> >>>>> * We will introduce a factory method which takes `Range<Version>`, to >>>>> specify >>>>> arbitrary open range. >>>>> >>>>> ```swift >>>>> // Constraint to an arbitrary open range. >>>>> .package(url: "/SwiftyJSON", "1.2.3"..<"1.2.6"), >>>>> ``` >>>>> >>>>> * We will introduce a factory method which takes >>>>> `ClosedRange<Version>`, to specify >>>>> arbitrary closed range. >>>>> >>>>> ```swift >>>>> // Constraint to an arbitrary closed range. >>>>> .package(url: "/SwiftyJSON", "1.2.3"..."1.2.8"), >>>>> ``` >>>>> >>>>> * We will remove all of the current factory methods: >>>>> >>>>> ```swift >>>>> // Constraint to a major version. >>>>> .Package(url: "/SwiftyJSON", majorVersion: 1), >>>>> >>>>> // Constraint to a major and minor version. >>>>> .Package(url: "/SwiftyJSON", majorVersion: 1, minor: 2), >>>>> >>>>> // Constraint to an exact version. >>>>> .Package(url: "/SwiftyJSON", "1.2.3"), >>>>> >>>>> // Constraint to an arbitrary range. >>>>> .Package(url: "/SwiftyJSON", versions: "1.2.3"..<"1.2.6"), >>>>> >>>>> // Constraint to an arbitrary closed range. >>>>> .Package(url: "/SwiftyJSON", versions: "1.2.3"..."1.2.8"), >>>>> ``` >>>> >>>> I'm ver happy with the versioning part of this proposal :-) >>>> >>>> >>>> Great! >>>>> * Adjust order of parameters on `Package` class: >>>>> >>>>> We propose to reorder the parameters of `Package` class to: `name`, >>>>> `pkgConfig`, `products`, `dependencies`, `targets`, >>>>> `compatibleSwiftVersions`. >>>>> >>>>> The rationale behind this reorder is that the most interesting parts >>>>> of a >>>>> package are its product and dependencies, so they should be at the top. >>>>> Targets are usually important during development of the package. >>>>> Placing >>>>> them at the end keeps it easier for the developer to jump to end of the >>>>> file to access them. Note that the compatibleSwiftVersions property >>>>> will likely >>>>> be removed once we support Build Settings, but that will be discussed >>>>> in a separate proposal. >>>> >>>> I would have liked this proposal to suggest modifying the API so the order >>>> is insignificant. While ordering feels important for me when calling a >>>> function or initializer with few arguments (like .package(url: "", from: >>>> "1.4.5")), the arguments to the Package function seem like a list of >>>> configuration options and shouldn't have a fixed order. My suggestion was >>>> to remove all arguments but the name and adds a configuration closure: >>>> >>>> let package = Package(name: "paper") { >>>> $0.products = [...] >>>> $0.dependencies = [...] >>>> } >>>> >>>> >>>> It will be possible to avoid using the initializer because all the >>>> properties will be made mutable. However I think if majority of packages >>>> uses the initializer and thus have a consistent ordering, it will be >>>> easier for other developers to read manifests on Github (or similar). >>>> >>>> PS: The closure syntax can also be added using extension in the manifest >>>> itself if someone really wants to use it. >>>> >>>>> <details> >>>>> <summary>View example</summary> >>>>> <p> >>>>> >>>>> Example: >>>>> >>>>> ```swift >>>>> let package = Package( >>>>> name: "Paper", >>>>> products: [ >>>>> .Executable(name: "tool", targets: ["tool"]), >>>>> .Libary(name: "Paper", type: .static, targets: ["Paper"]), >>>>> .Libary(name: "PaperDy", type: .dynamic, targets: ["Paper"]), >>>>> ], >>>>> dependencies: [ >>>>> .package(url: "http://github.com/SwiftyJSON >>>>> <http://github.com/SwiftyJSON>", from: "1.2.3"), >>>>> .package(url: "../CHTTPParser", .uptoNextMinor("2.2.0")), >>>>> .package(url: "http://some/other/lib <http://some/other/lib>", >>>>> .only("1.2.3")), >>>>> ] >>>>> targets: [ >>>>> Target( >>>>> name: "tool", >>>>> dependencies: [ >>>>> "Paper", >>>>> "SwiftyJSON" >>>>> ]), >>>>> Target( >>>>> name: "Paper", >>>>> dependencies: [ >>>>> "Basic", >>>>> .target(name: "Utility"), >>>>> .product(name: "CHTTPParser"), >>>>> ]) >>>>> ] >>>>> ) >>>>> ``` >>>>> </p></details> >>>>> >>>>> * Eliminate exclude in future (via custom layouts feature). >>>>> >>>>> We expect to remove the `exclude` property after we get support for >>>>> custom >>>>> layouts. The exact details will be in the proposal of that feature. >>>>> >>>>> ## Impact on existing code >>>>> >>>>> The above changes will be implemented only in the new Package Description >>>>> v4 >>>>> library. The v4 runtime library will release with Swift 4 and packages >>>>> will be >>>>> able to opt-in into it as described by >>>>> [SE-0152](https://github.com/apple/swift-evolution/blob/master/proposals/0152-package-manager-tools-version.md >>>>> >>>>> <https://github.com/apple/swift-evolution/blob/master/proposals/0152-package-manager-tools-version.md>). >>>>> >>>>> There will be no automatic migration feature for updating the manifests >>>>> from v3 >>>>> to v4. To indicate the replacements of old APIs, we will annotate them >>>>> using >>>>> the `@unavailable` attribute where possible. Unfortunately, this will not >>>>> cover >>>>> all the changes for e.g. rename of the target dependency enum cases. >>>>> >>>>> All new packages created with `swift package init` command in Swift 4 >>>>> tools >>>>> will by default to use the v4 manifest. It will be possible to switch to >>>>> v3 >>>>> manifest version by changing the tools version using `swift package >>>>> tools-version --set 3.1`. However, the manifest will needed to be >>>>> adjusted to >>>>> use the older APIs manually. >>>>> >>>>> Unless declared in the manifest, existing packages automatically default >>>>> to the Swift 3 minimum tools version; since the Swift 4 tools will also >>>>> include >>>>> the v3 manifest API, they will build as expected. >>>>> >>>>> A package which needs to support both Swift 3 and Swift 4 tools will need >>>>> to >>>>> stay on the v3 manifest API and support the Swift 3 language version for >>>>> its >>>>> sources, using the API described in the proposal >>>>> [SE-0151](https://github.com/apple/swift-evolution/blob/master/proposals/0151-package-manager-swift-language-compatibility-version.md >>>>> >>>>> <https://github.com/apple/swift-evolution/blob/master/proposals/0151-package-manager-swift-language-compatibility-version.md>). >>>>> >>>>> An existing package which wants to use the new v4 manifest APIs will need >>>>> to bump its >>>>> minimum tools version to 4.0 or later using the command `$ swift package >>>>> tools-version >>>>> --set-current`, and then modify the manifest file with the changes >>>>> described in >>>>> this proposal. >>>>> >>>>> ## Alternatives considered >>>>> >>>>> * Add variadic overloads. >>>>> >>>>> Adding variadic overload allows omitting parenthesis which leads to >>>>> less >>>>> cognitive load on eyes, especially when there is only one value which >>>>> needs >>>>> to be specified. For e.g.: >>>>> >>>>> Target(name: "Foo", dependencies: "Bar") >>>>> >>>>> might looked better than: >>>>> >>>>> Target(name: "Foo", dependencies: ["Bar"]) >>>>> >>>>> However, plurals words like `dependencies` and `targets` imply a >>>>> collection >>>>> which implies brackets. It also makes the grammar wrong. Therefore, we >>>>> reject this option. >>>>> >>>>> * Version exclusion. >>>>> >>>>> It is not uncommon to have a specific package version break something, >>>>> and >>>>> it is undesirable to "fix" this by adjusting the range to exclude it >>>>> because this overly constrains the graph and can prevent picking up the >>>>> version with the fix. >>>>> >>>>> This is desirable but it should be proposed separately. >>>>> >>>>> * Inline package declaration. >>>>> >>>>> We should probably support declaring a package dependency anywhere we >>>>> support spelling a package name. It is very common to only have one >>>>> target >>>>> require a dependency, and annoying to have to specify the name twice. >>>>> >>>>> This is desirable but it should be proposed separately. >>>>> >>>>> _______________________________________________ >>>>> swift-evolution mailing list >>>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org> >>>>> https://lists.swift.org/mailman/listinfo/swift-evolution >>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution> >>>> >>>> One thing that still really bothers me about the API is the inconsistency >>>> in leading dots and capitalization. Should a novice (or an expert) have to >>>> remember the following different writings: >>>> >>>> Target(name: "Foo", dependencies: ["Utility"]) >>>> .package(url: "http://github.com/SwiftyJSON >>>> <http://github.com/SwiftyJSON>", from: "1.2.3") >>>> .Library(name: "Paper", type: .static, targets: ["Paper"]) >>>> >>>> I understand the arguments brought forward in the proposal. But from a >>>> package author point of view, it's not obvious why Target is capitalized, >>>> why package is lowercase with a leading dot and why Library is capitalized >>>> with a leading dot. It looks confusing and inconsistent, which makes it >>>> less pleasant to read and harder to remember. >>>> >>>> Could we push for more consistency by having everything b lowercased with >>>> a leading dot? It does force us to introduce a Target factory method, to >>>> revert SystemPackageProvider back to an enum, to revert products back to >>>> an enum. But I think it's worth it. >>>> >>>> It is true that it might not be obvious when to use what initially, but we >>>> think this is a good rule to create a distinction between constructing >>>> things and referring to things. A downside of lowercasing everything would >>>> be: it might seem like the references support all the parameters that >>>> constructor supports. e.g. .target(name: "Foo", dependencies: [ >>>> .target(name: "Bar", dependencies: ["Baz"]) ]) >>>> >>>> >>>> >>>> >>>> >>>> >>>> _______________________________________________ >>>> swift-build-dev mailing list >>>> swift-build-...@swift.org <mailto:swift-build-...@swift.org> >>>> https://lists.swift.org/mailman/listinfo/swift-build-dev >>>> <https://lists.swift.org/mailman/listinfo/swift-build-dev> >>> _______________________________________________ >>> swift-build-dev mailing list >>> swift-build-...@swift.org <mailto:swift-build-...@swift.org> >>> https://lists.swift.org/mailman/listinfo/swift-build-dev >>> <https://lists.swift.org/mailman/listinfo/swift-build-dev>
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution