wiki:OpenWrt/SDK

Version 4 (modified by Cale Collins, 7 years ago) ( diff )

updated building using staging dir

Building applications for an OpenWrt Target

There are several ways you can use an OpenWrt Software Development Kit (SDK) or Toolchain to compile your own applications outside of the OpenWrt buildroot :

The point of using the OpenWrt toolchain or SDK is that it can be pre-built and installed on a host that does not have the OpenWrt buildroot.

Note: Custom programming can be achieved through shell scripts on the Gateworks boards (most examples on the Gateworks wiki are shell commands). C code can be used when desired.

OpenWrt Prebuilt Toolchain

If you are using pre-built firmware from http://dev.gateworks.com/openwrt then you can use the pre-built toolchain there to build your own code.

The steps involved:

  1. Download prebuilt toolchain/SDK, the toolchain contains the compiler and standard libraries only.
  2. Uncompress it.
  3. Add it to your path (optional)
  4. Use the toolchain cross compiler to cross compile your code.

Examples:

  • Example, if you wanted to build a hello-world for OpenWrt 14.08 for the laguna (cns3xxx) platform:
    $ wget http://dev.gateworks.com/openwrt/14.08/cns3xxx/OpenWrt-Toolchain-cns3xxx-for-arm_v6k-gcc-4.6-linaro_uClibc-0.9.33.2_eabi.tar.bz2
    $ tar xvf OpenWrt-Toolchain-cns3xxx-for-arm_v6k-gcc-4.6-linaro_uClibc-0.9.33.2_eabi.tar.bz2
    $ PATH=$PWD/OpenWrt-Toolchain-cns3xxx-for-arm_v6k-gcc-linaro_uClibc-0.9.32_eabi/toolchain-arm_v6k_gcc-linaro_uClibc-0.9.32_eabi/bin:$PATH
    $ cat << EOF > hello-world.c
    #include <stdio.h>
    
    int main (int argc, char** argv)
    {
    printf("Hello World\n");
    return 0;
    }
    EOF
    $ arm-openwrt-linux-uclibcgnueabi-gcc hello-world.c -o hello-world
    $ file hello-world
    hello-world: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
    
  • Example OpenWrt 16.02 for the Ventana (imx6) platform:
    # download toolchain
    wget http://dev.gateworks.com/openwrt/16.02/imx6/Gateworks-Toolchain-imx6_gcc-5.2.0_musl-1.1.12_eabi.Linux-x86_64.tar.bz2 
    # extract toolchain
    tar xvf Gateworks-Toolchain-imx6_gcc-5.2.0_musl-1.1.12_eabi.Linux-x86_64.tar.bz2 
    # add toolchain to path
    PATH=$PWD/Gateworks-Toolchain-imx6_gcc-5.2.0_musl-1.1.12_eabi.Linux-x86_64/toolchain-arm_cortex-a9+neon_gcc-5.2.0_musl-1.1.12_eabi/bin:$PATH 
    # create a simple program
    cat << EOF > hello-world.c
    #include <stdio.h>
    
    int main (int argc, char** argv)
    {
    printf("Hello World\n");
    return 0;
    }
    EOF
    # compile your program
    arm-openwrt-linux-gcc hello-world.c -o hello-world
    

Note: The prebuilt toolchain may have some issue if the script arm-openwrt-linux-uclibcgnueabi-wrapper.sh is used (with regard to paths having whitespace).

Ventana Notes

