How to build an ANTLR grammar with Gradle in a multi-platform project? - gradle

So I have been struggling all afternoon with getting some Gradle build to work for a Kotlin multiplatform project that involves an ANTLR grammar. What I'm trying to do is to have a parser generated by ANTLR from a shared grammar for both a Kotlin (or Java if that doesn't work) and JavaScript target. Based on this I'd like to write some library around the parser that can be used from the JVM and JavaScript.
So I have set up a Kotlin multi-platform project because that seemed like a nice way of killing two birds with one stone (here is a repo https://github.com/derkork/project.txt). I created a source set commonAntlr where I placed the grammar file under commonAntlr/antlr/project_txt.g4. According to the documentation of the ANTLR plugin this is how stuff should be set up. I also apply the antlr plugin at the top (here is the build.gradle.kts - https://github.com/derkork/project.txt/blob/master/build.gradle.kts).
Now I run gradle build in the hopes that the ANTLR plugin will at least try to generate some nice Java code for me from the grammar using the default settings. Alas, it does not. The ANTLR plugin does not even get started, which is what I can tell from the output. The build later fails with some obscure JavaScript problem, but that looks unrelated and I'd like to skip over it for now.
Now my Gradle-foo isn't exactly strong (I have only used it in extremely simple projects, most of my experience is in Maven), and I have the distinct feeling I'm missing something here. However the documentation of the plugin just says
To use the ANTLR plugin, include the following in your build script:
plugins {
antlr
}
Which I did. Since I get zero output, I have a feeling that I need to do a bit more for this to work. I have read a lot of the Gradle documentation up and down to find out how plugins work in general and I found that they add tasks to the build and also add some dependencies so that tasks are invoked when you try to build certain things. However I don't really understand how plugins work together with source sets and how you can tell Gradle "would you please run the generateGrammarSource task for this source set" (or if it even works like this).
So if some of the Gradle gods could enlighten me on this, this would be much appreciated :)

I have met a similar issue: https://gitlab.com/pika-lab/tuprolog/2p-in-kotlin/tree/feature/parser
My solution -- which is still a work in progress -- consists in decomposing the problem.
I reasonable solution in my opinion is to create a Kotlin/JVM project (say parser-jvm) where to put the generated Java code + any JVM specific facility, and a Kotlin/JS project where to put the generated JS code + any JS specific facility (say parser-js). The next step is to create a Kotlin/MPP (say parser-common) project whose JVM implementation depends on parser-jvm and whose JS implementation depends on parser-js.
My approach is actually working for JVM while I'm experiencing some issues for JS, which are mostly caused by this issue.
The main drawback of this approach is that some Gradle coding is required to setup ANTLR with Kotlin/JS. I already faced this problem in my build.gradle and I'm quite satisfied with the result and the overall architecture of the project. However, I believe that my proposal is far less troublesome than configuring a Kotlin/MPP project to work with ANTLR.

Related

Is Groovy knowledge required to understand Gradle?

So, I've been trying to avoid build tools for a while, but started to use Gradle for some time now. I'm able to use it for simple things like letting it download dependencies, like it's intended, but I've seen people use it to do really advanced staff like manage large projects with different modules, native dependencies, publish to Github when building, etc.
I feel like I still need to copy-paste a lot when trying to do anything more complicated, because even after finding some documentation to read, I'm still not sure where language syntax like {, }, :, (, ), are meant to be used.
So, my question is: Does it make sense to learn Groovy to understand Gradle better? Should reading the docs be enough? I'm not even asking because I would not be interested in Groovy, I'm just wondering how people got used to using Gradle and whether it makes sense to use it for more advanced tasks then fetching dependencies from repositories.
Gradle uses DSL (domain specific language) that is currently based on top of Groovy. That means, that you should be able to work with Gradle to some extend by learning the DSL only. It, of course, inherits some of the syntax from Groovy (like the parentheses etc) but the syntax pretty far away from a normal Groovy code.
If you want to start writing your own closures, tasks and plugins then you need some Groovy skills, yes. Groovy in Action 2nd edition is a great book, or if you are a Java developer, take a look at Making Java Groovy.
Saying that, please keep in mind that Gradle Inc announced that they are going to support Kotlin as another language to base the DSL on. It means that you will be able to write the "custom" parts of your build in Kotlin or Groovy. So, keep an eye on Kotlin as well, here's the best way to do it – Kotlin in Action.
To just use Gradle, you can go without understanding Groovy.
To understand how a Gradle file syntax works, you definitely need to understand Groovy. People generally struggle with Gradle when scripts become complex.
Gradle uses mostly vanilla Groovy as it's language, but the documentation and most examples use a specific style, that is different from the most conventional style when writing other Groovy code.
But except for a single compiler plugin (for turning some names without quotes into strings), all Gradle code is also valid Groovy code, and you could write any gradle file in the same style as you write any other Groovy file.

