Skip to content
DomenikP edited this page Aug 2, 2016 · 47 revisions

This page describes how to setup a build for MPS projects that are based on the mbeddr platform or on mbeddr itself. If your project depends on mbeddr, please continue reading in mbeddr, otherwise, please continue reading in mbeddr Platform.

mbeddr Platform

This section describes a template that we have created for illustrating how to setup a build script depending on the mbeddr platform. Further, we discuss for an example Base Language extension using the platform how to setup a build script by using this template.

Build Script Template

We have created a template illustrating how to setup a MPS build script for building a MPS project on top of the mbeddr platform. This template is named platform-extension.template and is shipped with the mbeddr platform distribution, which can either be downloaded from the release page or resolved via a gradle script. If you use the mbeddr platform from sources, you can find the template inside the the mbeddr build project that can be found here:

mbeddr.core
└─code
  └─languages
    └─com.mbeddr.build

The MPS Build Script guide explains parts that can be used in a MPS build script, specifically for this template, but also for the mbeddr build script template. Please read this guide before you continue reading.

<a name"ExamplePlatformProject"> Example mbeddr Platform based Project

After describing the build script template in the section before, we now continue by discussing an example MPS project that we have built on top of the mbeddr platform. The complete source code for this example is located in the language module com.baselanguage.unless that is part of the mbeddr repository and can be found at the following file system location:

mbeddr.core
└─code
  └─applications
    └─com.mbeddr.build-examples

The notion behind this example is to illustrate based on an UnlessStatement that we have written for MPS' base language how the previously described build script template is used for writing a real-world build script. To create an icon for the UnlessStatement, we have used the language com.mbeddr.mpsutil.iconchar coming with the mbeddr platform. By using this language, we have introduced a dependency from our unless language to the mbeddr platform. The build script com.baselanguage.unless.build (shown in the screenshot below) for our language com.baselanguage.unless reflects this dependency and is based on the template build script for the mbeddr platform (platform-extension.template) that we have described before. In addition to content from the template, this build script contains a macro mbeddr.github.core.home that points to the repository root and specifies the value of artifacts.root to point to a folder artifacts located right underneath the repository root. Further, the script enriches the idea plugin from the template with additional information and contains a mps group com.baselanguage.unless that contains a lanuage com.baselanguage.unless, referring to the .mpl file via the macro mbeddr.github.core.home. Running code generation on the build solution will generate the ant script that we can directly invoke from the command-line.

Build script for the UnlessStatement

After running code generation on the build solution that contains our build script, we will find a generated build.xml representing an ant script at the following file system location:

mbeddr.core
└─build
  └─com.baselanguage.unless.build
    └─build.xml

The ant script execution guide explains in detail how you can resolve the required dependencies and execute this generated ant script. After executing the script as explained in this guide, you will find the packaged MPS plugin at the following file system location:

mbeddr.core
└─build
  └─com.baselanguage.unless.build
    └─build
      └─artifacts
        └─com.baselanguage.unless.build
          └─com.baselanguage.unless.zip

mbeddr

This section describes two templates that we have created for illustrating how to setup a build depending on mbeddr. Further, we discuss for an example mbeddr C extension how to setup a build script by using these templates.

Build Script Templates

We have created two templates, first, a template to illustrate how to setup a MPS build script for building a MPS project on top of mbeddr, second, a template to create a build script that generates ant scripts from your build solutions. While you would use the former script to package your plugins, the latter script is used during the development for preventing developers to checkin generated ant scripts. For build script generation (the latter script), developers checkin only one ant script, that generates all other ant scripts before the actual build is started.

The template for building solutions/languages is named mbeddr-extension.template, while the second template to automatically generate ant scripts from your build solutions is named mbeddr-allScripts-extension.template.

We ship both scripts with the mbeddr allInOne distribution , which can either be downloaded from the release page or resolved via a gradle script. If you use mbeddr from sources, you can find the template inside the the mbeddr build project that can be found here:

mbeddr.core
└─code
  └─languages
    └─com.mbeddr.build

The MPS Build Script guide explains parts that can be used in a MPS build script, specifically for this template, but also for the mbeddr build script template. Please read this guide before you continue reading.

<a name"ExamplembeddrProject"> Example mbeddr-based Project

After describing the build script template in the section before, we now continue by discussing an example MPS project that we have built on top of mbeddr. The complete source code for this example is located in the language module com.mbeddr.unless that is part of the mbeddr repository and can be found at the following file system location:

