Command Line in EK9

This last section will discuss the command line options of the reference implementation of the compiler.

From a command prompt; just type ek9 someSource.ek9 for source to be compiled and executed. If all you have is a single source file and want to execute it - that's it!
But, if your ek9 source file has the 'execute' bit set on Linux, Unix and MacOs and the 'ek9' command is on your PATH, you can just type ./someSource.ek9 and the 'shebang of #!ek9 will trigger the use of the ek9 command.

Actually the EK9 compiler can do quite a bit more than just compile source code. Read the section on packaging for when you have a few sources files or thousands.

Is it a build system then?

Not quite; is probably the right answer. If you are doing a pure EK9 development then it will get you a very long way. It is designed to be used by other build systems, CI/CD pipelines and to fit into a larger build pipeline. For simple small/medium development it will probably suffice.

Can it be used with other build systems

The EK9 compiler has been designed to be usable in modern build pipelines either from other software like

So it has a number of options that don't actually compile code, but facilitate versioning and packaging.

When used with the '-ls' flag it can also be used as a language server with code editors like IntelliJ, Vim, Eclipse and VSCode. There is an extension for VSCode that can use EK9 in this mode, it also includes syntax highlighting and code snippets.

Why add all those options in?

Please read the introduction for the logic of this. These are the basic operations you need to be able to produce and manage modern software.
Developing software now goes way beyond just compilation. The very nature of software delivery has undergone enormous change. Building very large monolithic applications must be avoided if possible.

Packaging, version management and deployment provision are all critical aspects of creating modular software now. But also linking parts together as separate runnable modules with very specific and defined interfaces is the way forward.

Command line application

The reference implementation of the compiler has a wide range of options for very specific purposes, these are detailed below. To just run a program and have it automatically compiled see running programs.

By just running the ek9 (with no source file) like this below you will see the following options.

  • $ ek9
  • Usage: ek9 <options>
  • where possible options include:
  •   ...
  •   filename.ek9 - the main file to work with
  •   -r Program to run (if EK9 file as more than one)

Options

There are a number of options that are related and these are explained in relation to each other.

General

-v This just output lots of information relating to what the compiler is doing.

-V This just shows the version number of the compiler itself.

-h A general help message for all the options available.

-e <name>=<value> Define an environment variable,
for example user=Steve,
or user=\'Steve Limb\' if you must have spaces.

-T target architecture - defaults to 'java' if not specified (but see EK9_TARGET below) - actually Java the only architecture supported at present!

Also the environment variable EK9_TARGET can be used in place of -T. The -T optional will override the environment variable EK9_TARGET if used. This environment variable has been introduced so that it is not necessary to provide the command line parameter all the time.

Memory Configuration

EK9 provides two environment variables to control JVM memory allocation:

EK9_COMPILER_MEMORY - Sets the maximum heap size for the EK9 compiler itself. Defaults to -Xmx512m if not set. Useful for large projects or when running multiple compilations in parallel.

Example: export EK9_COMPILER_MEMORY="-Xmx1024m"

EK9_APPLICATION_MEMORY - Sets the maximum heap size for compiled EK9 applications when running them. Defaults to -Xmx512m if not set. Adjust this based on your application's memory requirements.

Example: export EK9_APPLICATION_MEMORY="-Xmx2048m"

Language Server

The compiler can be used just as a 'language server', in this mode it does not produce an executable as an output; but it does complete the 'front end' phase of compilation and provides diagnostics.

There is an EK9 VSCode Extension available as opensource, once development is complete this will be published.

-ls Use compiler as a 'Language Server' only with stdin/stdout as the protocol channel.

-lsh This flag will configure the EK9 language server so that it provides additional EK9 language hover help. This includes hover help for 'operators' such as ':= for example. So is very useful when first using EK9, the hover help also includes hyperlinks to the appropriate sections on this site.

Compilation

There are a number of different options to control compilation, this gives quite fine-grained control over full builds versus incremental builds. What constitutes the source files is described in small applications, medium applications, large applications and use of libraries.

-c Incremental compile; but don't run. Only source files that have changed get recompiled.

-cg As above; incremental compile but with debugging information.

-cd As above; incremental compile but with all dev code and debugging information.

-Cl Clean all, including dependencies.

-C Full recompile; but don't run. All source files are recompiled even if they have not changed.

-Cg As above; full recompile but with debugging information.

-Cd As above; full recompile but with all dev code and debugging information.

Dev Code

The idea of dev code is the concept of defining some source code that is not really part of your program/application or library; but is code used as an example or for testing.
It can be more than just unit test code, it could be a set of worked examples, templates, how-tos.

