Sams Teach Yourself Emacs in 24 Hours


Hour 19: Programming Utilities

Previous HourNext Hour

Sections in this Hour:


Compiling Programs

If you are authoring software in C, C++, or Java, it is important to know how to compile the software into a machine-usable program. For traditional software systems, this requires a compiler that is controlled by make, which includes the maintenance of a Makefile. For Java or Ada systems, the Makefile is not really necessary because the systems can provide their own commands for compilation and dependency management; however, a Makefile can be used to maintain other aspects of your system.

Regardless of the actual process, Emacs enables you to build your program, watch the output of the compilers, and to easily jump to error locations. If Emacs does not understand the errors that are produced by your compiler, it can be taught.

To compile a program under Emacs, use the compile command; type M-x compile. You are prompted for the shell command that is to be used to compile your program; the default is make -k. If you are not using make, just delete this text and replace it with the command that you need to make your program work. This command is remembered for the next time that you use compile. The compile command prompt is like any other prompt in Emacs in that it accepts M-p and M-n to move backward and forward through the compile command history.

Windows Notes - Microsoft, for reasons known only in Redmond, named their make utility nmake. For ease in compiling programs with Visual C++, insert the following into your .emacs file.

; Compilation setup:
; Visual C++ Debug:
(setq compile-command '("nmake -f .mak" . 10))
; Visual C++ Release:
; (setq compile-command '("nmake -f .mak CFG=\"MyProject - Win32 Release\"" . 10))

This prepares the compilation command default so that you are all set to edit in the name of your makefile just before you execute it.

I've provided you with two default compile commands: one for debug, one for release. If you program like I do, you will use the release one rarely. You can set the default compile command to the release version by evaluating the release version of the Lisp expression. Place the cursor at the end of the line and type C-x C-e.

After Emacs starts the compilation, a buffer titled *compilation* appears. The mode-line contains the string Compiling in all buffers to indicate that something is going on, even if you later hide the *compilation* buffer. When the compilation is finished, a message appears at the end of the buffer telling you the status, and the string Compiling disappears from the mode-line in all buffers. In the *compilation* buffer, the exit status of the compilation tells you how it went. A status of 0 indicates a successful compile.

Tip - To cause the *compilation* buffer to automatically scroll to the end of new output, set the variable compilation-scroll-output to t in your ~/.emacs file as follows:

(setq compilation-scroll-output t)

You do not need to wait for the compilation to complete before you can do something else. You can easily continue editing, or even visit errors and warnings, while the compilation occurs asynchronously. If things get out of hand during the compilation, for example if a runaway process occurs or you have ludicrous amounts of errors, you can put the cursor in the compilation buffer and press C-c C-k to kill the compilation process.

When errors appear in the buffer, Emacs can parse them and bring up the offending code. You can make this happen in a couple ways. First, you can place the cursor on the error that you want and press Enter or C-c C-c. You can also click on the error with the middle mouse button. Any of these techniques enable you to choose a specific error; the file with the error is loaded, and the cursor is positioned on the offending line.

After you've fixed your first error, however, it is not always convenient to move back to the *compilation* buffer. The command next error is available in all buffers that are bound to C-x ´. This command either starts with the first error or moves from the last error to which you went to the next consecutive error within any Emacs buffer. This makes it exceptionally convenient to move across all the errors that are produced by the compiler.

There are a few items available under the menu in a compile buffer as well. Recompile enables you to rerun the compile command using the same command as before. You can also jump to different errors, such as the first or previous error.

Note - You might have noticed that compiling a program is very similar to the grep command that is discussed in Hour 8, "Searching for Text in Multiple Files." compile and grep use the same system for running a subprocess and navigating between hits, which makes it easy to remember how to navigate using these different programs.

Minor Compilations

There are often situations in which the methods of compilation are inappropriate--or too little, too late. One such example involves building a program on a remote machine. You might want to edit your files locally using the virtual FTP filesystem that is covered in Hour 4, "Basic Editing," or you might be working in a *shell* buffer when the errors appear.

The case of the remote system is more interesting, so I'll cover that here. First, you can run a remote login program such as telnet or rlogin from a *shell* buffer, or you can just use the rlogin command, for example M-x rlogin. This enables you to run programs on the remote system and potentially run a compilation.

After a compilation has been started, you can turn on the compilation minor mode in the buffer, enabling the use of all the keystrokes that you learned earlier. To do this, type M-x compilation-minor-mode. You can now use C-c C-c to navigate to an error. Remote buffers such as rlogin are even smart enough to use the correct remote file name. You need to run the compilation-minor-mode command a second time to disable these features to regain use of C-c C-c as a cancel key and Enter for entering new commands in your shell.

Adding Compiler Parsing

Not all compiler error messages are created equal. Some compilers for new languages, or home-grown compilers in large corporations, might not have a recognizable format; therefore, Emacs cannot parse them. Fortunately, there is a method that can be used to teach Emacs about these elements. Performing these tasks requires a knowledge of the compiler and the errors it generates, in addition to some mastery of Hour 9, "Regular Expressions."

First, here's a look at a sample error message format. Pretend that your compiler makes the following error:

Error 51 on line 45 and column 23 of yourfile.c

Now that you have an error, you must create a regular expression to match it. Details on how to do this have already been covered, but in review, the expression "[0-9]+" finds a number, and "\\([0-9]+\\)" not only finds the number, but also tags it as a subexpression.

Therefore, an expression for finding and tagging the important elements for this error, with the added capability of finding warnings, looks similar to the following when it is coded in Lisp:

"\\(Error\\|Warning\\) [0-9]+ on line \\([0-9]+\\) and \ 
     column \\([0-9]+\\) of \\(.*\\)$" 

Now that you know how to create this expression, it's time to teach compile mode how to read it. You do this by modifying the variable compilation-error-regexp-alist. Each element of this list is also a list. The first element is the regular expression that you just created, followed by the tag of the file, the line number tag, and the column number tag. Unfortunately, you cannot just modify this variable in your .emacs file because you need to improve its value and the compilation package has not yet been loaded. You can easily get past this by adding the command

(require 'compile)

before your modification, but this can slow down the loading of Emacs. Instead, you want to add this expression into the main list in a hook. Because you don't want to have the expression loaded into the variable every time, use a function called add-to-list, which only adds something once. The end result follows:

(add-hook 'compilation-mode-hook 
  (lambda () 
    (add-to-list 'compilation-error-regexp-alist 
                 '("\\(Error\\|Warning\\) [0-9]+ on line \ 
\\([0-9]+\\) and column \\([0-9]+\\) of \\(.*\\)$" 
                   4 2 3))) 

You can read the documentation that is associated with the variable compilation-error-regexp-alist for additional details on the format of this list in case your errors are even more complex.

Sams Teach Yourself Emacs in 24 Hours


Hour 19: Programming Utilities

Previous HourNext Hour

Sections in this Hour: