Skip to content

GitLab

  • Projects
  • Groups
  • Snippets
  • Help
    • Loading...
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in
xenomai
xenomai
  • Project overview
    • Project overview
    • Details
    • Activity
    • Releases
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 4
    • Issues 4
    • List
    • Boards
    • Labels
    • Service Desk
    • Milestones
  • CI / CD
    • CI / CD
    • Pipelines
    • Jobs
    • Schedules
  • Operations
    • Operations
    • Incidents
    • Environments
  • Analytics
    • Analytics
    • CI / CD
    • Repository
    • Value Stream
  • Wiki
    • Wiki
  • Members
    • Members
  • Collapse sidebar
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
  • xenomai
  • xenomaixenomai
  • Wiki
  • App_Setup_And_Init

App_Setup_And_Init · Changes

Page history
merge original static contents from xenomai.org authored Feb 21, 2018 by Philippe Gerum's avatar Philippe Gerum
Page slugs have been fixed up from Wordpress to Wiki specs -- a few
issues may remain though.
Hide whitespace changes
Inline Side-by-side
Showing with 797 additions and 0 deletions
+797 -0
  • App_Setup_And_Init.asciidoc App_Setup_And_Init.asciidoc +797 -0
  • No files found.
App_Setup_And_Init.asciidoc 0 → 100644
View page @ 0ef1a71a
Application setup and init
==========================
:author: Philippe Gerum
:email: rpm@xenomai.org
:categories: Application
:tags: init, main-routine, C++
NOTE: This guide is specific to Xenomai 3. Most of the features
described here have no counterparts in Xenomai 2.
The description applies to both Cobalt and Mercury configurations
indifferently, unless otherwise stated. The reader may assume that
_application_ always refers to any executable program linked against
the Xenomai libraries, whatever its purpose.
[CAUTION]
This discussion exclusively refers to user-space programs forming an
application, based on the Xenomai libraries. There is no reference
whatsoever to any kernel-based context.
== How to build an application
The most important rule of thumb is to *always* retrieve the
compilation and link flags from a call to +xeno-config --cflags+ and
+xeno-config --ldflags+ respectively, mentioning the list of Xenomai
APIs your application uses. The complete usage of the +xeno-config+
script can be found at
http://www.xenomai.org/documentation/xenomai-3/html/man1/xeno-config/index.html[this
URL].
.Invoking +xeno-config+ from a Makefile
----------------------------------------------------
CFLAGS := $(shell xeno-config --posix --cflags)
LDFLAGS := $(shell xeno-config --posix --ldflags)
----------------------------------------------------
WARNING: Failing to use +xeno-config+ for retrieving the proper build
flags for a Xenomai application will produce a bad executable, which
simply can't work.
[[standard-app-options]]
== Standard Xenomai command line options
Any application linked against the Xenomai libraries automatically
recognizes a set of standard options that can be passed on the command
line, which applies to any Xenomai-based program. There is nothing you
need to add to your application code for these option switches to be
interpreted and acted upon. For instance, the +--dump-config+ switch
is always recognized by an application, dumping the settings used for
building the Xenomai libraries it is linked against:
-----------------------------------------------
Xenomai/mercury v3.0-rc5 -- #e91216a (2015-05-12 17:58:01 +0200)
CONFIG_MMU=1
CONFIG_SMP=1
CONFIG_XENO_ASYNC_CANCEL=1
CONFIG_XENO_BUILD_ARGS=" '-prefix=/home/rpm/install/xenomai/mercury' '--enable-async-cancel' '--enable-lores-clock' '--enable-debug=full' '--enable-smp' '--enable-tls' '--with-core=mercury' '--enable-registry' '--enable-pshared' '--enable-maintainer-mode'"
CONFIG_XENO_BUILD_STRING="x86_64-unknown-linux-gnu"
CONFIG_XENO_COMPILER="gcc version 4.9.2 20150212 (Red Hat 4.9.2-6) (GCC) "
CONFIG_XENO_DEBUG=1
CONFIG_XENO_DEBUG_FULL=1
CONFIG_XENO_DEFAULT_PERIOD=100000
CONFIG_XENO_FORTIFY=1
...
CONFIG_XENO_LIBS_DLOPEN is OFF
CONFIG_XENO_LORES_CLOCK_DISABLED is OFF
CONFIG_XENO_RAW_CLOCK_ENABLED is OFF
CONFIG_XENO_TLSF is OFF
CONFIG_XENO_WORKAROUND_CONDVAR_PI is OFF
-----------------------------------------------
The list of standard options is as follows:
[horizontal]
*--registry-root=<path>*::
Tells Xenomai to root the object registry at the given path,
instead of the default root (see the +--enable-registry+
switch from the configuration options).
*--session=<label>*::
Name of the session the new process will be part of (or create
if not present). If +--enable-pshared+ was given when
configuring the Xenomai libraries, this label allows multiple
processes giving the same label at startup to share objects
created by members of the same session.
All shared objects are allocated from a global heap backed by
the main memory pool (see --mem-pool-size).
*--shared-registry*::
Exports the registry of the process to other users. If access
is possible, also depends on permissions of the registry path.
By default, the registry is only accessible for the user that
started the Xenomai process.
*--no-registry*::
This switch disables registry support at runtime. No real-time
objects will be exported to the registry, despite the registry
code was compiled in.
*--mem-pool-size=<size[K|M|G]>*::
The size the main memory pool backing the session's heap,
which can be suffixed by a K(ilobyte), M(egabyte) or
G(igabyte) binary multiplier. Most of the dynamic allocation
requests issued from the Xenomai libraries are served from
this pool. In absence of suffix, the value is normally
interpreted as a count of bytes, except if lower than 65536,
see below.
[NOTE]
If the value is lower than 65536 with no suffix, it is
interpreted as a count of kilobytes for backward compatibility
purpose with the former syntax. This work around may disappear
anytime when transitioning to Xenomai 3.0 final, so make sure
to fix any launch script(s) accordingly. Typically, suffixing
the current value with a 'K' multiplier would address the issue.
[CAUTION]
The shared heap is living in the /tmpfs filesystem,
and therefore consumes RAM space.
*--cpu-affinity=<cpu[,cpu]...>*::
The set of CPUs available for running Xenomai threads created
by the application, in absence of explicit pinning of such
threads to a particular CPU when they are spawned. Defaults to
any online CPU. +
The argument is a list of valid (i.e. online) CPU numbers
separated by commas. This option may appear several times on
the command line, cumulating the settings.
*--main-prio=<priority>*::
*Cobalt only*. When +xenomai_init()+ is called for
bootstrapping the real-time services for the current process,
the calling context is automatically turned into a Xenomai
thread, managed by the Cobalt kernel. Normally, this call runs
over the +main()+ routine, hence the parameter name. By
default, the current scheduling policy and priority are kept
during the transition. + This parameter allows to force new
scheduling parameters for the thread invoking +xenomai_init()+
when it enters the Xenomai realm, according to the following
rules: +
- if <priority> is zero, the calling thread will be assigned
the SCHED_OTHER policy. +
- if <priority> is greater than zero, the calling thread will
be assigned the SCHED_FIFO policy, and the given priority
level. +
- if <priority> is negative, the scheduling parameters of the
calling context will be kept unchanged (default case).
*--print-buffer-size=<num-bytes>*::
*Cobalt only*. When symbol wrapping is in effect (default case
for applications based on Cobalt's POSIX API), Xenomai
interposes on common output calls from the +stdio+ support
such as +printf(3)+ fprintf(3) and puts(3), so that no delay
or loss of real-time guarantee is incurred by the caller. +
The underlying mechanism is based on relay buffers forming an
output ring, filled in by real-time threads locklessly, which
are periodically flushed by a regular (non real-time) Linux
helper thread to the process's destination stream (stdout,
stderr or any other particular stream). + This parameter
allows to set the size of a typical relay buffer. By default,
a relay buffer is 16k large.
*--print-buffer-count=<num-buffers>*::
*Cobalt only*. Use this parameter to set the total number of
relay buffers (see --print-buffer-size). By default, 4 relay
buffers are present in the output ring.
*--print-sync-delay=<ms>*::
Use this parameter to set the longest delay (in milliseconds)
before the output pending into the relay buffers is
synchronized (see --print-buffer-size). By default, the output
ring is flushed each 100 milliseconds by the helper thread.
*--[no-]sanity*::
Turn on[/off] sanity checks performed by the Xenomai
libraries, mostly during the application startup. Defaults to
the value set by the --enable-sanity switch when configuring
(which is enabled by default). +
For instance, running Xenomai libraries built for a
uni-processor system over a SMP kernel is detected by such
checks.
*--verbose[=level]*::
Set verbosity to the desired level, or 1 if unspecified. The
level argument may be interpreted differently depending on the
application, however --verbose=0 must mean fully quiet. The
interpretation of higher levels is
application-specific. Defaults to 1.
*--silent*::
*--quiet*::
Same as --verbose=0.
*--trace[=level]*::
Set tracing to the desired level, or 1 if unspecified. The
level argument may be interpreted differently depending on the
application, however --trace=0 must disable tracing. Level 1
allows tracing the Xenomai library bootstrap code. The
interpretation of higher levels is
application-specific. Defaults to 0.
*--version*::
Get the application and Xenomai version stamps. The program
immediately exits with a success code afterwards.
*--dump-config*::
Dump the settings used for building the Xenomai libraries the
application is linked against.
*--no-mlock*::
*Mercury only*. This switch disables the implicit +mlock()+
call at init, normally used for locking the calling process's
virtual address space into RAM, in order to avoid the extra
latency induced by virtual memory paging.
This option does not apply to the Cobalt core, which requires
memory locking from all clients unconditionally.
*--help*::
Display the help strings.
== Configuration and runtime tunables
Tunables are variables used as configuration values while setting up
the system (e.g. size of the main memory heap), or controlling its
runtime behavior (e.g. verbosity level).
Some of those tunables may be updated by the application's early code
until the system starts initializing the core data structures and
bringing up the services, then become read-only from that point. These
are called the configuration tunables.
Other tunables may be changed freely at any point in time during the
application process lifetime. These are called the runtime tunables.
=== Accessing the tunables
There is a simple API for reading and updating the current value of
any tunable, composed of the +{get/set}_config_tunable(name)+ and
+{get/set}_runtime_tunable(name)+ C macros.
When +--enable-assert+ is in effect for the Xenomai libraries,
+set_config_tunable()+ enforces read-only access after the
configuration tuning phase, by raising an exception on attempt to
change such tunable after that point.
Each tunable has an arbitrary name, which does not necessarily
reflects the name of the variable actually storing its value. For
instance, one could define tunable +foo+ eventually handling the +int
bar+ C variable under the hood, or even a set of related variables.
Typically, updating and reading back the +verbose_level+ tunable - which
holds the current verbosity level of an application - would look like
this:
-----------------------------------------------------------
#include <stdio.h>
#include <xenomai/tunables.h>
set_runtime_tunable(verbosity_level, 1);
printf("verbosity_level=%d\n", get_runtime_tunable(verbosity_level));
-----------------------------------------------------------
NOTE: When a configuration tunable is paired with a command line
option updating the same variable(s), the command line has precedence
over the +set_config_tunable()+ call.
=== Xenomai's built-in tunables
The Xenomai libraries define two sets of built-in tunables.
.Configuration tunables
[options="header",grid="cols",frame="topbot",cols="m,2*d"]
|================================================================================
^|NAME ^|DESCRIPTION ^|DEFAULT
|cpu_affinity | same as --cpu-affinity option | any online CPU
|no_mlock | same as --no-mlock option | off
|no_sanity | same as --no-sanity option | !CONFIG_XENO_SANITY
|no_registry | same as --no-registry option | off (i.e. enabled)
|mem_pool_size | same as --mem-pool-size option | 1Mb
|session_label | same as --session option | none (i.e. anonymous)
|registry_root | same as --registry-root option | CONFIG_XENO_REGISTRY_ROOT
|shared_registry | same as --shared-registry option | off (i.e. private)
|===============================================================================
.Runtime tunables
[options="header",grid="cols",frame="topbot",cols="m,2*d"]
|============================================================================
^|NAME ^|DESCRIPTION ^|DEFAULT
|verbosity_level | same as --verbose option | 1
|trace_level | same as --trace option | 0
|============================================================================
=== Defining your own tunables
You can add your own tunables using the
+define_{config/runtime}_tunable(name)+ and
read_{config/runtime}_tunable(name) C macros.
The +define_tunable+ syntax provides the helper code for updating the
C value(s) matching the tunable +name+. Conversely, the +read_tunable+
syntax provides the helper code for returning the C value(s) matching
the tunable +name+.
The application code should use +{get/set}_config_tunable(name)+ or
+{get/set}_runtime_tunable(name)+ for accessing the new tunable,
depending on its scope.
.Defining and using a simple tunable
------------------------------------------------------
/* Out of line definition. */
code.c:
int foo_runtime_variable;
define_runtime_tunable(foo, int, val)
{
/*
* The code to update the internal variable upon a call to
* set_runtime_tunable(foo).
*/
foo_runtime_variable = val;
}
read_runtime_tunable(foo, int)
{
/*
* The code to return the current tunable value upon a
* call to get_runtime_tunable(foo).
*/
return foo_runtime_variable;
}
header.h:
/* Declaration of the manipulation helpers */
define_runtime_tunable(foo, int, val);
read_runtime_tunable(foo, int);
/* Conversely, we could be using an inline definition */
header.h:
extern int foo_runtime_variable;
static inline define_runtime_tunable(foo, int, val)
{
foo_runtime_variable = val;
}
static inline read_runtime_tunable(foo, int)
{
return foo_runtime_variable;
}
/* Accessing the new tunable, inverting the value. */
int setting = get_runtime_tunable(foo);
set_runtime_tunable(foo, !setting);
-----------------------------------------------------
[[changing-default-tunable-value]]
=== Overriding factory default values of tunables
It may be convenient to provide your own factory default values for
some configuration tunables, before they are considered for
initializing the application.
For this early tuning to happen, you need to interpose your own
handler in the chain of tuning handlers the Xenomai bootstrap code
runs before starting the actual initialization process. This can be
done with a Xenomai setup descriptor as follows:
------------------------------------------------------
#include <xenomai/init.h>
#include <xenomai/tunables.h>
static int foo_tune(void)
{
/*
* We need more than 1MB which is Xenomai's default, make
* it 16MB before the Xenomai core starts initializing
* the whole thing. --mem-pool-size=<size> may override
* this value.
*/
set_config_tunable(mem_pool_size, 16MB);
/*
* Also turn verbosity off by default. --verbose=<level> on the
* command line may switch this to verbose mode.
*/
set_runtime_tunable(verbosity_level, 0);
return 0; /* Success, otherwise -errno */
}
/*
* CAUTION: we assume that all omitted handlers are zeroed
* due to the static storage class. Make sure to initialize them
* explicitly to NULL if the descriptor belongs to the .data
* section instead.
*/
static struct setup_descriptor foo_setup = {
.name = "foo",
.tune = foo_tune,
};
/* Register the setup descriptor. */
user_setup_call(foo_setup);
------------------------------------------------------
== Application entry (C/C++)
From the user code standpoint, every application starts in the
+main()+ routine as usual.
Some link flags used for building the application have an influence on
its initialization sequence; such flags are retrieved by a call to
+xeno-config --ldflags+, passing along the list of Xenomai APIs the
application depends on (e.g. +xeno-config --posix --alchemy --ldflags+).
The Xenomai libraries can take care of such sequence for bootstrapping
their services appropriately (i.e. _automatic bootstrap_), or leave
such duty to the application code (i.e. _manual bootstrap_).
=== Automatic bootstrap
If the automatic bootstrap mode is used, the application receives the
set of command line switches passed on invocation in the +main()+
routine, expunged from the Xenomai standard options. In this mode, all
Xenomai services are readily available when +main()+ is entered.
This is the default behavior most applications should use.
[[manual-bootstrap]]
=== Manual bootstrap
In manual bootstrap mode, the application receives the original
argument vector unaltered, with the Xenomai services not
initialized. You should use this mode if you need some early
initializations of your own to take place before the Xenomai services
are started.
The manual bootstrap mode is enabled by linking with the flags
received from +xeno-config --ldflags --no-auto-init+.
In such mode, the application code must call +xenomai_init(&argc,
&argv)+ at some point in the initialization step, to bootstrap the
Xenomai services for the process. This routine handles all standard
Xenomai options, then updates the arguments to point to a copy of the
original vector, expunged from the Xenomai options.
Afterwards, the application code can collect and handle the
unprocessed options from the command line, and use the Xenomai
services with no restriction.
=== Dealing with C++ static constructors
The initialization sequence guarantees that C++ constructors - with
default priorities - of objects instantiated *within the main
executable* will run *after* the Xenomai services have been
bootstrapped in automatic mode. This means that class constructors for
static objects from the main executable may call Xenomai services.
Since Xenomai services are not available until +xenomai_init()+ has
been called in <<manual-bootstrap,manual bootstrap mode>>, no such
guarantee exists in this case, until that routine is invoked and
returns successfully.
As described for the <<app-init-layers,initialization process>>
through the various software layers, C++ constructors of static
objects instantiated by shared libraries will *NOT* have access to
Xenomai services, since the Xenomai bootstrap code runs later.
[TIP]
If you have non-default static constructor priorities, or static
objects instantiated in shared libraries your executable depends on,
you may need to provide your own early bootstrap code, in case the
constructors need to call Xenomai services. This code should
eventually call +xenomai_init()+ for bootstrapping the Xenomai
services, before these C++ constructors may invoke them.
=== Handling application-defined arguments
You may want to provide for your own command line switches to be
interpreted by the application code.
If the automatic bootstrap mode is used, the application directly
receives the set of command line switches passed on invocation in the
+main()+ routine, expunged from the Xenomai standard options.
With a <<manual-bootstrap,manual bootstrap>>, the application receives
the original argument vector passed on the command line. Calling
+xenomai_init(&argc, &argv)+ processes then removes all standard
Xenomai options from the vector before returning to the caller.
In both cases, the application-specific options present in the
argument vector can be retrieved with the +getopt(3)+ parser as usual.
.Parsing application-specific arguments
----------------------------------------
#include <getopt.h>
#include <stdio.h>
#include <xenomai/init.h>
int foo_mode = 1; /* Default */
static const struct option options[] = {
{
#define foo_mode1_option 0
.name = "foo1",
.flag = &foo,
.val = 1,
},
{
#define foo_mode2_option 1
.name = "foo2",
.flag = &foo,
.val = 2,
},
{
/* sentinel */
}
};
int main(int argc, char *const *argv)
{
int lindex, ret, opt;
#ifdef MANUAL_BOOTSTRAP
/* xeno-config --no-auto-init --ldflags was given. */
ret = xenomai_init(&argc, &argc);
#endif
for (;;) {
lindex = -1;
opt = getopt_long_only(argc, argv, "", options, &lindex);
if (opt == EOF)
break;
switch (lindex) {
case foo_mode1_option:
case foo_mode2_option:
break;
default:
usage();
return 1;
}
}
...
}
----------------------------------------
== Under the hood
=== Initialization sequence
The Xenomai-specific application initialization process bootstraps the
software layers as follows:
[[app-init-layers]]
image:figures/app-init-layers.png[Layered initialization sequence]
[TIP]
+lib/boilerplate/init/bootstrap.c+ implements the bootstrap
handler which is glued as an object file to the main executable of the
application, so that it is guaranteed to run after any shared library
constructor the application depends on, regardless of the library
constructor priorities.
In automatic bootstrap mode, The +xenomai_main()+ routine interposes
on the real +main()+ entry point, for passing it the pre-processed
argument vector, expunged from the Xenomai standard options. This
trick is based on the linker's symbol wrapping feature
(--wrap). http://www.xenomai.org/documentation/xenomai-3/html/man1/xeno-config/index.html[
xeno-config] issues the right set of linker flags to enable
such interposition, unless +--no-auto-init+ is given.
=== Adding your own setup code
Xenomai implements a flexible mechanism for running setup code in an
orderly manner, on behalf of the bootstrap handler glued to the
application.
This mechanism is based on _setup descriptors_ (+struct
setup_descriptor+), each defining a set of optional handlers, which
shall be invoked by the Xenomai bootstrap code at different stages of
the initialization process. A priority level is assigned to each
descriptor, which defines the calling sequence among multiple
descriptors implementing the same handler. The corresponding C
definitions and types should be obtained by including
+<xenomai/init.h>+.
There are three initialization stages, listed by order of precedence,
each assigned a handler in the setup descriptor. NULL handlers can be
used to skip a descriptor for a given phase.
- Factory tuning step, via setup_descriptor->tune(). Each setup
descriptor is given a chance to assign a value to standard or
application-defined tunables. This is the handler we used for
<<changing-default-tunable-value,changing a default tunable value>>.
- Command line option parsing, via setup_descriptor->parse_option().
If this handler is present, setup_descriptor->options must point to a
getopt(3) option array, enumerating the valid options defined by this
descriptor.
The ->parse_option() handler is passed the position of each option
found into the command line which matches an entry into the
setup_descriptor->options array, along with the argument value
received. If the option does not carry any argument, NULL is passed
instead.
The ->help() handler is called whenever the --help switch is passed on
the command line. All help handlers from the descriptor chain will be
called in turn, from low priority to high.
Option parsing happens after the tuning step, so that command line
options affecting tunables can override the factory values defined by
the ->tune() handlers.
- Initialization step proper, via setup_descriptor->init(). Based on
the current settings obtained from the previous steps, this handler is
called for bringing up the feature or service it provides.
All handlers should return zero on success, or a negated POSIX error
code on error. Upon error, the bootstrap sequence is immediately
terminated, and the application exits with a fatal message.
The example below introduces a custom code into the initialization
sequence, for setting some base tunables then parsing a set of local
command line options, before bringing up a specific feature. These
custom handlers will be called after all Xenomai handlers from the
same category have been fired. Such code could be part of an ancillary
library attached to your application for instance, or implemented by
your main executable.
.Adding a custom setup code
-------------------------------------------------------------------
#include <getopt.h>
#include <stdio.h>
#include <xenomai/init.h>
#include <xenomai/tunables.h>
int half_value;
static int foo_value = 16; /* Default */
static const struct option foo_options[] = {
{
#define foo_option 0
.name = "foo-value",
.has_arg = 1,
},
{
/* sentinel */
}
};
static int foo_tune(void)
{
/*
* We want a 8MB heap by default. User may override
* this with --mem-pool-size if need be.
*/
set_config_tunable(mem_pool_size, 8MB);
return 0;
}
static int foo_parse_option(int optnum, const char *optarg)
{
/*
* Xenomai's command line parser will call us only for
* valid options we know about, we just need to evaluate
* the argument.
*/
switch (optnum) {
case foo_option:
foo_value = atoi(optarg);
break;
default:
/* Paranoid, can't happen. */
return -EINVAL;
}
return 0;
}
static void foo_help(void)
{
fprintf(stderr, "--foo-value=<val> some value for no usage\n");
}
static int foo_init(void)
{
if (foo_value & 1)
/* Uh, cannot deal with odd values. */
return -EINVAL;
half_value = foo_value / 2; /* Let's init stuff. */
return 0;
}
static struct setup_descriptor foo_setup = {
.name = "foo",
.tune = foo_tune,
.parse_options = foo_parse_option,
.options = foo_options,
.help = foo_help,
.init = foo_init,
};
/* Register the setup descriptor. */
user_setup_call(foo_setup);
-------------------------------------------------------------------
=== Extending the help strings
When --help is given on the command line, the Xenomai option handler
intercepts it and issues information from outer to inner code,
following the decreasing priorities of the registered setup
descriptor. i.e. from the most application-specific code to the most
generic libraries providing help strings. Typically, this should make
your application-defined help strings appear first.
-------------------------------------------------------------------
#include <xenomai/init.h>
#include <stdio.h>
/*
* This is a routine with a weak binding we may override for
* providing our own help message header. get_program_name()
* is a Xenomai helper readily available when including
* <xenomai/init.h>.
*/
void application_usage(void)
{
fprintf(stderr, "usage: %s [options]:\n", get_program_name());
}
-------------------------------------------------------------------
[TIP]
If you need to call the help string dumper manually (e.g. should a
different option than +--help+ trigger this), you can invoke +void
xenomai_usage(void)+.
=== Extending the version information
By default, the Xenomai core library issues its own version
information when +--version+ is found on the command line. The
application can insert its own signature in the output message to
+stderr+ by implementing the +void application_version(void)+ hook.
-----------------------------------------------------
#include <xenomai/init.h>
#include <stdio.h>
/*
* This is a routine with a weak binding we may override for
* providing our own version header. The version message
* would then be:
*
* $ ./foo --version
* foo utility v1.2
* based on Xenomai/mercury v3.0-rc4 -- #eaca2e7 (2015-05-13 12:17:21 +0200)
*/
void application_version(void)
{
fprintf(stderr, "foo utility v1.2\n");
}
-----------------------------------------------------
[TIP]
The current Xenomai version string is available from the +const char
*xenomai_version_string+ constant, exported by <xenomai/init.h>.
Clone repository
  • Analogy_General_Presentation
  • Analogy_Practical_Presentation
  • App_Setup_And_Init
  • Archive
  • Benchmarking_With_Xeno_Test
  • Building_Applications_For_Xenomai_3
  • Building_Debian_Packages
  • CXP_RTDM
  • Common_Xenomai_Platform
  • Configuring_For_X86_Based_Dual_Kernels
  • Dealing_With_X86_IRQ_Sharing
  • Dealing_With_X86_SMI_Troubles
  • Dovetail
  • Driver_Serial_16550A
  • FAQ
View All Pages