> 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
