Eclipse CDT

Introduction

Eclipse CDT (C/C++ Development Tools) is an open-source IDE for C and C++ development with advanced code assistance (inheritance/call graph explorer, jump to definition, refactoring, autocomplete, syntax highlighting, and so on).

System requirements

Eclipse will use a lot of memory to fully index the Mozilla source tree to provide code assistance features (easily 4 GB of RAM, although this will drop to just over 1 GB if you restart after indexing is complete). Therefore, it is not recommended for use if your machine only has 4 GB of RAM.

Installing Eclipse

Regarding llvm4eclipsecdt, do not install or select this toolchain for Mozilla development. This plugin is intended mainly for managed projects but we use an unmanaged project for Mozilla (since it has its own build system). Using this plugin will result in parts of the UI described below being hidden or disabled.

Download Eclipse IDE for C/C++ Developers from the Eclipse download page and add the directory containing the eclipse binary to your PATH (/Applications/Eclipse.app/Contents/Eclipse/ on Mac).

(While package managers like snap sometimes provide an eclipse package, they do not include the C++ Developer tools. Since it's a pain to install them and keep them up to date we do not recommend getting Eclipse this way.)

Increase Eclipse's memory limits!

Make sure you do this!

Before you use Eclipse with the Mozilla source you must increase its memory limits. When Eclipse's indexer tries to process the Mozilla source, Eclipse will need considerably more memory than the limits imposed by its default configuration.

You can increase Eclipse's memory limits using the eclipse.ini that lives alongside the eclipse binary. Set an initial heap space of 1 GB and max heap space of 5 GB, say, by modifying the values of the following two lines in eclipse.ini:

-Xms1G
-Xmx5G

If you fail to increase these limits, then you will likely find that Eclipse either hangs when it tries to index the Mozilla source or else that the code intelligence is very broken after the indexing "completes".

Express setup

For the Eclipse indexer to work well you must first build Mozilla, so that it includes headers from the objdir etc. These can be found and processed by Eclipse.

Note: Your MOZ_OBJDIR must be outside the Mozilla source directory.

Once your build is complete, mach can then generate a useful Eclipse project on your behalf. First, make sure that the directory of Eclipse's eclipse binary (typically /Applications/Eclipse.app/Contents/MacOS/ on macOS) is in your PATH. Then, to create the eclipse project and open it, run:

./mach ide eclipse

Or to create the eclipse project without opening it yet, run:

./mach build-backend -b CppEclipse

Building the Eclipse project should only take a few seconds. In the case of the build-backend command, instructions on how to open the project will be displayed after the command completes.

Manual setup, and more

More information can be found on the Eclipse CDT Manual Setup page. Much of that page is redundant (taken care of by the mach setup), but there is still some information there that is relevant that should make its way back here at some point.

Keeping the index up-to-date

As the source changes from day-to-day, you'll want to update the index to keep the code assistance working well.

Since the compiler options used to build the source change relatively infrequently, the "build" step above doesn't need to be rerun all that often. Rerun it (and then rebuild the index) once a week or so, or as necessary when you start to notice unusual code assistance issues that aren't fixed by rebuilding the index alone.

Rebuilding the index itself is required much more frequently since the source changes more frequently. In principle, you can set the index to rebuild automatically by opening the workspace preferences, selecting "C/C++ > Indexer", and reenabling "Automatically update the index". However, you may find this too disruptive, since re-indexing will then happen very frequently and code assistance can be broken while the index is rebuilding. The alternative is to leave that option disabled and update the index manually as necessary. To update the index manually, use the context menu in the Project Explorer tab on the left side of the window. To rebuild for changes in an individual directory (for example, to take account of some changes that you yourself made) select "Index > Freshen All Files" on that directory. To rebuild the entire index (for example when you pull from mozilla-central) select "Index > Rebuild" on the project root.

Usage tips

Below are some of the more useful user tips. (If you're thinking of adding tips, please first consider how widely useful they'll be before adding to this already lengthy page.) For further documentation see the official Eclipse user guide and Eclipse CDT user guide.

Keyboard shortcuts

Regarding key bindings (keyboard shortcuts), the bindings given below are the defaults. You can change the key bindings by opening the workspace preferences (Eclipse > Preferences, or Window > Preferences) and selecting "General > Keys". You can set the scheme to "Emacs" or "Microsoft Visual Studio" if that's your thing, or change individual key bindings. When changing individual key bindings, note that bindings are context sensitive and that any changes you make may be ignored if they conflict with existing bindings, or if they are overridden by a binding for a more specific context. For example, changing the Find Next command to cmd-G/ctrl-G is not sufficient. For that to work you also either need to find the existing bindings for that key combination (using the Bindings column to sort by key combination helps with this) and remove them, or else you need to make your binding very specific by setting the "When" field to "C/C++ Editor" instead of the more general "Editing Text".

Opening files

You can quickly open a file by name using Cmd-Shift-R/Ctrl-Shift-R. Although Eclipse doesn't do fuzzy matching when you type a file name, it does allow you to use wildcards.

To quickly switch between a source file and its header file, use Ctrl-Tab.

To quickly switch to a recently viewed document use Cmd-F6/Ctrl-F6. If you want to change this awkward key binding, the command you need to rebind is "Next Editor".

To show a filterable list of open documents (similar to the way Emacs gives you a list of open buffers), use Cmd-E/Ctrl-E.

If you click the yellow, double arrow button at the top of the Project Explorer tab on the left, it will keep the selected file in the Project Explorer tab in sync with the file that you're currently editing.

Organizing views

Use Ctrl-M to toggle maximization of the current editor view (the editor must be focused first).

To tab to another view, use Cmd-F7/Ctrl-F7. This is useful if you have maximized the editor using Ctrl-M and you want to quickly see your search results. For example, without un-maximizing the editor.

To side-by-side edit the same file in two different tabs, select the tab of the file that you want to edit, then from the menu bar select "Window > New Editor". This will open another tab containing the same file. Now simply drag that tab to position it beside, above, or below the original. Changes you make in one editor will be immediately reflected in the other.

Note that the Search, Call Hierarchy, and other tabs have a "Pin" button that allows you to open multiple tabs of these type. This is useful if you want to keep your existing search results open, for example, and have a new search open in a separate tab rather than overriding the contents of the existing Search tab.

Code assistance

Note: indexing, by its very nature, is specific to a given compiler configuration. Be aware that when Eclipse gives results for any of the actions that follow, it will not include results for sections of the code that are ifdef'ed out by the configuration used to create your object directory. For example, if you are using a Mac and you search for callers of nsDisplayListBuilder::IsInTransform, the results will not include the caller in nsObjectFrame.cpp because that caller is wrapped in "#ifndef XP_MACOSX". Just something to keep in mind. ;-)

To jump to the definition of a symbol (or the declaration of a symbol if already at the definition), hover over the symbol, hold down the Ctrl/Cmd key, move the mouse slightly to linkify the symbol, then click on it. (Having to move the mouse slightly is Eclipse bug 26873). Alternately, you can jump to the definition of the symbol under the cursor by pressing F3.

To do a C++ symbol search select "Search > C/C++" from the menubar, or use Ctrl-H and select the "C/C++" Search tab.

To quickly find the definition of an enum, class, method, etc. use Ctrl-shift-t/Cmd-shift-t.

To get a list of autocomplete options in an editor tab, start typing the name of an identifier and then type Ctrl-Space. Unfortunately, the autocomplete list cannot (currently) be configured to appear automatically as soon as you start typing a character that might be the start of an identifier name.

To see the callers of a method (and their callers, etc.), select the method and use the context menu to select "Open Call Hierarchy". Note that there are buttons to the right of the "Open Call Hierarchy" tab that open to switch between "Show Callers" and "Show Callees".

To see the inheritance tree for a class, select its name in an editor window and select "Open Type Hierarchy" from the context menu. Note that you can switch between "Show the Type Hierarchy", "Show the Supertype Hierarchy", and "Show the Subtype Hierarchy" using the buttons to the right of the "Type Hierarchy" tab.

To see the overrides of a virtual method, select that method's name in an editor window and select "Open Type Hierarchy" or, "Quick Type Hierarchy" from the context menu. The results for "Open Type Hierarchy" will show all classes in the class inheritance tree, and the classes that have methods that override the method will have a triangular red marker beside them. If you select one of these classes, then in the method pane to the right the method you searched for will be highlighted (you may need to scroll to it) - double click to see its definition. The results for "Quick Type Hierarchy" will only show those classes in the inheritance tree that override the method. Double click on a class to go straight to its override's definition.

Building from Eclipse

In short, don't do this. Eclipse doesn't have good facilities for building incrementally in individual directories in the way that Mozilla developers generally require. More importantly, unless you're willing to screw up Eclipse's code assistance (in which case why bother using Eclipse) you're going to have to set Eclipse's "Build" step to do a very slow, non-parallel, full rebuild. (See the "Code assistance" section above for why.)

Nevertheless, if you understand the above warning and you still want to configure Eclipse's "Build" button to invoke a real build, then read on.

Basically, you want to do something similar to the steps in the Initial project properties section above, but use "make -j1 -wB" (or just "make" if you don't care about keeping code assistance working) instead of using just-print-mozilla-build.py.

If you want to invoke "make -f client.mk" from your source directory instead of invoking 'make' from your object directory, then in the "C/C++ Build" section of the project properties, set "Build command" to "make -f client.mk" and set "Build directory" to just "${ProjDirPath}" (this is the top of the source tree). Select the Behavior tab and remove the "all" from the "Build (Incremental build)" field. Select "C/C++ Build > Build Variables", and add a variable "MOZCONFIG", and set it to the path of your .mozconfig file relative to the top source directory. Set any other environment variables you want to set for the build, then close the project properties window.

Now when you hit the Build button (the little hammer icon), you should see the source build in the Console tab at the bottom of the window.

The benefit of building from inside Eclipse is that build errors will appear in the Problems tab at the bottom of the window, and from there you can double click on the build error and it will take you straight to the source file and line where the problem occurred. For this to work reliably though, you still need to build using slow -j1 -w builds, so that make outputs non-interleaved "Entering"/"Leaving" lines. It also used to be necessary to add the following two lines to your mozconfig to make the compiler output errors all on a single line, but that may not be needed anymore:

export CFLAGS="-fmessage-length=0"
export CPPFLAGS="-fmessage-length=0"

Debugging

To create a debug configuration, open the project properties window, and select "Run/Debug Settings" on the left. Click "New", then select "C/C++ Application". In the window that opens enter the path to your firefox binary (something like {your-obj-dir}/dist/NightlyDebug.app/Contents/MacOS/firefox) and select "Disable auto build". Select the Arguments tab and enter any args you want to pass to firefox (such as "--no-remote -p my-testing-profile"). If you're on Linux, you may also need to set the "Working directory" to {your-obj-dir}/dist/bin, and then select the Environment tab and set LD_LIBRARY_PATH to ".:./plugins:." and LIBRARY_PATH to ".:./components:.". (Are these variables really necessary? If so, why? Isn't LIBRARY_PATH for compile time, not runtime, linking?)

In the workspace preferences, you may want to go to "C/C++ > Debug > GDB" and deselect "Stop on startup at", so that Eclipse won't automatically break in main() when it launches Firefox for debugging.

To debug, click the Debug button on the toolbar, or select "Run > Debug" from the menu bar.

It's not obvious, but you can get a gdb prompt in the console so that you can type gdb commands directly.

After you've finished debugging, you can get back to the C/C++ perspective (i.e. window layout) via the menubar by selecting "Window > Open Perspective > C/C++".

Upgrading GDB on Mac

The ancient, barely maintained Apple fork of GDB that comes with Xcode on Mac is really horrible. If you use Mac, you may want to build the latest FSF version of GDB and set Eclipse to use that GDB for debugging. One suggested configuration for building GDB is '--prefix="$HOME" --disable-debug --with-python=/usr' (create an optimized build with support for Python (so that you can use python to much better control when you break etc.), and install it in $HOME/bin). That done, open the workspace preferences, select "C/C++ > Debug > GDB", and set "GDB Debugger" to the full path of your new gdb executable.

GDB unexpectedly detaching

If GDB starts ignoring your breakpoints, or unexpectedly terminates or detaches from the Firefox process, this may be caused by out of date breakpoints (breakpoints that you set during a previous debug session, after which you've since rebuilt). Remove any such breakpoints and restart your debug session.

Known Issues

There are various known limitations and bugs when it comes to using Eclipse with Mozilla. Eclipse is open source, of course so if anyone feels like doing a bit of Java hacking to fix these issues that'd be great.

Headers are only parsed once

For performance reasons, Eclipse only processes header files that have include guards once, using the compiler options for the first source file it encounters that includes that header (Eclipse bug 380511). This is responsible for most of the parse errors in the source files displayed in Eclipse. One problem with the "parse once" strategy is that the compiler options for the original source file may ifdef out sections of the header, that would not be ifdef'ed out - and in fact are required by - source files in other parts of the tree.

For example, in content/svg/content/src/nsSVGEllipseElement.cpp Eclipse shows a parse error due to NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO not being defined. This define is in nsDOMClassInfoID.h, which is included via the following include chain:

content/svg/content/src/nsSVGEllipseElement.cpp
 content/svg/content/src/nsSVGPathGeometryElement.h
  content/svg/content/src/nsSVGGraphicElement.h
   content/svg/content/src/nsSVGStylableElement.h
    content/svg/content/src/nsSVGElement.h
     content/base/src/nsGenericElement.h
      obj-debug/dist/include/nsDOMClassInfoID.h

In nsDOMClassInfoID.h the NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO define is behind an |ifdef _IMPL_NS_LAYOUT|. The properties for nsSVGEllipseElement.cpp show that this define was picked up by the build option discovery and set on nsSVGEllipseElement.cpp, but somehow it's not set for nsDOMClassInfoID.h. However, if you right click on nsDOMClassInfoID.h in the Project Explorer and select "Index > Create Parser Log File", the log shows "Context" is set to "accessible/src/base/AccEvent.cpp", not "content/svg/content/src/nsSVGEllipseElement.cpp", and if you check the properties for AccEvent.cpp, indeed it is not built with the _IMPL_NS_LAYOUT define.

One way to mitigate this problem is to explicitly define defines on problem directories. For example, to solve the _IMPL_NS_LAYOUT issue described above, you would use the context menu for the 'layout' directory in the Project Explorer tab to open the directory's properties. You'd select "C/C++ General > Prepocessor Include Paths, Macros etc.", and select "GNU C++" and "CDT User Settings Entries". You'd then click "Add", select "Preprocessor Macro" from the drop-down, and set Name to _IMPL_NS_LAYOUT and leave Value blank. Finally, you'd click OK twice to return to the main Eclipse window, and then use the context menu for the 'layout' directory to re-index the 'layout' directory, and then to "Run C/C++ Code Analysis" on it to see if the problem is fixed.

This "parse once" strategy can also cause "Unresolved inclusion" errors in headers if the first time Eclipse sees the header is while indexing a file for which it doesn't have any build output parser data. (Since it then has no explicit include paths to search.) When this happens it frequently causes knock-on errors for the files that include that header (directly or indirectly), since they too now have things missing. People who have their object directory outside their source directory need to take special note of this issue. When the object directory is inside the source directory (and not filtered out by a resource filter), then Eclipse's "Allow heuristic resolution of includes" option (enabled by default) will generally allow the included headers to be found when Eclipse processes source files, that don't have any build output parser data. However, when the object directory is outside the source directory, Eclipse doesn't know about it - or the headers it contains - unless the user takes extra steps to tell it. This is the reason that the instructions in the Initial project properties section above instruct users that have their object directory outside their source directory to explicitly add {objdir}/dist/include to the project's "CDT User Setting Entries".

Fixing Eclipse bug 381601 would considerably reduce the impact of the "Unresolved inclusion" issue. (Update 2017-03-28: The option Index all header variants has been added in version 8.3.0, as explained in a comment of the mentioned bug. This option allows to have multiple definitions for the same header file, which might fix this issue. Update 2017-11-04 by jwatt: Ticking the "Index all header variants" option caused Eclipse to blow through the 12 GB of RAM I'd given it while indexing before it ran out of memory and crashed.)

There are parser errors

It is expected that Eclipse will show parser errors even for a known-good copy of the Mozilla source. Parser errors/warnings are indicated by red/yellow markers on files in the Project Explorer tab, and in the gutter down the right-hand side of open source files. In the case of the latter you can click on the marker to jump to the problem line and then hover over the "bug" icon to get an explanation of what's wrong.

The parser error indicators don't seem to show (reliably?) until you open a source file, then error markers will be added for that file. To force all markers to show for a directory in the Project Explorer tab, right-click that directory in the Project Explorer tab and select "Run C/C++ Code Analysis". As well as adding the markers, this will give you a list of the issues in the Problems tab at the bottom of the window where you can double-click to jump to the location of any given issue.

Many of the parser errors are the result of the Headers are only parsed once issue, while others are the result of Eclipse trying to do its best to process files that are not built under your configuration (e.g. files compiled only on other platforms) and that therefore have no build output parser data associated with them.

If you are trying to dig into a particular parser errors to figure out what it's about, here are a few things you can try:

  1. Select your project in the Project Explorer, then from the context menu select "Index > Search for Unresolved Includes".
  2. For problematic source files, select the file in the Project Explorer and from the context menu select "Index > Create Parser Log File".
  3. Select your project in the Project Explorer, then from the context menu select "Index > Rebuild". When the indexing is done, open the log using "Window > Show View > Other > General > Error Log" and check the summary and look for exceptions.

Searching

Free text search is not backed by a database, so it is extremely slow. Furthermore, the results are not saved so if you immediately search for the exact same text again without any changes to the source files having occurred, Eclipse will do a slow search all over again.

It is not easy to restrict searches to an arbitrary directory, which is pretty annoying given how slow free text search is. (You have to create a new working set containing that directory.)

Search history in a project is not preserved across restarts.

Duplicate searches in history - even consecutive ones - are not coalesced.

Duplicate files

Sometimes when searching for files or symbols you will be given the option between a file in the source tree, and a file of the same name under the object directory. (Some source and header files are copied to the object directory by the build process, so we end up with copies in both places.) This will happen if your object directory is inside the source directory. If you don't want to switch to using an object directory that's outside your source tree, then this is just one of those things that you'll have to live with. (If you do change the location of your object directory, then note the instructions that will then apply to you in the Initial project properties section above!) Since the indexer needs to be able to resolve header files in the object directory in order to produce good results, we can't have Eclipse ignore the object directory. But then there's no way to tell Eclipse that any given file in the object directory is actually just a copy of a given file in the source directory and that it should always show the user the copy in the source directory while using the file in the object directory for indexing.

Building

Eclipse's support for building only in certain directories is non-existent. It would be great if the Console tab gave you a shell prompt so that you could invoke commands to build directly from there.

Failing that, it would be nice if Eclipse could at least pass information about what files have changed to the build process, which could then decide on a faster way to do the build (e.g., "just make in layout/"). I (roc) have actually written a small change to the CDT Make builder that lets you specify that as an option, in which case Eclipse sends the names of all changed files to your build tool. The build tool is a Perl script that figures out if a faster build is possible and if so, does it.

FAQ

Here are some frequently asked questions.

Why does Eclipse need an object directory?

To provide good code assistance Eclipse needs you to have a build directory for two reasons.

First, Eclipse needs to be able to collect a usable set of defines, include paths, and preinclude files for the source files in the tree, as explained in the Code assistance section above.

Second, Eclipse CDT's indexer needs an object directory because virtually all Mozilla source files include header files (directly or indirectly) that have been copied to or generated in the object directory. Without an object directory, the indexer would find that a lot of header files are missing when processing the source files, which would significantly degrade its ability to index the source and provide good code assistance.

How can I open Eclipse for multiple trees at once?

To be able to open more than one workspace at a time, you currently need to launch a separate Eclipse process for each workspace.

On Mac, create a script called something like open-my-workspace.py, give it the following contents, replacing the bold paths as appropriate, and make it executable (chmod a+x open-my-workspace.py):

#!/usr/bin/env python
import os, subprocess
eclipse_app_path = "path/to/Eclipse.app/Contents/MacOS/eclipse"
workspace_path = os.path.join(os.environ['HOME'], "HOME/relative/path/to/the/directory/of/the/workspace/you/want/to/open")
subprocess.Popen([eclipse_app_path, "-data", workspace_path])
# Uncomment the following line to automatically close the Terminal window
# that opens if you run this script by double clicking it in Finder.
#subprocess.Popen(["osascript", "-e", 'tell application "Terminal"', "-e", "close front window", "-e", "end tell"])

TODO: add instructions for Linux and Windows.

Is there a Mercurial plugin for Eclipse?

There is MercurialEclipse, but probably most Mozilla developers will just prefer to use the command line. If you think we need our own documentation on MercurialEclipse, please consider adding a separate page for that tool since this page is already pretty long.

How can I delete my Eclipse project and start over?

If you followed the recommendation above to create one workspace containing only one project for each Mozilla tree, then this is easy. (If you didn't, and you have projects for more than one source tree entangled in a workspace directory, well, you're on your own.) Simply delete the .project and .cproject files and the .settings directory (if it exists) from the root of your Mozilla tree, and then delete the workspace directory corresponding to your tree. That's it; you can now create a new Eclipse workspace and project for your tree from scratch.

Isn't there a better method of build option discovery?

Yes, but Eclipse doesn't currently support it. Instead of processing build console output, Eclipse could use something like LD_PRELOAD to load its own little library into all the processes that are invoked as part of the build process. This library could then check whether the process is a compiler instance and, if so, use the processes' current working directory and the arguments that were passed to it to reliably obtain the information it needs for each source file that is compiled. This would eliminate the requirement for non-parallelized, non-silenced builds. You could also build from Eclipse and get the benefits that that brings.

How can I run a more recent CDT version?

This can be useful if you need to get certain bug fixes, or to help with testing to make sure that new Eclipse bugs that affect its use with Mozilla don't get shipped. If you've downloaded an Eclipse Developer build then you can use Eclipse's software update mechanism to update your developer snapshot to the latest nightly for that developer branch. To do that, carry out the following steps.

From Eclipse's "Help" menu select "Install New Software...", then in the "Install" window that opens, click "Available Software Sites". In the window that opens, click "Add", and in the prompt set Name to something like "Nightly" and Location to something like "http://download.eclipse.org/tools/cd...s/juno/nightly" (change "juno" to the current developer branch). Click "OK", then "OK" again. Type "Nightly" into the "Work with" field and select the repository that you just added. (If it doesn't appear, close the window, reopen it from the Help menu, and try again.) A "CDT Main Features" option should now have been added in the area below. Tick this (all of its sub-options should then be ticked), click "Next" twice, accept the license agreement, and then click "Finish". Eclipse should now update itself and ask you to restart.

Troubleshooting: If you get an error when trying to update, try clicking "Available Software Sites" in the "Install" window, make sure "Juno" is still unticked, that "Nightly" is ticked, highlight "Nightly", click "Reload", "OK", and then try again.

Troubleshooting

Here is a list of problems people have encountered, and suggestions for solutions.

Problem Occurred (Java heap space)

If Eclipse becomes glacially slow or hangs and then you get this error message, see the Increasing memory limits section above. If you already carried out the instructions in that section, then double check that your changes to Eclipse's memory limits actually took effect and are present in Eclipse/Help > About Eclipse > Installation Details > Configuration. If they did, then maybe you need to increase the limits still further for your OS/JVM combination.

Resource is out of sync with the file system

If you get the message "Resource is out of sync with the file system", then you didn't set the "Refresh" options above in the Initial workspace preferences section. Either set those, or else refresh the project (or an individual directory/file) manually using the Refresh item from the context menu in the Project Explorer tab.

Old

Everything that follows is old content that should maybe just be deleted now?

GDB Timeouts

I don't think this old comment from 2007/2008 is an issue anymore.

Out of the box, you may/will get GDB connection timeouts. This is because Eclipse is trying to push every subfolder in GDB's environment. The easiest way to resolve this issue is to remove any source entry from the debug configuration (Run->Open Debug Dialog...) in the Source tab. Doing so will, unfortunately, remove the binding between the binaries and the source code. To keep this feature working, you need to add a "Path Mapping" by clicking "Add..." in the Source tab. Once a "Path Mapping" is created, select "Edit..." and add an entry with these values

 Compilation path: / 
 Local file system path: /

This is the only known workaround to bind binaries to source files. It has been tested and works perfectly under Eclipse Europa (3.3.2) with Eclipse-CDT (4.0.3).