Hey guys, we have an upcoming TOP SECRET project that’s going to involve development work with a small ARM CPU based ‘System on a Board’ running Linux. During this process I’m going to document some of our experiences, trials, tribulations and successes so that others can learn from our mistakes and share in our victories.
Now I’m typically a Windows developer so building programs for Linux is fairly new to me. I also have the difficulty that there’s not enough on-board memory to develop software on the device itself; it also requires a special compiler for the ARM instruction set.
My only solution is to Cross-Compile, which is where I build my program on a different kind of system, but target the system that it’s going to wind up on. For ARM there are several free cross compiler solutions out there, though only a few support Windows and even less are frequently maintained. Some examples would be GNUARM (last updated 2006), YAGARTO, DevKitPro ARM and CodeSourcery G++ Lite.
Another piece of the puzzle is an IDE, notepad and command-line just don’t cut it when working on complex projects, at least not for a windows developer! Two good free IDEs spring to mind, both are powerful, cross-platform and support cross-compiling. The First is the Eclipse IDE, it’s highly user friendly, built in Java and is used as the basis of some commercial cross-compiling solutions, however from my experience a little unstable and resource hungry. A good alternative is the Code::Blocks IDE, it’s a little basic in comparison to Eclipse (though has a good plug-in system to expand functionality) but is built in C++ and as such provides great performance with a much smaller resource footprint, from experience I can say it’s also very stable.
For this project I’ve decided to use the Code::Blocks IDE along with CodeSourcery G++ Lite as my cross-compiler and toolset; it had a few advantages over alternatives: it’s a free aspect of a commercial solution, and so well maintained and optimised, does not require Cygwin and comes with the correct command-line tools ready for use by Code::Blocks. I’ll take a moment to recommend that anyone following in my footsteps installs their cross-compiler to a directory without any spaces in the name, as some libraries have trouble with this.
Now that I’m set-up, my first challenge is to familiarise myself with Code::Blocks, the library structure and system used by Linux and how to cross-compile a project with library prerequisites. I’m first going to take a look at compiling some prerequisite libraries. I’ll start with Boost, a great multi-platform library providing all the functionality that people felt was left out of the C++ Standard Library collection, in fact it’s so useful, it’s now slowly being integrated into the Standard. After extracting the latest packed release, you’ll find in the root that Boost has a file called bootstrap.bat, usefully this will generate boost’s own installer (Jam) for Windows; this does require the Microsoft Visual C++ (msvc) compiler and so make sure you have a version of Visual Studio installed, if you don’t own a copy you can download the free express edition. After running this file, to cross-compile, I need to configure project-config.jam, replacing the line using mscv ; with my cross-compiler settings using gcc : arm : “C:/Sourcery_G++_Lite/bin/arm-none-linux-gnueabi-g++.exe” ; I can now run the following command from within the Boost root directory in the command-line bjam install –prefix=myInstallLoation toolset=gcc-arm target-os=linux, optionally you may wish include the following compiler arguments within project-config.jam that can be ideal for embedded systems with limited memory:
- -fvisibility=hidden -fvisibility-inlines-hidden – Decreases library size by avoiding exporting of unneeded symbols.
- -ffunction-sections -fdata-sections – A more intensive but memory friendly garbage collection.
e.g. using gcc : arm : “C:/Sourcery_G++_Lite/bin/arm-none-linux-gnueabi-g++.exe” : <compileflags>-fvisibility=hidden ;
If your version of Boost won’t compile the thread library, it’s likely because it thinks you’re building for Windows, passing threadapi=pthread as a command-line argument will force the correct library to be built.
It’s particularly important to include install –prefix=myInstallLoation as opposed to simply compiling Boost, as this will lay out the correct Boost directory structure for easily including the library into future projects.
It can take a while but after this the boost library will be cross-compiled.
Linux libraries have different extensions to Windows:
- .a – Static Library (archive) equivalent of .lib
- .so – Dynamic Library (shared object) equivalent of .dll
Where possible I’m going to use static libraries as they’re memory friendly for individual programs; if you expect to be using the same library in multiple programs at the same time, dynamic libraries may be for you.
It’s worth noting that many libraries now come with support for the cross-platform CMake build system and so I made sure to install the latest copy. Usefully, it’s now possible to generate a Code::Blocks or Eclipse project with CMake.
To create a Code::Blocks project with CMake, open up CMake, complete the boxes Where is the source code and Where to build the binaries. The source-code field should point to the first folder in the library project with a cmake file present and you may enter any directory of your choice for the binaries, it’ll be created if it doesn’t exist.
Proceed by clicking Generate. Select CodeBlocks – Unix Makefiles as your generator and Specify options for cross-compiling.
For Operating System enter Linux, version enter 1. For Compilers, find the location of your CodeSourcery bin folder, for me it was C:/Sourcery_G++_Lite/bin/. For C select arm-none-linux-gnueabi-gcc.exe and for C++ select arm-none-linux-gnueabi-g++.exe. Finally, for Target Root, find the location of your CodeSourcery libc folder, for me it was C:/Sourcery_G++_Lite/arm-none-linux-gnueabi/libc; CMake will use this directory to search for target libraries, you may add other directories at any time by space-separating them.
A quick note, if you receive the error “…unable to find a build program…” at any stage when generating a CMake project. Head to your CodeSourcery bin folder, make a copy of cs-make.exe and rename it to make.exe.
Using the above instructions, I’m going to generate a Code::Blocks project for Wt (Witty – A C++ Web Tool-kit). Wt is a high-performance, highly secure tool for creating responsive web 2.0 applications, it also comes with its own web-server. Great for an embedded system with a network port!
When first generating a project in CMake, it will likely produce errors and highlight values in red. Typically these are requests for the location of various prerequisite libraries. How convenient it is then that Wt requires the Boost library that I just compiled! CMake is capable of automatically detecting the boost library with an entry in BOOST_PREFIX, however I need to give it a helping hand when cross-compiling. In BOOST_PREFIX, I enter the boost install directory I specified earlier along with some more of the generated file structure, C:/myInstallLocation/Boost/include/boost-1_47, this will of course change if using a different version of Boost. With this CMake is able to detect my Boost header files but not my library files; this is because it is expecting library files containing the phrase win32 instead of gcc, I can correct this by clicking + Add Entry in CMake and adding an entry with Name Boost_COMPILER, Type String and Value -gcc to force the CMake Boost search script to look for the correct libraries. With that it should be all over but CMake will still fail to find the boost_thread library, again, this is because it is expecting a different Windows related name, I can force CMake to search for the pthread version of boost_thread by adding a further entry of Name Boost_THREADAPI, Type String and Value pthread. Boost will now be detected successfully.
A quick note, in CMake 2.8.6 or older, there is a bug in the Boost search script that will prevent discovery of boost_thread. To fix this, locate the file FindBoost.cmake within the CMakeInstallation/share/cmake-2.8/Modules, this location will vary depending on the version of CMake. Inside this file, search for the line string(REPLACE “thread” “thread_${Boost_THREADAPI}” _threadapi_libnames ${_orig_libnames}) and replace it with string(REPLACE “thread” “thread_${Boost_THREADAPI}” _threadapi_libnames “${_orig_libnames}”). It’s worth noting that from the Modules directory, it is possible to view other automated CMake search scripts along with the custom entries that you can specify for each script.
In the same way I could provide options to memory optimise boost, I can provide options for Wt; a full list of options and advice can be found here: http://redmine.emweb.be/projects/wt/wiki/Wt_embedded. Once everything’s configured, hit Generate and your project files will be created. To open the new project, load up Code::Blocks and from the File menu, select Open. Navigate to your Wt build directory, searching for a .cbp file and you’re off!
I hope that my experiences will prove useful to the potential Windows cross-compilers out there. I’ll be making a separate post on configuring the cross-compiler and building in Code::Blocks.
Alistair
QuickForge – Rapid 3D Printing
Next Post: Cross-Compiling in Code::Blocks and Running Your Program on the Target Device
Side Note: A small side-note on CodeSourcery and Code::Blocks binary choices