NSH “Built-In” Applications
Overview. In addition to these commands that are a part of NSH, external programs can also be executed as NSH commands. These external programs are called “Built-In” Applications for historic reasons. That terminology is somewhat confusing because the actual NSH commands as described above are truly “built-into” NSH whereas these applications are really external to NuttX.
These applications are built-into NSH in the sense that they can be executed by simply typing the name of the application at the NSH prompt. Built-in application support is enabled with these configuration option:
CONFIG_BUILTIN
: Enable NuttX support for builtin applications.
CONFIG_NSH_BUILTIN_APPS
: Enable NSH support for builtin applications.
When these configuration options are set, you will also be able to see the built-in applications if you enter “nsh> help”. They will appear at the bottom of the list of NSH commands under:
Builtin Apps:
Note that no detailed help information beyond the name of the built-in application is provided.
Built-In Applications
Overview. The underlying logic that supports the NSH built-in
applications is called “Built-In Applications”. The builtin application
logic can be found at apps/builtin
. This logic simply does the
following:
It supports registration mechanism so that builtin applications can dynamically register themselves at build time, and
Utility functions to look up, list, and execute the builtin applications.
Built-In Application Utility Functions. The utility functions
exported by the builtin application logic are prototyped in
nuttx/include/nuttx/lib/builtin.h
and apps/include/builtin.h
.
These utility functions include:
int builtin_isavail(FAR const char *appname);
Checks for availability of application registered asappname
during build time.
const char *builtin_getname(int index);
Returns a pointer to a name of built-in application pointed by theindex
. This is the utility function that is used by NSH in order to list the available built-in applications when “nsh> help
” is entered.
int exec_builtin(FAR const char *appname, FAR const char **argv);
Executes built-in builtin application registered during compile time. This is the utility function used by NSH to execute the built-in application.
Autogenerated Header Files. Application entry points with their requirements are gathered together in two files when NuttX is first built:
apps/builtin/builtin_proto.h
: Prototypes of application task entry points.
apps/builtin/builtin_list.h
: Application specific information and start-up requirements
Registration of Built-In Applications. The NuttX build occurs in
several phases as different build targets are executed: (1) context
when the configuration is established, (2) depend when target
dependencies are generated, and (3) default (all
) when the normal
compilation and link operations are performed. Built-in application
information is collected during the make context build phase.
An example application that can be “built-in” is be found in the
apps/examples/hello directory
. Let’s walk through this specific
cause to illustrate the general way that built-in applications are
created and how they register themselves so that they can be used from
NSH.
apps/examples/hello
. The main routine for apps/examples/hello can be
found in apps/examples/hello/main.c
. The main routine is:
int hello_main(int argc, char *argv[])
{
printf("Hello, World!!\n");
return 0;
}
This is the built in function that will be registered during the
context build phase of the NuttX build. That registration is performed
by logic in apps/examples/hello/Makefile
. But the build system gets
to that logic through a rather tortuous path:
The top-level context make target is in
nuttx/Makefile
. All build targets depend upon the context build target. For theapps/
directory, this build target will execute the context target in theapps/Makefile
.The
apps/Makefile
will, in turn, execute the context targets in all of the configured sub-directories. In our case will include theMakefile
inapps/examples
.And finally, the
apps/examples/Makefile
will execute the context target in all configuredexample
sub-directories, getting us finally toapps/examples/Makefile
which is covered below.
NOTE: Since this context build phase can only be executed one time, any subsequent configuration changes that you make will, then, not be reflected in the build sequence. That is a common area of confusion. Before you can instantiate the new configuration, you have to first get rid of the old configuration. The most drastic way to this is:
make distclean
But then you will have to re-configuration NuttX from scratch. But if
you only want to re-build the configuration in the apps/
sub-directory, then there is a less labor-intensive way to do that. The
following NuttX make command will remove the configuration only from the
apps/
directory and will let you continue without re-configuring
everything:
make apps_distclean
Logic for the context
target in apps/examples/hello/Makefile
registers the hello_main()
application in the builtin
’s
builtin_proto.h
and builtin_list.h
files. That logic that does
that in apps/examples/hello/Makefile
is abstracted below:
First, the
Makefile
includesapps/Make.defs
:include $(APPDIR)/Make.defsThis defines a macro called
REGISTER
that adds data to the builtin header files:define REGISTER @echo "Register: $1" @echo "{ \"$1\", $2, $3, $4 }," >> "$(APPDIR)/builtin/builtin_list.h" @echo "EXTERN int $4(int argc, char *argv[]);" >> "$(APPDIR)/builtin/builtin_proto.h" endefWhen this macro runs, you will see the output in the build “
Register: hello
”, that is a sure sign that the registration was successful.The make file then defines the application name (
hello
), the task priority (default), and the stack size that will be allocated in the task runs (2K):APPNAME = hello PRIORITY = SCHED_PRIORITY_DEFAULT STACKSIZE = 2048And finally, the
Makefile
invokes theREGISTER
macro to added thehello_main()
builtin application. Then, when the system build completes, thehello
command can be executed from the NSH command line. When thehello
command is executed, it will start the task with entry pointhello_main()
with the default priority and with a stack size of 2K:context: $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main)
Other Uses of Built-In Application. The primary purpose of builtin applications is to support command line execution of applications from NSH. However, there is one other use of builtin applications that should be mentioned.
binfs. binfs is a tiny file system located at
apps/builtin/binfs.c
. This provides an alternative what of visualizing installed builtin applications. Without binfs, you can see the installed builtin applications using the NSH help command. binfs will create a tiny pseudo-file system mounted at/bin
. Using binfs, you can see the available builtin applications by listing the contents of/bin
directory. This gives some superficial Unix-like compatibility, but does not really add any new functionality.
Synchronous Built-In Applications
By default, built-in commands started from the NSH command line will run asynchronously with NSH. If you want to force NSH to execute commands then wait for the command to execute, you can enable that feature by adding the following to the NuttX configuration file:
CONFIG_SCHED_WAITPID=y
This configuration option enables support for the standard waitpid()
RTOS interface. When that interface is enabled, NSH will use it to wait,
sleeping until the built-in application executes to completion.
Of course, even with CONFIG_SCHED_WAITPID=y
defined, specific
applications can still be forced to run asynchronously by adding the
ampersand (&) after the NSH command.