MPS 2021.1 Help

Getting the dependencies right

Motivation

Modules and models are typically interconnected by a network of dependencies of various types. Assuming you have understood the basic principles and categorisations of modules and models, as described at the  MPS project structure  page, we can now dive deeper as learn all the details.

Getting dependencies right in MPS is a frequent cause of frustration among inexperienced users as well as seasoned veterans. This page aims to solve the problem once and for all. You should be able to find all the relevant information categorised into sections by the various module and dependency types.

All programming languages have a notion of "imports". In Java you get packages and the "import" statement. In Ruby or Python you have "modules" and "require" or "import" statements. In MPS we provide a similar mechanism for packaging code and expressing dependencies in a way that works universally across languages - code is packages into models and these models can express mutual dependencies.

In addtion, since MPS is a multi-language development environment, models can specify the languages (aka syntaxes) enabled in them. This is different from when writing code in Java, Ruby or other languages, where the language to be used is given and fixed by conventions (e.g. the file extension).

Useful keyboard shortcuts

Whenever positioned on a  model  or a  node  in the left-hand-side  Project Tool Window  or when editing in the editor, you can invoke quick actions with the keyboard that will add dependencies or used languages into the current model as well as its containing solution.

  • Ctrl+L  - Add a used language

  • Ctrl+M  - Add a dependency

  • Ctrl+R  - Add a dependency that contains a root concept of a given name

  • Ctrl+Shift+A  - brings up a generic action-selction dialog, in which you can select the desired action applicable in the current context

Solution

Solutions represent programs written in one or more languages. They typically serve two purposes:

  1. Sandbox solutions  - these solutions hold an end user code. The IDE does not treat the code in any special way.

  2. Runtime  solutions  - these solutions contain code that other modules (Solutions, Languages or Generators) depend on. The code can consist of MPS models as well as of Java classes, sources or jar files. The IDE will reload the classes, whenever they get compiled or changed externally.

  3. Plugin solutions  - these solutions extend the IDE functionality in some way. They can contribute new menu entries, add side tool panel windows, define custom preference screens from the Project settings dialog, etc. Again, MPS will keep reloading the classes, whenever they change. Additionally the IDE functionality will be updated accordingly.

We'll start with the properties valid for all solutions and then cover the specifics of runtime and plugin solutions.

Solution1

Common

Properties

  • Name  - name of the solution

  • File path  - path the module file

  • Generator output path  - points to the folder, where generated sources should be placed

  • Left-side panel  - contains model roots, each of which may hold one or more models.

  • Right-side panel  - displays the directory structure under the  model root  currently selected in the left-side panel. Folders and jar files can be selected and marked/unmarked as being models of the current model root.

Model root types

Solutions contain model roots, which in turn contain models. Each model root typically points to a folder and the contained models lie in one or more sub-folders of that folder. Depending on the type of contained models, the model roots are of different kinds:

  • default- the standard MPS model root type holding MPS models

  • java_classes- a set of directories or jar files containing Java class files

  • javasource_stubs- a set of directories or jar files containing Java sources

Dependencies

The dependencies of a solutions are other solutions and languages, the models of which will be visible from within this solution.

The Export flag then specifies whether the dependency should be transitively added as a dependency to all modules that depend on the current solution. For example, of module A depends on B with export on and C depends on A, then C depends on B.

Used Languages

The languages as well as devkits that the solution's models may use are listed among used languages. Used languages are specified on the model level and the Used Languages  tab on modules only shows a collection of used languages of its all models.

Java

This is where the different kinds of Solutions differ mostly.

The Java tab contains several options:

  • Solution kind  - different kinds of solutions are treated slightly differently by MPS and have access to different MPS internals
    • None  - default, used for user code, which does not need any special class-loading strategy - use for  Sandbox solutions

    • Other  - used by typical libraries of reusable code that are being leveraged by other languages and solutions - use for  Runtime solutions

    • Core plugin  - used by code that ties into the MPS IDE core and needs to have its class-loading managed accordingly - use for  Plugin solutions

    • Editor plugin  used by code that ties into the MPS editor and needs to have its class-loading managed in sync with the rest of the editor- use for  Plugin solutions that only enhance the editor

  • Compile in MPS  - indicates, whether the generated artifacts should be compiled with the Java compiler directly in MPS and part of the generation process

  • Source Paths  - Java sources that should be made available to other Java code in the project

  • Libraries  - Java classes and jars that are required at run-time by the Java code in one or more models of the solution

Facets

  • Custom Generation  - allows attaching a generator plan to the module. More on explicit generator plans is to be found at the Generator plans documentation.

  • Idea Plugin  - checked, if the solution hooks into the IDE functionality

  • Java  - checked, if the solution relies on Java on some way. Keep this checked in most cases.

  • tests  - checked, if the solution contains test models

Solution models

Solutions contain one or more models. Models can be mutually nested and form hierarchies, just like, for example, Java packages can. The properties dialog hides a few configuration options that can be tweaked:

Model1

Dependencies

Models from the current or imported modules can be listed here, so that their elements become accessible in code of this model.

Used languages

The languages used by this model must be listed here.

Advanced

A few extra options are listed on the Advanced tab:

  • Do not generate  - exclude this model from code generation, perhaps because it cannot be meaningfully generated

  • File path  - location of the model file

  • Languages engaged on generation  - lists languages needed for proper generation of the model, if the languages are not directly or indirectly associated with any of the used languages and thus the generator fails finding these languages automatically

Virtual packages

