APPNAME vs. PROGNAME

Q: Both APPNAME and PROGNAME are used to describe the entry point into an application. What is the difference?

A: Let's answer this question by dissecting one case: apps/examples/hello

apps/examples/hello/Kconfig

First, notice in the apps/examples/hello Kconfig file that the PROGNAME is only selected for the kernel build (CONFIG_BUILD_KERNEL). It is not defined or used in other build modes.

  config EXAMPLES_HELLO_PROGNAME
      string "Program name"
      default "hello"
      depends on BUILD_KERNEL
      ---help---
              This is the name of the program that will be use when the NSH ELF
              program is installed.

Kernel Build Mode

What is different about the kernel build mode? In the kernel build, the RTOS is built as a separately linked kernel that lives in its own kernel address space. There are no tasks in the sense used in the flat build. There are still kernel threads but tasks are now referred to as processes: A process is simply a task that lives in its own protected address space.

In the the kernel build, you cannot reference any task/process by an address in memory. Remember that each process lives in its own separate address spaces that is not accessible from any other process. So you cannot do task_create() or task_spawn() or any of those APIs that include the absolute address of an task entry point. That virtual entry point address has meaning only within the context of the process and is useless in the kernel build.

The APPNAME variable provides information for the task entry point address. None of this can be used in the kernel build.

Instead, for the kernel build, the process code must be loaded into memory and mapped into its own address space before it can be executed. The process code is referred to as a program and is typically saved in a file system. If you are familiar with Linux, then then you are familiar with processes and separately linked programs in files.

apps/examples/hello_main.c

Look in the task/process entry point in apps/examples/hello/hello_main.c:

  #ifdef CONFIG_BUILD_KERNEL
  int main(int argc, FAR char *argv[])
  #else
  int hello_main(int argc, char *argv[])
  #endif
  {
    printf("Hello, World!!\n");
    return 0;
  }

The APPNAME is hello_main(). But for the kernel build, the standard entry point name main() is used. Every program in the NuttX build has the entry point main() in the kernel build (You could not do that in the flat build because the symbol main() would be multiply defined. But since each program is separately built there is no issue in the kernel build).

When the NuttX program is linked, it is linked with special object called crt0.o. You can see the ARMv7-A crt0 file at nuttx/arch/arm/src/armv7-a/crt0.c.

apps/examples/hello/Makefile

Finally, there are a few interesting things in the hello Makefile at apps/examples/hello/Makefile:

First, it defines the MAINSRC variable to hold the file that includes the main() function:

  MAINSRC = hello_main.c

There is nothing special about MAINSRC in the flat or protected builds, but MAINSRC is special in the kernel build as we will see below.

It also defines the program name, PROGNAME. PROGNAME is simply a file name in some file system.

  CONFIG_EXAMPLES_HELLO_PROGNAME ?= hello$(EXEEXT)
  PROGNAME = $(CONFIG_EXAMPLES_HELLO_PROGNAME)

At this point, the original question has been answered: The difference be APPNAME and PROGNAME is that APPNAME is the name a task entry address in the a flat or protected build; PROGNAME is the name of a program file in the kernel build. But let's continue on anywayl

And, finally, it includes Appliction.mk that does the rest of the job:

  include $(APPDIR)/Application.mk

apps/Application.mk

The final link of each link of each program is performed by the install target in Application.mk:

  ifeq ($(CONFIG_BUILD_KERNEL),y)
  $(BIN_DIR)$(DELIM)$(PROGNAME): $(OBJS) $(MAINOBJ)
      @echo "LD: $(PROGNAME)"
      $(Q) $(LD) $(LDELFFLAGS) $(LDLIBPATH) -o $(INSTALL_DIR)$(DELIM)$(PROGNAME) $(ARCHCRT0OBJ) $(MAINOBJ) $(LDLIBS)
      $(Q) $(NM) -u $(INSTALL_DIR)$(DELIM)$(PROGNAME)
  install: $(BIN_DIR)$(DELIM)$(PROGNAME)
  else
  install:
  endif

Notice that the final linked programs are stored in INSTALL_DIR which will be apps/bin.

Preparing the File System

The overall build sequency for the kernel build is a little more involved than just typing make. You have to also do some steps in order to create the file system containing the separately linked programs. The following instructions come from nuttx/configs/sama5d4-ek/README.txt.

  6a. General build directions (boot from SD card):
  
      $ cd nuttx/tools                    : Go to the tools sub-directory
      $ ./configure.sh sama5d4-ek/kernel  : Establish this configuration
      $ cd ..                             : Back to the NuttX build directory
      $ export PATH=???                   : Set up the PATH variable
      $ make                              : Build the kerne with a dummy ROMFS image
                                          : This should create the nuttx ELF
      $ make export                       : Create the kernel export package
                                          : You should have a file like
                                          : nuttx-export-*.zip
      $ cd apps/                          : Go to the apps/ directory
      $ tools/mkimport.sh -x <zip-file>   : Use the full path to nuttx-export-*.zip
      $ make import                       : This will build the file system.
  
    You will then need to copy the files from apps/bin to an SD card to
    create the the bootable SD card.
  6b. General build directions (boot from ROMFS image):
  
      $ cd nuttx/tools                    : Go to the tools sub-directory
      $ ./configure.sh sama5d4-ek/kernel  : Establish this configuration
      $ cd ..                             : Back to the NuttX build directory
      $ export PATH=???                   : Set up the PATH variable
      $ touch configs/sama5d4-ek/include/boot_romfsimg.h
      $ make                              : Build the kernel with a dummy ROMFS image
                                          : This should create the nuttx ELF
      $ make export                       : Create the kernel export package
                                          : You should have a file like
                                          : nuttx-export-*.zip
      $ cd apps/                          : Go to the apps/ directory
      $ tools/mkimport.sh -x <zip-file>   : Use the full path to nuttx-export-*.zip
      $ make import                       : This will build the file system
      $ tools/mkromfsimg.sh               : Create the real ROMFS image
      $ mv boot_romfsimg.h ../nuttx/configs/sama5d4-ek/include/boot_romfsimg.h
      $ cd nuttx/                         : Rebuild the system with the correct
      $ make clean_context all            : ROMFS file system

NOTE the use of the these two special tools:

apps/tools/mkimport.sh

This does the complement of make export in the NuttX directory. make export bundles up all of the OS components for use with some external build. mkimport.sh takes this bundle, installs it in the apps/ directory and performs the build of the separately linked programs.

apps/tools/mkimport.sh

This will (optionally) put the separately linked programs into a ROMFS file system that can be included in system FLASH.