Skip to content
DomenikP edited this page Sep 29, 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. Further, we also explain how to setup an RCP build to package your plugins in a customized MPS.

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

Packaging a custom RCP

This how-to explains how to package your languages into a custom MPS packaging that doesn't contain any "meta stuff". So you get a specialized just for your languages and nothing more. This tutorial assumes that you already know the basics of building and packaging languages/solutions with MPS and ANT.

Terminology

MPS Distribution

Is the generic MPS distribution that can be download from jetbrains here it is important to use this distribution and not a platform specific one. Only this distribution contains all the necessary files to create RCP.

Build solution

A solution primarily used for building plugins and languages. There is nothing special about it in MPS. Its more a convention that it is only used for build languages and plugins.

Build Project

A special root node the in the model which is needed to generate an XML build script from it. It contains all information needed for the build process. For instance languages that are build, dependencies on other build script and information about how to package the build artifacts.

Build Script

An XML file containing the actual steps executed by ANT. This is generated from the Build Solution.

Plugin

An Idea plugin definition created in a build script. A plugin contains several languages and solutions.

Build Layout

The Build Layout is a part of the build solution. It specifies the information how the plugins and languages should be packaged. It is used to create zip files for a single plugin or to bundle multiple plugins into a single zip file. Like any other content of a build solution these parts can be reused by other build solutions.

Branding

todo

Setting up the build project

First of all you need a build solution in your model. Now you have this open the com.mbeddr.mpsutil.rcpconfig.template solution and copy the content of the template build solution into your own. While you do this you will be asked to add some dependencies, you don't need all of them. The dependency on jetbrains.mps.ide.build is enough. Once you have finished it should look like this:

build overview

Macros

The template has two macros, the first one version is used to name the zips and later in the optional branding. The second one mps.home is a path macro that should point to your MPS distribution.

Dependencies

There is only one dependency needed for the MPS files: mpsStandalone. This is the place where you add the dependencies on your own build scripts to include your files.

Project Structure

There is no content here. But the optional Branding will be placed here.

Default Layout

The build layout contains 3 files, one for each platform. Beside the platform specific files those three zips should contain the plugins that you want to ship. We will talk about how to add them in the next section.

Adding your own plugins

Now you have a skeleton in which you can insert your plugins. The plugins reside in the plugins folder of the RCP. In this case it is easy because mbeddr already provides a complete package of its plugins. So I can directly include the contents of the zip file. To do so we need a dependency on the build solution that creates the mbeddr zip file. It is named com.mbeddr.allInOne. Then we put the content of the plugins folder to the plugins folder of our RCP build. If you have such a zip file you can do the same. If you don't, you have to package your plugins manually (don't forget to include your dependencies, like jars or other resources). The RCP Layout should looks like this:

mbeddr plugins

Make sure you include your plugins into all of the three packages.

Branding

MPS allows you to brand the RCP version of MPS that you build. The branding allows you to customize:

branding

Codename

An internal code name not shown to the user but used when fetching updates and plugins

Version

A version number presented to the user. It is also transmitted when the IDE looks for updates.

Full Name

The Name presented to the user in various places like the about screen or in the new project wizard.

Build Number

The build number of your IDE. It must have the following format {platform build number}.{applcation build number} where the platform build number must match the platform build number of your MPS. If this number doesn't match the platform build number of MPS some plugins will not load and your RCP build won't start. If have any issues loading certain plugins check if your platform build number is correct.

Build Date

A string representing the build date of your IDE. There is nothing special about this. As far as I know it is only used to show in the about screen.

Icons (16x16, 32x32 and 32x32 opaque)

Icon used in various places in the IDE and as a APP Icon of the Mac version of your RCP.

Splash Screen & Text Color

The splash screen shown at startup until the IDE is ready to use. Some information like the Fullname and the build number are rendered on it by MPS. You can change the color of the text with the text color property which must be the hex value of the color.

About Screen

The about screen used to show when the user clicks on "About {Full Name}" in some places in the RCP. The same text color specified in the splash screen is used to render some information on that screen.

Dialog Image

Image used for popup dialogs. Those appear rarely in MPS. Most likely in fatal error situations where IDE crashes completely.

Welcome Screen

welcome screen

In the left upper corner is the logo, the text in the middle is the caption and right upper corner the slogan. All of these have to be images.

Update Website

There is no official documentation availabe for this. All of these information is based on observation ann reading the MPS sources.

Check Url

The check url must point to a update.xml file which contains the update informations. The xml should look like this. You will find references to the other values in the branding there. If you plan to use this for notifying your users about updates you need to create a update.xml with similar information adapted for your RCP.

Update Url

The Url your RCP opens when it notices that there is an update though the check url.

Channel

The channel chosen from the update.xml.

Custom file locations

Once you have your custom RCP build of MPS you will notice that it will still interfere with a normal MPS installation. For instance plugins, settings and cache are stored in the same location as for a normal MPS. You can control the location of these with an idea.properties file which has to be placed in the bin directory of your RCP. A sample file might look like this:

#---------------------------------------------------------------------
# Uncomment this option if you want to customize path to MPS config folder
#---------------------------------------------------------------------
idea.config.path=${user.home}/.mbeddr/config

#---------------------------------------------------------------------
# Uncomment this option if you want to customize path to MPS system folder
#---------------------------------------------------------------------
idea.system.path=${user.home}/.mbeddr/system

#---------------------------------------------------------------------
# Uncomment this option if you want to customize path to user installed plugins folder
#---------------------------------------------------------------------
idea.plugins.path=${user.home}/.mbeddr/config/plugins

#---------------------------------------------------------------------
# Uncomment this option if you want to customize path to MPS logs folder. Make sure you are using forward slashes
#---------------------------------------------------------------------
idea.log.path=${user.home}/.mbeddr/system/log

For your RCP you should replace the .mbeddr in the paths with something that fits your product. Once you have created a idea.properties file you have to place it in the bin folder of your RCP by adding a new copy rule to the build solution. First you need to remove the original idea.properties file from the zip:

exclude original idea.properties

Then you copy your custom file:

copy idea.properties

Additional information

Troubleshooting

Known Pitfalls