Getting Started



Goes through the steps of installing:

  • visual studio code (here on 'vsc').

  • visual studio code support for c++

  • the ninja build system

  • the sing plugin for vsc.

Installing Visual studio code

Follow the instructions at:

based on your development platform

Installing visual studio support for c++

Follow the instructions at:


On Windows you should install MinGw-64 and the vsc c++ extension from Microsoft.
On Linux, you just need to load the extension.

Installing Ninja

download and install Ninja from


The distribution zipfile contains a single executable. 
Move the executable in a directory listed in the "path" environment variable.

For example on Linux /usr/bin is a good place. To move the file there, download the zipfile and extract the content. Then open a command prompt in the directory where the ninja file is placed and issue:
sudo cp ninja /usr/bin/ninja

On Windows you may want to place ninja in the mingw binaries directory (the one you just added to the path as parg of mingw installation).
If instead you want to keep the programs cleanly separated you can put it in C:\Program Files\ninja and add this new path to the environment variable "path".


Installing the sing plugin

You must follow the same procedure you did for the c++ plug-in:

  • Open VS Code.

  • Select the Extensions view icon on the Activity bar or use the keyboard shortcut (Ctrl+Shift+X).

  • Search for 'singlang'.

  • Select Install.

NOTE: after installing the plugin, and after each plugin update, you may need to restart visual studio code.

Building your first project


  1. Create a folder which is meant to contain all the project's files.

  2. Run vsc, issue File->Open Folder to open the folder.

  3. Press ctl-shift-P, select and issue the 'sing:update project' command. In an empty folder this command creates a simple hello-world project. 

  4. Press ctl-shit-B and select Debug to compile the project in debug mode.

  5. Press the F5 key to run the hello world program.

About the updater (the sing:update project command)


You need to run again the updater to fix the project when:

  • you add/delete/move source files (either cpp or sing)

  • If you have just updated/cloned a project from a repository (to fix some details that may depend on the platform or local sing installation).

The standard directory structure of a sing project


The 'sing:update project' command creates/updates the following directory tree:



Contains some json files used to configure the visual studio code behavior:



configures the action to be taken when F5 is pressed.
The most important properties in launch.json are "args" and "cwd": respectively the command line arguments and the working directory of the launched program.


configures the command vsc runs to build the project.
It just runs ninja with appropriate parameters. Unless you whant to use a build system different than ninja or you have special requirements you should not alter this file.


configures the c/c++ plugin. One of the most important properties is "includePath", which configures the paths where intellisense searches external c/c++ symbols.


lists the directories searched by the sing intellisense system.


Contains the compiled and linked application in two versions: debug and release. 
By default, the release version has the same name of the project root folder, the debug version is called the same with a _d suffix.
You can change the binary name in build/build_<platform>, build/build_<platform> If you do that, don't forget to change the "program" property in the launch file accordingly.




  • The ninja files, which specify which sing and gcc commands the ninja build system should run.

  • All the intermediate .o files in the obj_d and obj_r sub-directories, respectively for the debug and release build.

The ninja files strictly depend on the directory tree structure. You may want to change them for a number of reasons (both the directory structure and the ninja file): to create a static library, to have multiple sub-projects, different build configurations, etc..
In any case the updater will always try to be respectful of your changes and try to add new sources to the same sub-target other sources from the same directory belong to.


Keeps all the intermediate cpp sources generated starting from sing files, in the debug and release sub-directories, respectively for the debug and release build.


Contains the sing sources


Contains manually crafted c++ sources

NOTE: If you whant to have a common tree for sing and cpp sources, please:

  • change the line "sing = ../../sing" into "sing = ../../src" in the build/ file.

  • change the content of .vscode/sing_sense.txt from "sing" to "src".

The ninja build files

It holds the dependencies and configurations which are common to all the build configurations and target platforms. In the following variables are of special interest:

cc_flags  where you can add new flags for the c++ compiler
ln_libs     where you can list additional obj files or libraries to link (the latter with -l<library> syntax).


You can also define more rules to be used to compile different sources but don't add variables in the scope of a single dependency. (sing:update project doesn't support them).


Per configuration, per platform options. The most important are:

