LiveScope and new Resources [message #1828391] |
Tue, 09 June 2020 06:36 |
Konrad Jünemann Messages: 93 Registered: December 2018 |
Member |
|
|
Hi,
My DSL generates new DSL files when building. These files must be able to refer to already existing DSL-files. For example, if A.dsl compiles, it should generate B.dsl, which has a cross reference to A.dsl.
I should mention, I am talking about building under Eclipse, so not standalone.
I currently do it this way:
- I use the MyDslGenerator generated by Xtext
- XText calls doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) . Let's call the provided resource resource "A".
- My implementation constructs the new EObjects using the EMF factories. Let's call the created EObject "B".
- The new EObjects are added to the ResourceSet of resource A, like this:
//val A a;
//val B b;
val bPath = getPath(b)
val uri = fsa.getURI(bPath, MyOutputConfigurationProvider.OUTPUT_FOLDER)
val rset = a.eResource.resourceSet
res = rset.createResource(uri)
res.contents.add(b)
- then, I serialize B by using the XText Serializer:
//val B b;
val Serializer ser = gsp.findService(b, Serializer)
val content = ser.serialize(b)
fsa.generateFile(bPath, MyOutputConfigurationProvider.OUTPUT_FOLDER, content)
Unfortunately, this does not work, as B does not see A and the serializer can thus not generate the cross-reference from B to A. The Serializer throws a RunTimeException:
java.lang.RuntimeException: No EObjectDescription could be found in Scope <SoAndSo>
EStructuralFeature: commonmetamodel::Import.member
at org.eclipse.xtext.serializer.diagnostic.ISerializationDiagnostic$ExceptionThrowingAcceptor.accept(ISerializationDiagnostic.java:132)
at org.eclipse.xtext.serializer.tokens.CrossReferenceSerializer.getCrossReferenceNameFromScope(CrossReferenceSerializer.java:139)
at org.eclipse.xtext.serializer.tokens.CrossReferenceSerializer.serializeCrossRef(CrossReferenceSerializer.java:112)
at org.eclipse.xtext.serializer.acceptor.SequenceFeeder.getToken(SequenceFeeder.java:483)
at org.eclipse.xtext.serializer.acceptor.SequenceFeeder.accept(SequenceFeeder.java:240)
Now, what I learned is that I should use LiveScopeResourceSetInitializer in order to allow the target resourceSet (which in my case is the same as the source resourceSet) "see" dirty resources. How is this properly done?
What I tried so far:
1. Just using the A-resourceSet and initializing it using the LiveScopeResourceSetInitializer. This does not work as I get the following exception when running a full build:
java.lang.IllegalStateException: Ambiguous scope for the resource set. Can't combine org.eclipse.xtext.scoping.namespaces.DefaultGlobalScopeProvider.BUILDER_SCOPE and org.eclipse.xtext.scoping.LIVE_SCOPE
2. Creating a new resourceSet (using an IResourceSetProvider) each time my generator is called, initializing the newly created rset (just using the XtextLiveScopeResourceSetProvider works fine, too), and adding all resources from the A-resourceSet to the B-resourceSet.
This approach kinda works, but the performance is really bad. The performance is bad, because in a full build, a new resourceSet is created for every single compiled EObject and the JavaProjectResourceSetInitializer calls EcorePlugin.computePlatformPluginToPlatformResourceMap every time. I can provide the call tree of my profiler, if helpful.
I imagine I am missing something fundamentally. What is the correct way construct my own EObjects in a generator (with incremental and full build)? Do I add add the EObjects to the incoming resourceSet, create a new resourceSet for each built resource (how to tackle the performance issue then?), or do I use a completey different approach?
|
|
|
Re: LiveScope and new Resources [message #1828399 is a reply to message #1828391] |
Tue, 09 June 2020 08:02 |
|
When I had a similar issue I solved that by triggering a second build job. We added a small delay and then the project builder took up the new resources and just run the builder again as if you would have written the resources manually. IIRC we collected all generated DSL resources and touched them after the delay.
|
|
|
|
|
Re: LiveScope and new Resources [message #1828410 is a reply to message #1828407] |
Tue, 09 June 2020 10:37 |
Konrad Jünemann Messages: 93 Registered: December 2018 |
Member |
|
|
Hi Christian,
That was my second approach (see post above). I basically created a fresh resourceSet every time the generator got called and added the required resources. This worked, but (as it turned out) is incredibly slow when running a FULL_BUILD, as a new resourceSet gets created for every file parsed. Is that a known problem ? Maybe I just use a bad setting?
My DSL Project (that contains the user files, i.e., A and B, not my xtend-sourcecode) has the JavaNature and a plugin dependency to one of my plugins, as I provide some static, "well known" DSL-files through this mechanic. Not sure if this might affect performance.
I uploaded an image of my profiler run here:
https://ibb.co/Lv478w3
As you can see, the performance issue mainly arises as EcorePlugin keeps calculating its computePlatformPluginToPlatformResourceMap , triggered by JavaProjectResourceSetInitializer .
I am trying to resolve this performance issue, as this way a full build takes ~8 min when it should be way under 1 min.
|
|
|
|
|
|
|
Re: LiveScope and new Resources [message #1828449 is a reply to message #1828436] |
Wed, 10 June 2020 06:47 |
Konrad Jünemann Messages: 93 Registered: December 2018 |
Member |
|
|
Hi Christian,
For documentation purposes, I understand there at least the following approaches:
- Creating a new ResourceSet on each Generator Call (so multiple resourceSets on a single full build)
- Creating a new ResourceSet on each Generator Call, but deviate on full builds: create only one resourceSet in this case (not sure how I would achive that)
- <I don't understand your n:1 proposal> Edit: Create a new Generator-Interface that allows to compile multiple Resources at once, as described here:
https://kthoms.wordpress.com/2011/07/12/xtend-generating-from-multiple-input-models/
- Avoid the serializer all together and create text (I chose this approach in a former project, which worked well, but was a bit redundant to the grammar)
- Adapt the serializer (not to check the Scope) -> I guess this will become a bit dirty quickly
Thank you very much for this insight. I thought mayby one of these solution was the clearly prefered way to do it. I think I will first try to stick to option 1 first while trying to tackle the mentioned performance issue. If that fails, I will try to get option 2 working. If that also fails I will use option 4 (text generation), as I know this will work properly.
Many thanks!
[Updated on: Wed, 10 June 2020 11:44] Report message to a moderator
|
|
|
|
|
|
Powered by
FUDForum. Page generated in 0.06412 seconds