Search code examples
javaeclipseeclipse-plugineclipse-cdt

Eclipse .cproject programmatic creation


I've got Eclipse plugin code that programmatically creates an Eclipse project. The gist of it is here: Programmatic creation of Eclipse project in the Eclipse workspace (the code shown on this post is the same coding project as I am currently asking about).

In my use-cases, the projects created are always C/C++ projects.

I initially thought just adding a CNature to the instance of IProjectDescription would suffice when it is assigned to the instance of an IProject but this does not appear to be enough. The code runs seemlessly (no errors), but I'm rightly or wrongly expecting a .cproject file to be created also. I've tried various things to create this, including this:

IProject newProject = workspace.getRoot().getProject(projectName);
try {
       newProject.create(newProjectDescription, monitor);  // create Eclipse project
       CoreModel model = CoreModel.getDefault();           // get default CDT model
       ICProject cproject = model.create(newProject);      // create CDT model for project
    } catch (CoreException ex) {
       // <snipped - does some logging>
    }

...with this later...

try {
        newProject.open(monitor);
        newProject.setDescription(newProjectDescription, null);
        cproject.save(null, true);  
    } catch (CoreException e) {
        // <snipped - does some loggging>
    }

...to no avail.

The programmatically created project is a duplicate of an existing project. The existing project was imported in to Eclipse using the "Existing Projects into Workspace..." option. I did not specify a toolchain for it. Neither does it actually have anything like make files in its structure, it's purely C and C++ files only. Yet, when I right-click on each and examine the context menu, the original manually imported one has "Build Project", "Clean Project" and "Make Targets". Similarly, if I compare properties, the original has a "C/C++ Build" section, but the programmatically created one lacks this. The same is true in that the original has a .cproject file and the programmatically created one does not.

I wish them to be identical such that the programmatically created one has the items I mention it currently lacks, in order to have the same context menu, "C/C++ Build" section in its properties and the important .cproject file.

I suspect it is the presence of the .cproject file that makes the difference in IDE behaviour, and I wish to know how to ensure that gets created also.

UPDATE 1:

Based on @nitind idea of tracing in to Eclipse code, I have discovered that the .cproject file is written from package org.eclipse.cdt.internal.core.settings.model.xml and class DesSerializationRunnable, which has the following function (given it implements Runnable):

public void run(IProgressMonitor monitor) throws CoreException {
  JobChangeAdapter notifyJobCanceller = new NotifyJobCanceller((NotifyJobCanceller)null);
  try {
    Job.getJobManager().addJobChangeListener(notifyJobCanceller);
    ResourcesPlugin.getWorkspace().run(new IWorkspaceRunnable() {
        public void run(IProgressMonitor monitor) throws CoreException {
        }
    }, (ISchedulingRule)null, 1, (IProgressMonitor)null);
    XmlProjectDescriptionStorage.this.serializingLock.acquire();
    LanguageSettingsProvidersSerializer.serializeLanguageSettings(this.fDes);
    XmlProjectDescriptionStorage.this.projectModificaitonStamp = XmlProjectDescriptionStorage.this.serialize(this.fDes.getProject(), ".cproject", this.fElement);
    ((ContributedEnvironment)CCorePlugin.getDefault().getBuildEnvironmentManager().getContributedEnvironment()).serialize(this.fDes);
  } finally {
    XmlProjectDescriptionStorage.this.serializingLock.release();
    Job.getJobManager().removeJobChangeListener(notifyJobCanceller);
  }
}

and specifically the line referring to ".cproject" writes the file.

I now just need to see how this gets called, and deduce if I can mimic it in my scenario, or better still, find a way to re-use this Eclipse code.


Solution

  • OK, so after as much tracing in to Eclipse as I could do, I found some but not all things that I needed to directly create a project with a .cproject file.

    However, after finding that there are some project conversion functions on the Eclipse CCorePlugin class, I decided to try those (at the time mixed in with some other code). Ultimately, I only needed to call a single method after calling open(...) on my IProject reference.

    I discovered that converting to a CProjectNature is only suitable for C and that I need to also cover C++. Converting solely to a CCProjectNature (note the extra C at the front) would add both types of nature to the project. It also ultimately calls the code I put in my question update, so writes the .cproject file. I checked the context menus and and the project properties and they now match what the Eclipse import wizard was producing.

    So short version is this original code:

    try {
          newProject.open(monitor);
        } catch (CoreException e) {
          // <snipped - do some logging>
    }
    return newProject; 
    

    ...becomes...

    try {
          newProject.open(monitor);
          cdtCorePlugin.convertProjectToNewCC(newProject, DEFAULT_PREFERENCE_CONFIG, monitor);
        } catch (CoreException e) {
          // <snipped - do some logging>
    }
    return newProject; 
    

    where cdtCorePlugin is simply defined earlier as:

    CCorePlugin cdtCorePlugin = CCorePlugin.getDefault();
    

    and DEFAULT_PREFERENCE_CONFIG is a constant defined as:

    private static final String DEFAULT_PREFERENCE_CONFIG = "org.eclipse.cdt.managedbuilder.core.configurationDataProvider";