wiki:OpenWrt/SDK

Goals

The goal of this page is to describe the OpenWrt SDK and Toolchain, and how to build source code using one of these. latest/

OpenWrt SDK/Toolchain Information

OpenWrt allows the building of both an SDK and a Toolchain for a specified processor family (e.g. Freescale imx6). The OpenWrt SDK is typically used for building OpenWrt specific packages, without the need of the entire buildroot. This means that you can create an OpenWrt cross compile and package it into a .ipk packaged package. The OpenWrt Toolchain is typically used for cross compiling single programs, without having to create an entire OpenWrt specific package Makefile.

Gateworks provides downloadable SDK's and Toolchains from the 13.06 release to the current releases of the Gateworks OpenWrt BSP. Please refer to this site and navigate to the appropriate BSP version, product family (e.g. cns3xxx for the Laguna product), and download either the OpenWrt-SDK-* or OpenWrt-Toolchain-*, depending on what your desired end goal is.

OpenWrt Toolchain Usage

A prebuilt toolchain can be downloaded our developer downloads site. Please navigate to the appropriate BSP version->product family to find a download link. A toolchain will have the following naming scheme: OpenWrt-Toolchain-<cpu type>-*

Setting up the Toolchain

Once the appropriate toolchain has been obtained, extract it to a location familiar and accessible by you. The following example will grab the 16.02 toolchain for imx6 and install it to an appropriate location:

cd ~/ && mkdir toolchains && cd toolchains
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
tar xvf Gateworks-Toolchain-imx6_gcc-5.2.0_musl-1.1.12_eabi.Linux-x86_64.tar.bz2
ls 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  # View newly created directory contents

Note that the above is entirely optional. If you have built a version of the Gateworks OpenWrt BSP with which you require a toolchain from, you may use that build's staging_dir/toolchain* instead. For example, the imx6 toolchain in 14.08 would look as follows: <path to openwrt>/trunk/staging_dir/toolchain-arm_cortex-a9+neon_gcc-5.2.0_musl-1.1.12_eabi

Cross Compilation

Now that the appropriate toolchain has been installed to a known location, next is to configure the current shell to use it for compilation.

Note that these commands must be repeated for every new shell opened:

export TOOLCHAIN="${HOME}/toolchains/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"
export STAGING_DIR="${TOOLCHAIN}"
export PATH=${PATH}:${TOOLCHAIN}/bin
export CC="arm-openwrt-linux-gcc" # Change to arm-openwrt-linux-g++ for C++ Code
export LD="arm-openwrt-linux-ld"

*Note: TOOLCHAIN should be set to the full path of your toolchain directory; do not use ~.

Now that our environment is setup, we can cross compile some programs.

Notes:

  • Path locations will change based on the Toolchain you're using. Change the TOOLCHAIN environment to point to your specified tool chain directory
  • If you are using a toolchain from the staging_dir, please take care in setting the TOOLCHAIN environmental variable to point to it instead, e.g. export TOOLCHAIN="<path to openwrt>/trunk/staging_dir/toolchain-arm_cortex-a9+neon_gcc-5.2.0_musl-1.1.12_eabi"

Simple C Program

  1. Write the sample program
    cat <<EOF > hello.c
    #include <stdio.h>
    
    int main(void) {
        puts("Hello, world!");
        return 0;
    }
    EOF
    
  2. Compile
    export CC="arm-openwrt-linux-gcc"
    ${CC} hello.c -o hello_c
    file hello_c # Show that it's an ARM executable
    
  3. Put onto target board and execute
    # Assume board has file now
    chmod +x hello_c
    ./hello_c
    

Simple C++ Program

  1. Write the sample program
    cat <<EOF > hello.cpp
    #include <iostream>
    
    int main() {
        std::cout << "Hello, world!" << std::endl;
        return 0;
    }
    EOF
    
  2. Compile
    export CC="arm-openwrt-linux-g++"
    ${CC} hello.cpp -o hello_cpp
    file hello_cpp # Show that it's an ARM executable
    
  3. Put onto target board and execute
    # Assume board has file now
    chmod +x hello_cpp
    ./hello_cpp
    

Notes: Execution of C++ programs will only work if you have the libstdcpp package installed on your target device. Gateworks had not installed this package in the past, but has started to moving forward. Please verify the installation of this library before executing any C++ compiled code.

Troubleshooting

Most run-time problems can be solved by installed the required package, as is the case in running C++ binaries requiring the libstdcpp package.

Other packages that might be of interest to install:

Packages Notes
libc C Library
libstdcpp C++ STD Libraries
libthread PTHREAD Support

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)
    
    

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 musl (default). The non-defaults are not well supported and you may find varied results( eg eglibc and uClibc).
  • 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)
  • Valgrind is a tool that has been asked about by many customers. Valgrind is not installed by default and must be added. Make sure you use unstripped libc.so and valgrind libs. OpenWrt will strip all .so by default so copying the unstripped versions works.

Additional Resources

Other C code examples:

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

As seen above in the toolchain section, please configure your environment. The compilation line for the below program is as follows:

export CC="arm-openwrt-linux-gcc"
${CC} gsc_monitor.c -o gsc_monitor

Code:

#include <stdio.h>
#include <stdlib.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(1);
        }

        while(!feof(fp)) {
                if(fscanf(fp,"%d", &val)!=1)
                        break;
                else
                        printf("%d\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(1);
        }

        while(!feof(fp)) {
                if(fscanf(fp,"%s", &label)!=1)
                        break;
                else
                        printf("%s=",label);
        }

        fclose(fp);
}

/* dispatch name and value request Gateworks Boards */
void getNameValuePair(char *file)
{
        char filelabel[256];

        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[256];
        char ival[2];
        printf("Reading 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;
}

References

Last modified 3 weeks ago Last modified on 06/09/17 10:20:03