Difference between maven/ant/gradle [duplicate]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
What does another build tool targeted at Java really get me?
If you use Gradle over another tool, why?
I don't use Gradle in anger myself (just a toy project so far) [author means they have used Gradle on only a toy project so far, not that Gradle is a toy project - see comments], but I'd say that the reasons one would consider using it would be because of the frustrations of Ant and Maven.
In my experience Ant is often write-only (yes I know it is possible to write beautifully modular, elegant builds, but the fact is most people don't). For any non-trivial projects it becomes mind-bending, and takes great care to ensure that complex builds are truly portable. Its imperative nature can lead to replication of configuration between builds (though macros can help here).
Maven takes the opposite approach and expects you to completely integrate with the Maven lifecycle. Experienced Ant users find this particularly jarring as Maven removes many of the freedoms you have in Ant. For example there's a Sonatype blog that enumerates many of the Maven criticisms and their responses.
The Maven plugin mechanism allows for very powerful build configurations, and the inheritance model means you can define a small set of parent POMs encapsulating your build configurations for the whole enterprise and individual projects can inherit those configurations, leaving them lightweight. Maven configuration is very verbose (though Maven 3 promises to address this), and if you want to do anything that is "not the Maven way" you have to write a plugin or use the hacky Ant integration. Note I happen to like writing Maven plugins but appreciate that many will object to the effort involved.
Gradle promises to hit the sweet spot between Ant and Maven. It uses Ivy's approach for dependency resolution. It allows for convention over configuration but also includes Ant tasks as first class citizens. It also wisely allows you to use existing Maven/Ivy repositories.
So if you've hit and got stuck with any of the Ant/Maven pain points, it is probably worth trying Gradle out, though in my opinion it remains to be seen if you wouldn't just be trading known problems for unknown ones. The proof of the pudding is in the eating though so I would reserve judgment until the product is a little more mature and others have ironed out any kinks (they call it bleeding edge for a reason). I'll still be using it in my toy projects though, It's always good to be aware of the options.
Gradle can be used for many purposes - it's a much better Swiss army knife than Ant - but it's specifically focused on multi-project builds.
First of all, Gradle is a dependency programming tool which also means it's a programming tool. With Gradle you can execute any random task in your setup and Gradle will make sure all declared dependecies are properly and timely executed. Your code can be spread across many directories in any kind of layout (tree, flat, scattered, ...).
Gradle has two distinct phases: evaluation and execution. Basically, during evaluation Gradle will look for and evaluate build scripts in the directories it is supposed to look. During execution Gradle will execute tasks which have been loaded during evaluation taking into account task inter-dependencies.
On top of these dependency programming features Gradle adds project and JAR dependency features by intergration with Apache Ivy. As you know Ivy is a much more powerful and much less opinionated dependency management tool than say Maven.
Gradle detects dependencies between projects and between projects and JARs. Gradle works with Maven repositories (download and upload) like the iBiblio one or your own repositories but also supports and other kind of repository infrastructure you might have.
In multi-project builds Gradle is both adaptable and adapts to the build's structure and architecture. You don't have to adapt your structure or architecture to your build tool as would be required with Maven.
Gradle tries very hard not to get in your way, an effort Maven almost never makes. Convention is good yet so is flexibility. Gradle gives you many more features than Maven does but most importantly in many cases Gradle will offer you a painless transition path away from Maven.
This may be a bit controversial, but Gradle doesn't hide the fact that it's a fully-fledged programming language.
Ant + ant-contrib is essentially a turing complete programming language that no one really wants to program in.
Maven tries to take the opposite approach of trying to be completely declarative and forcing you to write and compile a plugin if you need logic. It also imposes a project model that is completely inflexible. Gradle combines the best of all these tools:
It follows convention-over-configuration (ala Maven) but only to the extent you want it
It lets you write flexible custom tasks like in Ant
It provides multi-module project support that is superior to both Ant and Maven
It has a DSL that makes the 80% things easy and the 20% things possible (unlike other build tools that make the 80% easy, 10% possible and 10% effectively impossible).
Gradle is the most configurable and flexible build tool I have yet to use. It requires some investment up front to learn the DSL and concepts like configurations but if you need a no-nonsense and completely configurable JVM build tool it's hard to beat.
Gradle nicely combines both Ant and Maven, taking the best from both frameworks. Flexibility from Ant and convention over configuration, dependency management and plugins from Maven.
So if you want to have a standard java build, like in maven, but test task has to do some custom step it could look like below.
build.gradle:
apply plugin:'java'
task test{
doFirst{
ant.copy(toDir:'build/test-classes'){fileset dir:'src/test/extra-resources'}
}
doLast{
...
}
}
On top of that it uses groovy syntax which gives much more expression power then ant/maven's xml.
It is a superset of Ant - you can use all Ant tasks in gradle with nicer, groovy-like syntax, ie.
ant.copy(file:'a.txt', toDir:"xyz")
or
ant.with{
delete "x.txt"
mkdir "abc"
copy file:"a.txt", toDir: "abc"
}
We use Gradle and chose it over Maven and Ant. Ant gave us total flexibility, and Ivy gives better dependency management than Maven, but there isn't great support for multi-project builds. You end up doing a lot of coding to support multi-project builds. Also having some build-by-convention is nice and makes build scripts more concise. With Maven, it takes build by convention too far, and customizing your build process becomes a hack. Also, Maven promotes every project publishing an artifact. Sometimes you have a project split up into subprojects but you want all of the subprojects to be built and versioned together. Not really something Maven is designed for.
With Gradle you can have the flexibility of Ant and build by convention of Maven. For example, it is trivial to extend the conventional build lifecycle with your own task. And you aren't forced to use a convention if you don't want to. Groovy is much nicer to code than XML. In Gradle, you can define dependencies between projects on the local file system without the need to publish artifacts for each to a repository. Finally, Gradle uses Ivy, so it has excellent dependency management. The only real downside for me thus far is the lack of mature Eclipse integration, but the options for Maven aren't really much better.
This isn't my answer, but it definitely resonates with me. It's from ThoughtWorks' Technology Radar from October 2012:
Two things have caused fatigue with XML-based build tools like Ant and
Maven: too many angry pointy braces and the coarseness of plug-in
architectures. While syntax issues can be dealt with through
generation, plug-in architectures severely limit the ability for build
tools to grow gracefully as projects become more complex. We have come
to feel that plug-ins are the wrong level of abstraction, and prefer
language-based tools like Gradle and Rake instead, because they offer
finer-grained abstractions and more flexibility long term.
Gradle put the fun back into building/assembling software. I used ant to build software my entire career and I have always considered the actual "buildit" part of the dev work being a necessary evil. A few months back our company grew tired of not using a binary repo (aka checking in jars into the vcs) and I was given the task to investigate this. Started with ivy since it could be bolted on top of ant, didn't have much luck getting my built artifacts published like I wanted. I went for maven and hacked away with xml, worked splendid for some simple helper libs but I ran into serious problems trying to bundle applications ready for deploy. Hassled quite a while googling plugins and reading forums and wound up downloading trillions of support jars for various plugins which I had a hard time using. Finally I went for gradle (getting quite bitter at this point, and annoyed that "It shouldn't be THIS hard!")
But from day one my mood started to improve. I was getting somewhere. Took me like two hours to migrate my first ant module and the build file was basically nothing. Easily fitted one screen. The big "wow" was: build scripts in xml, how stupid is that? the fact that declaring one dependency takes ONE row is very appealing to me -> you can easily see all dependencies for a certain project on one page. From then on I been on a constant roll, for every problem I faced so far there is a simple and elegant solution. I think these are the reasons:
groovy is very intuitive for java developers
documentation is great to awesome
the flexibility is endless
Now I spend my days trying to think up new features to add to our build process. How sick is that?
It's also much easier to manage native builds. Ant and Maven are effectively Java-only. Some plugins exist for Maven that try to handle some native projects, but they don't do an effective job. Ant tasks can be written that compile native projects, but they are too complex and awkward.
We do Java with JNI and lots of other native bits. Gradle simplified our Ant mess considerably. When we started to introduce dependency management to the native projects it was messy. We got Maven to do it, but the equivalent Gradle code was a tiny fraction of what was needed in Maven, and people could read it and understand it without becoming Maven gurus.
I agree partly with Ed Staub. Gradle definitely is more powerful compared to maven and provides more flexibility long term.
After performing an evaluation to move from maven to gradle, we decided to stick to maven itself for two issues
we encountered with gradle ( speed is slower than maven, proxy was not working ) .

what is the default code for gradle

I was asked a very awesome question from someone starting to use gradle and I realize it would be extremely cool and probably already exists.
When we go to override a task like jar, many times you want to actually see the original gradle code that is used for the jar task or compileJava task. Does such a thing exist? (or did they end up writing that stuff in java). If that does exist, please give us a link? and it would be awesome to wire into the command line or documentation online(or maybe it is wired in somewhere and I missed it as the documentation online is one huge book, which is great, don't get me wrong.).
thanks,
Dean
The code is on github, as detailed on the web site, so you can easily check it out and grep for specific implementations.
For example this is the code for the Jar task.
The Gradle build language you use in your scripts is a DSL implemented in Groovy and Java. The language reference is a useful resource for mapping between the stuff you write in your project and the API docs for the underlying code.

Imperative vs Declarative build systems

I have recently started using Gradle as a build system.
They first comparison that Gradle makes with the likes of Ant and Maven is that,
Ant is an imperative build system, whereas Maven is a declarative build system.
While Gradle is a declarative build system without the rigidity enforced by Maven.
I wanted to understand these terms declarative and imperative better when it comes to talking about build systems.
In short, an ant script tells the ant tool what to do - "compile these files and then copy them to that folder. Then take the contents of this folder and create an archive."
While a maven pom declares what we would like to have as the result - "here are the names of the libraries the project depends upon, and we would like to generate a web archive". Maven knows how to fetch the libraries and where to find the source classes on it's own.
While ant gives you more flexibility, it also forces you to constantly reinvent the wheel.
Maven on the other side requires less configuration, but may feel too constraining, especially if you are used to a different workflow.
EDIT: An important aspect of the ant-maven comparison is that maven has a convention, describing where the files should lie, where the dependencies are found, where to put the resulting artifact, while ant does not.
So you can think of using maven like riding a bus - you select the stop where you enter and the one where you leave. Using ant is like driving a car - you have to do it yourself. You dont have to tell the bus driver what to do, but the stops may be too far from where you want to go.
EDIT2: 'Reinventing the wheel' metaphor seems to be less clear than I had hoped. This is what I mean:
Without sensible defaults/conventions, you have to define the project structure and the build lifecycle explicitly for each project, often making it a matter of taste and opinion. As preferences vary between teams and companies, so do build processes. This requires more cognitive effort for new project members and later maintainers. Depending on the experience and expertise of the developers, the final solution may be hard to extend and use.
As I said in a comment below, while best practices for ant builds exist, they still have to be implemented for each project, or copy-pasted from project to project, instead of becoming an out-of-the-box default of the build tool itself.
Maven is a bit too far on the other side of the trade-off for my taste. Changing the defaults is not as easy as it could and should be.

How do you start with writing a mavenized Java application

I am pretty new to Java and Maven and today was studying about maven, how to Mavenize a java app, how to make it good for EClipse, etc... so now I have a question: when we want to write a Java and we know that we want to use Maven too, then we start writing application and creating out directory structure with the layout that Maven likes it? or we just write our app and at the end we mavenize it? Where do we start from when we want to create a java app from beginning and we want it to be mavenized too.
Use Maven from the beginning. Why write in a different structure and convert it again at the end, while you can do it in correct way from start? If you don't use Maven from the start, what build tools you will use then? Ant? I don't see any gain in productivity in such approach.
As Adrian said, you should definitely use Maven since the beggining.
One of its main value is to guide you on "the right way". I should say "The right Maven way". It's sometimes very restrictive, but it's the main advantage : if you do like Maven is waiting for, you are probably on the way that every community or big project do.
If you start your project "by yourself", you may forgot or miss something that will trouble you. For instance, main java sources are expected to be in src/main/java. Most of the plugin use the variable sourceDirectory to bind it ... but you may have to redefine this variable many times for plugins.
Another instance, and quite often confusing, is the multi module project. If you have 2 or more project that are binded (in their life cycle), you should set up a multi module project. If you don't, you will face of code or action duplication (2 tags, 2 build, 2 deployement, etc...).
So, in order to give you a straight answer :
read http://www.sonatype.com/books/mvnref-book/reference/
use the more appropriate archetype to build your project
if you create it under command line (not with an IDE), import it
then work :)
What I'm saying will appear you more and more clear using Maven :).
See Why does Maven have such a bad rep? to better understand why :)

Resources