Compiling SNL Programs
======================

*snc*, the SNL to C Compiler
----------------------------

The SNL to C compiler *snc* compiles the state notation
language into C code. The resulting file can then be compiled
with a C compiler.

.. _CompilerOptions:

Compiler Options
^^^^^^^^^^^^^^^^

SNC options start by a plus or minus sign, followed by a single
character. A plus sign turns the option on, and a minus turns the
option off.

======  ===============================================================
Option  Description
======  ===============================================================
  +a    Asynchronous ``pvGet``: the program continues without
        waiting for completion of the ``pvGet`` operation.
  -a    Synchronous ``pvGet``: the program waits for completion.
        This is the default if an option is not specified.
  +c    Wait for process variables to connect before allowing the
        program to begin execution. This is the default.
  -c    Allow the program to begin execution before connections
        are established to all channel.
  +d    Turn on run-time debug messages.
  -d    Turn off run-time debug messages. This is the default.
  +e    Use the new event flag mode. This is the default.
  -e    Use the old event flag mode (clear flags after executing a
        when statement).
  +i    Generate registrar procedure that registers shell commands
        and programs with an IOC shell. This is the default.
  -i    Do not generate registrar procedure.
  +l    Add line markers to the generated code, so that C compiler
        messages refer to the SNL source file. This is the default.
  -l    Do not produce line markers.
  +m    Include main procedure (seqMain.c) for a stand-alone program.
  -m    Do not include seqMain.c. This is the default.
  +s    :ref:`Safe mode`: variables are local to state set
        and must be communicated explicitly. Implies +r.
  -s    Traditional (non-safe) mode. This is the default for
        compatibility.
  +r    Make the generated code reentrant, thus allowing more than one
        instance of the program to run on an IOC.
  -r    Generated code is not reentrant. This is the default.
  +w    Display SNC warning messages. This is the default.
  -w    Suppress SNC warnings.
======  ===============================================================

Note that :option:`+a` and :option:`-a` are ignored for calls to
:c:func:`pvGet` that explicitly specify ``SYNC`` or ``ASYNC`` in the
2nd argument.

Options may also be set from within the program (somewhere between the
program name/parameter and the state set definitions), see
:ref:`option definition` in the :doc:`Reference`.

Prior to Version 1.8 of the sequencer, event flags were cleared
after a ``when`` statement executed. Currently, event flags must be
cleared explicitly with either :c:func:`efTestAndClear` or
:c:func:`efClear`. The :option:`-e` compiler option can be used to
restore the old behaviour.

Output File
^^^^^^^^^^^

The output file name is that of the input file with the extension
replaced with *.c*. The :option:`-o` option can be used to override the
output file name.

Actually the rules are a little more complex than stated above: *.st*
and single-character extensions are replaced with *.c*; otherwise *.c*
is appended to the full file name. In all cases, the :option:`-o`
compiler option overrides.

Errors
^^^^^^

If *snc* detects an error, it displays a message describing the error
and the location in the source file and aborts further compilation.
Note, however, that *snc* does *not* contain a type checker: all it
knows (and cares) about C is the syntax. This means that many errors
will only be found only during the C compilation phase. The C compiler
will attributed these to the corresponding location in the SNL source
file, since by default *snc* generates line markers in the output that
point back to the original source. This can be turned off with the
:option:`-l` ("ell") compiler switch.

Warnings
^^^^^^^^

In certain cases *snc* cannot ultimately decide whether the code is
erroneous. In such cases it will issue a warning message and continue.

The most prominent example is the use of a variable or CPP macro that
has not been declared in the SNL code, but could well be defined when
compiling the generated C code (for example if the declaration has been
in embedded C code, which *snc* does not interpret at all). Warnings
can be suppressed with the :option:`-w` compiler option.

Note that since version 2.1 you can avoid these warnings by declaring
such variables in SNL, see the :ref:`foreign entities` declaration.

C Pre-processor
---------------

Depending on the application, it might be useful to pre-process the SNL
source with a C pre-processor (*cpp*). Using the C pre-processor allows
you to include other SNL files, define macros, and perform conditional
compilation. *snc* supports this by interpreting *cpp*-generated line
markers, so that error and warning messages refer to the line numbers
in the un-pre-processed SNL source.

