C++11 and ACAP

As a C++11 developer, you may find yourself stymied by the C++ compiler provided in the official ACAP SDK toolchain.  Full C++11 support was not available in GCC until version 4.8; the ACAP SDK provides GCC version 4.3.  This post provides a high-level overview of solving what is an enduring issue for most embedded Linux development environments: building your own bleeding-edge toolchain.

For the remainder of this post I will assume that you have a functional Linux development environment with the ACAP SDK already installed, and an Axis ARTPEC-4 or ARTPEC-5 camera (the following instructions can be directly adapted for Ambarella-based cameras, as well).

Buildroot

In order to provide C++11 support, we must compile several new system libraries (notably libstdc++) for the camera.  We use Buildroot, a tool for generating embedded Linux systems through cross-compilation:

git clone git://git.buildroot.net/buildroot
cd buildroot
export AXIS_BUILDROOT=$PWD

Buildroot provides a GTK-based configuration tool that compiles on your machine.  To use this, you will need to install development versions of libglade2, libglib2.0, and libgtk2.0.  Make and run the configuration tool:

make gconfig

For ARTPEC processors, select the following configuration options:

  • Target options → Target Architecture ⇒ “MIPS (little endian)”
  • Target options → Target Architecture Variant ⇒ “mips32r2”
  • Target options → Use soft-float ⇒ enabled
  • Toolchain → custom toolchain vendor name ⇒ a string of your choice, such as “acap”
  • Toolchain → Kernel Headers ⇒ “Manually specified Linux version”
  • Toolchain → linux version ⇒ “2.6.35”
  • Toolchain → C library ⇒ “glibc”
  • Toolchain → GCC compiler Version ⇒ “gcc 5.x”.
  • Toolchain → Enable C++ support ⇒ enabled
  • Toolchain → Build cross gdb for the host ⇒ enabled

Save and exit the configuration utility, then build your toolchain and target libraries:

nice make

Compile

When this is complete, GCC 5.x for mips32r2 will be available in your Buildroot output directory.  Add this to your path:

export PATH="$AXIS_BUILDROOT/output/host/usr/bin:$PATH"

We are now ready to compile some C++11!  Save the following text as test_program.cpp:

#include <cstdlib>
#include <iostream>
#include <thread>

int main(int argc, char *argv[])
{
    auto message = { "Hello", " ", "world", "!" };
    std::thread t([&]()
    {
        for(const auto& word : message)
            std::cout << word;
        std::cout << std::endl;
    });
    t.join();

    return EXIT_SUCCESS;
}

Compile test_program.cpp with your new compiler:

mipsel-acap-linux-gnu-g++ \
    -std=c++11 \
    -pthread \
    test_program.cpp -o test_program

