> On Jul 13, 2016, at 1:56 AM, Honza Dvorsky <[email protected]> wrote:
> 
> Very happy to see this proposal, thanks Ankit for pushing it forward! I can't 
> wait to be able to hide many example executables in my packages, as I've been 
> getting a steady stream of complaints from people being annoyed about the 
> polluted compilation log and slower compilation times.
> 
> However I'm leaning towards keeping the default module visibility to public, 
> not private. I appreciate all the arguments that compare targets with code in 
> Swift, where the default is internal - and it makes sense. But the more 
> pragmatic side of me feels that it might become a piece of boilerplate we'll 
> have to write in our manifests for a long time, without much benefit (but 
> with regret). And adding magic to sometimes export by default (single module 
> packages or modules matching the packages name) IMO just complicates the 
> conceptual model of how SwiftPM treats package manifests. I think we should 
> be very careful with adding such nonlinear behaviors (where e.g. adding 
> another module suddenly breaks the package's visible targets), and in this 
> case I don't believe it's justified. (That's while completely ignoring the 
> fact that such a change would break 100% of packages out there, which could 
> be a toll on the good will the project seems to have right now. Not that we 
> should never make breaking changes, I just feel we should give a good reason 
> we're making them, potentially to allow a new feature. Which is not the case 
> here.) 

I agree, this is a big concern of mine as well.

Ankit and I discussed this at length last night and he has updated the proposal 
here:
  
https://github.com/aciidb0mb3r/swift-evolution/blob/swiftpm-module-access-control/proposals/xxxx-swiftpm-target-access-control.md
 
<https://github.com/aciidb0mb3r/swift-evolution/blob/swiftpm-module-access-control/proposals/xxxx-swiftpm-target-access-control.md>

> That's my two cents. :)
> 
> Overall I'm enthusiastic about this proposal, it will solve a few real issues 
> I'm having with my projects! 
> 
> While I don't think we should add this to the proposal - it might be very 
> useful to add a mode to SwiftPM that dumps the module visibility information. 
> I think that should be added regardless of what the default visibility ends 
> up being.

I agree. I would like a `swift package describe` which shows how the convention 
system and manifest are causing the package to be interpreted. It would show 
things like the targets, dependencies, etc.

 - Daniel

> Something like:
> $ swift package show-target-visibility
> Found 3 modules
> 
> Public:
> Foo
> 
> Private:
> PrivateBar
> ExampleFoo
> 
> - Honza
> 
> On Tue, Jul 12, 2016 at 8:16 PM Ankit Agarwal via swift-build-dev 
> <[email protected] <mailto:[email protected]>> wrote:
> I have updated the proposal accommodating recent discussion
> 
> Link: 
> https://github.com/aciidb0mb3r/swift-evolution/blob/swiftpm-module-access-control/proposals/xxxx-swiftpm-target-access-control.md
>  
> <https://github.com/aciidb0mb3r/swift-evolution/blob/swiftpm-module-access-control/proposals/xxxx-swiftpm-target-access-control.md>
> 
> SwiftPM Target Access Control
> Proposal: SE-XXXX 
> <https://github.com/apple/swift-evolution/blob/master/proposals/xxxx-swiftpm-target-access-control.md>
> Author: Ankit Aggarwal <https://github.com/aciidb0mb3r>
> Status: In Discussion
> Review manager: TBD
> Introduction
> This proposal aims to address two issues:
> 
> Control over the targets exposed (and built) when a SwiftPM package is used 
> as a dependency i.e. the targets which are exported and can be used in other 
> packages.
> 
> Specify external target dependencies of a target.
> 
> swift-evolution thread 
> <https://lists.swift.org/pipermail/swift-build-dev/Week-of-Mon-20160704/000531.html>
> Motivation
> 1. Control over exposed targets:
> 
> SwiftPM allows multiple targets (or modules) inside a package. Most of the 
> time package author will want to provide one (or more) stable public/exported 
> target which should be utilised by other packages. We should actively 
> discourage use of targets which are not meant to be imported by other 
> packages.
> 
> Additionally packages usually contain sample usage or example targets which 
> are useful during development or testing of the package but are redundant 
> when the package is used as a dependency. This increases compilation time for 
> the user of the package which can be avoided.
> 
> As a concrete example: Vapor has a target called Development 
> <https://github.com/qutheory/vapor/tree/master/Sources/Development>.
> 
> 2. Specify external target dependencies of a target:
> 
> Currently all the targets of an external dependency are implicitly built and 
> exposed to the user package. This works well for one target package but 
> becomes unclear which targets are using which target of an external 
> dependency.
> 
> Moreover user of a package may only be interested in few targets of a 
> dependency instead of all the exposed targets. Currently there is no way to 
> state this in Package.swift.
> 
> For e.g.: One would like to use the targets libc, POSIX, Basic of SwiftPM but 
> don't want other targets to be built or exposed in their package.
> 
> Proposed Solution
> 1. Control over exposed targets:
> 
> I propose that all targets should by default be private/unexported. Authors 
> should explicitly mark the targets they want to expose as exported/public.
> 
> To mark a target as exported/public I propose PackageDescription's Target 
> gains a flags property which would be a Set of the following Flag enum 
> declared inside Target class:
> 
> public enum Flag {
>     /// Makes the target public or "exported" for other packages to use.
>     case public
> }
> The Flag enum will be flexible in case we need to add more attributes in 
> future as opposed to a boolean property to mark the public nature of the 
> target.
> 
> exported is also a choice instead of public which matches the semantics here. 
> However public is equally clear in current context.
> 
> We can keep some obvious defaults for targets which can be implicitly public 
> for e.g. 
> 
> Package has only one target.
> Target with same name as package.
> Or have all targets be public (the current behaviour) until some target uses 
> the public flag assuming full control over all the exported target. This has 
> an advantage that only larger projects which cares about this need to 
> maintain it.
> 
> However I believe private by default and explicit public declaration is the 
> right way to go here to avoid the misuse of packages/targets which are not 
> intended to act as a dependency and the public targets will become obvious 
> (and documented) in the manifest file.
> 
> It should be noted that this behaviour cannot be enforced by the compiler 
> right now and there is no way to stop symbols from other modules from leaking 
> out. For e.g. there could be a type used in the public interface which 
> belongs to a private target.
> 
> Dependencies of the public targets will also leak and can be imported since 
> they'll become transitive dependency of some target.
> 
> Hopefully we can enforce this using compiler feature in future.
> 
> Swift compiler might gain support for package-level namespaces and access 
> control in future to solve problems like module name collision i.e. two 
> packages have modules with same name. At that point we will probably need to 
> rethink the manifest file.
> 
> 2. Specify external target dependencies of a target:
> 
> I propose that enum Target.Dependency gains a new case External(package: 
> String, target: String) to declare dependency on an external package's 
> target. The enum would look like this after modification:
> 
> /// The description for an individual target or package dependency.
> public enum Dependency {
>     /// A dependency on a target in the same project.
>     case Target(name: String)
>     /// A dependency on a target in a external package.
>     case External(package: String, target: String)
> }
> Note that the package name is not really needed (at least currently) because 
> the target names has to be unique across the dependency graph but it keeps 
> the manifest file cleaner i.e. which external package this external target 
> belongs to.
> 
> An external package dependency declaration implicitly becomes dependency of 
> each target in the package. I propose this behaviour should be retained but 
> if a target dependency contains an External declaration then all other 
> targets which wants to use that external dependency should explicitly state 
> their dependency on that external package using External.
> 
> Detailed Design
> 1. Control over exposed targets:
> 
> Consider a package with following structure: 
> 
> ├── Package.swift
> └── Sources
>     ├── FooLibrary
>     │   └── Foo.swift
>     └── SampleCLI
>         └── main.swift
> The manifest with a public target could look like:
> 
> import PackageDescription
> 
> let package = Package(
>    name: "FooLibrary",
>    targets: [
> 
>        Target(name: "FooLibrary", flags: [.public]),
>        Target(name: "SampleCLI", dependencies: ["FooLibrary"]),
>    ])
> When this package is used as a dependency only FooLibrary is built and is 
> importable.
> 
> 2. Specify external target dependencies of a target:
> 
> Consider a dependency with following manifest file:
> 
> import PackageDescription
> 
> let package = Package(
>    name: "FooLibrary",
>    targets: [
>        Target(name: "Foo"),
> 
>        Target(name: "Bar", dependencies: ["Foo"], flags: [.public]),
>        Target(name: "Baz", flags: [.public]),
>    ])
> To get only the Bar target from the above package, following manifest could 
> be written:
> 
> import PackageDescription
> 
> let package = Package(
> 
>    name: "BarUser",
>    targets: [
>         Target(name: "BarUser", 
>                dependencies: [.External(package: "FooLibrary", target: "Bar")
>                ])
>    ],
> 
>    dependencies: [
>        .Package(
>            url: "../FooLibrary",
>  
>            majorVersion: 1)
>    ])
> Note: In this case since Bar depends on Foo, Foo will be also be implicitly 
> built but Baz need not be compiled at all.
> 
> Also Note: If the external dependency is not declared then both Bar and Baz 
> will be available to BarUser.
> 
> Impact on Existing Code
> 1. Control over exposed targets:
> 
> All targets will become private by default so package authors will need to 
> mark the targets they want to expose as public.
> 
> 2. Specify external target dependencies of a target:
> 
> None as all the public targets will still be dependencies to the overall 
> package when External is not used.
> 
> Alternatives Considered
> None at this time.
> 
> _______________________________________________
> swift-build-dev mailing list
> [email protected] <mailto:[email protected]>
> https://lists.swift.org/mailman/listinfo/swift-build-dev 
> <https://lists.swift.org/mailman/listinfo/swift-build-dev>

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to