If desired, download the Ventana OpenWrt Toolchain/SDK and skip to step 4:

  1. Turn on Toolchain in make menuconfig -> Build the OpenWrt based Toolchain
  2. Compile using make -j8 v=99 in trunk directory
  3. Find compiled toolchain in trunk/bin/imx6/OpenWrt-Toolchain-imx6-for-arm_cortex-a9+neon-gcc-4.6-linaro_uClibc-0.9.33.2_eabi.tar.bz2
  4. Download the toolchain to a different directory on your PC where you will want to do some compiling, such as ~/compiling
  5. Extract the toolchain
    ryan@Ryan:~/Documents/toolchain$ tar xvf OpenWrt-Toolchain-imx6-for-arm_cortex-a9+neon-gcc-4.6-linaro_uClibc-0.9.33.2_eabi.tar.bz2 
    OpenWrt-Toolchain-imx6-for-arm_cortex-a9+neon-gcc-4.6-linaro_uClibc-0.9.33.2_eabi/
    OpenWrt-Toolchain-imx6-for-arm_cortex-a9+neon-gcc-4.6-linaro_uClibc-0.9.33.2_eabi/LICENSE
    OpenWrt-Toolchain-imx6-for-arm_cortex-a9+neon-gcc-4.6-linaro_uClibc-0.9.33.2_eabi/toolchain-arm_cortex-a9+neon_gcc-4.6-linaro_uClibc-0.9.33.2_eabi/
    OpenWrt-Toolchain-imx6-for-arm_cortex-a9+neon-gcc-4.6-linaro_uClibc-0.9.33.2_eabi/toolchain-arm_cortex-a9+neon_gcc-4.6-linaro_uClibc-0.9.33.2_eabi/lib64
    OpenWrt-Toolchain-imx6-for-arm_cortex-a9+neon-gcc-4.6-linaro_uClibc-0.9.33.2_eabi/toolchain-arm_cortex-a9+neon_gcc-4.6-linaro_uClibc-0.9.33.2_eabi/share/
    ......
    .....
    
  6. Set PATH
    ryan@Ryan:~/Documents/toolchain$ PATH=$PWD/OpenWrt-Toolchain-imx6-for-arm_cortex-a9+neon-gcc-4.6-linaro_uClibc-0.9.33.2_eabi/toolchain-arm_cortex-a9+neon_gcc-4.6-linaro_uClibc-0.9.33.2_eabi/bin:$PATH
    
  7. Create hello-world.c file as shown above,
  8. Compile hello-world.c. Note, when compiling, Gateworks uses hard float, so you may have to specify -mfloat-abi=hard as shown below
    ryan@Ryan:~/Documents/toolchain$ arm-openwrt-linux-uclibcgnueabi-gcc -mfloat-abi=hard hello-world.c -o hello-world
    arm-openwrt-linux-uclibcgnueabi-gcc.bin: warning: environment variable 'STAGING_DIR' not defined
    arm-openwrt-linux-uclibcgnueabi-gcc.bin: warning: environment variable 'STAGING_DIR' not defined
    arm-openwrt-linux-uclibcgnueabi-gcc.bin: warning: environment variable 'STAGING_DIR' not defined
    /home/ryan/Documents/toolchain/OpenWrt-Toolchain-imx6-for-arm_cortex-a9+neon-gcc-4.6-linaro_uClibc-0.9.33.2_eabi/toolchain-arm_cortex-a9+neon_gcc-4.6-linaro_uClibc-0.9.33.2_eabi/bin/../lib/gcc/arm-openwrt-linux-uclibcgnueabi/4.6.4/../../../../arm-openwrt-linux-uclibcgnueabi/bin/ld: warning: .init_array section has zero size
    ryan@Ryan:~/Documents/toolchain$
    
  9. Verify hello-world has been compiled in current directory
    ryan@Ryan:~/Documents/toolchain$ file hello-world
    hello-world: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
    

OpenWrt Prebuilt SDK

If you are using pre-built firmware from http://dev.gateworks.com/openwrt then you can use the pre-built SDK there to build OpenWrt packages. The SDK contains a cross toolchain, libraries, and the Makefile structure to be able to build OpenWrt packages without having an entire buildroot tree. Note that you must also have the OpenWrt Toolchain (see below) in your path. For example to build the OpenWrt nuttcp package for laguna (cns3xxx):

$ wget http://dev.gateworks.com/openwrt/latest/cns3xxx/OpenWrt-SDK-cns3xxx-for-linux-x86_64-gcc-4.6-linaro_uClibc-0.9.33.2.tar.bz2
$ tar xvf OpenWrt-SDK-cns3xxx-for-Linux-i686-gcc-linaro_uClibc-0.9.32.tar.bz2
$ PATH=$PWD/OpenWrt-SDK-imx61-for-linux-x86_64-gcc-4.6-linaro_uClibc-0.9.33.2/staging_dir/toolchain-arm_v7-a_gcc-4.6-linaro_uClibc-0.9.33.2_eabi/bin:$PATH
$ cd OpenWrt-SDK-imx61-for-linux-x86_64-gcc-4.6-linaro_uClibc-0.9.33.2
$ svn export svn://svn.openwrt.org/openwrt/packages/net/nuttcp package/nuttcp
$ make package/nuttcp/compile
$ ls bin/cns3xxx/packages/
nuttcp_6.1.2-2_cns3xxx.ipk  nuttcp-xinetd_6.1.2-2_cns3xxx.ipk

