Skip to main content

C Package Example

Introduction

This guide will show how to compile a C program into a package for the Omega2, by using a Docker image that uses Onion's OpenWRT SDK wrapper. We'll demonstrate how this is done using a sample C program from Onion.

The C program sends an HTTP request to an API and then outputs the response to a terminal. The API response includes a To Do list item in JSON format.

Why is this important?

This guide and the sample program provide a sure-fire way to build a C program into a package. You can use the procedure and sample code to build your own custom packages based on C programs.

Packages make deploying your own custom applications much easier as opposed to copying loose files to your devices:

  • Packages can be easily installed, updated, and removed with the OPKG package manager
  • The Package definition and OPKG take care of any dependencies for the application
  • Versioning is built into the package definition and creation process

Output

Onion's sample program compiled into an ipk package file you can install on an Omega using the opkg package manager.

How long will this take?

From start to finish, the example takes 15 minutes, assuming your development computer has all the required software installed.

Environment set up

You will need the following set up and software installed to follow along with the example.

  • A development computer

    • Running Mac OS, Windows, or Linux.

    • Access to terminal/command line

    • Git installed

    • Docker installed and running

      • Tip: For those new to Docker, see Docker's installation guide and the manual on running a Docker container.

      • Important Note on Macs with Apple Silicon: The OpenWRT build system, SDK, and Image Builder expect an x86_64 processor architecture. Attempting to build in a Docker container on a Mac with Apple Silicon will result in compilation errors. We recommend using an x86_64 machine for best results. Some users have reported successful compilation if Rosetta for x86/amd64 emulation on Apple Silicon is enabled in Docker.

  • An Omega2 device

Application source code

What we're doing in this step

Getting some package source code that you’ll compile into a package.

Learn more about package source code and software packages in the Create a Custom Package article.

Onion's sample is a small C program that uses libcurl to send an HTTP request to an API (that returns dummy data) and outputs the response to the terminal.

Download the sample code

You'll need to download the source code for the example application from Onion’s repo.

Open a terminal on your development computer and type in the following commands:

git clone https://github.com/OnionIoT/Example-OpenWRT-Packages.git
cd Example-OpenWRT-Packages

Compile the sample package with Docker

What we're doing in this step

At this stage of the example, you'll use the OpenWRT SDK in a Docker container to compile the sample package. After compiling the sample package in the Docker container, you’ll transfer it to the development computer.

We're using Docker because it provides a clean, ready to go, reproducible development environment that will work on Mac, Windows, or Linux development computers. The onion/openwrt-sdk-wrapper Docker image used in this guide already has all the dependencies needed by OpenWRT SDK installed and the OpenWRT SDK Wrapper configured and ready to use for package creation. Using Docker and this image saves time on environment setup and allow you to focus more of your efforts on the packages themselves.

Within your terminal, make sure you are in the top level directory of the source code. If you run an ls -l command, your terminal should look something like this:

total 16
-rw-r--r--@ 1 lazar staff 1062 24 Oct 14:34 LICENSE
-rw-r--r-- 1 lazar staff 52 24 Oct 14:34 README.md
drwxr-xr-x 4 lazar staff 128 24 Oct 14:35 c-example
drwxr-xr-x 4 lazar staff 128 24 Oct 16:21 hello-world-c
drwxr-xr-x 4 lazar staff 128 14 Nov 12:32 hello-world-python
drwxr-xr-x 176 lazar staff 5632 30 Oct 21:18 output
drwxr-xr-x 4 lazar staff 128 14 Nov 12:33 webserver-example-python

Step 1: Download the onion/openwrt-sdk-wrapper image:

docker pull onion/openwrt-sdk-wrapper
note

It might take a few minutes to download the Docker image depending on your internet connection. After the image downloads, you won't need to download it again and this step can be skipped the next time you compiled a package.

Step 2: Start a Docker container based on the onion/openwrt-sdk-wrapper image with the following command:

docker run -it --name openwrt-sdk-wrapper -v "$(pwd)":/root/openwrt-sdk-wrapper/openwrt-sdk/package/apps --rm onion/openwrt-sdk-wrapper
Notes

The -v option will mount the current directory with your sample program as a volume in the openwrt-sdk/package directory. During the build, the SDK will automatically index any changes made to the project source.

The --rm flag means the container will be deleted after it is stopped to save disk space. For a subsequent compilation, you will start with a fresh container and compile again. If you prefer to keep the same container for future re-use, remove the --rm flag from the launch command. To start an existing container run docker start -ai openwrt-sdk-wrapper.

Once the Docker container is running you should see something similar to:

root@3368eeceae37:~/openwrt-sdk-wrapper#

You are now inside the Docker container.

Step 3: Build the package in the Docker container:

The generic command to build a package is:

bash onion_buildenv build_packages {package_name}

For our specific example, the command is:

bash onion_buildenv build_packages c-example