Nodes in models can be logically organised into hierarchies of virtual packages. Use the Set Virtual Package  option from the node's context pop-up menu and specify a name, possibly separating nested virtual folder names with the dot  symbol.

Adding external Java classes and jars to a project - runtime solutions

Runtime solutions represent libraries of reusable code in MPS. They may contain models holding MPS code as well as stub models that refer to external Java sources, classes or jar files. To properly include external Java code in a project, you need to follow a few steps:

  1. Create a new Solution in your project.

  2. Copy the desired jar files, classes or Java sources into a directory under the solution's root folder, such as "/libs".

  3. In the Solution's properties dialog (Alt+Enter) attach the Java code. This requires a few steps:

    Model roots1

    1. First, in the left-hand side panel of the Common tab, which is used to manage model roots (i.e. locations of models that belong to the module), delete the existing model root unless you want to preserve or create code that you write in MPS as part of your runtime library.

    2. Second, also in the Common tab, click on  Add Model Root, select  javaclasses  for classes or jars, select  javasource_stubs  for Java sources and navigate MPS to your lib folder. This will add a new entry into the list of model roots. This entry will represent the "libs" folder

    3. Third, when the new model root is selected in the left-hand side panel, select the folder(s) or jar(s) listed in the right-side panel of the properties dialog and click on the blue "Models" button at the top of the right-hand side panel. The selected folders and jars will be shown with a blue icon next to them in the right-hand side panel.

    4. Switch to the Dependencies tab and add the JDK solution as a dependency. Do not forget to turn on the Export flag. This will allow your jar files to refer to the JDK classes.

      Model roots6

    5. Then head to the  Java tab   to add all the jars or the classes root folders to the  Libraries  part of the window, otherwise the solution using the library classes would not be able to compile. When using  java_sourcestubs, add the sources into the  Source paths  part of the  Java tab  window, instead. Also add any dependencies of the libraries that you have added to the module.

      Model roots2

    6. Additionally, set Solution Kind to Other to have MPS reload the classes properly.

  4. A new folder named  stubs  should appear in your solution

    Model roots3
    .

  5. Now after you import the solution into another module (solution, language, generator) the classes will become available in that module's models.

  6. The languages that want to use the runtime solution as a runtime dependency of the code that gets generated by the language's generator will need to refer to it in the Runtime Solutions section of the  Runtime tab of their module properties.

    Model roots4

  7. Include the runtime jars in the build models - If you use the MPS build scripts to build a plugin with your languages you should also package the runtime libraries in the plugin by copying them into the desired location within the target layout definition.

    Model roots5

    If you forget to do so, you'll be getting errors like "No such path in local layout" when rebuilding the build script's model.

Language

Languages represent a language definition and consist of several models, each of which represent a distinct aspect of the language. Languages also contain a single Generator  module. The properties dialog for languages is in many ways similar to the one of Solutions. Below we will only mention the differences:

Language1

Common

A language typically has a single model root that points to a directory, in which all the models for the distinct aspects are located.

Dependencies

The dependencies of a language are other solutions and languages, the models of which will be visible from within this solution. The  Export  flag then specifies whether the dependency should be transitively added as a dependency to all modules that depend on the current language.

A dependency on a language offers thee Scope  options:

  • Default- only makes the models of the other language/solution available for references (aggregation)
    The structure aspects manifest languages they incorporate by aggregation (i.e. using a foreign concept in a child role), there's no need to import such languages explicitly into a model that uses the aggregating language or to 'extend' language modules.

  • Extends  - allows the language to define concepts extending concepts from the there language

  • Generation Target  - specifies that the current language is generated into the other language, thus placing a generator ordering constraint that the other language must only be generated after the current one has finished generating

Used Languages

This is the same as for solutions.

Runtime

  • Runtime Solutions- lists solutions of reusable code that the language requires. See the "Adding external Java classes and jars to a project - runtime solutions" section above for details on how to create such a solution.

  • Accessory models  - lists accessory models that the language needs. Nodes contained in these accessory models are implicitly available on the Java classpath and the Dependencies of any model using this language.

Java

This is the same as for solutions, except for the two missing options that are not applicable to languages.

Facets

This is the same as for solutions.

Language models/aspects

Dependencies / Used Languages / Advanced

These settings are the same and have the same meaning as the settings on any other models, as described in the Solution  section.

Generator

The generator module settings are very similar to those of other module types:

Generator1

Common

This is the same as for languages.

Dependencies

This is the same as for solutions. Additionally generator modules may depend on other generator modules and specify Scope:

  • Default  - only makes the models of the other language/solution available for references

  • Extends  - the current generator will be able to extend the generator elements of the extended generator

  • Design  - the target generator is only needed to be referred from a priority rule of this generator

Used Languages

This is the same as for languages.

Generators priorities

This tab allows to define priority rules  for generators, in order to properly order the generators in the generation process. Additionally, three options are configurable through the check-boxes at the bottom of the dialog:

  • Generate Templates  - indicates, whether the generator templates should be generated and compiled into Java, or whether they should be instead interpreted by the generator during generation

  • Reflective queries  - indicates, whether the generated queries will be invoked through Java reflection or not. (Check out the Generator documentation for details)

  • IOperationContext parameter  - indicates, whether the generator makes use of the operationContext  parameter passed into the queries. The parameter will be removed in the future and generators should gradually stop using it.

Java

This is the same as for languages.

Facets

This is the same as for languages.

Generator models

This is the same as for solutions.

Last modified: 12 May 2021