I recently experienced these pain points when trying to support SwiftPM on some of our libraries. I think this proposal goes a long way to alleviate most of the those I experienced.
On Fri, Mar 24, 2017 at 4:26 PM, Ankit Aggarwal via swift-evolution < [email protected]> wrote: > Hi, > > We would love to get some feedback on a draft proposal for defining custom > target layouts in the Package Manager. This proposal allows overriding the > target layout rules set by the Package Manager and simplifies some complex > "magic" behaviours. > > You can find the proposal at the link below. The text is also included in > the email. > > https://github.com/aciidb0mb3r/swift-evolution/blob/custom-targets-layout/ > proposals/NNNN-package-manager-custom-targets-layout.md > > Thanks, > Ankit > > -- > > Package Manager Custom Targets Layout > > - Proposal: SE-NNNN > - Author: Ankit Aggarwal <https://github.com/aciidb0mb3r> > - Review Manager: TBD > - Status: *Discussion* > - Bug: SR-29 <https://bugs.swift.org/browse/SR-29> > > Introduction > > This proposal enhances the Package.swift manifest APIs to support custom > target layouts, and removes a convention which allowed omission of targets > from the manifest. > Motivation > > The Package Manager uses a convention system to infer targets structure > from disk layout. This works well for most packages, which can easily adopt > the conventions, and frees users from needing to update their > Package.swift file every time they add or remove sources. Adopting the > conventions is more difficult for some packages, however – especially > existing C libraries or large projects, which would be difficult to > reorganize. We intend to give users a way to make such projects into > packages without needing to conform to our conventions. > > The current convention rules make it very convenient to add new targets > and source files by inferring them automatically from disk, but they also > can be confusing, overly-implicit, and difficult to debug; for example, if > the user does not follow the conventions correctly which determine their > targets, they may wind up with targets they don't expect, or not having > targets they did expect, and either way their clients can't easily see > which targets are available by looking at the Package.swift manifest. We > want to retain convenience where it really matters, such as easy addition > of new source files, but require explicit declarations where being explicit > adds significant value. We also want to make sure that the implicit > conventions we keep are straightforward and easy to remember. > Proposed solution > > - > > We propose to stop inferring targets from disk. They must be > explicitly declared in the manifest file. The inference was not very > useful, as targets eventually need to be declared in order to use common > features such as product and target dependencies, or build settings (which > are planned for Swift 4). Explicit target declarations make a package > easier to understand by clients, and allow us to provide good diagnostics > when the layout on disk does not match the declarations. > - > > We propose to remove the requirement that name of a test target must > have suffix "Tests". Instead, test targets will be explicitly declared as > such in the manifest file. > - > > We propose a list of pre-defined search paths for declared targets. > > When a target does not declare an explicit path, these directories > will be used to search for the target. The name of the directory must match > the name of the target. The search will be done in order and will be > case-sensitive. > > Regular targets: package root, Sources, Source, src, srcs. Test > targets: Tests, package root, Sources, Source, src, srcs. > > It is an error if a target is found in more than one of these paths. > In such cases, the path should be explicitly declared using the path > property proposed below. > - > > We propose to add a factory method testTarget to the Target class, to > define test targets. > > .testTarget(name: "FooTests", dependencies: ["Foo"]) > > - > > We propose to add three properties to the Target class: path, sources > andexclude. > - > > path: This property defines the path to the top-level directory > containing the target's sources, relative to the package root. It is not > legal for this path to escape the package root, i.e., values like > "../Foo", > "/Foo" are invalid. The default value of this property will be nil, > which means the target will be searched for in the pre-defined paths. > The > empty string ("") or dot (".") implies that the target's sources are > directly inside the package root. > - > > sources: This property defines the source files to be included in > the target, relative to the target path. The default value of this > property > will be an empty array, which means all valid source files found in the > target's path will be included. This can contain directories and > individual > source files. Directories will be searched recursively for valid source > files. Paths specified are relative to the target path. > > Each source file will be represented by String type. In future, we > will consider upgrading this to its own type to allow per-file build > settings. The new type would conform to CustomStringConvertible, so > existing declarations would continue to work (except where the strings > were > constructed programatically). > - > > exclude: This property can be used to exclude certain files and > directories from being picked up as sources. Exclude paths are relative > to > the target path. This property has more precedence than sources > property. > > *Note: We plan to support globbing in future, but to keep this > proposal short we are not proposing it right now.* > - > > It is an error if the paths of two targets overlap (unless resolved > with exclude). > > // This is an error:.target(name: "Bar", path: > "Sources/Bar"),.testTarget(name: "BarTests", dependencies: ["Bar"], path: > "Sources/Bar/Tests"), > // This works:.target(name: "Bar", path: "Sources/Bar", exclude: > ["Tests"]),.testTarget(name: "BarTests", dependencies: ["Bar"], path: > "Sources/Bar/Tests"), > > - > > For C family library targets, we propose to add a publicHeadersPath > property. > > This property defines the path to the directory containing public > headers of a C target. This path is relative to the target path and default > value of this property is include. This mechanism should be further > improved in the future, but there are several behaviors, such as modulemap > generation, which currently depend of having only one public headers > directory. We will address those issues separately in a future proposal. > > *All existing rules related to custom and automatic modulemap remain > intact.* > - > > Remove exclude from Package class. > > This property is no longer required because of the above proposed > per-target exclude property. > - > > The templates provided by the swift package init subcommand will be > updated according to the above rules, so that users do not need to manually > add their first target to the manifest. > > Examples: > > - Dummy manifest containing all Swift code. > > let package = Package( > name: "SwiftyJSON", > targets: [ > .target( > name: "Utility", > path: "Sources/BasicCode" > ), > > .target( > name: "SwiftyJSON", > dependencies: ["Utility"], > path: "SJ", > sources: ["SwiftyJSON.swift"] > ), > > .testTarget( > name: "AllTests", > dependencies: ["Utility", "SwiftyJSON"], > path: "Tests", > exclude: ["Fixtures"] > ), > ]) > > > - LibYAML > > let packages = Package( > name: "LibYAML", > targets: [ > .target( > name: "libyaml", > sources: ["src"] > ) > ]) > > > - Node.js http-parser > > let packages = Package( > name: "http-parser", > targets: [ > .target( > name: "http-parser", > publicHeaders: ".", > sources: ["http_parser.c"] > ) > ]) > > > - swift-build-tool > > let packages = Package( > name: "llbuild", > targets: [ > .target( > name: "swift-build-tool", > path: ".", > sources: [ > "lib/Basic", > "lib/llvm/Support", > "lib/Core", > "lib/BuildSystem", > "products/swift-build-tool/swift-build-tool.cpp", > ] > ) > ]) > > Impact on existing code > > These enhancements will be added to the version 4 manifest API, which will > release with Swift 4. There will be no impact on packages using the version > 3 manifest API. When packages update their minimum tools version to 4.0, > they will need to update the manifest according to the changes in this > proposal. > > There are two flat layouts supported in Swift 3: > > 1. Source files directly in the package root. > 2. Source files directly inside a Sources/ directory. > > If packages want to continue using either of these flat layouts, they will > need to explicitly set a target path to the flat directory; otherwise, a > directory named after the target is expected. For example, if a package > Foo has following layout: > > Package.swift > Sources/main.swift > Sources/foo.swift > > The updated manifest will look like this: > > // swift-tools-version:4.0import PackageDescription > let package = Package( > name: "Foo", > targets: [ > .target(name: "Foo", path: "Sources"), > ]) > > Alternatives considered > > We considered making a more minimal change which disabled the flat layouts > by default, and provided a top-level property to allow opting back in to > them. This would allow us to discourage these layouts – which we would like > to do before the package ecosystem grows – without needing to add a fully > customizable API. However, we think the fuller API we've proposed here is > fairly straightforward and provides the ability to make a number of > existing projects into packages, so we think this is worth doing at this > time. > > _______________________________________________ > swift-evolution mailing list > [email protected] > https://lists.swift.org/mailman/listinfo/swift-evolution > >
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
