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:
c
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.defs
This 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" endef
When 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 = 2048
And 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.