{"id":346,"date":"2025-02-10T15:45:06","date_gmt":"2025-02-10T15:45:06","guid":{"rendered":"https:\/\/kinori.tech\/blog\/?p=346"},"modified":"2025-02-11T18:07:15","modified_gmt":"2025-02-11T18:07:15","slug":"building-an-xtext-project-with-tycho","status":"publish","type":"post","link":"https:\/\/kinori.tech\/blog\/en\/2025\/02\/10\/building-an-xtext-project-with-tycho\/","title":{"rendered":"Building an Xtext project with Tycho"},"content":{"rendered":"\n<p>I am fond of <a href=\"https:\/\/en.wikipedia.org\/wiki\/Integrated_development_environment\">IDE<\/a>s. They make my life simpler, mainly because I am not fond of memorizing every thing. Code completion, syntax highlighting, run configurations, automatic code generation&#8230; Well, to be honest, &#8216;automated&#8217; things is where I usually start getting aggravated. Not because they don&#8217;t work, but because they usually hide complex configurations and use &#8216;sensible defaults&#8217; that are strongly opinionated and that blow everything up when you try to do things your way. In today&#8217;s post the culprit is Xtext.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Hiding behind curtain number one<\/h2>\n\n\n\n<p>There are two Xtext features that do tons of work, and one is particularly heavy on sensible defaults. The first one is the use of Xtend; although to be honest Xtext has tried to distance itself from Xtend as the Java API has made Xtend a bit redundant. The second one is the language generation via MWE2.<\/p>\n\n\n\n<p>For Xtend, you have not probably realized that Xtend code has to be actually compiled into Java code. You probably have not realized it, because it is <em>automatically <\/em>done by the Xtend editor when you save your code. If curios, go ahead and delete the files in  your <em>xtend-gen<\/em> folders. Because it is usually frowned upon to commit generated code, you will happily run your Tycho build just to find out that your build fails, if you are lucky, do to missing classes; if you are out of luck, your build will fail because &#8216;no tests where found&#8217; and you would spend 2 days looking at your Xtend test, asking why you see the test in your editor and your build refuses to find it. Well, it can&#8217;t find any tests because your Xtend test classes have not been compiled.<\/p>\n\n\n\n<p>For Xtext, you know that every time you change your language you need to run your &#8216;Generate XXX (yyy) Language Infrastructure&#8217; run configuration. Unless you are using imported ecore metamodels or complex language mixins, you have probably never looked at the MWE2 file that Xtext creates for you. And even if you did, you probably made changes to the parts that do not affect the &#8216;sensible defaults&#8217; that will ruin your week&#8230; OK, I am over reacting.<\/p>\n\n\n\n<p>So the MWE2 file is responsible for generating the language infrastructure. This means it generates the ECore metamodel for your language, and all the required java classes for your language to work. If curios, go ahead and delete the files in  your <em>src-gen<\/em> folders. Again, all those <em>src-gen<\/em> files should not be committed, so your Tycho build will fail do to missing classes. Thus, your Tycho build must run the MWE2 configuration&#8230; and here is where the sensible defaults will test your deduction skills.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Solving the Xtend compilation<\/h2>\n\n\n\n<p>There are some considerations and assumptions we need to get straight before you understand what we need to do to make it work. First things are simpler for the source bundles than for the tests. I have a feeling that the <kbd>tycho-source-plugin<\/kbd> has something to do with this; I assume it is responsible for the tweaks I had to do to make the tests work. Second, your test bundles SHOULD ONLY USE xTend sources. If you try to mix java with xtend tests, then you will have another problem in your hands as maven does not like projects with multiple source folders. There is an <a href=\"https:\/\/maven.apache.org\/guides\/mini\/guide-using-one-source-directory.html\">official guide<\/a> on how to make it work; perhaps you can adapt his post to that scenario.<\/p>\n\n\n\n<p>In both cases all you need to do is use the Xtend maven plugin. Easy right? Just need to add it to the poms of all the projects that use xtend. I am not a mojo expert, but from the source code of the <kbd>xtend-maven-plugin<\/kbd>, I think it is designed to work on a per-project basis. If your project is pom-less then you need to add poms to all the projects with xtend sources. In the pom, you need to add the <kbd>xtend-maven-plugin<\/kbd>. We are setting to paramters in the configuration, the encoding and the output dir. To keep it in sync with Eclipse, we will use the <kbd>xtend-gen<\/kbd> folder.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;project&gt;\n  ...\n  &lt;build&gt;\n    ...\n    &lt;pluginManagement&gt;\n      &lt;plugins&gt;\n  &lt;plugin&gt;\n    &lt;groupId&gt;org.eclipse.xtend&lt;\/groupId&gt;\n    &lt;artifactId&gt;xtend-maven-plugin&lt;\/artifactId&gt;\n    &lt;version&gt;${xtext-version}&lt;\/version&gt;\n    &lt;configuration&gt;\n\t  &lt;encoding&gt;${project.build.sourceEncoding}&lt;\/encoding&gt;\n\t  &lt;!-- need to prefix by basedir to generate to currently built module --&gt;\n\t  &lt;outputDirectory&gt;${basedir}\/xtend-gen&lt;\/outputDirectory&gt;\n\t   &lt;\/configuration&gt;\n  &lt;\/plugin&gt;\n  ...\n<\/pre><\/div>\n\n\n<p>So for the source plugins that, is all there it&#8217;s to it. Now for the test plugins&#8230;<\/p>\n\n\n\n<p>First, the xtend-maven-plugin runs during the <kbd>testCompile<\/kbd> phase for the test plugins. In that phase, maven will look for classes to compile (e.g. xtend) in the <kbd>testCompileSourceRoots<\/kbd> folder. In a typical Xtext project, that would be your <kbd>src<\/kbd> folder. So we could add the <kbd>src<\/kbd> folder to the project&#8217;s <kbd>testCompileSourceRoots<\/kbd>. However, not all projects have sources that need compilation in the src folder, so how can we avoid this? I found a helpful plugin called <a href=\"https:\/\/github.com\/lengors\/init-sources-maven-plugin\">init-sources-maven-plugin<\/a>. This plugin allows you to add folders to the <kbd>testCompileSourceRoots<\/kbd> on a per-project basis. Sweet! <\/p>\n\n\n\n<p>The second part of the tweaks is that we genrated our java test files in the <kbd>xtend-gen<\/kbd> folder, so we need to tell maven where to find them. Fianaly, we need to make suer that the<kbd> tycho-compiler-plugin<\/kbd> is called after the xtend files are generated, and that the <kbd>tycho-surefire-plugin<\/kbd> finds the compiled test classes in the correct location. Additionally, I also cleaned the xtend-gen folder, to make sure remanent classes don&#8217;t hide compilation problems. The resulting pom for the TEST projects would be:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;build&gt;\n  &lt;testSourceDirectory&gt;${project.basedir}\/xtend-gen&lt;\/testSourceDirectory&gt;\n  &lt;plugins&gt;\n    ...\n\t&lt;plugin&gt;\n\t  &lt;groupId&gt;org.eclipse.xtend&lt;\/groupId&gt;\n\t  &lt;artifactId&gt;xtend-maven-plugin&lt;\/artifactId&gt;\n\t  &lt;version&gt;${xtext-version}&lt;\/version&gt;\n\t  &lt;executions&gt;\n\t\t&lt;execution&gt;\n\t\t  &lt;goals&gt;\n\t\t\t&lt;goal&gt;testCompile&lt;\/goal&gt;\n\t\t  &lt;\/goals&gt;\n\t\t&lt;\/execution&gt;\n\t  &lt;\/executions&gt;\n\t  &lt;configuration&gt;\n\t    &lt;encoding&gt;${project.build.sourceEncoding}&lt;\/encoding&gt;\n\t\t  &lt;!-- need to prefix by basedir to generate to currently built module --&gt;\n\t\t  &lt;testOutputDirectory&gt;${basedir}\/xtend-gen&lt;\/testOutputDirectory&gt;\n\t  &lt;\/configuration&gt;\n\t&lt;\/plugin&gt;\n\t&lt;plugin&gt;\n\t  &lt;groupId&gt;io.github.lengors&lt;\/groupId&gt;\n\t  &lt;artifactId&gt;init-sources-maven-plugin&lt;\/artifactId&gt;\n\t  &lt;version&gt;1.0.0&lt;\/version&gt;\n\t\t&lt;executions&gt;\n\t\t  &lt;execution&gt;\n\t\t\t&lt;goals&gt;\n\t\t\t  &lt;goal&gt;init-sources&lt;\/goal&gt;\n\t\t\t&lt;\/goals&gt;\n\t\t\t&lt;configuration&gt;\n\t\t\t  &lt;testCompileSourceRoots&gt;\n\t\t\t\t&lt;testCompileSourceRoot&gt;${project.basedir}\/src&lt;\/testCompileSourceRoot&gt;\n\t\t\t  &lt;\/testCompileSourceRoots&gt;\n\t\t\t&lt;\/configuration&gt;\n\t\t  &lt;\/execution&gt;\n\t\t&lt;\/executions&gt;\n\t&lt;\/plugin&gt;\n    &lt;plugin&gt;\n      &lt;artifactId&gt;maven-clean-plugin&lt;\/artifactId&gt;\n      &lt;version&gt;3.0.0&lt;\/version&gt;\n      &lt;executions&gt;\n          &lt;execution&gt;\n              &lt;id&gt;auto-clean&lt;\/id&gt;\n              &lt;phase&gt;clean&lt;\/phase&gt;\n              &lt;goals&gt;\n                  &lt;goal&gt;clean&lt;\/goal&gt;\n              &lt;\/goals&gt;\n              &lt;configuration&gt;\n                  &lt;filesets&gt;\n                      &lt;fileset&gt;\n                          &lt;directory&gt;${basedir}&lt;\/directory&gt;\n                          &lt;includes&gt;**\/xtend-gen\/**&lt;\/includes&gt;\n                      &lt;\/fileset&gt;\n                  &lt;\/filesets&gt;\n              &lt;\/configuration&gt;\n          &lt;\/execution&gt;\n      &lt;\/executions&gt;\n    &lt;\/plugin&gt;\n    &lt;plugin&gt;\n      &lt;groupId&gt;org.eclipse.tycho&lt;\/groupId&gt;\n      &lt;artifactId&gt;tycho-compiler-plugin&lt;\/artifactId&gt;\n      &lt;version&gt;${tycho.version}&lt;\/version&gt;\n      &lt;executions&gt;\n          &lt;execution&gt;\n            &lt;goals&gt;\n              &lt;goal&gt;testCompile&lt;\/goal&gt;\n            &lt;\/goals&gt;\n          &lt;\/execution&gt;\n        &lt;\/executions&gt;\n    &lt;\/plugin&gt;\n    &lt;plugin&gt;\n      &lt;groupId&gt;org.eclipse.tycho&lt;\/groupId&gt;\n      &lt;artifactId&gt;tycho-surefire-plugin&lt;\/artifactId&gt;\n      &lt;version&gt;${tycho-version}&lt;\/version&gt;\n      &lt;configuration&gt;\n        &lt;testClassesDirectory&gt;target\/test-classes&lt;\/testClassesDirectory&gt;\n      &lt;\/configuration&gt;\n    &lt;\/plugin&gt;\n    ...\n\n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\">Solving the Xtext generation<\/h2>\n\n\n\n<p><strong>TL;DR<\/strong> Execute the MWE2 from Tycho (maven).<\/p>\n\n\n\n<p>But for this to work, we need a bit more work and some special considerations. First, credit where credit&#8217;s due. The Xtext project has a <a href=\"https:\/\/eclipse.dev\/Xtext\/documentation\/350_continuous_integration.html\">post<\/a> on how to do this (which also includes information about Xtend). However, their guide assumes that you don&#8217;t deviate from the &#8216;sensible defaults&#8217;. So this are my considerations, and why the sensible defaults wont work:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>I want my project to use the &#8216;standard&#8217; eclipse project layout, which is also required for Tycho pom-less to work. In this layout the bundles\/plugins are in a separate folder than the tests. <\/li>\n\n\n\n<li>I should still be able to run the MWE2 generator from Eclipse.<\/li>\n<\/ol>\n\n\n\n<p>Both require some modifications to the Xtext guide, because the guide assumes that the language bundles reside side-by-side with the tests. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Modifying the core language project&#8217;s POM<\/h3>\n\n\n\n<p>The first is a small modification and addition to the Tycho pom-less <a href=\"https:\/\/tycho.eclipseprojects.io\/doc\/main\/StructuredBuild.html\">structured build layout<\/a>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><kbd><mark style=\"background-color:#eceff1\" class=\"has-inline-color has-vivid-red-color\">root folder<\/mark><\/kbd> &#8211; contains parent pom\n<ul class=\"wp-block-list\">\n<li><kbd><mark style=\"background-color:#eceff1\" class=\"has-inline-color has-vivid-red-color\">bundles<\/mark><\/kbd> (or plugins)\n<ul class=\"wp-block-list\">\n<li><kbd><mark style=\"background-color:#eceff1\" class=\"has-inline-color has-vivid-red-color\">bundle1<\/mark><\/kbd><\/li>\n\n\n\n<li><kbd><mark style=\"background-color:#eceff1\" class=\"has-inline-color has-vivid-red-color\">bundle2<\/mark><\/kbd><\/li>\n\n\n\n<li><kbd><mark style=\"background-color:#eceff1\" class=\"has-inline-color has-vivid-red-color\">xtextlanguange-bundle<\/mark><\/kbd>  &#8211; language core project contains your grammar&#8217;s xtext file and the mwe2\n<ul class=\"wp-block-list\">\n<li><kbd><mark style=\"background-color:#eceff1\" class=\"has-inline-color has-vivid-red-color\">pom.xml<\/mark><\/kbd>  &#8211; needed to run the MWE2 build<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>&#8230;<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><kbd><mark style=\"background-color:#eceff1\" class=\"has-inline-color has-vivid-red-color\">features<\/mark><\/kbd><\/li>\n\n\n\n<li><kbd><mark style=\"background-color:#eceff1\" class=\"has-inline-color has-vivid-red-color\">sites<\/mark><\/kbd><\/li>\n\n\n\n<li><kbd><mark style=\"background-color:#eceff1\" class=\"has-inline-color has-vivid-red-color\">products<\/mark><\/kbd><\/li>\n\n\n\n<li><kbd><mark style=\"background-color:#eceff1\" class=\"has-inline-color has-vivid-red-color\">tests<\/mark><\/kbd>  &#8211; contains tests bundles, including your xtext grammar and ui tests<\/li>\n\n\n\n<li><kbd><mark style=\"background-color:#eceff1\" class=\"has-inline-color has-vivid-red-color\">releng<\/mark><\/kbd> &#8211; contains a bundle with the target platform<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>The changes are the inclusion of the tests folder, and the addition of a pom to the Xtext grammar plugin. The&nbsp;<kbd>pom.xml<\/kbd>&nbsp;for the language project contains information about how Maven should run the Xtext\u2019s code generator. The first plug-in invokes the MWE2 file through a standard Java process:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;project&gt;\n  ...\n  &lt;parent&gt;\n    &lt;relativePath&gt;..\/..\/pom.xml&lt;\/relativePath&gt;\n    ...\n  &lt;\/parent&gt;\n  &lt;build&gt;\n    ...\n\t&lt;plugins&gt;\n\t  &lt;plugin&gt;\n\t\t&lt;groupId&gt;org.codehaus.mojo&lt;\/groupId&gt;\n\t\t&lt;artifactId&gt;exec-maven-plugin&lt;\/artifactId&gt;\n\t\t&lt;version&gt;3.5.0&lt;\/version&gt;\n\t\t&lt;executions&gt;\n\t\t\t&lt;execution&gt;\n\t\t\t  &lt;id&gt;mwe2Launcher&lt;\/id&gt;\n\t\t\t  &lt;phase&gt;generate-sources&lt;\/phase&gt;\n\t\t\t  &lt;goals&gt;\n\t\t\t\t&lt;goal&gt;java&lt;\/goal&gt;\n\t\t\t  &lt;\/goals&gt;\n\t\t\t&lt;\/execution&gt;\n\t\t  &lt;\/executions&gt;\n\t\t  &lt;configuration&gt;\n\t\t\t&lt;mainClass&gt;org.eclipse.emf.mwe2.launch.runtime.Mwe2Launcher&lt;\/mainClass&gt;\n\t\t\t&lt;arguments&gt;\n\t\t\t  &lt;argument&gt;\/${project.basedir}\/src\/some\/path\/GenerateXXX.mwe2&lt;\/argument&gt;\n\t\t\t  &lt;argument&gt;-p&lt;\/argument&gt;\n\t\t\t  &lt;argument&gt;rootPath=\/${project.basedir}\/..&lt;\/argument&gt;\n\t\t\t&lt;\/arguments&gt;\n\t\t\t&lt;classpathScope&gt;compile&lt;\/classpathScope&gt;\n\t\t\t&lt;includePluginDependencies&gt;true&lt;\/includePluginDependencies&gt;\n\t\t\t&lt;cleanupDaemonThreads&gt;false&lt;\/cleanupDaemonThreads&gt;&lt;!-- see https:\/\/bugs.eclipse.org\/bugs\/show_bug.cgi?id=475098#c3 --&gt;\n\t\t  &lt;\/configuration&gt;\n\t\t  &lt;dependencies&gt;\n\t\t\t&lt;dependency&gt;\n\t\t\t  &lt;groupId&gt;org.eclipse.emf&lt;\/groupId&gt;\n\t\t\t\t&lt;artifactId&gt;org.eclipse.emf.mwe2.launch&lt;\/artifactId&gt;\n\t\t\t\t&lt;version&gt;${mwe-version}&lt;\/version&gt;\n\t\t\t  &lt;\/dependency&gt;\n\t\t\t  &lt;dependency&gt;\n\t\t\t\t&lt;groupId&gt;org.eclipse.emf&lt;\/groupId&gt;\n\t\t\t\t&lt;artifactId&gt;org.eclipse.emf.common&lt;\/artifactId&gt;\n\t\t\t\t&lt;version&gt;${emf-version}&lt;\/version&gt;\n\t\t\t  &lt;\/dependency&gt;\n\t\t\t  &lt;dependency&gt;\n\t\t\t\t&lt;groupId&gt;org.eclipse.xtext&lt;\/groupId&gt;\n\t\t\t\t&lt;artifactId&gt;org.eclipse.xtext.common.types&lt;\/artifactId&gt;\n\t\t\t\t&lt;version&gt;${xtext-version}&lt;\/version&gt;\n\t\t\t  &lt;\/dependency&gt;\n\t\t\t  &lt;dependency&gt;\n\t\t\t\t&lt;groupId&gt;org.eclipse.xtext&lt;\/groupId&gt;\n\t\t\t\t&lt;artifactId&gt;org.eclipse.xtext.xtext.generator&lt;\/artifactId&gt;\n\t\t\t\t&lt;version&gt;${xtext-version}&lt;\/version&gt;\n\t\t\t  &lt;\/dependency&gt;\n\t\t\t  &lt;dependency&gt;\n\t\t\t\t&lt;groupId&gt;org.eclipse.xtext&lt;\/groupId&gt;\n\t\t\t\t&lt;artifactId&gt;org.eclipse.xtext.xbase&lt;\/artifactId&gt;\n\t\t\t\t&lt;version&gt;${xtext-version}&lt;\/version&gt;\n\t\t\t  &lt;\/dependency&gt;\n\t\t\t  &lt;dependency&gt;\n\t\t\t\t&lt;groupId&gt;org.eclipse.xtext&lt;\/groupId&gt;\n\t\t\t\t&lt;artifactId&gt;xtext-antlr-generator&lt;\/artifactId&gt;\n\t\t\t\t&lt;version&gt;&#x5B;2.1.1, 3)&lt;\/version&gt;\n\t\t\t  &lt;\/dependency&gt;\n\t\t\t&lt;\/dependencies&gt;\n\t\t  &lt;\/plugin&gt;\n          ...\n\t\t&lt;\/plugins&gt;\n        &lt;pluginManagement&gt;\n\t\t  &lt;plugins&gt;\n\t\t\t&lt;plugin&gt;\n\t\t\t  &lt;groupId&gt;org.eclipse.m2e&lt;\/groupId&gt;\n\t\t\t  &lt;artifactId&gt;lifecycle-mapping&lt;\/artifactId&gt;\n\t\t\t  &lt;version&gt;1.0.0&lt;\/version&gt;\n\t\t\t  &lt;configuration&gt;\n\t\t\t\t&lt;lifecycleMappingMetadata&gt;\n\t\t\t\t  &lt;pluginExecutions&gt;\n\t\t\t\t\t&lt;pluginExecution&gt;\n\t\t\t\t\t  &lt;pluginExecutionFilter&gt;\n\t\t\t\t\t\t&lt;groupId&gt;org.codehaus.mojo&lt;\/groupId&gt;\n\t\t\t\t\t\t&lt;artifactId&gt;exec-maven-plugin&lt;\/artifactId&gt;\n\t\t\t\t\t\t&lt;versionRange&gt;&#x5B;1.2.1,)&lt;\/versionRange&gt;\n\t\t\t\t\t\t&lt;goals&gt;\n\t\t\t\t\t\t  &lt;goal&gt;java&lt;\/goal&gt;\n\t\t\t\t\t\t&lt;\/goals&gt;\n\t\t\t\t\t  &lt;\/pluginExecutionFilter&gt;\n\t\t\t\t\t  &lt;action&gt;\n\t\t\t\t\t    &lt;ignore&gt;&lt;\/ignore&gt;\n\t\t\t\t\t  &lt;\/action&gt;\n\t\t\t\t\t&lt;\/pluginExecution&gt;\n\t\t\t\t  &lt;\/pluginExecutions&gt;\n\t\t\t\t&lt;\/lifecycleMappingMetadata&gt;\n\t\t\t  &lt;\/configuration&gt;\n\t\t\t&lt;\/plugin&gt;\n\t\t  &lt;\/plugins&gt;\n\t\t&lt;\/pluginManagement&gt;\n    ...\n<\/pre><\/div>\n\n\n<p>It&#8217;s basically the same as in the Xtext guide, with two small additions. One, the referencing the root pom as a parent, as we are using a pom-less build so there are no other poms. Make sure to use your correct root coordinates (groupId, artifactId and version). The second addition is done to map the <kbd>exec-maven-plugin<\/kbd> (used for generating the grammar) to the java goal. This ensures that the required test classes are generated before the testing phase. Another task that we wanted to have is cleaning the generated source and model folders. We used the <kbd>maven-clean-plugin<\/kbd> for this (replace your plugin paths accordingly):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;project&gt;\n  ...\n  &lt;plugins&gt;\n    ...\n\t&lt;!-- Cleans the directories containing generated resources during the clean phase --&gt;\n\t&lt;plugin&gt;\n\t  &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;\n\t  &lt;artifactId&gt;maven-clean-plugin&lt;\/artifactId&gt;\n\t  &lt;version&gt;3.4.0&lt;\/version&gt;\n\t  &lt;configuration&gt;\n\t\t&lt;filesets&gt;\n\t  \t  &lt;fileset&gt;\n\t\t\t&lt;directory&gt;plugins\/core.language\/src-gen\/&lt;\/directory&gt;\n\t\t\t&lt;includes&gt;\n\t\t\t  &lt;include&gt;**\/*&lt;\/include&gt;\n\t\t\t&lt;\/includes&gt;\n\t\t  &lt;\/fileset&gt;\n\t\t  &lt;fileset&gt;\n\t\t\t&lt;directory&gt;plugins\/core.language.ide\/src-gen\/&lt;\/directory&gt;\n\t\t\t&lt;includes&gt;\n\t\t\t  &lt;include&gt;**\/*&lt;\/include&gt;\n\t\t\t&lt;\/includes&gt;\n\t\t  &lt;\/fileset&gt;\n\t\t  &lt;fileset&gt;\n\t\t    &lt;directory&gt;plugins\/core.language.ui\/src-gen\/&lt;\/directory&gt;\n\t\t\t&lt;includes&gt;\n\t\t\t  &lt;include&gt;**\/*&lt;\/include&gt;\n\t\t\t&lt;\/includes&gt;\n\t\t  &lt;\/fileset&gt;\n\t\t  &lt;fileset&gt;\n\t\t\t&lt;directory&gt;tests\/core.language.tests\/src-gen\/&lt;\/directory&gt;\n\t\t\t&lt;includes&gt;\n\t\t\t  &lt;include&gt;**\/*&lt;\/include&gt;\n\t\t\t&lt;\/includes&gt;\n\t\t  &lt;\/fileset&gt;\n\t\t  &lt;fileset&gt;\n\t\t\t&lt;directory&gt;tests\/core.language.ui.tests\/src-gen\/&lt;\/directory&gt;\n\t\t\t&lt;includes&gt;\n\t\t\t  &lt;include&gt;**\/*&lt;\/include&gt;\n\t\t\t&lt;\/includes&gt;\n\t\t  &lt;\/fileset&gt;\n\t\t  &lt;fileset&gt;\n\t\t    &lt;directory&gt;plugins\/core.language\/model\/generated\/&lt;\/directory&gt;\n            &lt;includes&gt;\n\t\t\t  &lt;include&gt;**\/*&lt;\/include&gt;\n\t\t\t&lt;\/includes&gt;\n\t\t  &lt;\/fileset&gt;\n\t\t&lt;\/filesets&gt;\n\t  &lt;\/configuration&gt;\n\t&lt;\/plugin&gt;\n    ...\n<\/pre><\/div>\n\n\n<p>The final part of the changes will allow the MWE2 to work with the new folder structure both from the Tycho build and from within Eclipse. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Tweaking the Language Generator<\/h3>\n\n\n\n<p>The language generation <a href=\"https:\/\/eclipse.dev\/Xtext\/documentation\/302_configuration.html\">section<\/a> of the Xtext documentation, states that the default MWE configuration &#8220;<strong>uses two convenience classes&nbsp;<a href=\"https:\/\/github.com\/eclipse-xtext\/xtext\/blob\/main\/org.eclipse.xtext.xtext.generator\/src\/org\/eclipse\/xtext\/xtext\/generator\/model\/project\/StandardProjectConfig.java\">StandardProjectConfig<\/a>&nbsp;and&nbsp;<a href=\"https:\/\/github.com\/eclipse-xtext\/xtext\/blob\/main\/org.eclipse.xtext.xtext.generator\/src\/org\/eclipse\/xtext\/xtext\/generator\/StandardLanguage.java\">StandardLanguage<\/a>, both of which are designed to apply default configurations that work for the majority of language projects.<\/strong>&#8221; So basically that if you are not using a <em>standard<\/em> project, they will not work. In our case, what fails is that the StandardProjectConfig assumes that the language and tests projects are in the same folder. Since we moved the test folders, then it wont be able to find them during the build.<\/p>\n\n\n\n<p>Looking at the <kbd>StandardProjectConfig<\/kbd>, the assumption of the projects in the same location is used to generate the &#8216;root&#8217; value for the nested <kbd>SubProjectConfig<\/kbd>. And since I assume you did not understand any of that, let me explain with an example MWE:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\n...\nWorkflow {\n  component = XtextGenerator {\n    configuration = {\n\t  project = StandardProjectConfig {\n\t\tbaseName = &quot;my.text.language&quot;\n\t\trootPath = rootPath\n\t\truntimeTest = {\n\t\t  enabled = true\n\t\t}\n        ...\n<\/pre><\/div>\n\n\n<p>What that configuration does is use the <kbd>baseName<\/kbd> to look for all the Xtext bundles of your language; your core bundle will use that name. Next, the <kbd>runtimeTest<\/kbd> part instructs the generator that you have a test plugin for your language. Looking at the <kbd>StandardProjectConfig<\/kbd> implementation, it will use  <kbd>baseName + \".tests\"<\/kbd> to find the test bundle. Since that value actually translates to a path, it will effectively try to find the <kbd>my.text.language.tests<\/kbd> bundle in the same folder as your core bundle. Looking a bit more into the source code, I found that the <kbd>runtimeTest<\/kbd> (and other nested configurations) are instantiated as <kbd>SubProjectConfig<\/kbd>s. And, <kbd>SubProjectConfig<\/kbd>s have a root attribute we can specify, to change the location\/path where the bundle is located. So, we can modify the MWE workflow to make the paths explicit.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n...\nWorkflow {\n  component = XtextGenerator {\n    configuration = {\n\t  project = StandardProjectConfig {\n\t\tbaseName = &quot;my.text.language&quot;\n\t\trootPath = rootPath\n\t\truntimeTest = {\n\t      root = &quot;tests\/my.text.language.tests&quot;\n\t\t}\n\t\teclipsePlugin = {\n\t\t  enabled = true\n\t\t}\n\t\teclipsePluginTest = {\n\t\t  enabled = true\n\t\t  root = &quot;tests\/my.text.language.ui.tests&quot;\n\t\t}\n        ...\n<\/pre><\/div>\n\n\n<p>Finally, note that the paths we provide are relative to the repository root. This is required because when running the generator from Tycho, the working directory is the root folder. In order to make the modified MWE also work from eclipse, we need to make sure the Run Configuration also runs from the root folder. In the <strong>Arguments<\/strong> tab of the run configuration, you can change the working directory, as shown below:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"915\" height=\"784\" src=\"https:\/\/kinori.tech\/blog\/wp-content\/uploads\/2025\/02\/image.png\" alt=\"\" class=\"wp-image-366\" srcset=\"https:\/\/kinori.tech\/blog\/wp-content\/uploads\/2025\/02\/image.png 915w, https:\/\/kinori.tech\/blog\/wp-content\/uploads\/2025\/02\/image-300x257.png 300w, https:\/\/kinori.tech\/blog\/wp-content\/uploads\/2025\/02\/image-768x658.png 768w\" sizes=\"auto, (max-width: 915px) 100vw, 915px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Those pesky Eclipse dependencies<\/h3>\n\n\n\n<p>The final piece of the code is access to eclipse plugins from Tycho (maven). From my experience, it is not always easy to find Eclipse projects&#8217; plugins in the maven repositories (it takes some effort to separate the pure java from the plugin code, and to configure your build to publish your plugins to a maven repo). In particular, the Ecore ones, AKAIK, are not officially published by the EMF project. Non the less, you can find them in the sonatype repositories. So in my root pom, I added the snapshot and releases repos, just in case:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n  ...\n  &amp;lt;repositories&gt;\n\t&amp;lt;repository&gt;\n\t  &amp;lt;id&gt;sonatype-snapshots&amp;lt;\/id&gt;\n\t  &amp;lt;url&gt;https:\/\/oss.sonatype.org\/content\/repositories\/snapshots&amp;lt;\/url&gt;\n\t  &amp;lt;releases&gt;&amp;lt;enabled&gt;false&amp;lt;\/enabled&gt;&amp;lt;\/releases&gt;\n\t  &amp;lt;snapshots&gt;&amp;lt;enabled&gt;true&amp;lt;\/enabled&gt;&amp;lt;\/snapshots&gt;\n\t&amp;lt;\/repository&gt;\n\t&amp;lt;repository&gt;\n\t  &amp;lt;id&gt;sonatype-releases&amp;lt;\/id&gt;\n\t  &amp;lt;url&gt;https:\/\/oss.sonatype.org\/content\/repositories\/releases&amp;lt;\/url&gt;\n\t  &amp;lt;releases&gt;&amp;lt;enabled&gt;true&amp;lt;\/enabled&gt;&amp;lt;\/releases&gt;\n\t  &amp;lt;snapshots&gt;&amp;lt;enabled&gt;false&amp;lt;\/enabled&gt;&amp;lt;\/snapshots&gt;\n\t&amp;lt;\/repository&gt;\n  &amp;lt;\/repositories&gt;\n<\/pre><\/div>\n\n\n<p>An  that should get you going! Happy building :).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I am fond of IDEs. They make my life simpler, mainly because I am not fond of memorizing every thing. Code completion, syntax highlighting, run configurations, automatic code generation&#8230; Well, to be honest, &#8216;automated&#8217; things is where I usually start [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[12,15,25,24],"series":[],"class_list":["post-346","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-eclipse","tag-plugin","tag-tycho","tag-xtext"],"_links":{"self":[{"href":"https:\/\/kinori.tech\/blog\/wp-json\/wp\/v2\/posts\/346","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kinori.tech\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kinori.tech\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kinori.tech\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/kinori.tech\/blog\/wp-json\/wp\/v2\/comments?post=346"}],"version-history":[{"count":27,"href":"https:\/\/kinori.tech\/blog\/wp-json\/wp\/v2\/posts\/346\/revisions"}],"predecessor-version":[{"id":375,"href":"https:\/\/kinori.tech\/blog\/wp-json\/wp\/v2\/posts\/346\/revisions\/375"}],"wp:attachment":[{"href":"https:\/\/kinori.tech\/blog\/wp-json\/wp\/v2\/media?parent=346"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kinori.tech\/blog\/wp-json\/wp\/v2\/categories?post=346"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kinori.tech\/blog\/wp-json\/wp\/v2\/tags?post=346"},{"taxonomy":"series","embeddable":true,"href":"https:\/\/kinori.tech\/blog\/wp-json\/wp\/v2\/series?post=346"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}