mbeddr.core
└─code
  └─applications
    └─com.mbeddr.build-examples

The notion behind this example is to illustrate based on an UnlessStatement that we have written as an mbeddr extension how the previously described build script templates are used for writing a real-world build script. The language depends on mbeddr, because UnlessStatement extends mbeddr Statement and holds an Expression. More specifically, our implementation depends on the language module com.mbeddr.statement (contains Statement) and com.mbeddr.expression (contains Expression). The build script com.mbeddr.unless.build (shown in the screenshot below) for our language com.mbeddr.unless reflects this dependency and is based on the template build script for the mbeddr platform (mbeddr-extension.template) that we have described before. In addition to content from the template, this build script contains a macro mbeddr.github.core.home that points to the repository root and specifies the value of artifacts.root to point to a folder artifacts located right underneath the repository root. Further, the script enriches the idea plugin from the template with additional information and contains a mps group com.mbeddr.unless that contains a lanuage com.mbeddr.unless, referring to the .mpl file via the macro mbeddr.github.core.home. Running code generation on the build solution will generate the ant script that we can directly invoke from the command-line.

Build script for the UnlessStatement

After running code generation on the build solution that contains our build script, we will find a generated build.xml representing an ant script at the following file system location:

mbeddr.core
└─build
  └─com.mbeddr.unless.build
    └─build.xml

The ant script execution guide explains in detail how you can resolve the required dependencies and execute this generated ant script. After executing the script as explained in this guide, you will find the packaged MPS plugin at the following file system location:

mbeddr.core
└─build
  └─com.mbeddr.unless.build
    └─build
      └─artifacts
        └─com.mbeddr.unless.build
          └─com.mbeddr.unless.zip

Besides the script for building a plugin for the com.mbeddr.unless language, the same build solution contains another build script com.mbeddr.unless-allScripts.build that we use for generating an ant script for the former build script. The idea behind this approach is that developers do not check-in generated ant scripts, instead, only the ant script that has been generated from this build script. Before running the actual build, we first of all invoke this ant script to generate the other build scripts. While this approach prevents users from checking in generated files, it also supports developers as the build gets interrupted, if dependencies change while your languages evolve.

Finally, the build solution contains the build script com.mbeddr.unless.sandbox.build that we use for building application code that uses our com.mbeddr.unless language. These three scripts give you an impression of how to run build script generation, build language plugins that base on mbeddr and build an application that uses mbeddr and your own mbeddr extension.

MPS Build Scripts

Build scripts declare on top (see screenshot below) a set of macros that we use for resolving paths during the build, e.g., mps.home refers to your MPS installation, artifacts.root points to a file system location where all of your dependencies will be located. In the screenshot below, we specify a macro platform.distribution.artifacts that refers to the location of the mbeddr platform distribution, a build artifact representing the compiled and packaged mbeddr platform release. In case you write a build script using the mbeddr template, then you will have a macro for the mbeddr build script, e.g., mbeddr.allInOne.artifacts.

Macros defined in build script template

Below the macros section is the dependencies section (see screenshot below) that defines through referenced build scripts a set of artifacts that have to be present at build time. In our templates we define dependencies on mps, mpsBuild and mpsDebuggerPlugin, all three coming with MPS. Further, we use the previously described mps.home macro to resolve these artifacts from the MPS installation. You can specify artifact locations by typing an opening parenthesis behind the build script name. It's good practice to have such an artifact locations for each dependency. Besides MPS, we define in build scripts dependencies on build scripts that bundle plugins on which we base our languages or solutions. In case of the build script examples discussed in this guide, this is either com.mbeddr.platform.distribution or com.mbeddr.allInOne. The screenshot below demonstrates an example dependency on com.mbeddr.platform.distribution.

Build time Dependencies defined in build script template

The project structure is used for configuring the build, describing plugin descriptors and listing all solutions and languages that should be built. On top of this section (see screenshot below), we usually have generator options being used for configuring the code generator with the same options that we use in mbeddr. Next, java options configures the Java compiler being used for compiling languages, and solutions containing Base Language code. Next, is a template for an idea plugin (see screenshot below) that contains dummy names, which you should replace with project-specific names. Each idea plugin ends up in an idea plugin descriptor, serialized to xml and packaged with the compiled plugin code. While these plugin descriptors specify a set of names, they additionally require a version number, optional vendor information, content referring to solutions and language described in same section and being packaged with the plugin. Finally, runtime dependencies lists other plugins that should be available in the MPS target environment where your plugin is deployed.

