skip to Main Content
Cross-Compiling C & C++ Programs: Part 3 – C Programming With Libraries

Cross-Compiling C & C++ Programs: Part 3 – C Programming with Libraries

The second bullet of this week’s 2-Bullet Tuesday! Check out the first bullet here. Subscribe to receive the newsletter on the 2-Bullet Tuesday page!

Omega Tip

We’re continuing our series on cross-compiling programs for the Omega2. A couple weeks ago, we covered how to cross-compile a hello world C program. This week, we’ll be showing you how to cross-compile more complex C programs that make use of external libraries!

In this example, we will write and cross compile a program that will read and print the input value on a user-specified GPIO once a second for 20 seconds. Our program will use the ugpio library to interact with the GPIOs. See our c-cross-compile-example repo on GitHub for the code.

You may ask, why do I need to cross-compile this program when I already know how to compile C programs on my Omega?

Well, as a space saving measure, header files for libraries that are not regularly part of the C standard library are not included on the Omega’s filesystem. So we are not be able to compile programs that make use of external libraries directly on the Omega, the compiler would complain that it can’t filnd the ugpio/ugpio.h header file.

However, the Omega’s filesystem does include shared object files of many external libraries, including ugpio (see /usr/lib on your Omega). This means that compiled programs that use these libraries can be executed on the Omega, if they have been previously cross compiled on a system that has all of the required header files and shared object files.

Cross Compilation Process

Head to your omega2-source Docker container and let’s dive in! Go to the /root directory and we’ll start by cloning the repo that has the C code:

git clone https://github.com/OnionIoT/c-cross-compile-example.git

Now that you have all of the code, you’ll notice that there’s a makefile as well as a xCompile.sh script. The makefile is fairly standard as far as makefiles go, it’s the xCompile.sh script that makes all of the cross compilation magic happen. It’s responsible for invoking the makefile in such a way that:

  • The compilers are set to the cross-compilers created by the LEDE build system
  • The compilation and linking flags are set to allow compilation of programs that use external libraries

For more details on how the xCompile.sh script works its magic, check out the README in the repo, or take a look at the script itself.

Since we love to write code that’s reusable, the script takes two arguments:

  1. The location of the LEDE build system (so it knows where to look for the cross-compiler and the header files & static object files for any external libraries)
  2. The names of any libraries that are used by the program

So, the script should be called like this:

sh xCompile.sh -buildroot ‹PATH TO BUILD SYSTEM› -lib ‹REQUIRED LIBRARY›

A Small but Important Note

We keep mentioning that the program will use the ugpio library. In order for this to be possible, the library must first be compiled by LEDE build system.

If you’re using our omega2-source Docker image or building based on our source GitHub repo, you’re all good as it’s selected for compilation by default.

If not, you’ll have to run make menuconfig in the build system to select the libugpio package to be compiled and then compile it by running make.

Back to Cross Compiling

Ok, let’s run our cross compilation script. If you’re following along in the omega2-source Docker container, the following command is what you should run:

sh xCompile.sh -buildroot /root/source/ -lib ugpio

As you can see from the output, we now have a gpioRead executable file. Let’s take a closer look at this file:

root@6cef4c9123cb:~/c-cross-compile-example# file gpioRead
gpioRead: ELF 32-bit LSB executable, MIPS, MIPS32 rel2 version 1, dynamically linked, interpreter /lib/ld-musl-mipsel-sf.so.1, not stripped

Success! It’s a MIPS executable!

Getting the Program to the Omega

To get this program onto your Omega, transfer the gpioRead binary executable file to https://transfer.sh/ and then download it on your Omega.

curl --upload-file ./gpioRead https://transfer.sh/gpioRead

It will upload the file and output a link you can use to download the file.

Now switch over to your Omega and we’ll download the executable using the wget command:

root@Omega-F16B:~# wget https://transfer.sh/MVr7R/gpioRead
--2017-10-10 15:48:25--  https://transfer.sh/MVr7R/gpioRead
Resolving transfer.sh... 51.15.75.10, 2001:bc8:4700:2000::4423
Connecting to transfer.sh|51.15.75.10|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 9804 (9.6K) []
Saving to: 'gpioRead'

gpioRead                                             100%[=====
===============================================================
===============================================>]   9.57K  --.-
KB/s    in 0.005s

2017-10-10 15:48:27 (1.79 MB/s) - 'gpioRead' saved [9804/9804]

One last step, we’ll need to change the downloaded file’s permissions to make it executable:

chmod +x gpioRead

Another Small but Important Note

Our gpioRead executable was compiled with the ugpio library dynamically linked. So, when the gpioReadprogram executes, it will be looking for the libugpio shared object when it needs to execute code from the library.

What that means is that for the gpioRead program to run properly, your Omega needs to have the libugpio package installed. If you’re using an Onion firmware, you’re all good since it comes with libugpio by default. If not, you’ll have to use opkg to install it.

Running the Program

Back to the show: you’re all set to run your cross-compiled program! Select the GPIO that you would like to read and let’s run the program:

root@Omega-F16B:~# ./gpioRead 1
> setting to input
> begin reading GPIO1
  > Read GPIO1: value '1'
  > Read GPIO1: value '1'
  > Read GPIO1: value '0'

It will read the input value on the specified GPIO 20 times in a row and display it on the command line.

Try running a jumper wire from your GPIO to GND, starting the program, and then moving it from GND to 3.3V after a while.

You’ve Made It!

So now you’ve successfully cross compiled your second program, one that has a makefile and uses an external library! Now, it’s your turn to make some awesome projects and share them with us! Try using some of the C Libraries we’ve made! Happy Hacking!

 

Thanks for reading & have a great week!

Have you seen the Omega2S, the smaller and surface-mount version of the Omega2 for high volume commercial and industrial OEMs? See our Omega2S page for more details!

Let us know what kind of stuff you would like to see featured on 2-Bullet Tuesday! Send a tweet to @OnionIoT with your suggestions!

 

P.S. We can still hardly believe it! The Omega2 family is now available on SparkFun!

Back To Top