[swift-evolution] [Draft] Package Manager Custom Targets Layout

Aaron Crespo aaroncrespo at gmail.com
Sat Mar 25 10:00:12 CDT 2017


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 <
swift-evolution at swift.org> 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
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170325/6a589072/attachment.html>


More information about the swift-evolution mailing list