Now upload test_program to your camera (I prefer rsync, but FTP works as well).  For the remainder of this discussion, I will assume that you have an SD card mounted in the camera’s filesystem at /var/spool/storage and that you upload test_program to this location.  Now telnet or SSH into your camera and run test_program.  The results are not what we hoped for:

 ./test_program: /lib/libstdc++.so.6: version `GLIBCXX_3.4.11' not found (required by ./test_program)
 ./test_program: /lib/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by ./test_program)

Let’s check what libraries test_program is linked against:

  ldd ./test_program

    libstdc++.so.6 => /lib/libstdc++.so.6 (0x2aaaa000)
    libm.so.6 => /lib/libm.so.6 (0x2abb6000)
    libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x2ac96000)
    libpthread.so.0 => /lib/libpthread.so.0 (0x2acd0000)
    libc.so.6 => /lib/libc.so.6 (0x2acfa000)
    /lib/ld.so.1 (0x55550000)

Notice that even though we compiled our new program with GCC 5.x, the dynamic loader on the camera will link our new C++11 executable to the old libraries provided by the camera. We want our executable to use the libraries we just compiled with Buildroot, so copy the entire $AXIS_BUILDROOT/output/target/staging directory tree to the camera at /var/spool/storage/mips32r2_buildroot.

Compile Again

Now let’s recompile our test program, but specify the rpath to tell the linker to preferentially use the libraries that we just uploaded rather than the camera’s system libraries:

CAMERA_BUILDROOT=/var/spool/storage/mips32r2_buildroot
mipsel-acap-linux-gnu-g++ \
   -std=c++11 \
   -pthread \
   -Wl,-rpath,$CAMERA_BUILDROOT/lib:$CAMERA_BUILDROOT/usr/lib \
   test_program.cpp -o test_program

Upload your new executable to the camera and run it to get another error:

./test_program

    ./test_program: relocation error: /var/spool/storage/mips32r2_buildroot/lib/libc.so.6: symbol _dl_find_dso_for_object, version GLIBC_PRIVATE not defined in file ld.so.1 with link time reference

Unfortunately, the dynamic loader (an executable responsible for satisfying our program’s dynamic library dependencies at runtime) on the camera is too old for our new libraries. All executables that use shared libraries are hard-coded to use the dynamic loader at /lib/ld.so.1, but we can manually call a different dynamic loader. From the command line we’ll use the dynamic loader compiled by Buildroot:

/var/spool/storage/mips32r2_buildroot/lib/ld.so.1 ./test_program
 
    Hello world!

It works!

Compile Yet Again

As a final step, we recompile our test program one last time to manually specify the location of our Buildroot-provided dynamic loader:

CAMERA_BUILDROOT=/var/spool/storage/mips32r2_buildroot
mipsel-axis_acap-linux-gnu-g++ \
 -std=c++11 \
 -pthread \
 -Wl,-rpath,$CAMERA_BUILDROOT/lib:$CAMERA_BUILDROOT/usr/lib \
 -Wl,dynamic-linker=$CAMERA_BUILDROOT/lib/ld.so.1 \
 test_program.cpp -o test_program

With our Buildroot tree installed on the camera, we can now execute our C++11 program like any other executable!

./test_program

    Hello world!

Jamming all of the foregoing into an ACAP installation package is left as an exercise for the reader. 🙂

10 comments

  1. Hi there,

    I’m not able to make Toolchain → C library ⇒ “glibc”. Once I set Toolchain → Kernel Headers ⇒ “Manually specified Linux version” buildroot doesn’t allow me to choice “glibc”.

    I tried to use leaving only one of those options (glibc + Kernel Header Linux 3.2.x OR uClibc-ng + Linux Header Kernel 2.6.35 with custom kernel header 2.6.x) no success.

    Like

  2. Hi, i’m a new axis user. I have a lot of questions ! it seems that axis use gstreamer as a server and i would like to know of it’s possible to use something like gst-launch to get one local video stream (rtsp ?) and push it with rtmp to a remote server ? Or do u think its possible to make an ffmpeg package for my artpec-4 caméra ? Thanks in advance.

    Like

      1. Hi. Thanks for your reply. Yes i know camstreamer and i would like to be able to do the same without all the package they sale. I just need one rtsp client and push the stream to the outside world … like ffmpeg does like that; ffmpeg -i rtsp://localhost/axis-media/media.amp -f flv rtmp://outsideworld.com/streamname.

        Like

  3. Eric,

    Hi, I just stumbled across this site and have some experience with Axis cameras. In lieu of CamStreamer, You can stream to YouTube (for private or public use) using the Axis Streaming Assistant and Adobe Flash Media Encoder. Or you can use Streamedian to play in HTML5 video element using MSE via websockets via rtsp. The former option requires Windows for the Streaming Assistant, but that is how we stream from an older Axis Camera with v4.x firmware. I have tested the Streamedian code and seems to work well but need to install their websocket rtsp server on linux. I setup an Amazon Lightsail vps for testing and it worked well.

    Hopefully that helps you out

    Like

    1. Hi Mike, Thanks for your suggest. Finally, i’ve patched and ported FFMPEG to the Axis cameras and i’m now working on making an ACAP package. I don’t find on Axis web site the complete documentation on how to complete this. Does somebody have a link to this doc ?
      Furthermore if an ACAP specialist want to take part of it i would be interested. Eric

      Like

      1. Hi, I add this message to the last one, i finally have found the docs in the ‘docs’ directory of ACAP package.

        Like

        1. Glad you got ffmpeg ported to the camera and found the docs you were looking for. Hopefully it runs well on the camera and I am sure you are learning a lot. I always wondered if ffmpeg was ‘part’ of CamStreamer app but have not explored it. They need something to transcode the h264 stream, right? I know the cameras natively use gStreamer, and I am not sure if that app or a plugin could help you. I am not an ACAP specialist but enjoy working and exploring with the cameras. I developed a camera application that can ‘control’ multiple cameras running custom paths with snapshots and allows user control. We use YouTube Live Streaming but the user in control gets a LiveView due to the ~30 sec latency of the youtube stream. Plus it has ‘map’ control by clicking anywhere on the google map and calculates the ptz values. FoxRiverSystemWebcams.com if interested.
          Good Luck with your project!

          Like

          1. Hi Mike,

            We have problem to run cgi script ont the axis cameras with apache 2.4 embeded, do you know something about this ? No problems with old versions embeded with boa web server.

            Eric

            Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s