Using Atom For C++ And Embedded Development
By Romain Picard on Monday 1 February 2016, 10:00 - Permalink
I recently discovered Atom, a code editor developed by GitHub. When a friend showed it to me last year I must admit that I made fun of him : It was still at an early stage, quite slow, and really buggy. But since that time its development was really fast. So I decided to try it seriously two months ago, and something incredible happened: After 15 years of addiction to vim, I switched to Atom within 2 weeks.
Atom Is The New Vim
Most of the advanced features of vim are supported by atom, and if you have something missing you will probably find a package for your need. A good example is column editing and selection. This is something really convenient, but the key bindings make it hard to use on vim. This feature become very natural to use in Atom.
Another killer feature is snippets. I never found such a plugin that I liked on vim. But the default snippets on Atom are really great, even for C and C++ code.
Now let's see how this code editor designed for web development can be tuned for C/C++ and embedded development.
If you develop in C++, then the first thing that you need is to change the ".h" files scope.
By default they are recognized a C files, so you will not be able to use C++ snippets on them. Modify you local configuration file located in "~/.atom/config.json" this way:
core: customFileTypes: 'source.cpp': [ 'h' ]
Now you have access to snippets for class declaration (cl), namespace declaration (ns) and several other ones. If you develop for a company you can replace the default "legal" snippet with your copyright. Add this to your "~/.atom.snippets.cson" files:
'.source.c, .source.cpp': 'my legal': 'prefix': 'legal' 'body': """ copyright me """
Build and test
If you projects uses a make based buildsystem, then the "build" package is all you need to build and run your unit tests. It requires a configuration file (".atom-build.json") at the root of the project containing the build command to run. You can specify several build targets available. Personally I use 3 targets: One to build (make all), one to clean (make clean), and one to run the tests. Since I do not want to write this configuration file for each component that I build, I use a script that generates it. A simplified version is available on github that you can use as a base for your own needs.
A clang based code completion package is available: autocomplete-clang. It needs a ".clang_complete" configuration file a the root of the project. Since writing such a file by hand is also boring, I also wrote a script to generate it. It simply searches where header files are present to add them in the configure script. This plugin works really well by it is quite slow. One can generate pre-compiled headers to speed it but I did not try it.
One feature that is really nice on vim is navigation in C code. Thanks to ctags, it requires very little memory and is really fast. Unfortunately, it does not work as well for C++. There are clang based solutions such as YouCompleteMe but it is a real pain to install.
Atom has a wonderful plugin for this task: atomic-rtags. You must install rtags to use this plugin. Rtags is a code indexer based on clang, with a client/server architecture. So the indexation is done in the background on the server, as you edit your files. This makes the navigation in the code really fast.
So rtags requires that the files to index are provided to the server. This is done via a clang compilation database, a json file named "compile_commands.json" at the root of the project. Generating this configuration file can be very easy or tricky depending on you build system. If you use CMake then it can directly generate it. If you use make you need another tool to generate the compilation database: Bear. Its configuration can be tricky with cross-compilers. See later for details how to get a working installation.
With all this you should be able jump to any C++ code implementation. However, you cannot jump back to the previous location. The "last-cursor-position" package is supposed to do this, but it work correctly only when you navigate in the same file.
Bear works well out of the box as long as your toolchain is built for the same architecture than your system. When doing embedded development, it is common to use a 64bits system and using a 32bits toolchain. In this case bear does not work correctly because the shared library cannot be preloaded on the toolchain binaries: The preload of a 64bit library obviously fails on a 32bits binary execution. The tip to get it working correctly is to generate both 32 and 64bits bear libraries, and preload both libraries. This allows to successfully preload one of the 2 libraries while the other one fails, for 32 and 64bit executables.
So download bear twice and configure it once for 32 bit systems:
CFLAGS=-m32 CXXFLAGS=-m32 cmake -DCMAKE_INSTALL_PREFIX=/home/xx/local
and once for 64bit systems:
CFLAGS=-m64 CXXFLAGS=-m64 cmake -DCMAKE_INSTALL_PREFIX=/home/xx/local
You can omit the CMAKE_INSTALL_PREFIX option if you install it on the standard location. Then run bear with these two libraries preloaded. You can look at my atom-rtags-gen script for an example.
These tips should allow you to setup Atom for C++ development and cross-compilation. If you are a vim or emacs addict, you should really give it a try. You may be happily surprised. As I said in the beginning of the article, its development is really fast. So new feature will probably be available soon. One of the things that I am waiting for is the ability to debug code via gdb.