Basically it can be anything that another developer might find useful that is not part of the main functionality your software provides. So by default a user of your library (if that's what you are creating) would not use any of the code in your /dev directory in production use. But would really value real examples and tests that you have provided to show how your library can and should be used.

So it's best to make these /dev code examples short, tight to the point and easy to snip to enable the developer using your library to take that snip and rework it into their application.

So rather than the developer searching the internet for examples of how to use the library, include real examples and tests to show and help that developer get going.

Integration/Unit tests, any programs that start with 'test' in the /dev directory or subdirectories are considered integration/unit tests (see -t optional later).

Dependencies

-Dp Resolve all dependencies, this triggers -Cl clean all first. If you have altered the EK9 source file that contains the package construct and altered the dependencies this will be automatically run. As you can see it will trigger a Clean and that will mean a full recompilation will also be required.

The resolved dependencies will be pulled down from repo.ek9lang.org validated and put in your $HOME/.ek9/lib directory and unpacked. So if you wanted to look at the examples, snips or tests the developer of that dependency provided then just look in your library! You can then lift some of those examples or snips from the dependency /dev directory into your own code and try them out.

Packaging

The packaging of the software for some form of reuse does not mean the software has to be 'open source' You can package your modules and re-use them all internally to your organisation, or even just on your own PC!

-P Package ready for deployment to artefact server/library.
You decide if the software is fit to package. I'd suggest a range of unit tests in the /dev area of your project.

-I Install packaged software to your local library ($HOME/.ek9/lib).

-Gk Generate signing keys for deploying packages to an artefact server - only needed if publishing to a remote server.

-D Deploy packaged software to an artefact server, this triggers -P packaging first and -Gk if necessary. Note you will need to have an account on the remote server and also have your $HOME/.ek9/config and $HOME/.ek9/credentials setup for your package to be deployed.

Version Numbers

So that you can include versioning into your other processes, such as creating new branches in your source code repository, triggering new builds of the software - EK9 has a number of commands to help alter the version number for you. The package construct is essential for managing versioning of EK9 software.

-IV [major|minor|patch|build] - increment part of the release vector. EK9 will work out the next value to be used. You just decide it is major, minor, patch or just the build number to increment.

-SV major.minor.patch - force setting to specific value i.e 6.8.1-0 (always zeros build on setting). Useful when you want to create a new branch in your source code repository and need to ensure your code uses the same numbering.

-SF major.minor.patch-feature - force setting to specific value for features i.e 6.8.0-specials-0 (always zeros build on setting). As above but useful for feature branches.

-PV print out the current version i.e 6.8.1-0 or 6.8.0-specials-0 for a feature. Saves you having to grep it out!

Features

While features are not a unique concept to EK9 and are used very widely with git repositories - but they probably are worth a quick mention.

As outlined in versioning any release of software must have a unique version number. However, there are times when a large team need to work on the next release. Now the tricky bit, different groups of developers will form to work on a feature together. But there may be several features planned for this next release, and they all need to be worked on concurrently but with some form of isolation from each other.

This is where a new set of feature branches are created, each group then work on their features in a sort of semi isolated manner. All striving to get their features ready for the next main build. During this time all the members of the team working on a feature work on the same code (git enables this). But critically they also need to run full automated builds and tests of their group effort. In some cases they may even need to deploy their feature and demonstrate it to end users, product owners or parts of the testing team (or even marketing departments).

That software needs a version number so that any issues, new ideas, defects or alterations can be made. Importantly it must include some name that the teams understand i.e. the feature. That is why EK9 has a special locations in the version numbering for a feature name.

Some features never see the light of day, others are fit for purpose and get folded back into the main development branch. Others need more work and don't quite make the 'cut' for the next major version to be delivered; hence they have to go into another release scheduled later. Sometimes features are merged and refined further by merging git feature branches. EK9 supports this by enabling the version number to be manipulated in a controlled manner.

The 'run' options

These are really the options you care about, running your software. By default, if no options are given then -r (run) is assumed. But importantly if the source code has not been compiled yet; the EK9 compiler will trigger a full build - including resolving dependencies. This means you can just write (or download) some EK9 source and then 'run it'. First time though it will be checked and compiled, subsequently if nothing has been altered it will just be 'run' without recompiling.

-t Runs all unit tests that have been found, this triggers -Cd full compile first. To define tests store them in the /dev directory just by the main source file you reference. EK9 will find all the code in the /dev directory and compile that as well as your main source. It will then find all programs that start with 'test' (just in the /dev and subdirectories) and run them all. For Java guys this is a bit like junit. The test programs cannot have any command line parameters, because they are automated.

-d port Run in debug mode (requires debugging information to have been compiled in). The use of edb the EK9 debugger will be covered once developed.

-r Run in normal mode (assumed if no other option provided).

Using Standard Input and Output

EK9 programs can read from standard input (stdin) and write to standard output (stdout), making them work seamlessly with Unix-style pipes and shell redirection. This is essential for creating CLI tools, filters, and pipeline-based applications.

Simple Example

Here's a minimal EK9 program that reads from stdin and writes to stdout:

#!ek9
defines module introduction

  defines program

    PassThrough()
      stdin <- Stdin()
      stdout <- Stdout()

      inputLine <- stdin.next()
      stdout.println(inputLine)
//EOF

Running with Pipes

Once compiled, you can use standard Unix piping to pass data to your EK9 program:

  • $ echo "Hello World" | ek9 PassThrough.ek9
  • Hello World

On Unix, Linux, and macOS systems with the shebang (#!ek9) and execute permissions set, you can run it directly:

  • $ chmod u+x PassThrough.ek9
  • $ echo "Hello World" | ./PassThrough.ek9
  • Hello World

Chaining with Unix Tools

EK9 programs integrate naturally with Unix command-line tools, allowing you to build processing pipelines:

  • $ cat data.txt | ek9 filter.ek9 | sort | uniq

Learn More

For comprehensive documentation on Stdin, Stdout, and Stderr usage, including advanced patterns with stream pipelines and iterator-style access, see:

Exit Codes

The ek9 command uses specific exit codes to enable integration with shell scripts, build systems, and CI/CD pipelines. Understanding these exit codes is essential for automation and error handling in production environments.

How Exit Codes Work

The ek9 command is a wrapper that invokes the EK9 compiler (a Java program). The wrapper translates the compiler's internal exit codes to standard Unix conventions where exit code 0 means success:

Exit Codes You Will See

When you run the ek9 command, you will see these exit codes following standard Unix conventions:

0 - Success. Either a successful operation completed (compilation, versioning, packaging, etc.), or your EK9 program executed and returned 0.

1 - Cannot execute. The system was unable to run the EK9 compiler or your compiled program. Check that EK9 is properly installed and you have the necessary permissions. Error details are printed to stderr.

2 - Invalid parameters. The command line parameters provided were not valid or could not be parsed.

3 - File processing error. The specified file was not found, could not be read, or had missing content.

4 - Invalid combination of parameters. The parameters provided were individually valid but incompatible when used together.

5 - No programs found. The EK9 file does not contain any programs that can be executed.

6 - Program not specified. The EK9 file contains more than one program, and you must specify which one to run using the -r flag.

7 - Language Server failed to start. The EK9 compiler could not start in Language Server Protocol mode when using the -ls flag.

8 - Compilation failed with errors. The EK9 source code contains syntax errors, type errors, or other compilation issues. Error messages will be printed to stderr.

9 - Wrong number of program arguments. The program requires a specific number of arguments, but a different number was provided at runtime. This is detected during the generated code's argument validation.

10 - Cannot convert argument to required type. A program argument could not be converted to the type required by the program's parameter (e.g., passing "notInteger" when an Integer is required). This is detected during the generated code's argument conversion.

Exit Codes from Your EK9 Programs

When you use ek9 -r yourProgram.ek9 or ./yourProgram.ek9, if compilation succeeds (compiler returns exit code 0), the wrapper executes your program and returns your program's exit code.

Your EK9 programs can set their own exit codes using the Exception class, which supports holding an exit code. If an Exception propagates back to the main program without being caught, the application will exit with that exception's exit code. See the Exceptions section for details.

This means your EK9 programs can return any exit code (0 for success, non-zero for errors), and that exit code will be propagated through the wrapper to the shell. This is essential for writing CLI applications that work correctly in shell scripts and automation.

Shell Script Usage

In shell scripts and CI/CD pipelines, you can use standard Unix exit code patterns:

  • $ ek9 -C myprogram.ek9
  • $ if [ $? -eq 0 ]; then
  • $   echo "Compilation successful"
  • $ elif [ $? -eq 8 ]; then
  • $   echo "Compilation failed"
  • $ fi

Or use the simpler standard pattern:

  • $ if ek9 -C myprogram.ek9; then
  • $   echo "Success"
  • $ else
  • $   echo "Failed with exit code $?"
  • $ fi

CI/CD Integration

Build systems and CI/CD pipelines (such as GitHub Actions, AWS CodePipeline, or Azure Pipelines) will automatically detect non-zero exit codes and mark builds as failed. Exit codes 8, 9, and 10 are particularly important for detecting compilation and runtime errors in automated builds.

Summary

There are quite a few options available with the EK9 CLI but in general if you just want to write some source and run it - very few options are actually needed. On Linux/macOS platforms just change the execute bit of your source file (chmod u+x someSource.ek9) and then just run it (./someSource.ek9) as long as you installed the EK9 CLI correctly the code will get compiled and run. On Windows you need to just type ek9 someSource.ek9 for it to get compiled and executed.

Conclusion

Well if you got this far, well done! Because this is the last section.

What's been attempted with EK9 is to bridge the gap between pure software development with a compiled language and the packaging, releasing and publishing of software. But doing it in a way that employs a fairly simple language structure that easy to read/write, but is performant and has a range of sophisticated software engineering design patterns built in.

This is ambitious, difficult (technically) and very hard in terms of building the necessary human ecosystem that is essential to make a programming language successful.

The reason the EK9 language is so large is because it incorporates language structure, new constructs, design patterns, API's, versioning, building, packaging and deployment. But hopefully you will find it can provide value for you as a developer; in layers as you need them.

Only time will tell if we can succeed. But thank you for taking the time to read these documents.

Next Steps

Jump back to the main page and download the compiler and some examples and get started.