Global training solutions for engineers creating the world's electronics

Configuring (X)Emacs for Arm RVCT

Marcus Harnisch, Doulos, 2010

Introduction

With today's hype about IDE (Integrated Develpoment Environments) in general and the well deserved popularity of Eclipse in particular, one tends to forget that there are other facilities to enter text and manage projects.

For decades Emacsen have been known to be very powerful tools for all sorts of text editing tasks, including source code. In fact XEmacs has been used as IDE in past versions of the Sun WorkShop. Following this paragraph, the term Emacs will refer to all popular implementations of this great editor.

In this article I would like to introduce Emacs as editor that can be customized easily to support Arm's RealView Compilation Tools (RVCT)

Compiling source code

The basic requirement for anything that wants to call itself "IDE" is to compile code without switching to a command line window. In Emacs the command M-x compile RET is what you are looking for. M-x means that you hold the "Meta"-key (typically associated with the left "Alt" key on contemporary PC keyboards) while at the same time depressing the key for the letter X. This will prompt you for a command which you respond to by typing the letter sequence c o m p i l e followed by hitting the "Return"-key. Depending on your configuration the same function might also be available in either menubar or toolbar above the text window.

In a small text area te the bottom of the window ("frame" in Emacs terms) you will be prompted for a compile command which defaults to

make -k

This will invoke a make utility on your system which builds your project provided that a proper description (Makefile) exists. This also works on Windows systems since RVDS comes with a complimentary copy of GNU make.

If all you are looking for is compiling this single file you may want to change the command to something like

armcc month.c

in case the file name happens to be month.c.

You may ask yourself what exactly the benefit of this is over just invoking this from the command line. Just give it a try. You will notice that the frame got split into two halves and a new text area ("buffer" in Emacs terms) named *compilation* will have popped up showing all messages reported by the tool. For instance:

cd c:\Users\Training\intro\session2\
armcc month.c
"month.c", line 17: Error:  #18: expected a ")"
    printf("\ne.g. 1972 02 17\n\n";
                                  ^
"month.c", line 20: Error:  #70: incomplete type is not allowed
    scanf ("%d%d%d", &date.year, &date.month, &date.day);
                      ^
"month.c", line 20: Error:  #70: incomplete type is not allowed
    scanf ("%d%d%d", &date.year, &date.month, &date.day);
                                  ^
"month.c", line 20: Error:  #70: incomplete type is not allowed
    scanf ("%d%d%d", &date.year, &date.month, &date.day);
                                               ^
"month.c", line 22: Error:  #70: incomplete type is not allowed
           date.year, date.month, date.day);
           ^
"month.c", line 22: Error:  #70: incomplete type is not allowed
           date.year, date.month, date.day);
                      ^
"month.c", line 22: Error:  #70: incomplete type is not allowed
           date.year, date.month, date.day);
                                  ^
"month.c", line 23: Error:  #70: incomplete type is not allowed
    dflag = date.day;
            ^
"month.c", line 24: Error:  #70: incomplete type is not allowed
    mflag = date.month;
            ^
"month.c", line 27: Error:  #70: incomplete type is not allowed
    while (date.day != dflag && date.month - mflag < 2)
           ^
"month.c", line 27: Error:  #70: incomplete type is not allowed
    while (date.day != dflag && date.month - mflag < 2)
                                ^
"month.c", line 30: Error:  #70: incomplete type is not allowed
             date.year, date.month, date.day);
             ^
"month.c", line 30: Error:  #70: incomplete type is not allowed
             date.year, date.month, date.day);
                        ^
"month.c", line 30: Error:  #70: incomplete type is not allowed
             date.year, date.month, date.day);
                                    ^
"month.c", line 40: Error:  #70: incomplete type is not allowed
    switch (date.month)
            ^
"month.c", line 43: Error:  #70: incomplete type is not allowed
            if (date.year % 400 == 0)
                ^
"month.c", line 46: Error:  #70: incomplete type is not allowed
              if (date.year % 4 == 0)
                  ^
"month.c", line 58: Error:  #70: incomplete type is not allowed
    if (date.day == daysInMonth)
        ^
"month.c", line 60: Error:  #70: incomplete type is not allowed
      date.day = 1;
      ^
"month.c", line 61: Error:  #70: incomplete type is not allowed
      if (date.month == 12)
          ^
"month.c", line 63: Error:  #70: incomplete type is not allowed
        date.month = 1;
        ^
"month.c", line 64: Error:  #70: incomplete type is not allowed
        date.year++;
        ^
"month.c", line 67: Error:  #70: incomplete type is not allowed
        date.month++;
        ^
"month.c", line 70: Error:  #70: incomplete type is not allowed
      date.day++;
      ^
"month.c", line 11: Error:  #235: variable "date" was declared with a never-completed type
  struct Date_Format date;                              /* Variable declaration */
                     ^
month.c: 0 warnings, 25 errors

Compilation exited abnormally with code 1 at Mon Oct 11 12:43:32

Unlike your command line window which will even on the second glance not look much different from this, Emacs supports error parsing in this window, controlled by a variable with the funny name compilation-error-regexp-alist-alist. This variable holds regular expressions that match output in the *compilation* buffer and determines which part of a message identifies the file name, line and column number. Since regular expressions for different tool chains could be interfering with each other, they are grouped by a descriptive name typically indicating a tool chain. My configuration includes this:

(add-to-list 'compilation-error-regexp-alist-alist
    '(armcc ("\\\"\\(.+?\\)\\\", line \\([0-9]+\\):" 1 2 )))

Depending on your variant and version of Emacs, things might work slightly differently and I recommend reading Creating Your Own Compile Error Regexp for details. With those instructions we can now type the command M-x recompile and look at the output once again.

The key combo C-x ` (press&hold the "Ctrl"-key, hit X, release both and hit the "grave" accent key in the top-left corner on a US keyboard) entered in the source code window executes the command next-error and gets us to the source code location (line) of the first error message and from there to subsequent errors in turn. It is perhaps worthwhile pointing out that error messages affecting the same line will be skipped and the next position would be an erroneous source line that is different from the current line.

Changing to the *compilation* buffer will give you more commands to navigate your build output. Check out the list of commands that C-h b will print.

CEDET

The Collection of Emacs Development Environment Tools extends your favorite Emacs variant with functionality supported by many modern IDE. It can even draw UML class diagrams of your programs in ASCII-art. Explaining the entire configuration of CEDET would lead too far and only sidetrack us from our original topic of configuring Emacs for RVCT.

When you configure a generic project in CEDET, you will create a Lisp structure describing the project. The project will have a name, here "Cortex-M3", and will be associated to a distinctive file. In our case this would be the top-level Makefile which contains all project settings relevant to building the project. The member :include-path contains a list of all project specific include paths. System wide header files will be specified by the member :system-include-path, which in our case gets its value from the environment variable RVCT40INC.

(ede-cpp-root-project "Cortex-M3"
                      :file "~/Desktop/projects/cortex-m3/Makefile"
                      :include-path '("/include"
                                      "/targets/ISSM/include"
                                      "/cpu/cortex-m3/include")
                      :system-include-path (list (getenv "RVCT40INC"))
                      :spp-files '("config.h"))

Configuring CEDET properly can be a challenging task, but thanks to its extensive documentation and mailing lists you will be rewarded with a very powerful code analysis tool.