10 min. reading time

Did you know that YAKINDU Statechart Tools Professional Edition brings great additional features to the Open Edition? The newest addition is the headless code generation. In this article, I'll show you, how to integrate it into your favorite build tools.


Using the headless compiler means invoking the supplied launcher script ‘scc’, short for Statechart Compiler. This script resides in the installation folder of your YAKINDU Statechart Tools installation. In case you are using the Open Edition of YAKINDU Statechart Tools, you will need to install the headless code generator from the Professional Edition’s update site, free of charge. The process is explained in the documentation.

Working with scc is greatly simplified when its location is part of your PATH variable. You can either add the location of your YAKINDU SCT (short for YAKINDU Statechart Tools) installation to it manually, or, on Mac/Linux, you could also create a symlink to the scc script in /usr/bin or similar. The latter variant is more elegant and you will not need to modify the path variable on every login. All further examples assume you somehow added scc to your path.

Boring setup stuff aside, let’s get to the exciting part and generate some code together!


Generating state machine code from command line

To get an overview of scc’s command line options, you can invoke it with -h to get a list, as you might be used to:

# scc -h
Launching /home/rbeckmann/Downloads/yakindu-sctpro/SCT...
OpenJDK 64-Bit Server VM warning: ignoring option PermSize=256m; support was removed in 8.0
--------------------------------------------------------
YAKINDU Statechart Tools Headless Generator ((c) by itemis AG)

Visit http://www.statecharts.org
--------------------------------------------------------
usage: scc [-d <path>] [-h] [-m <path(s)>]
-d,--baseDir <path> Relative/absolute path to the working directory that contains your statechart projects. If not set the current directory is used.
-h Shows help content.
-m,--model <path(s)> A list of comma separated relative/absolute paths to model(s) used during execution. If not set the runtime value of baseDir is used.

As you can see, all options are purely optional. If you invoke scc without any options, it just generates everything that can be found in the current working directory – for example your project’s root folder. That’s the way I use it mostly.

If navigating to that folder first is not an option for you, you can specify the base directory with the -d switch. That is, navigating to /home/user/ws/project and invoking scc is the same as invoking it from elsewhere with scc -d /home/user/ws/project.

The other interesting switch is -m, which allows you to fine tune what you want to generate exactly. If you have a project with a statechart and two sgen files with different options, specifying one of both sgen files will only generate that one. Note you will need to specify the statechart as well.

Consider the following structure in your project root:

ls
defaultSM2.sgen defaultSM.sct defaultSM.sgen main.c


Invoking ‘scc’ will generate both sgen files.


If you only want to execute one of them, the call would look like this:

scc -m defaultSM2.sgen,defaultSM.sct


That’s it, basically. Now let’s explore how to integrate code generation with scc into your build tools.

Integration in GNU Make

With Makefiles, you are able to define your compile targets and its dependencies. Every time a dependency is changed, the next run of Make will recompile said target. Using this infrastructure it is pretty simple to generate code from statecharts whenever needed.

Consider the following very basic example project:

File tree of example project: headless code generation integration in GNU
The build of this project can be viewed as a dependency tree. To build the executable, we would need to link the object files main.o and defaultSM.o. To create these, we need to compile main.c and defaultSM.c. To have defaultSM.c we need to generate the statechart from defaultSM.sct and defaultSM.sgen – that’s it.

The makefile looks like this:

.PHONY: all
.PHONY: clean

all: main

main: src-gen/DefaultSM.o main.o
gcc -o main src-gen/DefaultSM.o main.o

clean:
rm -rf src src-gen *.o main

main.o: main.c
gcc -Wall -c main.c

src-gen/DefaultSM.o: src-gen/DefaultSM.c
gcc -Wall -c src-gen/DefaultSM.c -o src-gen/DefaultSM.o

src-gen/DefaultSM.c: defaultSM.sct defaultSM.sgen
scc


It’s a good practice to name the default target ‘all’, but you could remove it.

The line main: src-gen/DefaultSM.o main.o states that the file main (the final executable, no file ending is needed on Linux) depends on both these object files. The order is important here, because otherwise the compiler would fail, stating that the header files also generated from the statechart are not available when compiling main.c – you could work around this but this is an easy solution.

