nuttx/Documentation/applications/nsh/builtin.rst
2023-10-30 20:29:42 +08:00

204 lines
8.4 KiB
ReStructuredText

===========================
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 as ``appname`` during build
time.
- ``const char *builtin_getname(int index);`` Returns a pointer to a
name of built-in application pointed by the ``index``. 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:
.. code-block:: 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 the ``apps/``
directory, this build target will execute the *context* target in the
``apps/Makefile``.
#. The ``apps/Makefile`` will, in turn, execute the *context* targets in
all of the configured sub-directories. In our case will include the
``Makefile`` in ``apps/examples``.
#. And finally, the ``apps/examples/Makefile`` will execute the
*context* target in all configured ``example``\ sub-directories,
getting us finally to ``apps/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`` includes ``apps/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 the ``REGISTER`` macro to added
the ``hello_main()`` builtin application. Then, when the system build
completes, the ``hello`` command can be executed from the NSH command
line. When the ``hello`` command is executed, it will start the task
with entry point ``hello_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.