The c-example package name is defined in the package makefile: https://github.com/OnionIoT/Example-OpenWRT-Packages/blob/main/c-example/Makefile#L6.

This will compile the C program for the Omega2 and create an installable ipk file, as well as compile any dependencies. For the c-example package, this will take about 5 minutes. It might be more or less depending on the CPU performance of your development computer.

If a package has dependencies, all the dependencies will be built as separate ipks.

note

The package makefile specifies the dependencies. Since libcurl is a dependency, this package will automatically be compiled. To learn more about the package makefile, refer to the c-example makefile on https://github.com/OnionIoT/Example-OpenWRT-Packages/blob/main/c-example/Makefile#L20.

For additional details on the package makefile, see the Compile a Package article.

Step 4: Copy the compiled ipk file from the Docker container to your development computer's file system.

In the Docker container, run the following commands:

mkdir openwrt-sdk/package/apps/output
cp openwrt-sdk/bin/packages/mipsel_24kc/base/*.ipk openwrt-sdk/package/apps/output

Outside the Docker container in the top level directory of the source code, run ls -l output to see the contents of the output directory.

You'll see c-example_1.0-1_mipsel_24kc.ipk listed, which is the file you're interested in.

Note: To run the commands outside of the Docker container, either use a new terminal window or type exit to stop the container.

info

For further details on using the OpenWRT SDK wrapper, see the Compile a Package article.

The procedure in your example uses a slightly modified method than the one in the article, but the same principles apply.

Transfer the package to Omega

What we're doing in this step

Now that you’ve compiled the package, you’ll need to transfer it to an Omega so it can be installed.

You'll use the sftp protocol to transfer the ipk file from your development computer to the Omega.

Step 1: Install the sftp server on the Omega so it can receive the ipk file.

Connect to Omega's command line and enter the following commands:

opkg update
opkg install openssh-sftp-server

See the Serial Command Line article in the quick start section of the documentation for details on working with Omega's serial command line.

Step 2: Find Omega's IP address and note it down for use in the next step

See the Finding the Omega's IP address article for the procedure.

Step 3: Copy the ipk file from step 1 to Omega's /tmp directory.

Use the scp utility to copy the ipk file to the Omega.

In the terminal outside of the Docker container.

scp output/c-example_1.0-1_mipsel_24kc.ipk root@[IP ADDRESS FROM PREVIOUS STEP]:/tmp/

For example if the IP address from the previous step was 192.168.1.150, the command would be:

scp output/c-example_1.0-1_mipsel_24kc.ipk root@192.168.1.150:/tmp/

When prompted, enter Omega's password onioneer.

note

If the dependencies for your custom package are not custom as well (they are already part of the OpenWRT SDK), then you don't need to copy those ipks over. OPKG on the Omega is smart enough to pull readily available dependencies from the package repos. In this case, it will install libcurl for you.

Install the package

What we're doing in this step

Now that you’ve transferred the compiled package to the Omega, you’ll use the opkg package manager to install the package. Opkg will also install any package dependencies.

On your Omega:

cd /tmp

You can do a ls -l to see the ipk file.

opkg update

To install a generic package:

opkg install <package ipk file name>

To install the example package:

opkg install c-example_1.0-1_mipsel_24kc.ipk

Opkg will first install the dependencies and then the package.

Run the program

What we're doing in this step

Next, you’ll run the program you just installed.

To locate where the program is installed, consult the package makefile for package installation instructions.

Look for the Package/$(PKG_NAME)/install block in the c-example package makefile: https://github.com/OnionIoT/Example-OpenWRT-Packages/blob/main/c-example/Makefile#L43

Since your program executable is installed in /usr/bin, and /usr/bin is in the PATH variable, you can just call the executable name directly.

Linux PATH variable

The PATH variable has a list of directories the system checks before running a command. It allows you to run executables in those directories without using the absolute path – this is good for time saving. To learn more, see this tutorial on the Linux PATH variable.

To run the program type in c-example. The program output will be in JSON format.

root@Omega-FB94://# c-example

The program will run and output:

Fetching To Do from the API at: `http://dummyapi.online/api/todods/2`

{"id":2,"title":"Buy groceries","completed":false,"priority":"medium"}

Next steps

You can use the information in this guide to compile other C packages or make your own!

Take a look at other C examples in the OnionIoT/Example-OpenWRT-Packages repo and try them out for yourself.

The hello-world-c is a basic C program that prints out "Hello world".

Making your own packages

You can also try making your own C software package based on the hello world template.

When working on your own packages, remember to begin with the package makefile.

Important notes
  • Set the package name and version number at the very top.
  • Any dependencies should be added to the package definition (Package/$(PKG_NAME)) and to the compile flags (TARGET_LIB).
  • Change the package installation instructions as required define Package/$(PKG_NAME)/install.

Work on the application source code in the src directory to customize it to your application.