Using Emacs for Programming


Emacs has many capabilities that making it useful for creating, editing, compiling and debugging programs. This tutorial discusses:

  1. Showing different parts of a program in different colors
  2. C++ Mode
  3. Using multiple buffers inside Emacs
  4. Compiling inside Emacs
  5. Debugging (with Gdb) inside Emacs


  1. Color-coding:

    Emacs can display C++ source code files in a color-coded manner.

    This means that:

    will be displayed using different colors.

    This can be useful in helping you understand a program and to find typos. For example, suppose you had the following:
    
    cout << "The sum is: << sum << endl;
    

    when it is color-coded:
    
    cout << "The sum is: << sum << endl;
    

    it displays the entire line after cout << ( in the color used for a string literal. Since the variable sum and the manipulator endl are obviously not intended to be part of the string literal, it's easy to see there is an error, a missing quote (").


    As another example, suppose you are doing a science project on the properties of materials. You are writing a program that keeps track of properties of test objects, for example:
    
    int rigid;  // Is the object rigid
    int float;  // Whether the object can float
    

    With color-coding:
    
    int rigid;  // Is the object rigid
    int float;  // Whether the object can float
    

    you can see that you accidentally used a reserved word float for the name of a variable.


    In conclusion, color-coding can be useful in finding certain kinds of mistakes. Emacs' color-coding is not, however, all-powerful, and there are many problems it will not help you find.

    If you need to set up your account so that Emacs will color-code your C and C++ programs, follow these instructions.

  2. C++ Mode:

    Now let's see how else Emacs can help us with writing/editing C++ code.

    Download the program sum1.cpp into your current directory.

    Now, start up Emacs:

    emacs &
    

    To load the file, choose Open File... from the Emacs File menu. When it prompts you with:

    Find file: curr-dir/
    
    (where curr-dir is your current directory), type in the name of the file, giving:
    Find file: curr-dir/sum1.cpp
    
    and press <Return>.


    Aside: The tilde (~) is shorthand for your home directory in many programs and at the UNIX prompt. Thus, tilde (~) will appear at the beginning of what Emacs lists as your current directory if it is under your home directory.

    You should now see the source code in Emacs. Note that since we have loaded C++ code, Emacs has gone into C++ mode. Emacs knows it is editing C++ code because the filename ends in .cpp.


    Aside: It may also recognize other common C++ file extensions like .cc. For files ending in .c or .h, Emacs will go into a similar C mode. Even though a header file (.h) might have either C or C++ code, Emacs cannot tell the difference.

    C++ Menu

    Note that when you are in C++ mode in Emacs, there is an additional menu named C++, with commands for navigating and editing C++ programs.


    Aside: A very similar C menu will appear in C mode.

    Let's use one of the C++ menu's commands. In the Emacs window, put the cursor at the end of the first line that uses cout:
    cout << "Enter how many numbers I will sum: "; 
    

    If you now choose Forward Statement from the C++ menu, it will go to the next statement, which is the one using cin:
    cin >> howmany; 
    


    Aside: Roughly, a statement is something that ends in a semi-colon (;), which is a simple statement. There are also compound statements--all of the stuff in a block (i.e., between braces, { and }) forms a single compound statement.

    You might use the Forward Statement command to advance through statements in a program when you cannot easily tell where statements begin and end.

    Automatic Indentation

    Another feature you can use when Emacs is in C++ mode is automatic indentation. You can use this before or after the fact. In other words, you can press the <Tab> key before you type a line of code for it to indent to the proper place. Or, you can press the <Tab> key while on a line, to fix its indentation after the fact.

    Look at the loop in sum1.cpp, whose indentation is messed up:

        for (int i = 0; i < howmany; i++) {
          float value;  // The current value.
    
      // Read the ith number.
          cout << "Enter number: " ;
          cin >> value;
        
       // Increment the sum.
          sum += value;
          }
    
    Now, go to each line of the loop and press <Tab>, it should fix the indentation for each line, producing something like:
      for (int i = 0; i < howmany; i++) {
        float value;  // The current value.
    
        // Read the ith number.
        cout << "Enter number: " ;
        cin >> value;
        
        // Increment the sum.
        sum += value;
      }
    }
    

    You'll want to explore the other features that Emacs gives you in C++ mode.

    Don't forget to save your changes when you are done by using Save Buffer from the Emacs Files menu. Shut down Emacs by choosing Exit Emacs from the Emacs Files menu.

  3. Using multiple buffers inside Emacs:

    While working on a program, we may need to edit some source code, compile and run it, edit other files and so on. There is no need to start up and shut down Emacs each time we need to go back to the UNIX prompt or need to load a different file. Instead, using features of UNIX and Emacs, we can leave Emacs up during our entire login session.

    First, we should take care to start up Emacs as:

    % emacs &
    

    By using the ampersand (&) at the end of the command, we'll get a UNIX prompt back right away, where we can type more UNIX commands. Without the &, the UNIX window waits for Emacs to exit before it will let us type more commands.


    Note: Use & at the end of any UNIX command that brings up its own window and runs for a while.

    Suppose, we need to work with 2 files in Emacs, like sum1.cpp and avg1.cpp.

    (If you don't already have those files, download them into your current directory now.)

    Now, let's load them into Emacs. Choose Open File... from the Emacs Files menu. At the bottom of the Emacs screen, it will prompt your for a file name:

    Find file: curr-dir/
    
    (where curr-dir is your current directory), type in the name of the file, giving:
    Find file: curr-dir/sum1.cpp
    
    and press <Return>. It should load the file into the window.

    Now, let's split the Emacs window into 2 by choosing Split Window from the Emacs Files menu.

    Note that Emacs has split its window into 2 parts (or subwindows), each with the same file in it:

    Picture of divided Emacs screen

    Then, click in the lower window, and use the Open File... command (again, from the Files menu) to load avg1.cpp in the lower window.

    We can now click in the 2 subwindows to edit either one.

    Suppose we want to spent some time on sum1.cpp, so we want it to be the only window. We can do so by clicking in the upper window (where sum1.cpp is loaded) and the choosing One Window from the Emacs Files menu.

    Finally, suppose we need avg1.cpp back. Just click in the Emacs subwindow where you want it (there is only one now) and choose avg1.cpp from the Buffers menu.

    Until we exit Emacs, we can switch between loaded files in this way.

  4. Compiling inside Emacs:

    Not only can we compile programs at the UNIX prompt, but we can also compile them inside of Emacs. Compiling programs while inside Emacs makes it very easy to go through the source code and look at what caused the errors and warnings reported by the compiler.

    For this example, we'll use a program that sums numbers, sum1.cpp.

    (If you don't already have that file, download it into your current directory now.)

    If you are not already running Emacs, start it up:

    emacs &
    

    To compile while in Emacs, use the Emacs command:

    <Esc> x compile

    At the bottom of the Emacs screen, it will ask you what UNIX command to use for compilation. The default is make -k (make is a separate topic), so erase that and type whatever compilation command you'd use at the UNIX prompt:

    g++ -o total sum1.cpp
    

    Note that we told g++ to name the executable total.


    Aside: The code you are compiling should be in the same directory as the one in which you started up Emacs.

    Note that Emacs has split its window into 2 parts (or subwindows), one of which contains the output of the attempt to compile the program:

    Picture of divided Emacs screen

    This compilation window contains all the usual output from the compilation process, including some compiler warnings/errors:

    sum1.cpp: In function `int main()':
    sum1.cpp:21: parse error before `float'
    sum1.cpp:28: `O' undeclared (first use this function)
    sum1.cpp:28: (Each undeclared identifier is reported only once
    sum1.cpp:28: for each function it appears in.)
    sum1.cpp:36: `sum' undeclared (first use this function)
    sum1.cpp:39: confused by earlier errors, bailing out
    

    We could search through the source code in an another Emacs subwindow to examine and fix the errors, but there is an easier way:

    1. Click in the compilation window (this is the one where the compilation errors appeared). Note that a new menu appears, labeled Compile.

    2. Pull down the menu to look at its contents...

      Picture of Compile Menu

      Remember, Emacs has special modes depending on what it is doing. This menu appears when you are in a compilation window.

    3. Choose First Error from the Compile menu. Note that it automatically loads the source code containing the error in the other Emacs subwindow (if it wasn't already there) and places the cursor on the right line.
      What is the error? Fix it.

    4. Now, click in the compilation window again to get the Compile menu back and choose Next Error from the menu this time.
      Once it is at the next error, determine the error and fix it.

    5. Since we fixed the first 2 errors, let's recompile the program and see if what we fixed was causing the other error messages (i.e., errors often cause other errors).

      Bring up the Compile menu again, and choose Recompile. Note that Emacs knows that you should save the file you are about to recompile, and asks you to do so (choose Yes). Emacs will use the same command we typed originally to recompile.

    6. If you corrected the first 2 errors properly, the program should recompile successfully.

    Since we are done with the compilation window for now, let's get rid of it. Click in the Emacs subwindow that has the source code sum1.cpp and then choose One Window from the Emacs Files menu. We can bring back the compilation window when needed (during this session with Emacs), by choosing it from the Buffers menu.

    Go to the UNIX prompt and run the executable total that was created if you like.

  5. Debugging inside Emacs:

    For this example, we'll use a program that calculates an average, avg1.cpp.

    (If you don't already have that file, download it into your current directory now.)

    If you are not already running Emacs, start it up:

    emacs &
    

    Then, compile the program under Emacs. Remember to:

    1. Use <Esc> x compile
    2. Erase the default, make -k
    3. Type in the proper compilation command (we'll give it an executable name other than a.out):
      g++ -o avg -g avg1.cpp
      

      Note: We've added a new flag -g. If you want to be able to debug a program, you'll have to add this -g option when you compile it.

    The program should compile without any errors or warnings.

    Since we will be running the executable several times to debug it, download this data file numdata.


    Aside: The data file tells the program that there are 4 numbers to average, which are: 10, 20, 30, and 40.

    Now, run the executable on the data file from the UNIX prompt:

    % avg < numdata
    Enter how many numbers I will average: Enter number:
    Segmentation fault
    

    You'll notice that the program produces a nice Segmentation fault. This calls for using the debugger, Gdb! We could run Gdb from the UNIX prompt, but it is more useful to run it under Emacs.

    Running Gdb under Emacs:

    Let's start up Gdb under Emacs:

    1. Select the compilation window by clicking in it (we'll reuse this window for Gdb)
    2. Type <Esc> x gdb
    3. When it prompts you for the command to use to start Gdb:
      Run gdb (like this): gdb 
      
      complete the command with the name of the executable, as in:
      Run gdb (like this): gdb avg
      
    Gdb should now be running in that window. Let's run our executable avg under Gdb.

    If we just wanted to run the executable without using a data file (i.e., the user types in needed input), we could just type "run". However, since we want to use our data file, numdata, we should use input redirection, as in:

    (gdb) run < numdata
    Starting program: yourdir/avg < numdata
    Enter how many numbers I will average: Enter number: 
    Program received signal SIGSEGV, Segmentation fault.
    0x18b5c in _IO_vfscanf (fp=0x32fdc, fmt0=0x0, ap=0xeffff898, errp=0xeffff7c4)
        at /csa/src/egcs-1.1.2/libio/iovfscanf.c:671
    

    The output of the program is shown, just like when the program was run at the UNIX prompt. In fact, we still get the Segmentation fault. What's really nice about Gdb, however, is that it gives us additional information, telling us where the Segmentation fault occurred.

    What may happen, as in this case, is that the Seg fault occurs not in code you wrote, but in some library you used. (Note that it may have loaded that nasty library code in the other Emacs subwindow.)

    Examining the calling chain:

    Although the Seg fault occurred in library code, it was most likely still caused by an error on your part. We need to know how the program got to that library function. To display the calling chain, i.e., the sequence of function calls that lead to the current point in the program, use:
    (gdb) where
    #0  0x18b5c in _IO_vfscanf (fp=0x32fdc, fmt0=0x0, ap=0xeffff898, 
        errp=0xeffff7c4) at /csa/src/egcs-1.1.2/libio/iovfscanf.c:671
    #1  0x15f34 in streambuf::vscan (this=0x32fdc, fmt0=0x22640 "%g", 
        ap=0xeffff894, stream=0x32e84) at /csa/src/egcs-1.1.2/libio/sbscan.cc:33
    #2  0x15e50 in istream::scan (this=0x32e7c, format=0x22640 "%g")
        at /csa/src/egcs-1.1.2/libio/isscan.cc:34
    #3  0x132bc in istream::operator>> (this=0x32e7c, x=@0xadfb2020)
        at /csa/src/egcs-1.1.2/libio/iostream.cc:358
    #4  0x120d4 in main () at avg1.cpp:44
    

    Aha! Now we see that the problem was caused by the code at line 44 in avg1.cpp (i.e., in main()).

    We could load the source code into Emacs and go to line 44 (use <Esc> x goto-line perhaps) and see what is there. Instead, however, we can go back up the calling chain until we are in our code. To do so, use the Gdb up command until we're in main():

    (gdb) up
    #1  0x15f34 in streambuf::vscan (this=0x32fdc, fmt0=0x22640 "%g", 
        ap=0xeffff894, stream=0x32e84) at /csa/src/egcs-1.1.2/libio/sbscan.cc:33
    (gdb) up
    #2  0x15e50 in istream::scan (this=0x32e7c, format=0x22640 "%g")
        at /csa/src/egcs-1.1.2/libio/isscan.cc:34
    (gdb) up
    #3  0x132bc in istream::operator>> (this=0x32e7c, x=@0xadfb2020)
        at /csa/src/egcs-1.1.2/libio/iostream.cc:358
    (gdb) up
    #4  0x120d4 in main () at avg1.cpp:44
    

    Conveniently, Emacs has loaded the source code (avg1.cpp) in the other subwindow and is pointing (with an arrow, =>) to the offending line, i.e., where the program stopped because of the Seg fault.

    Since the line contains an array access, perhaps the problem is an out of range array index? We can display the value of index variable i by using the Gdb print command:

    (gdb) print i
    $1 = -276903488
    

    It's now obvious that i has an incorrect value. Find the source of this problem and then fix it.

    With that error fixed, we should recompile. While the cursor is in the source code subwindow, call up the compilation window...Do this by bringing back its buffer, i.e., choose the *compilation* buffer from the Buffers menu:

    [Buffers menu]


    Aside: Note the *gud-avg* listing for gdb running on avg.

    After bringing up the compilation window, choose Recompile from the Compile menu. Note that it will prompt you to save the edited source code, which you want to do. Make sure that everything compiles ok.

    Now, let's debug this new version of the executable. To get back to Gdb, click in Emacs' gdb window after the (gdb) prompt:

    (gdb)
    We need to re-run the executable; however, we don't want to have to type the redirection stuff every time. So, first do:
    (gdb) set args < numdata
    

    This tells Gdb to use "< numdata" as the argument to the run command.

    Then, run the program:

    (gdb) run
    The program being debugged has been started already.
    Start it from the beginning? (y or n) y
    
    It will ask you if you want to restart the program (remember, we were already running it and it Seg faulted). Just say y.
    `yourdir/avg' has changed; re-reading symbols.
    Starting program: yourdir/avg < numdata
    Enter how many numbers I will average: Enter number: Enter number: Enter number\
    :Enter number: The average is: 0
    Thank you for using the averager!
    
    Program exited normally.
    

    Notice that Gdb automatically notices that there is a new version (i.e., we just recompiled it) of the executable. Once it loads in the new version of the executable, it will run it on the data file.

    What's nice is that the Segmentation fault is now gone, and the "Program exited normally." However, we now seem to have a logic error since the average shouldn't be zero.

    Stopping the program while it is running:

    A main feature of a debugger is that we can tell it to stop a program while it is running so that we can examine variables, etc.

    The first thing we might check to find this error is to make sure the numbers are read into our program properly.

    Bring the source code back:

    1. Click in the compilation window
    2. Choose avg1.cpp from the Buffers menu

    Now scroll to the line just after when the numbers are read in, i.e., go to:

    cout << "The average is: " << avgNumbers(numbers, howmany) << endl;
    

    Note this statement's line number (listed at the bottom of the Emacs subwindow with the source code). It should be line 47, but might be something else if you added blank lines, etc. This line would be a good place to stop the program and then check all the numbers. We can tell Gdb to stop the program at this line by setting a breakpoint.

    Go back to the Gdb window (i.e., click in it after the prompt) and type:

    (gdb) break 47
    Breakpoint 1 at 0x120ec: file avg1.cpp, line 47.
    


    Aside: Gdb assumes the line number refers to a line in the source code file from which it last performed a statement. Since, right now, our executable is only made up of one source code file, this doesn't matter.

    However, if you needed to refer to a line in another source code file, you'd use the form "filename:line" as in:

    break avg1.cpp:47
    

    Now, re-run the program:

    (gdb) run
    Starting program: yourdir/avg < numdata
    Enter how many numbers I will average: Enter number: Enter number: Enter number\
    : Enter number: 
    Breakpoint 1, main () at avg1.cpp:47
    

    The program should stop at the designated line. Also, notice that Emacs is following the source code (with an arrow, =>) in the other subwindow.


    Note: When Gdb stops at a line, it hasn't performed that line yet. For example, line 47 has not been done in this case.

    Now, we can display the elements of the numbers array with the print command (you can use print to display the result of any expression). Do:

    (gdb) print numbers[0]
    $1 = 10
    (gdb) print numbers[1]
    $2 = 20
    

    These seem to be ok, so we won't really need this breakpoint (notice it's breakpoint #1) anymore. Remove it with:

    (gdb) delete 1
    

    The next place we might look is in the function that calculates the average, avgNumbers(). To set a breakpoint that will stop the program when it gets in that function, we can do:

    (gdb) break avgNumbers
    Breakpoint 2 at 0x121a8: file avg1.cpp, line 59.
    


    Aside: When setting a breakpoint for a member function (method) of a class, you'll need to specify the function in the form "Class::member-function-name" as in:
    break Point::get_x
    

    Continuing program once it has been stopped:

    What we want to do now is to have the program continue to run until it hits another breakpoint. Do:
    (gdb) continue
    Continuing.
    
    Breakpoint 2, avgNumbers (numbers=0xeffff920, howmany=4) at avg1.cpp:59
    

    The program continued and then should have stopped in avgNumbers() like we asked it to.


    Note: It displays the values of the parameters of the function avgNumbers() in which it stopped. Since numbers is an array, it displays its address.

    As usual, it is following the code in the source code window.


    We may want to see what happens after it performs the statement:

    int sum = sumNumbers(numbers, howmany);
    

    To just perform this statement and have the program stop again, use the next command. Then, we can examine the sum with print:

    (gdb) next
    (gdb) print sum
    $3 = 0
    

    A sum of zero is clearly wrong. This implies that function sumNumbers() is probably not calculating the sum correctly. Let's explore this theory...

    Start by re-running the program under Gdb:

    (gdb) run
    The program being debugged has been started already.
    Start it from the beginning? (y or n) y
    
    Starting program: yourdir/avg < numdata
    Enter how many numbers I will average: Enter number: Enter number: 
    Breakpoint 2, avgNumbers (numbers=0xeffff920, howmany=4) at avg1.cpp:59
    

    We again stop at our breakpoint in avgNumbers(). This time, instead of using next to perform the call to sumNumbers(), let's use step, so that we step into that function:

    (gdb) step
    sumNumbers (numbers=0xeffff920, howmany=4) at avg1.cpp:65
    

    Now that we are in sumNumbers(), we see that the variable we'll want to examine is sum. Rather than using print to view its value as we go through the function, we can use the display command:

    (gdb) display sum
    1: sum = 0
    

    which will display the value of that variable every time the program stops.

    We'll want to go through the loop statement by statement and see how sum changes. First, go to the loop with:

    (gdb) next
    1: sum = 0
    

    Now, start the loop with:

    (gdb) next
    1: sum = 0
    
    Since this is a for loop, it has done what part(s) of the loop?

    Now, let's do the assignment statement in the loop body:

    (gdb) next
    1: sum = 0
    

    Hmmm...The sum did not change (we want it to!)

    Let's continue the loop for another iteration:

    (gdb) next
    1: sum = 0
    
    What part(s) of the loop did it just do?

    Do the assignment in the body of the loop one more time:

    (gdb) next
    1: sum = 0
    
    Again, sum does not change. Aha! We think we know what is causing the error.

    Changing variables while program is running:

    What we can do now is correct the value of sum and see if the rest of the program doesn't mess it up. Let's give the sum variable the value it should have:
    (gdb) set variable sum = 100
    
    (i.e., 10+20+30+40).

    And, we'll let the program continue to run:

    (gdb) continue
    Continuing.
    The average is: 25
    Thank you for using the averager!
    
    Program exited normally.
    

    You can see that we get the correct average, based on the value we just gave sum. So, the error in sumNumbers() is probably the only place needing to be fixed.

    Fix the problem, recompile, and see if the program runs properly now.

    Getting help in Gdb:

    Note that the Gdb commands we've learned (plus others) are described by the Gdb help command. Use:
    (gdb) help
    

    to look up categories of help topics. Use help category, e.g.:

    (gdb) help running
    

    to list the commands in that category. And, use help command, e.g.:

    (gdb) help run
    

    to look up a specific command.

    The End:

    Finally, don't forget to quit the debugger:
    (gdb) quit
    
    Debugger finished
    

    before exiting Emacs.


BU CAS CS - Using Emacs for Programming
Copyright © 1993-2000 by Robert I. Pitts <rip at bu dot edu>. All Rights Reserved.