Both these dependencies are reinterpreted as targets, which have other dependencies. This is standard make stuff. The most interesting entry is this:

src-gen/DefaultSM.c: defaultSM.sct defaultSM.sgen
scc


This says “to produce src-gen/DefaultSM.c, which depends on defaultSM.sct and defaultSM.sgen, call ‘scc’". Calling scc without arguments is possible here, because the Makefile is located in the project and scc will just generate everything in there.

Adding both the *.sct and the *.sgen file has the additional benefit that a change in either of them results in a re-generation of the statechart sources – for example when you change the options in the *.sgen file.

The clean target removes all object files and the folders src and src-gen, both generated by YAKINDU Statechart Tools. Pay attention when you have sources in ‘src’ as well.

Integration in Apache Maven

Maven allows you to automatically build and deploy your Java projects. Its operation is mainly revolving around the so-called “build lifecycle” and a number of plugins. One of them is the exec-maven-plugin, which allows the user to execute arbitrary tools.

This time, the project structure is a tad more complicated:

File tree of example project: headless code generation integration in Apache Maven
The Greeter-class imports the statemachine sources and adds “Hello World!” to a string everytime the statemachine cycles until it is finalized.

For Maven, instead of a Makefile, there is the pom.xml file.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>gs-maven</artifactId>
<packaging>jar</packaging>
<version>0.1.0</version>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<id>Generate</id>
<phase>generate-resources</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<configuration>
<executable>scc</executable>
</configuration>
</plugin>
</plugins>
</build>
</project>


As you can see, it is pretty big. If you have never worked with Maven before, you will likely be overwhelmed. The interesting part is the plugin in the bottom, it specifies which plugin will be used and what it should do – namely, execute scc. Another interesting detail is the binding to a phase inside of the execution block: Maven executes generate-resources before the compile phase, thus the needed sources will be there when we need them.


Integration in Apache Ant

Apache Ant is another build tool specialized for building Java projects. It uses an xml as well, but one that is a bit less talkative. The exact same project can be built with Ant using the following xml:

<project>
<target name="clean">
<delete dir="build"/>
</target>

<target name="generate">
<exec executable="scc"/>
</target>

<target name="compile" depends="generate">
<mkdir dir="build/classes"/>
<javac srcdir="src/main/java" destdir="build/classes"/>
</target>

<target name="jar" depends="compile">
<mkdir dir="build/jar"/>
<jar destfile="build/jar/HelloWorld.jar" basedir="build/classes">
<manifest>
<attribute name="Main-Class" value="hello.HelloWorld"/>
</manifest>
</jar>
</target>

<target name="run" depends="jar">
<java jar="build/jar/HelloWorld.jar" fork="true"/>
</target>

</project>


The important bit is the part with “generate” and that the step “compile” depends on it.


Integration in Gradle

While both Maven and Ant rely on a xml file to specify the build process, Gradle uses a DSL based on Groovy. This allows Gradle to have the shortest build configuration file of the three Java build tools mentioned here. Also, keep in mind that Gradle isn’t only a Java build tool, but can be used to build projects such as C/C++ and Android, as well. This script, named build.gradle, is located in the project root. It will allow you to build the project from the Ant and Maven example.

apply plugin: 'java'
apply plugin: 'application'

mainClassName = 'hello.HelloWorld'

jar {
baseName = 'sct-gradle-example'
version = '0.1.0'
manifest {
attributes 'Main-Class': 'hello.HelloWorld'
}
}

task generateStatechart(type:Exec) {
commandLine 'scc'
}

compileJava.dependsOn(generateStatechart)


Just like with Ant and Maven, the important part is the task specification (generateStatechart) and defining that compiling the Java depends on that task.


Summary

As you can see, using the headless code generator in your favorite build tools is quite easy, no matter if you are building embedded software or a huge enterprise project in Java. If you have got the Professional Edition of Statechart Tools, you can of course use the Deep C Integration in headless mode as well. Either way, try it out!

Try the Professional Edition now

Comments