Categories
graalvm Quarkus

Integrate Quarkus with C language without an issue

Imagine that your team used C language for few decades and written many different applications and tools with it. For some reason team switches to Java and now hundreds of hundreds of C logic will be abandoned? No, with Quarkus, you can execute any of this logic without leaving your Java environment.

When you use GraalVM with Quarkus(or any other environment), you have access to wide range of supported languages, starting from Python, R, and going as deep as C++ and C. In this article we’ll start looking into C language that powers many ISS software.

Getting started

Firstly, we need to prepare our machine to handle all the logic we have. This article will use Ubuntu 16. We assume that you’ve installed GraalVM already, let’s install additional software.

Install llvm toolchain

This can be done as simple as calling one line:

gu install llvm-toolchain

This command will install the required LLVM compiler and many more tools required to compile your C.

Install libpng library

This step is optional and is required only to compile our example of image generation, to do this, you need to install some apt dependencies, for Ubuntu 16 its:

sudo apt-get update && sudo apt-get install libpng-dev

Hello world from Hello world

Let’s write simple app that will call C function from Java.

Firstly, let’s init simple Quarkus project

mvn io.quarkus:quarkus-maven-plugin:1.3.2.Final:create \
    -DprojectGroupId=tech.donau.quarkify \
    -DprojectArtifactId=quarkus-cpp \
    -DclassName="tech.donau.quarkify.ExampleResource" \
    -Dpath="/hello"

Next, let’s create our first C example. I use src/main/cpp folder to hold all the C sources, feel free to use any other place. We’ll create src/main/cpp/hello.c, here’s content:

#include <stdio.h>
int main() {
   // printf() displays the string inside quotation
   printf("Hello, World!\n");
   return 0;
}

Perfect, next step is to compile this C code into bytecode.

GraalVM C compilation

If you’ll look into example root folder, you’ll can find handy shell script called buildc.sh. This script will build c code and move it into corresponding folder.

export LLVM_TOOLCHAIN=$(lli --print-toolchain-path)
$LLVM_TOOLCHAIN/gcc -I/usr/local/include -L/usr/local/lib ./src/main/cpp/example.c -o example
mv example ./src/main/resources/

Firstly, we import LLVM_TOOLCHAIN env variable that has such executables as gcc. Next, we compile with GraalVM’s gcc our C code into binaries. And finally we move it to resources folder, that we will use later.

Execute C from Java

Final step is to execute our C code from Java, which is super simple:

Testing execution

Now that everything is in place, we can call our C code. Go to http://localhost:8080/hello, you’ll see See terminal output :). Now go to output and you’ll see expected result from C code:

As you’ve seen, we don’t have any Java code that outputs hello world string, only in C.

Practical example(maybe)

Best part of using C language is that you’re not limited to any default libraries, but can use any. I initially wanted to show you Tensorflow example, but turns out it’s too much code for example. Instead, I’ll show you how you can generate avatar from C code and output it to user.

Firstly, let’s add one more c file called hello.c, here’s whole code for it:

I found and combined this example from some stackoverflow answer.

Next, let’s modify our build.c example as next:

export LLVM_TOOLCHAIN=$(lli --print-toolchain-path)
$LLVM_TOOLCHAIN/gcc -I/usr/local/include -L/usr/local/lib ./src/main/cpp/hello.c -lpng -o hello
$LLVM_TOOLCHAIN/gcc -I/usr/local/include -L/usr/local/lib ./src/main/cpp/example.c -lpng -o example
mv hello ./src/main/resources/
mv example ./src/main/resources/

This will build both hello and example, feel free to optimise this scrip 🙂

And, finally, let’s create new resource in our Quarkus project called AvatarResource.java

Now you can test it by executing ./mvnw quarkus:dev and going to http://localhost:8080/avatar

This is output of our endpoint if you run it few times. Each avatar is a little bit different in green color.

In conclusion

GraalVM provides full support for LLVM compatible languages such as C. If you have some logic that you want to serve via Java, Quarkus is a great option.

There’s even more that you can do with C++, and we’ll cover it in a next topic

Categories
graalvm maven Native Quarkus

Command-line tools with Quarkus and Picocli

Quarkus 1.4 introduced to us Command mode, Quarkus 1.5 took it one step forward and introduced a new Picocli extension, which makes the development of command-line tools a breeze.

Let’s create one command-line tool that will help us upgrade old Quarkus project to 1.5

Initial setup

We, firstly, need to have some initial project. You can either use https://code.quarkus.io/ to generate a project, in this case, add picocli extension.

Alternatively, you can generate new project with next command:

mvn io.quarkus:quarkus-maven-plugin:1.5.0.Final:create \
    -DprojectGroupId=net.quarkify.qdm \
    -DprojectArtifactId=qdm \
    -DclassName="net.quarkify.qdm.GreetingResource" \
    -Dextension="picocli,io.quarkus:quarkus-jsonb"
cd qdm

qdm stands for Quarkus Dependency Manager. qpm is already used by Qt package manager, so I decided to mix it up a bit.

Existing project

If you want to add extension to your existing project, use next:

./mvnw quarkus:add-extension -Dextensions="picocli,io.quarkus:quarkus-jsonb"

Or add maven extension:

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-jsonb</artifactId>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-picocli</artifactId>
</dependency>

Strip out Rest API

Command-line tool doesn’t require serving any API(well, maybe in some cases, but not in our), so let’s remove this extensions from our project, firstly, remove Resteasy extension(in bold) from maven.

