From 7b05766a8ffe0e339e57540696c09860988fe781 Mon Sep 17 00:00:00 2001 From: Dmitry Lomov Date: Fri, 10 Jun 2016 10:07:30 +0000 Subject: [PATCH] IDE support blog post. Fixes #31. -- MOS_MIGRATED_REVID=124545704 --- site/blog/_posts/2016-06-10-ide-support.md | 93 +++++++++++++++++++++ site/blog/e4b-workflow.png | Bin 0 -> 21967 bytes site/blog/e4b-workflow.svg | 4 + 3 files changed, 97 insertions(+) create mode 100644 site/blog/_posts/2016-06-10-ide-support.md create mode 100644 site/blog/e4b-workflow.png create mode 100644 site/blog/e4b-workflow.svg diff --git a/site/blog/_posts/2016-06-10-ide-support.md b/site/blog/_posts/2016-06-10-ide-support.md new file mode 100644 index 00000000000000..eeb5bda715a011 --- /dev/null +++ b/site/blog/_posts/2016-06-10-ide-support.md @@ -0,0 +1,93 @@ +--- +layouts: posts +title: [IDE support] +--- +One of Bazel’s longest-standing feature requests is integration with IDEs. +With the 0.3 release, we finally have all machinery in place that allows +implementing integration with Bazel in IDEs. Simultaneous with that +Bazel release we are also making public two IDE plugins: + +* [Tulsi](http://tulsi.bazel.io): Bazel support for Xcode. +* [e4b](https://github.com/bazelbuild/e4b): a sample Bazel plugin for Eclipse. + +In this post, we will look into how Bazel enables IDE integration +and how an IDE plugin integrating with Bazel can be implemented. + + +## Principles of Bazel IDE support + +Bazel BUILD files provide a description of a project’s source code: what +source files are part of the project, what artifacts (targets) should be +built from those files, what the dependencies between those files are, etc. +Bazel uses this information to perform a build, that is, it figures out the set +of actions needed to produce the artifacts (such as running a compiler or +linker) and executes those actions. Bazel accomplishes this by constructing a +_dependency graph_ between targets and visiting this graph to collect +those actions. + +IDEs (as well as other tools working with source code) also need the same +information about the set of sources and their roles; but instead of building +the artifacts, IDEs use it to provide code navigation, autocompletion and +other code-aware features. + +In the 0.3.0 Bazel release, we are adding a new concept to Bazel - +[_aspects_](/docs/skylark/aspects.html). +Aspects allow augmenting build dependency graphs with additional information +and actions. Applying an aspect to a build target creates a "shadow +dependency graph" reflecting all transitive depenedencies of that target, +and the aspect's implementation determines the actions that Bazel executes +while traversing that graph. +The [documentation on aspects](/docs/skylark/aspects.html) explains this in more +detail. + +## Architecture of a Bazel IDE plugin. + +As an example of how aspects are useful for IDE integration, we will take +a look at a sample +[Eclipse plugin for Bazel support, e4b](https://github.com/bazelbuild/e4b). + +e4b includes an aspect, defined in a file +[e4b_aspect.bzl](https://github.com/bazelbuild/e4b/blob/master/com.google.devtools.bazel.e4b/resources/tools/must/be/unique/e4b_aspect.bzl), +that when +applied to a particular target, generates a small JSON file with information +about that target relevant to Eclipse. Those JSON files are then consumed +by the e4b plugin inside Eclipse to build [Eclipse's representation +of a project](https://github.com/bazelbuild/e4b/blob/master/com.google.devtools.bazel.e4b/src/com/google/devtools/bazel/e4b/classpath/BazelClasspathContainer.java), +[IClasspathContainer](http://help.eclipse.org/juno/index.jsp?topic=%2Forg.eclipse.jdt.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fjdt%2Fcore%2FIClasspathContainer.html): + +![e4bazel workflow](e4b-workflow.png) + +Through the e4b plugin UI, the user specifies an initial set of targets +(typically a java or android binary, a selection of tests, all targets +in certain packages, etc). E4b plugin then invokes bazel as follows: + +``` +bazel build //java/com/company/example:main \ +--aspect e4b_aspect.bzl%e4b_aspect \ +--output_groups ide-info +``` + +(some details are omitted for clarity; see +[e4b source](https://github.com/bazelbuild/e4b/blob/master/com.google.devtools.bazel.e4b/src/com/google/devtools/bazel/e4b/command/BazelCommand.java) for complete +invocation) + +The "--aspect" flag directs Bazel to apply e4b_aspect, exported from +e4bazel.bzl Skylark extension, to target //java/com/company/example:main. + +The aspect is then applied transitively to the dependencies of the specified +targets, producing `.e4b-build.json` files for each target in the transitive +closure of dependencies. The e4b plugin reads those outputs and provides +a Classpath for Eclipse core to consume. If the input BUILD files change +so that a project model needs to be re-synced, the plugin still invokes +the exact same command: Bazel will rebuild only those files that are affected +by the change, so the plugin need only reexamine only those newly built +`.e4b-build.json` files. `ide-info` is an output group defined by e4b_aspect; +the `--output_groups` flag ensures that only the artifacts belonging to that +group (and hence only to the aspect) are built, and therefore that no +unnecessary build steps are performed. + +The aspect uses the +['java' provider](/docs/skylark/lib/JavaSkylarkApiProvider.html) on the targets +it applies to to access a variety of information about Java targets. + + diff --git a/site/blog/e4b-workflow.png b/site/blog/e4b-workflow.png new file mode 100644 index 0000000000000000000000000000000000000000..412822da72faf39038e61f4e28ef571ea0131ea4 GIT binary patch literal 21967 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 + + +