Below the idea plugin is a mps group <your solutions/languages group> that you can use for grouping languages and solutions that you want to build and package in a plugin. After copying the template, please change the group name accordingly to your project. Inside this group, you can either type the word language or solution on the cell containing the text <empty> to specify a module that you want to build with your build script. While you will normally list here the languages you want to build, you might also list the build solutions (solutions) for which you want to generate ant scripts. Next, you can specify in the load from section of your instantiated module a path to the .msd (solution) or .mpl (language) file that contains meta information for your module. While you can enter this path in a relative way using the "./" prefix, we encourage you to define a macro on top of your build script for resolving the file system path. Further, you should also create a macro for your repository, e.g. <your repository name>.home, that you can use as a base path for resolving the file system location of your modules. By using macros for this purpose, you can overwrite their values from outside the build script when executing the ant script that gets generated from your MPS build script.

Next, in default layout, we describe the structure of our packaged artifacts. Inside our template, we configure the build to package our compiled plugin (yourplugin) inside a zip file (<your plugin.zip>). Finally, below this section, we configure via mps settings the headless MPS instance being used throughout the build. In this configuration, first, we enable bootstrapping allowing MPS to break up modules (solutions/languages) into multiple smaller chunks while running code generation and compilation. This option is used in case of cyclic dependencies, and is only relevant for code generation and compilation, it does not influence the layout of classes or packaging of plugins. It's good practice to leave this options disabled, because MPS will interrupt code generation for your build script with an error message, pointing you to cycles between your modules. Finally, both heap-related options at the bottom of this configuration are important, if you run into out of memory issues during code generation.

Build time Dependencies defined in build script template

Resolving the mbeddr/platform Release

You can either download the mbeddr and the mbeddr platform release from our GitHub release page, or resolve these artifacts from our Nexus by using a Gradle script that can be found inside the mbeddr.core repository:

mbeddr.core
└─download.gradle

This script provides three tasks, one for resolving the required MPS distribution (resolveMPS), one for resolving the mbeddr release (resolveMbeddr) and another one for resolving the mbeddr platform release (resolvePlatform). This script declares two variables that specify file system locations where resolved artifacts should be copied to, both paths can be overwritten from outside when executing the script. Per default, the resolved MPS is downloaded to a folder <current directory>/mps (mpsLocation), whereas mbeddr and the mbeddr platform is downloaded to <current directory>artifacts (artifacstLocation).

Executing generated Ant Scripts

Before executing a generated ant script, we first of all make sure all dependencies are in place. For the mbeddr platform exaple, this comprises resolving MPS and additionally the mbeddr platform release. In contrast, the mbeddr exaple requires the mbeddr release and MPS. While we could download these artifacts for both example projects from the release page and MPS from the JetBrains release page, we use a gradle script to resolve these artifacts. The following command demonstrates how we invoke this script in the mbeddr.core repository root from the command line to resolve the mbeddr platform distribution and MPS:

gradle -b download.gradle resolveMPS resolvePlatform

Afterwards, we will see the artifacts shown below on the file system of the mbeddr.core repository.

mbeddr.core
└─artifacts
  └─artifacts
    └─com.mbeddr.platform.distribution
      └─platform-distribution.zip
└─MPS

Next, remember, paths specified in macros will not be correct for your local machine, hence, we have to update them for your build environment. We don't do this inside the MPS build script, instead, we overwrite these values from the command-line, passing a set of arguments using the following syntax: -D<name>=<value>. In the snippet below, we do this for Dartifacts.root and mps.home, providing the path of the resolved MPS folder that is located inside the mbeddr.core repository (e.g., C:/repos/mbeddr.core/MPS). To execute the generated ant script, we invoke the targets clean, generate, and assemble. The following snippet shows the complete command being executed in the folder where your generated script is located:

ant -Dmps.home=<path to mbeddr.core repo>/MPS -Dartifacts.root=<path to mbeddr.core repo>/artifacts -f build.xml clean generate assemble

After executing your build script, you will find your packaged plugin at the following file system location:

<folder where your generated ant script is located>
└─ <your generated ant script>.xml (your generated ant script)
└─ build
   └─ artifacts
      └─ <name of your build solution>
      └─ <name of your packaged plugin>.zip