CDT Developers FAQ - temporary
Table of Contents

Intro

If you write Eclipse plug-ins that integrate with CDT http://www.eclipse.org/CDT on some level, you often need to access and/or manage the project's CDT configuration programmatically. Unfortunately, there's little documentation on the CDT build system's internals; also, Javadoc comments in the source are rare, and actually useful & up-to-date Javadoc comments are even rarer.

The purpose of this page is to collect some information in a FAQ form, to help developers get started with this task. If you come by some useful piece of information, please add it here!

This page is not part of the CDT Devopers FAQ (http://wiki.eclipse.org/CDT/Developer/FAQ) because I didn't want to give the false impression that any of it is "official" information, but I'll be happy to contribute it to the FAQ if someone from the CDT Team reviews it and weeds out the mistakes.

If you want to contact me: a n d r a s omnetpp org, remove the spaces


Project, project description, build info

Accessing the build info

The starting point anything related to build info is ManagedBuildManager.getBuildInfo():

IProject project = ...;
IManagedBuildInfo buildInfo = ManagedBuildManager.getBuildInfo(project);

ManagedBuildManager is a central class with lots of static methods, most of them utility methods.

NOTE: ManagedBuildManager.getBuildInfo() actually takes IResource, but don't be fooled by that: it will return exactly the same object for any resource in the project (it only uses resources.getProject()). The argument should really be IProject.

IManagedBuildInfo can tell you all build-related information about the project, including configurations, pre and post-build steps, include paths etc.


How do I change the contents of the ".cproject" file?

There seems to be two way: (A) via the project description (cdt.core plug-in), and (B) via the managed build managed (cdt.build plug-in)

(A) Get the project description (ICProjectDescription) for the project,
modify the project description, and set it back on the project.

IProject project = ...;
ICProjectDescription projectDescription = CoreModel.getDefault().getProjectDescription(project);
// manipulate projectDescription...
CoreModel.getDefault().setProjectDescription(project, projectDescription);

TODO It is unclear what needs to be done for the changes to get reflected in IManagedProject and IManagedBuildInfo.

(B) Obtain the IBuildInfo from ManagedProjectManager, do changes on it, then invoke ManagedBuildManager.saveBuildInfo(IProject, boolean).

IProject project = ...;
IManagedBuildInfo buildInfo = ManagedBuildManager.getBuildInfo(project);
// change things in the buildInfo
ManagedBuildManager.saveBuildInfo(project, true);

This seems to be the preferred way.


How do I get an IProject?

That's basic platform stuff, handled by the resources plugin. For example, if you know the project name, you can write:

String name = ...;
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(name);

How do I get an ICProjectDescription for my project?

Use CoreModel.getDefault().getProjectDescription(IProject).


What are IManagedProject, IManagedBuildInfo and ICProjectDescription, and how are they related?

IManagedBuildInfo seems to wrap an IManagedProject. I guess IManagedProjects don't exist independently (?).

TODO figure out relationship of IManagedBuildInfo vs ICProjectDescription. They look similar, e.g. both manage configurations (IConfiguration vs ICConfigurationDescription).

In any case, the first two are "build" stuff (managed by ManagedBuildManager, "cdt.build" plugin), and ICProjectDescription is "core" stuff (managed by CoreModel, "cdt.core" plugin).

TODO figure out how they are kept consistent…


Should I prefer ManagedBuildManager.saveBuildInfo(…) or CoreModel.setProjectDescription(…)?

Some comments from Mikhail Sennikovsky on cdt-dev on this:

"Actually you could use both methods. There is a slight difference between them though. With the first method the “real” configurations are accessed/modified directly and then applied, i.e. you are directly modifying configurations being used by the other parts of the CDT (e.g. the project builder), thus there is a risk that your modifications are made concurrently with accessing those settings by others (e.g. builder) making there behavior inconsistent. The second approach is more “safe” in that the modifications are being made to the configuration “copy” and then atomically applied to the entire system. So I would prefer using the second approach [i.e. setProjectDescription()]."


What are the MakeProject and ManagedMakeProject classes for?

They are probably dead code, left over from earlier CDT versions (at least they are not used anywhere). Should probably be removed.


Configurations

How do I access the active configuration, or all configurations?

CDT configurations (as in "Release", "Debug") are represented by IConfiguration. You can get the currently active configuration by calling IBuildInfo.getDefaultConfiguration():

IConfiguration activeConfig = buildInfo.getDefaultConfiguration();

NOTE: Don't confuse this with getSelectedConfiguration(), which is a UI thing (it returns the configuration last selected in the property pages).


What is the relationship of IConfiguration and ICConfigurationDescription? If I change one, does the other change as well?

ICConfigurationDescription represents configuration in CDT core level, and IConfiguration represents configuration in CDT build system level. While only one CDT core implementation exists, there may be a lot of different build systems (at least in theory). The existing Managed Build System is only one among other ones.

ICConfigurationDescription, in principle, does not know about build-system specific features implemented by IConfiguration instances. So we should change "common" properties in ICConfigurationDescription, and build system-related properties in IConfiguration implementor. When setProjectDescription() called, both changes would be applied.


How to get IConfiguration from ICConfigurationDescription, or the other way round?

One way to get IConfiguration is ManagedBuildManager.getConfigurationForDescription(ICConfigurationDescription). What this method really does is unclear.

TODO ICConfigurationDescription from IConfiguration


Accessing and changing settings

How do I find out if a project uses Managed Make or Standard Make?

On the UI this corresponds to the "Generate Makefiles automatically" checkbox on the "C/C++ Build" page of the project properties dialog.

In the ".cproject" XML, you will find a managedBuildOn="true/false" attribute on the <builder> element within the <configuration> elements. (Note that this is a per-configuration setting!!!)

Programmatically, the same value is returned by the IConfiguration.isManagedBuildOn() method. Example:

IProject project = ...;
IConfiguration activeConfig = ManagedBuildManager.getBuildInfo(project).getDefaultConfiguration();
boolean isManagedMake = activeConfig.isManagedBuildOn();

You may want to check this setting in all configurations not only on the active one.


How do I switch a project from Managed Make to Standard Make or vica versa?

Use the IConfiguration.setManagedBuildOn(boolean) method. You may want to change only the active ("default") configuration, or all configurations. To save the changes, call ManagedBuildManager.saveBuildInfo(IProject, boolean).

IProject project = ...;
IConfiguration activeConfig = ManagedBuildManager.getBuildInfo(project).getDefaultConfiguration();
activeConfig.setManagedBuildOn(true);  // or false
ManagedBuildManager.saveBuildInfo(project, true);

How do I set the indexer settings on a Standard Make project?

Unfortunately there is only one internal class to do this: IndexerPreferences

// activate project specific settings
IndexerPreferences.setScope(project, IndexerPreferences.SCOPE_PROJECT_PRIVATE);

Properties props = new Properties();
props.put(IndexerPreferences.KEY_INDEXER_ID, "org.eclipse.cdt.core.nullindexer");
props.put(IndexerPreferences.KEY_INDEX_ALL_FILES, "true");
//        props.put(IndexerPreferences.KEY_FILES_TO_PARSE_UP_FRONT, "hugo.h");
//        props.put(IndexerPreferences.KEY_SKIP_ALL_REFERENCES, "false");
props.put(IndexerPreferences.KEY_SKIP_TYPE_REFERENCES, "false");

IndexerPreferences.setProperties(project, IndexerPreferences.SCOPE_PROJECT_PRIVATE, props);

CCoreInternals.savePreferences(project);

Attention: The indexer id used in the preferences is not the id of the "CIndexer" extension point but the id of the "IndexerPage" extension point.


How do I set the build command on a Standard Make project?

Use IConfiguration's methods: setBuildCommand(String), setBuildArguments(String), then save it via ManagedBuildManager.saveBuildInfo(). A slightly different (but apparently more or less equivalent) way is to get an IBuilder using IConfiguration.getEditableBuilder(), and use IBuilder's setter methods. Still needs to be saved afterwards.

IProject project = ...;
IConfiguration configuration = ManagedBuildManager.getBuildInfo(project).getDefaultConfiguration();
configuration.setBuildCommand("gmake");
configuration.setBuildArguments("-f Makefile.mine");
ManagedBuildManager.saveBuildInfo(project, true);

Again, this only changes the active configuration; you may want to iterate over and change all configurations.

Another way via project descriptions (the "core" model). (Based on code from Oleg Krasilnikov):

IProject project = ...;
ICProjectDescription projectDescription = CoreModel.getDefault().getProjectDescription(project);
IConfiguration configuration = ManagedBuildManager.getConfigurationForDescription(projectDescription.getActiveConfiguration());
configuration.setBuildCommand("gmake");
configuration.setBuildArguments("-f Makefile.mine");
CoreModel.getDefault().setProjectDescription(project, projectDescription);

How do I set the build directory on a Standard Make project?

The build directory (which is found on the "C/C++ Build" page in the project properties dialog) is the working directory when "make" is invoked.

The the managed builder API, it can be accessed via IConfiguration.getEditableBuilder():

IConfiguration configuration = ...;
String buildPath = ...;
configuration.getEditableBuilder().setBuildPath(buildPath);

Then save the changes via ManagedBuildManager.saveBuildInfo(..).

In the "core model", the same can be accessed via the following classes: ICProjectDescription —> ICConfigurationDescription —> ICBuildSetting:

ICConfigurationDescription configDesc = ...;
IPath buildPath = ...;
configDesc.getBuildSetting().setBuilderCWD(buildPath);

Don't forget to save the project description afterwards (CoreModel.getDefault().setProjectDescription(…)).


How do I know which folders are marked as source folders in my project?

Use IConfiguration.getSourceEntries() (so, source folders are per configuration!). This method returns an array of ICSourceEntry objects; each one corresponds to a source folder tree, and contains the list of resources that have been excluded from build. Any folder which is outside all source folders also counts as excluded.

Note: the name of ICSourceEntry.getFullPath() is misleading, it actually returns project-relative path!


How do I know if a folder or file is excluded from build?

Resources can be excluded per configuration. The sources entries (ICSourceEntry) in the configuration store whether the resource is excluded. Exclude patterns (*,?) are also supported.

Some confusion arises about how ICSourceEntry stores/returns exclusion entries. getExclusionPatterns() returns IPaths which are relative to the source folder; fullExclusionPatternChars() returns character arrays (!!!) which represent project-relative paths.

Two families of utility functions can be use to check whether a resource is excluded:
CoreModelUtil.isExcluded(…), and CDataUtil.isExcluded(…). The former can only be used if the resource is not null, is under the source folder etc; the latter does these checks for you then delegates to the former. Thus, the latter, CDataUtil.isExcluded(…) is recommended for general use.

The following code checks if the given resource is excluded from build:

IResource resource = ...;
IConfiguration configuration = ...; // see FAQ above
ICSourceEntry[] sourceEntries = configuration.getSourceEntries();
boolean isExcluded = CDataUtil.isExcluded(resource.getProjectRelativePath(), sourceEntries);

How do I access the include paths?

The Include paths are displayed on the UI at properties -> "C/C++ General" / "Paths and symbols" page -> "Includes" tab, and can be specified per language (in addition to per-configuration and per-resource).

They are accessible via the CDT Core model. In nutshell: CoreModel -> ICProjectDescription -> ICConfigurationDescription -> ICFolderDescription -> ICLanguageSetting -> ICLanguageSettingEntry. The ICLanguageSettingEntry you get in the end will also be an ICIncludePathEntry.

Along the way you'll need to know which configuration you want (the active one?), which folder (the project root?), which language (i.e. assembly/C/C++ — this is tricky, see later), and that the "kind" of the ICLanguageSetting we want is ICSettingEntry.INCLUDE_PATH.

Now the code example:

IProject project = ...;
ICProjectDescription projectDescription = CoreModel.getDefault().getProjectDescription(project);
ICConfigurationDescription activeConfiguration = projectDescription.getActiveConfiguration(); // or another config
ICFolderDescription folderDescription = activeConfiguration.getRootFolderDescription(); // or use getResourceDescription(IResource), or pick one from getFolderDescriptions()
ICLanguageSetting[] languageSettings = folderDescription.getLanguageSettings();
ICLanguageSetting lang = ...; // pick one from languageSettings, by id
ICLanguageSettingEntry[] includePathSettings = lang.getSettingEntries(ICSettingEntry.INCLUDE_PATH);

What to do with entries in the ICLanguageSettingEntry[] array you get:

  • toString() prints everything important about the entry — very useful
  • getValue() will tell you the path as string: "C:/mingw/include/c++/3.4.5", "/myproject/myfolder"
  • (getFlags() & ICSettingEntry.VALUE_WORKSPACE_PATH) tells you whether the value string is to be interpreted as a workspace path or a filesystem path
  • isBuiltIn() tells you whether it's a compiler system path ("C:/mingw/include", "/usr/bin", etc). isBuiltIn() is equivalent to (getFlags() & ICSettingEntry.BUILTIN).
  • there are other flags as well that you might be interested in

Getting back to language IDs: it's tricky because they're subject to subclassing. "GNU C++" is "org.eclipse.cdt.core.g++", but MSVC C++ likely has a different ID, so you may want to check for some superclass language ID (or check if the name contains "C++" as substring, but that's dodgy…).


How do I access the library paths?

Much the same way as the include paths, but use ICSettingEntry.LIBRARY_PATH as the "kind" constant.


How do I access the macros (preprocessor symbols)?

Much the same way as the include paths, but use ICSettingEntry.MACRO as the "kind" constant. In the ICLanguageSettingEntry objects, getName() will be the macro name and getValue() the macro value.


CDT Nature

How do I add CDT Nature and Managed Build to an existing project?

If you have an existing project type and want to add CDT capabilities & features to it, you can try the code below in your plug-in:

CProjectNature.addCNature(fProject, mon);
ICProjectDescriptionManager mgr = CoreModel.getDefault().getProjectDescriptionManager();
ICProjectDescription des = mgr.getProjectDescription(fProject, true);

if (des != null)
        return; // C project description already exists

des = mgr.createProjectDescription(fProject, true);

ManagedBuildInfo info = ManagedBuildManager.createBuildInfo(fProject);
IProjectType projType =
         ManagedBuildManager.getExtensionProjectType("my.project.type"); // or get projectType from UI
IToolChain toolChain =
         ManagedBuildManager.getExtensionToolChain("my.toolchain"); // or get toolChain from UI

ManagedProject mProj = new ManagedProject(fProject, projType);
info.setManagedProject(mProj);

IConfiguration[] configs = ManagedBuildManager.getExtensionConfigurations(toolChain, projType);

for (IConfiguration icf : configs) {
    if (!(icf instanceof Configuration)) {
        continue;
    }
    Configuration cf = (Configuration) icf;

    String id = ManagedBuildManager.calculateChildId(cf.getId(), null);
    Configuration config = new Configuration(mProj, cf, id, false, true);

    ICConfigurationDescription cfgDes =
    des.createConfiguration(ManagedBuildManager.CFG_DATA_PROVIDER_ID,
                                         config.getConfigurationData());
    config.setConfigurationDescription(cfgDes);
    config.exportArtifactInfo();

    IBuilder bld = config.getEditableBuilder();
    if (bld != null) { bld.setManagedBuildOn(true); }

    config.setName(toolChain.getName());
    config.setArtifactName(fProject.getName());

}

mgr.setProjectDescription(fProject, des);

Of course, you have to replace "my.project.type" and "my.toolchain" with the appropriate CDT project type and toolchains, respectively.

There's still one caveat, though. You will notice the code directly instantiates an instance of Configuration which is inside an internal package of CDT. Unfortunately, as of now there's no "valid" way to create it with the same parameters as we did. We will have to request an addition to the API to support this.


Toolchains

How does CDT decide whether MinGW, Cygwin or some other toolchain is supported on the computer?

For each toolchain, one can specify a class implementing IManagedIsToolChainSupported in the plugin.xml, and its isSupported() method decides. For MinGW and Cygwin these classes are MingwIsToolChainSupported and IsGnuCygwinToolChainSupported (this is also in use, despite an obsolete comment claiming it is not).

What the code actually does is best to look up in the source, but at CDT 4.0.2 it roughly looks like this:

MingGW

MinGW is supported if the MinGW "bin" directory can be found. The "bin" directory is located in the following way:

  1. Does the <platform-install-dir>/mingw/bin directory exist? if so, use that. Else:
  2. Does the <platform-install-dir>/../mingw/bin directory exist? if so, use that. Else:
  3. Does the "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\MinGW\InstallLocation" registry key exist, and does it contain the name of a directory that has a "bin" subdirectory? If so, that is used, else:
  4. Does "C:\MinGW\bin" exist? Use that if so, otherwise no bonus.

Cygwin

To detect Cygwin, the code first it tries to find the "etc" directory of the Cygwin installation, then it checks whether all required packages are installed.

  1. Finding the "etc"directory is done by checking the registry. "[HKLM|HKCU]\SOFTWARE\Cygnus Solutions\Cygwin\mounts v2" is checked (via launching regedit.exe!)
  2. Checking required packages: The <etc>/setup/installed.db file is supposed to contain lines starting with the following texts: "gcc", "binutils", "make".

Can I add a tool that produces C/C++ source code?

As of CDT 4.0.2, this cannot be gotten to work, due to the following bug: https://bugs.eclipse.org/bugs/show_bug.cgi?id=211858.

A workaround is to bypass CDT, i.e. write your own incremental builder and add it to the platform (org.eclipse.core.resources.builders extension point). Your builder should run before the CDT builder, so that the CDT builder will see the source files your builder created. Of course this is suboptimal — if you can do something so that the above bug gets fixed, please help.


Can I add new tools to a toolchain?

Currently the only way to add tools to toolchains is to "subclass" them in plugin.xml. (See Managed Build Extensibility Document.) This is problematic because:

  1. You have to subclass from each and every toolchain individually (resulting in toolchains like "Mingw GCC with lex/yacc", "Cygwin GCC with lex/yacc", "Linux GCC with lex/yacc", "Solaric GCC with lex/yacc" etc)
  2. Toolchains subclassed into different directions don't mix. If your team adds the bison/flex tools, and my team adds swig support, then a third team wanting to use both in the same project is still doomed: they HAVE TO choose between "MinGW GCC with lex/yacc" and "MinGW GCC with SWIG"!

This is insane. In addition to subclassing, CDT should also allow 3rd party plugins to contribute tools to existing toolchains. Same applies to macro providers etc.

See https://bugs.eclipse.org/bugs/show_bug.cgi?id=212127, and related discussions (or rather, monologues) on the cdt-dev mailing list.

If you agree that this is an important issue and should be fixed in CDT asap, then please make your voice heard in the bugtracker (add comments to #212127) and/or the cdt-dev mailing list. Thanks!


Indexer

Given a function name, how do I find where it is defined and open it?

This method will query the Indexer to find all *definitions* of a function within a project.

public void findFunctionInSource(IProject  project,  String  functionName)  {
  List files = new ArrayList() ;
  ICProject cProject = CoreModel.getDefault().getCModel().getCProject(project.getName());
  IIndexManager manager = CCorePlugin.getIndexManager();
  try {
    index = manager.getIndex(cProject);
    index.acquireReadLock();
    IBinding[] bindings = index.findBindings(functionName.toCharArray(), IndexFilter.ALL, null);
    for (int  binding = 0;  binding < bindings.length; binding++)  {
      if  (bindings[binding] instanceof IFunction)  {
        IFunction  ifunction = (IFunction)  bindings[binding];
        IIndexName[] names = index.findNames(ifunction, IIndex.FIND_DEFINITIONS);
        for  (int j = 0; j < names.length; j++)  {
           IIndexFile  file = names[j].getFile();
           if  (file != null)  {
              IIndexFileLocation filelocation = file.getLocation();
              files.add( filelocation.getFullPath());
           }
           IASTFileLocation location = names[j].getFileLocation();
           if  (location != null)
             int  offset = location.getNodeOffset();
       }
    }
  } catch  (Exception  e)  {
    //..
  } finally  {
    if  (index  !=  null)
      index.releaseReadLock();
  }
}

Other sources of info

Readings


Where can I find examples of programmatic manipulation of the build configuration?

You can find some samples of config setting in CDT Property pages UI.

They are located in 2 places:

  • org.eclipse.cdt.managedbuilder.ui.properties (for MBS-specific settings)
  • org.eclipse.cdt.ui.newui (for CDT core settings).

All classes representing Property pages context have "*Tab" name (ex.: ErrorParsTab.java)

For example, changing build command is performed in org.eclipse.cdt.managedbuilder.ui.properties/BuilderSettingsTab.java, and clean build enabling is made on neighbour tab: org.eclipse.cdt.managedbuilder.ui.properties/BuildBehaviourTab.java.

page_revision: 51, last_edited: 1200053232|%e %b %Y, %H:%M %Z (%O ago)
Unless stated otherwise Content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License