Complete Build
--------------

The C code generated by *snc* from an SNL program is not a complete
program, but merely a collection of procedures, data types, and
variables. The generated procedures are supposed to be called by the
sequencer library, which must be linked to the program. Furthermore,
the generated code includes a number of header files, both from the
sequencer and from EPICS base. Thus the compiler needs to have the
EPICS base and sequencer include directories in its include path, and
when linking it needs to link with sequencer and some EPICS base
libraries.

Assume you have a SNL program file named *test.st* then the steps to
build are, in principle::

   snc test.st
   cc -c test.c -o test.o ...additional compiler options...
   cc test.o -o test ...additional linker options...

or, if SNL sources are to be pre-processed::

   cc -E -x c test.st > test.i
   snc test.i
   cc -c test.c -o test.o ...additional compiler options...
   cc test.o -o test ...additional linker options...

.. image:: Figure3-1.png

Assuming that ``EPICS_BASE`` contains the path to your EPICS base
installation, and ``SEQ`` to your sequencer installation, then the
extra include directories are:

*  $SEQ/include
*  $EPICS_BASE/include/os/<osclass>
*  $EPICS_BASE/include

where ``<osclass>`` corresponds to your operating system, see
Section 4.3.6 "Specifying osclass specific definitions" of the EPICS
Application Developer's Guide. Here is an excerpt:

|  For vxWorks-* targets <osclass> is vxWorks.
|  For RTEMS-* targets <osclass> is RTEMS.
|  For solaris-* targets <osclass> is solaris.
|  For win32-* targets <osclass> is WIN32.
|  For linux-* targets <osclass> is Linux.
|  For hpux-* targets <osclass> is hpux.
|  For darwin-* targets <osclass> is Darwin.
|  For aix-* targets <osclass> is AIX.

What libraries to link against and where to find them depends
on whether you want to create a stand-alone program (e.g. a Unix
executable), or create a library for an IOC.

.. todo:: explain what libraries to link and where to find them

.. _Building a Stand-alone Program:

Building a Stand-alone Program
------------------------------

The :option:`+m` compiler option can be used to create a stand-alone program,
otherwise an iocshell is needed to start sequencer programs. Since version 2.1
the main procedure is no longer hard-coded. Instead, the code generator adds a
define and an include statement ::

   #define PROG_NAME name_of_your_snl_program
   #include "seqMain.c"

at the end of the generated C file, where ``name_of_your_snl_program`` is the
name (identifier) whose address is to be passed to the ``seq`` function. This means you can provide your own version of main
simply by placing a file named ``seqMain.c`` in your source directory (the
EPICS build system usually takes care that the source directory is at the front
of the C compiler's include path).

A simple default ``seqMain.c`` is provided and installed into the sequencer's
``include`` directory. Note that since version 2.1 the default main starts an
ioc shell; this can be disabled by providing a ``-S`` (capital 's') argument.
The old ``-s`` switch is accepted for backward compatibility but does nothing.

Using makeBaseApp
-----------------

The easiest way to build a sequencer program is to use
``makeBaseApp.pl``, a perl script that comes with your EPICS base.
Assuming you have it in your ``PATH``, create an empty directory, go
there, and issue the command::

   ben@sarun[1]: .../tmp/test > makeBaseApp.pl -t example
   Name the application(s) to be created.
   Names given will have "App" appended to them.
   Application names? test
   ben@sarun[1]: .../tmp/test > ls -l
   total 12
   -rw-rw-r-- 1 ben ben  467 May 14 22:25 Makefile
   drwxrwxr-x 2 ben ben 4096 May 14 22:25 configure
   drwxrwxr-x 4 ben ben 4096 May 14 22:25 testApp

In ``testApp/src/`` you will find example ``.st`` and ``.stt`` files
and a ``Makefile`` that shows how to define the make variables so
that everything is compiled and linked correctly.

All that's left to do is add::

   SNCSEQ=/path/to/your/seq/installation

to ``configure/RELEASE`` (that is, the one in the ``configure``
directory that ``makeBaseApp.pl`` just created).