GDB - GNU Debugger

GDB can be used on Gateworks SBC's.

Gateworks has tested GDB in the following way on OpenWrt:

  1. Compile GDB as a package using the make menuconfig option. Be sure it is GDB and not GDB server (example shows GDB server): OpenWrt/Configuration
  2. Install the ipk file on the target board: ipkupload
  3. Compile your program using the toolchain described above but with GDB support. Example is hello-world.
    arm-openwrt-linux-uclibcgnueabi-gcc -g -mfloat-abi=hard hello-world.c -o hello-world
    
  4. Copy program to target board and be sure it is executable (chmod)
  5. Start gdb on target board (Ventana)
  6. Run the gdb command from the Ventana command prompt:
    (gdb) file hello-world 
    Load new symbol table from "/hello-world"? (y or n) y
    Reading symbols from /hello-world...done.
    
  7. Then type the run command:
    (gdb) run  
    Starting program: /hello-world 
    warning: Unable to find dynamic linker breakpoint function.
    GDB will be unable to debug shared library initializers
    and track explicitly loaded dynamic code.
    warning: no loadable sections found in added symbol-file /lib/libgcc_s.so.1
    warning: no loadable sections found in added symbol-file /lib/libc.so.0
    Hello World
    [Inferior 1 (process 17906) exited normally]
    
  8. For more GDB reference please see this page: GDB Documentation and other examples on Google search.

Remote Debugging

A brief example:

  1. From the target start the server using the command to use over TCP on port 2345 the application hello-world
    root@OpenWrt:/# gdbserver host:2345 hello-world 
    

Example Continues to step 2 below, shown below is the rest of the output:

root@OpenWrt:/# gdbserver host:2345 hello-world 
Process hello-world created; pid = 21696
Listening on port 2345
Remote debugging from host 192.168.1.22
Hello World

Child exited with status 0
GDBserver exiting
root@OpenWrt:/# 
  1. From the host start the GDB from the SDK (Ventana example shown)
    ryan@Ryan:~/sdk_ventana/OpenWrt-SDK-imx6-for-linux-x86_64-gcc-4.8-linaro_uClibc-0.9.33.2$ ./staging_dir/toolchain-arm_cortex-a9+neon_gcc-4.8-linaro_uClibc-0.9.33.2_eabi/bin/arm-openwrt-linux-uclibcgnueabi-gdb
    
  2. Attach to target:
    (gdb) target remote 192.168.1.1:2345
    Remote debugging using 192.168.1.1:2345
    0x76ff1e38 in ?? ()
    (gdb) 
    
  3. Use the continue command and notice the program run on the target as shown in step 1
    (gdb) continue
    Continuing.
    Cannot access memory at address 0x0
    [Inferior 1 (process 23862) exited normally]
    (gdb) 
    
    

Using Toolchain from staging_dir

If you are running firmware from your own OpenWrt build directory you can use the toolchain provided there. The OpenWrt toolchain is placed in staging_dir under a directory name appropriate for your target configuration (toolchain-<arch-info>) and you can use it there to build applications for your target directly without using the buildroot:

  • laguna - staging_dir/toolchain-arm_v6k_gcc-linaro_uClibc-0.9.32_eabi
  • davinci - staging_dir/toolchain-arm_v5t_gcc-linaro_uClibc-0.9.32_eabi
  • avila/cambria (ixp4xx) - target-armeb_v5te_gcc-linaro_uClibc-0.9.32/

Examples:

  • Cross-compile hello-world.c for Ventana (imx6) using the OpenWrt 16.02, built in the present working directory:
    export STAGING_DIR=$PWD/staging_dir
    export PATH=$STAGING_DIR/toolchain-arm_cortex-a9+neon_gcc-5.2.0_musl-1.1.12_eabi/bin:$PATH
    arm-openwrt-linux-gcc hello-world.c -o hello-world
    
  • Cross-compile hello-world.c for Laguna (cns3xxx) using the OpenWrt 14.08, built in the present working directory:
    export STAGING_DIR=$PWD/staging_dir
    export PATH=$STAGING_DIR/toolchain-arm_v6k_gcc-linaro_uClibc-0.9.32_eabi/bin:$PATH
    arm-openwrt-linux-uclibcgnueabi-gcc hello-world.c -o hello-world
    

