IMHO defining relations between project elements should be delegated
to each type of project. For example Java Project knows where are
sources/tests/resources and can setup that using Project API.
Moreover in one project (lets call it Meta Project) there
should be a way to configure a set of language specific
subprojects, each one having its own backend(s) setup
(for code completion, docs, etc.).
A backend would be chosen by a mode in the current buffer (region?).
For example in a common "Java" webapp, the Meta Project setup could be:
{ languages:
{ java: {backend: classpath-indexer, build-tool: gradle,
other-options: ...}
javascript: {backend: tags-backend, build-tool: npm, ...}
groovy: ...} }
Support for build tools seems more straightforward, someone should
just collect an overview of how users interact with different ones,
like Make, Maven, Gradle, Rake, etc, to firmly establish the common
ground.
IMHO better approach would be to provide an API that could be
used by build tool specific plugins to add build tasks
(in a Command Pattern manner). Such registered commands could be
presented to a user in some uniform form. For example:
In Maven plugin:
(build-api-add-command
{name: "compile", command: function-ref})
When user selects a command the unified build tools runner does:
(defun build-api-run (command)
(apply command.function-ref))
Of course, there can be more than one build tool in a project,
so, if windows/menus were presented, the user would see for each of them
or maybe depending on current buffer's mode.
But the point is to provide an API not an implementation.