cc_extra_flags    gcc flags
sing_extra_flags  sing flags
bin_target        the executable name
ln_extra_libs     must follow the -l<library> syntax, libraries for a configuration/platform.


Contains the definition of the sdk location.

The sing command line

The sing compiler itself prints this output if invoked with -h

Usage : 

sing [options] <source_file_name>

-h or -?    prints an usage description. Also includes some seldom used or not-active options not listed here.
-g          debug build.
-I <dir>    included sing search directory. You can specify multiple search directories.
-MF         generate a makefile with dependencies too (extension: .d)
-o <file>   output filename (3 files are generated with extensions: .h, .cpp and .sm)"
-u          don't emit error if a private declaration is left unused.    
-p          generate only the header. accept partial function declarations (without the body).
@<file>     read command line arguments from <file>".

Please note the spaces between the option flags and the option values !!

What 'sing:update project' (the updater) exactly does


If you want to make deep modifications to the project files and be sure those modifications are compatible with the updater's behaviour, this chapter is saving you some guesswork.

This is what the updater does wen run:

  • If there are no sources, initialises the project with the 'hello world' code.

  • If there is no ./build directory, creates a build directory with the standard build files

  • If there is no ./build/ or if it exists but it has an invalid content, creates the file.

  • Updates the ./out directory tree to fit the tree of sing sources

  • Creates ./build/obj_d, ./build/obj_r, ./bin/linux, ./bin/win directories if they don't exist (so you don't need to save them in git) 

  • Creates and fills the .vscode directory if it doesn't exits.

  • Fixes ./.vscode/launch.json for the current platform.

  • fixes ./.vscode/c_cpp_properties.json so that the intellisense detects the sing sdk include files.

  • Creates ./.vscode/sing_sense.txt and .gitignore if they don't exits.

  • Tries to fix rules. (see below)

Note that updater respects all the modifications you do to all the files (it doesn't touch them if they are present) except:

  • ./build/ (only if contains a non existing path)

  • ./out

  • ./.vscode/launch.json

  • ./.vscode/c_cpp_properties.json

  • ./build/


It is important to know how the Updater affects because it may be maintained in part manually.

The Updater:

  • Assumes ninja runs in the objs directory.

  • Assumes there are no variables in the scope of a single dependency.

  • Assumes $cpp, $sing, $temp are respectively the paths of:

    •   original (user crafted) cpp files

    •   sing sources

    •   cpp files as generated by the sing compiler

  • Affects only 'build' commands depending from:

    •   $cpp, $sing, $temp sources with consistent filename extension

    •   .o files (assuming the build command is a link/library command)

  • Tries to guess which rule applies to which file based on its source directory path

note that you can compile different files with different options if you define different build rules and use them consistently (files from the same directory using the same rule).

As long as you make the tool assumptions true, it is pretty safe to use update to fix the ninja project when you add/delete/move sources.

If you want to manually update only some rules, just place the sources outside /src or /sing and avoid using $cpp, $sing, $temp in the rules. If the Updater doesn't find the sources in /src or /sing, it deletes all dependencies which have the form of <name>.o from the link and librarian targets, so please use a variable to include those obj files:

manual_objs = manobj.o manobj2.o
build $bin_target: ln maual_objs ...

If you want to prevent update from changing your build_aux file at all, just change its name.

If you want "sing:update project" to restore a build_aux beyond repair, just delete the whole build directory. 
(note that in this case he will assume you want to generate a single executable from all the sources)

About vsc and ninja


A few words for those who don't know vsc and ninja:


Ninja files have a super simple syntax. check here the ninja manual:

I found vsc really similar to any other IDE I have used in the past. here are just some tips as a beginner  I had to google for:

As you single-click on a file in the file list, it opens in the editor in temporary mode (it closes as you switch to another file). To open in standard mode you need to double click.

You can navigate back and forth using:

On Windows: alt-<arrow right>, alt-<arrow left>

On Ubuntu: ctl-alt-<plus>, ctl-alt-<minus>

In general take a look at the shortcuts in the "go" menu item.

​You can select a rectangle area placing the cursor in one corner and then alt-shift-clicking on the opposite corner of the area.​

If you are using git and you made some changes, use the "open changes" button to see what you changed.​

I recently experienced a debugger crash that I solved deleting all the watch expressions from the watch list. (most of them being out of scope)