Other Notes

  • uclibc is missing certain things that glibc on your desktop has - There really isn't a clear list of what those items are.
  • uclibc isn't your only libc option - OpenWrt has support for other popular alternatives to glibc as well (make menuconfig, Advanced configuration options -> Toolchain Options -> C Library implementation).

  • Current OpenWrt (ie using our trunk BSP) supports uClibc (default) as well as eglibc and musl.
  • Note that eglibc is extremely popular and I believe Ubuntu has even switched to using it.
  • If you are missing features in the c++ lib then you can instead/also choose an alternative to uClibc++ via menuconfig 'Global build settings -> Preferred standard C++ library.

  • Also, if you want to use compiler tools such as 'nm' you need to use the ones from the cross toolchain (ie arm-openwrt-linux-nm)

Additional Resources

OpenWrt

OpenWrt is a open source software. There are many OpenWrt resources around the web.
Open WRT Wiki for Cross Compile: http://wiki.openwrt.org/doc/devel/crosscompile
OpenWrt Buildroot : http://wiki.openwrt.org/doc/howto/buildroot.exigence OpenWrt Creating Packages : http://wiki.openwrt.org/doc/devel/packages

Other C code examples:

A userspace daemon has been written by Gateworks, source code is available
http://trac.gateworks.com/wiki/gsc#GSCuserspaceDaemon



Another small sample C program to read through input registers such as temp and voltage on the Gateworks GSC http://trac.gateworks.com/wiki/gsc#SystemTemperatureandVoltageMonitor

Steps:

  1. Write the C code as a .c file such as input.c
  2. Compile the C code with the instructions above
  3. Transfer the resulting executable over to the Gateworks board. One way to do this is through a wget command on the Gateworks board if the executable is hosted on a web server.
  4. Run the executable by chmod 777 if needed, and the type at the command line ./input
    #include <stdio.h>
    #include <string.h>
    /*******************************
    *
    *  get value  of inputs on Gateworks Boards
    *
    **********************************/
    int getValue(char *file)
    {
    
    FILE *fp;
    
    int val=0;
    
    fp = fopen(file,"r");
    if ( fp == NULL)
    {
            printf("Bad open\n");
            exit(0);
    }
    
    while(!feof(fp))
    {
    if(fscanf(fp,"%d", &val)!=1)
    {
            break;
    }
    else
    {
    
            printf("\nVal=%d\n\n",val);
    }
    }
    
    fclose(fp);
    
    return val;
    
    
    
    }
    /*******************************
    *
    *  get name of inputs on Gateworks Boards
    *
    **********************************/
    const char * getName(char *file)
    {
    
    FILE *fp;
    
    char label[100];
    
    fp = fopen(file,"r");
    if ( fp == NULL)
    {
            printf("Bad open\n");
            exit(0);
    }
    
    while(!feof(fp))
    {
    if(fscanf(fp,"%s", &label)!=1)
    {
            break;
    }
    else
    {
            printf("\n\nLabel=%s",label);
    }
    }
    
    fclose(fp);
    
    }
    
    /*******************************
    *
    *  dispatch name and value request Gateworks Boards
    *
    **********************************/
    void getNameValuePair(char *file)
    {
    char filelabel[360];
    
    strcpy(filelabel,file);
    strcat (filelabel,"_label");
    getName(filelabel);
    strcat (file,"_input"); 
    getValue(file);
    }
    
    /*****************************
    *
    *   MAIN  read inputs such as voltage
    *
    *****************************/
    int main (int argc, char** argv)
    {
    
            int i=0;
            char str[360];
            char ival[2];
            printf("About to read values...\n");
    
    
            for(i=0;i<13;i++)
            {
                    strcpy (str," ");
                    strcpy (str,"/sys/class/hwmon/hwmon0/device/in");
                    sprintf(ival,"%d",i);
                    strcat (str,ival);
                    getNameValuePair(str);
    
            }
            return 0;
    }
    
    
    
    

The output once ran on the target Gateworks board looks like:

root@OpenWrt:/# ./input 
About to read values...


Label=vin
Val=23852



Label=3p3
Val=3295



Label=bat
Val=3037



Label=5p0
Val=4983



Label=core
Val=1257



Label=cpu1
Val=16777215



Label=cpu2
Val=16777215



Label=dram
Val=1837



Label=ext_bat
Val=16777215



Label=io1
Val=2505



Label=io2
Val=16777215



Label=pci2
Val=1517



Label=current
Val=775

root@OpenWrt:/# 

Note: See TracWiki for help on using the wiki.