Thanks for the detailed and thoughtful feedback!
As you note, the source files of dependencies are available to the plugin, but currently the outputs defined by other plugins aren't. But this is a great point. The proposal could define that plugins are invoked in dependency order (with independent ones being allowed to be invoked in parallel, of course), and provide for a way of passing the results of those invocations on to downstream plugins.
The idea with the current proposal was that the
TargetBuildContext would contain enough information to allow each plugin to construct a module mappings file for the closure of dependency targets, and the plugin would be able to write this out directly to the output directory (and not have to use a separate external command) since the information is known before any commands are run. But as you point out it might be better to allow access to the outputs of the other plugins, so that the component module mappings could be reused.
Would it be important for the plugin to be able to distinguish between original source files and those produced by another plugin? In the case of
protoc this might not matter, but for different kinds of plugins (e.g. linters) there might be a need to distinguish original sources from generated sources.
Having a custom type for a file set would make sense. There should also perhaps be a way for the plugin to provide a filter for the set of input files it sees. Having access to all the files is flexible but it might make sense to specify a filename filter up-front (in the declaration of the plugin, for example).
In this proposal the plugins are invoked before the build (while the build plan is being created), so if the proposal is amended to define plugins as being invoked in dependency DAG order (and the
TargetBuildContext is extended with the appropriate fields), the plugins for a target would have access to any intermediates written by plugins for its dependencies. Even as written, in this proposal the commands produced by a plugin would have access to the outputs of other commands run for the dependency targets.
So this would not work if a plugin needs to see the outputs of running build-time commands from other plugins, but it does work if, for example, the plugins themselves write out the module map files (which was the intent in the example in the proposal).
This is one of the simplifications that this proposal makes, with an eye toward being able to loosen that restriction in the future. Ideally a plugin would be able to be invoked as needed by a build system capable of doing that, and as long as the inputs and outputs of the plugin are well defined.
This initial proposal is focused on source generation, and initially any platform differences would need to be written into the generated source files using conditionals. To support tools that do actual compilation, or to allow more flexible source generation, I would expect this proposal to be extended in the future to let the plugin have access to target platform information (and to declare whether it wants to be invoked once for all the platforms, or once per platform, etc).
The current approach does let the plugins write "up-front" information that can be derived just from the configuration and structure of the target to which it's being applied and it's dependency closure (such as the module mappings). But it's a good point that it might be better to require it to use custom APIs to provide the contents of any such files, if that makes the invocation more portable. The idea would be that a plugin would always generate the same outputs (in terms of command lines defined using
addCommand as well as intermediate inputs to those commands written up-front), but it might be better to extend the API to support that rather than allow the output directory to be mutable.