<dependencies>
  <dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-resteasy</artifactId>
  </dependency>
  <dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-junit5</artifactId>
    <scope>test</scope>
  </dependency>
..

Next, remove GreetingResource.java and test folder(unit tests are a good thing to your project, but because we won’t write unit test we can just remove them for now). You can also remove resource/META-INF folder as well.

Disable logs

Add next two lines to application.properties. We want to still see error messages and we assume that our tool won’t be used in a pipe with other tool (e.g if qpm host | curl - will return error it will fail the curl call which is okay for us)

Adding root command

Every middle+ command-line tool developed in Picocli will require root(or top) command. This command will aggregate all the other commands and serve as entry point for parsing our command line

We’ll need to create QdmCommand in root package location

It’s empty Runnable class and it’s okay.

  1. @TopCommand notifies Quarkus that it’s entry point for our CLI tool
  2. @Command is a Picocli interface that marks the current class as a command. You can read more here
    1. mixinStandardHelpOptions specifies that we want Picocli to generate help options for us. This will automatically add --help option
    2. in version we specify current version of app, there’s also versionProvider, but we won’t cover it in this article

You can do next now:

./mvnw clean package -Pnative
cd target/
./qdm-1.0.0-SNAPSHOT-runner --version
1.0.0

Implement upgrade command

Now we have basic skeleton to start implementing specific commands. For this article, we’re only interested in qdm upgrade method. This function will upgrade your Quarkus project to latest version

Here’s simple and complete code:

We have few different options to pass into our upgrade command.

  1. --releaseUrl specifies where to look for latest release, by default it looks for github releases
  2. -v or --version allows you to specify your own version, e.g 1.5.0.Final
  3. -f or --file allows you to specify pom.xml location. By default, it looks for the current folder.

Other logic in class makes a request to GitHub, looks for properties in pom.xml and replaces the required properties. The only thing is that we have GithubRelease.java which showed below

package net.quarkify.qdm.data;

import io.quarkus.runtime.annotations.RegisterForReflection;

@RegisterForReflection
public class GithubRelease {
public String name;

public GithubRelease() {
}

}

It only contains name which is release name.

Add subcommand to main command

We also need to declare our Upgrade command in main, or top command. It can be done via the next additional line for QdmCommand(in bold)

@Command(mixinStandardHelpOptions = true,
        version = "1.0.0",
        subcommands = UpgradeCommand.class
)
public class QdmCommand implements Runnable {

Build native command

Now that we have our CLI tool ready, let’s build it natively:

./mvnw clean package -Pnative

Install on pc

If you want to use your tool on your machine globally, you can do it with the following command:

mv ./target/qdm-1.0.0-SNAPSHOT-runner /usr/local/bin/qdm

Now you can use in any folder, e.g

cd ~
qdm --help

Verify

But is it even working? For this, I have one of old project repos, let’s clone it :

git clone https://github.com/quarkus-course/lecture-cors-test.git
cd lecture-cors-test

Now let’s use our qdm command:

qdm upgrade --help

Result is good, even though we haven’t included help command we still can see available arguments:

Unknown option: '--help'
Usage:
upgrade [-f=] [--releaseUrl=]
[-v=]
-f, --file= location of pom.xml file
--releaseUrl=
-v, --version= Set specific version for upgrade

If you inspect pom.xml you’ll see that current Quarkus version is 1.2.1.Final, let’s fix it

qdm upgrade

Review the xml file again, you’ll see that it’s set to new version, for me it’s 1.3.4.Final. But we already have 1.5.0.Final, we can use -v command for this

qdm upgrade -v 1.5.0.Final

Nice, let’s verify if backend is working

./mvnw quarkus:dev

You should see upgraded Quarkus up and running

In conclusion

We made Quarkus command-line tool which uses Quarkus repo to upgrade Quarkus project to a newer version. Almost like rewriting the C++ compiler with C++.

I wrote previously a few different command-line tools in C++ and Go, hashsc, for example. And can say that writing CLI tools in the favorite language is more than enjoyable.

In the next article, we’ll see how to setup Github Actions to build executables for Ubuntu and macOS.

This is not the end for qdm. I’ll probably implement some more commands and improve existing one. If you want to improve qdm, I’m happy to accept pull requests.

Categories
graalvm Java Quarkus R

How to use R scripts with Quarkus

There’s a time when you need to call some R script from Quarkus. One option is to create microservice, but what if it’s something really small and you just want to call it in a single place without overwhelming project architecture. This is where GraalVM comes in. With GraalVm you can execute R scripts directly from Java without any conversion, microservices, or endpoints. We already have seen an example in Python, let’s see how to do it in R.

Categories
graalvm Java Python Quarkus

How to use Python with Quarkus and GraalVM

Quarkus is not just a backend framework. Rather, it’s a platform or ecosystem. With Quarkus you can write as JavaEE, as well as Spring applications, and even mix them, without thinking of underlying details.
We also must not forget that we can use GraalVM. GraalVM is a polyglot language and you can run Java, JavaScript, Python, R, C++ from each other without large overload. Calling code from different languages can be beneficial in terms of saving lots of hours, firstly of course because you don’t need to re-write code from one language to another, that can lead to potential bugs, and second thing is that you don’t need to rewrite anything from start.
So taking all that in mind, let’s see how you can freely re-use some of your Python code in Java

Categories
graalvm Java Quarkus

How to install GraalVM and native-image on Ubuntu

In this guide, you gonna see how easy it is to install GraalVM on Ubuntu Linux and start using awesome features like cross-language communication, faster JVM and more.