View Javadoc
1   /**
2    * All rights reserved. This program and the accompanying materials
3    * are made available under the terms of the Eclipse Public License v1.0
4    * which accompanies this distribution, and is available at
5    * http://www.eclipse.org/legal/epl-v10.html
6    */
7   package org.eclipse.papyrus.designer.languages.cpp.cdt.project;
8   
9   import org.eclipse.cdt.core.model.CoreModel;
10  import org.eclipse.cdt.core.settings.model.CIncludePathEntry;
11  import org.eclipse.cdt.core.settings.model.CMacroEntry;
12  import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
13  import org.eclipse.cdt.core.settings.model.ICFolderDescription;
14  import org.eclipse.cdt.core.settings.model.ICLanguageSetting;
15  import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry;
16  import org.eclipse.cdt.core.settings.model.ICProjectDescription;
17  import org.eclipse.cdt.core.settings.model.ICProjectDescriptionManager;
18  import org.eclipse.cdt.core.settings.model.ICSettingEntry;
19  import org.eclipse.cdt.managedbuilder.core.BuildException;
20  import org.eclipse.cdt.managedbuilder.core.IConfiguration;
21  import org.eclipse.cdt.managedbuilder.core.IOption;
22  import org.eclipse.cdt.managedbuilder.core.ITool;
23  import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager;
24  import org.eclipse.cdt.ui.wizards.CDTCommonProjectWizard;
25  import org.eclipse.core.resources.IProject;
26  import org.eclipse.core.resources.IWorkspaceRoot;
27  import org.eclipse.core.resources.ResourcesPlugin;
28  import org.eclipse.core.runtime.CoreException;
29  import org.eclipse.emf.common.util.BasicEList;
30  import org.eclipse.emf.common.util.EList;
31  import org.eclipse.emf.common.util.UniqueEList;
32  import org.eclipse.jface.window.Window;
33  import org.eclipse.jface.wizard.WizardDialog;
34  import org.eclipse.papyrus.designer.languages.common.extensionpoints.AbstractSettings;
35  import org.eclipse.papyrus.designer.languages.common.extensionpoints.ILangProjectSupport;
36  import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.ExternLibrary;
37  import org.eclipse.swt.widgets.Display;
38  import org.eclipse.ui.IWorkbench;
39  import org.eclipse.ui.PlatformUI;
40  import org.eclipse.uml2.uml.Classifier;
41  import org.eclipse.uml2.uml.Element;
42  import org.eclipse.uml2.uml.Package;
43  import org.eclipse.uml2.uml.util.UMLUtil;
44  
45  /**
46   * Supports the creation and configuration of CDT projects
47   */
48  public class C_CppProjectSupport implements ILangProjectSupport {
49  
50  	// TODO specific "root" is only required for component based code generation
51  	public static final String WS_PREFIX = "ws:"; //$NON-NLS-1$
52  
53  	private static final String C = "c"; //$NON-NLS-1$
54  
55  	private static final String CPP = "cpp"; //$NON-NLS-1$
56  
57  	protected int dialogStatus;
58  
59  	/**
60  	 * Create a C++ project. Caller should test before calling, whether the
61  	 * project exists already
62  	 *
63  	 * @param projectName
64  	 * @return the created project
65  	 */
66  	@Override
67  	public IProject createProject(String projectName) {
68  		IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
69  
70  		IProject project = root.getProject(projectName);
71  		dialogStatus = 0;
72  		try {
73  			IWorkbench wb = PlatformUI.getWorkbench();
74  
75  			// create CDT wizard for C++ or C
76  			final CDTCommonProjectWizard wiz = this instanceof CppProjectSupport ? new CCNamedProjectWizard(projectName)
77  					: new CNamedProjectWizard(projectName);
78  
79  			wiz.setWindowTitle("create project " + projectName); //$NON-NLS-1$
80  			wiz.init(wb, null);
81  
82  			Display.getDefault().syncExec(new Runnable() {
83  
84  				@Override
85  				public void run() {
86  					WizardDialog wizDiag = new WizardDialog(Display.getCurrent().getActiveShell(), wiz);
87  
88  					wizDiag.create();
89  					dialogStatus = wizDiag.open();
90  				}
91  			});
92  			if (dialogStatus == Window.OK) {
93  				// update project (name might have changed by user)
94  				project = wiz.getLastProject();
95  			} else if (dialogStatus == Window.CANCEL) {
96  				return null;
97  			}
98  		} catch (Exception e) {
99  			e.printStackTrace();
100 			project = null;
101 		}
102 
103 		if ((project == null) || !project.exists()) {
104 			throw new RuntimeException(
105 					"Could not create CDT project. This might indicate that there is a problem with your CDT installation."); //$NON-NLS-1$
106 		}
107 		return project;
108 	}
109 
110 	@Override
111 	public void setSettings(IProject project, AbstractSettings abstractSettings) {
112 		CDTSettings settings = (CDTSettings) abstractSettings;
113 		try {
114 			// ((CProject) project).
115 			// IProjectDescription desc = m_project.getDescription();
116 
117 			ICProjectDescriptionManager mngr = CoreModel.getDefault().getProjectDescriptionManager();
118 			ICProjectDescription cdesc = mngr.getProjectDescription(project, true);
119 
120 			// loop over all configurations
121 			for (ICConfigurationDescription configDescr : cdesc.getConfigurations()) {
122 
123 				ICFolderDescription folderDescription = configDescr.getRootFolderDescription();
124 
125 				ICLanguageSetting[] languageSettings = folderDescription.getLanguageSettings();
126 
127 				// copy string array into ICLanguageSetting array
128 				ICLanguageSettingEntry[] icIncludePaths = new ICLanguageSettingEntry[settings.includePaths.size()];
129 				for (int i = 0; i < settings.includePaths.size(); i++) {
130 					String path = settings.includePaths.get(i);
131 					if (isWsRelPath(path)) {
132 						icIncludePaths[i] = new CIncludePathEntry(removeWsPrefix(path),
133 								ICSettingEntry.VALUE_WORKSPACE_PATH);
134 					} else {
135 						icIncludePaths[i] = new CIncludePathEntry(path, 0);
136 					}
137 				}
138 
139 				// define name of used operating system from model (attribute of
140 				// "Target" stereotype)
141 				// and add it to list of macros
142 				if (settings.targetOS != null) {
143 					settings.macros.add("OS_" + settings.targetOS); //$NON-NLS-1$
144 				}
145 
146 				// define macros
147 				EList<ICLanguageSettingEntry> icMacros = new BasicEList<ICLanguageSettingEntry>();
148 				for (int i = 0; i < settings.macros.size(); i++) {
149 					// TODO: need to define values for macros as well?
150 					icMacros.add(new CMacroEntry(settings.macros.get(i), "", 0)); //$NON-NLS-1$
151 				}
152 
153 				// now set include path and preprocessor code
154 				for (ICLanguageSetting lang : languageSettings) {
155 					// selection better via ID? (instead of extension)
156 					// Log.log(Status.INFO, Log.CODEGEN, "CppLanguageSupport:
157 					// lang.getID: " + lang.getId() + " lang.getLanguageID: " +
158 					// lang.getLanguageId());
159 					for (String ext : lang.getSourceExtensions()) {
160 						if (ext.equals(CPP) || ext.equals(C)) {
161 							lang.setSettingEntries(ICSettingEntry.INCLUDE_PATH, icIncludePaths);
162 							ICLanguageSettingEntry icOldMacros[] = lang.getSettingEntries(ICSettingEntry.MACRO);
163 							for (ICLanguageSettingEntry entry : icOldMacros) {
164 								icMacros.add(entry);
165 							}
166 							lang.setSettingEntries(ICSettingEntry.MACRO, icMacros);
167 							break;
168 						}
169 					}
170 				}
171 				IConfiguration main = ManagedBuildManager.getConfigurationForDescription(configDescr);
172 				// change artifact name
173 				// main.setArtifactName(main.getArtifactName () + ".bin");
174 
175 				// add to -l (libraries)
176 				ITool cfTool = main.calculateTargetTool();
177 
178 				// IOption libOption = cfTool.getOptionBy(IOption.TYPE_LIB);
179 
180 				for (IOption opt : cfTool.getOptions()) {
181 					if (opt.getValueType() == IOption.LIBRARIES) {
182 						main.setOption(cfTool, opt, settings.libs.toArray(new String[0]));
183 					} else if (opt.getValueType() == IOption.LIBRARY_PATHS) {
184 						main.setOption(cfTool, opt, settings.libPaths.toArray(new String[0]));
185 					}
186 				}
187 				mngr.setProjectDescription(project, cdesc, true, null);
188 			}
189 			ManagedBuildManager.saveBuildInfo(project, true);
190 		} catch (BuildException be) {
191 			throw new RuntimeException(be.getMessage());
192 		} catch (CoreException ce) {
193 			throw new RuntimeException(ce.getMessage());
194 		}
195 	}
196 
197 	@Override
198 	public AbstractSettings initialConfigurationData() {
199 		CDTSettings settings = new CDTSettings();
200 		settings.includePaths = new UniqueEList<String>();
201 		// include project directory (all paths are relative to it)
202 		// TODO: choose source folder depending on model (which is currently not
203 		// passed as a parameter)
204 		settings.includePaths.add(WS_PREFIX + "src-gen"); //$NON-NLS-1$
205 
206 		settings.libs = new UniqueEList<String>();
207 		settings.libPaths = new UniqueEList<String>();
208 		settings.macros = new UniqueEList<String>();
209 		return settings;
210 	}
211 
212 	@Override
213 	public void gatherConfigData(Classifier implementation, AbstractSettings abstractSettings) {
214 		CDTSettings settings = (CDTSettings) abstractSettings;
215 		Element owner = implementation.getNearestPackage();
216 		while (owner instanceof Package) {
217 			ExternLibrary cppLibrary = UMLUtil.getStereotypeApplication(owner, ExternLibrary.class);
218 			if ((cppLibrary != null) && (settings != null)) {
219 				settings.includePaths.addAll(cppLibrary.getIncludePaths());
220 				for (String libPath : cppLibrary.getLibPaths()) {
221 					if (isWsRelPath(libPath)) {
222 						// libPaths starting with a slash (separator char) are
223 						// relative to workspace location
224 						// TODO: need to support absolute paths (host file
225 						// system?) as well?
226 						// (additional prefix. Eclipse standards?) Problem:
227 						// workspace_loc is added
228 						// automatically for absolute includePaths
229 						settings.libPaths.add("${workspace_loc:" + removeWsPrefix(libPath) + "}");
230 					} else {
231 						// relative to project root, otherwise
232 						settings.libPaths.add(libPath);
233 					}
234 				}
235 				settings.libs.addAll(cppLibrary.getLibs());
236 				settings.macros.addAll(cppLibrary.getMacros());
237 			}
238 			owner = owner.getOwner();
239 		}
240 	}
241 
242 	public static String removeWsPrefix(String path) {
243 		return path.substring(WS_PREFIX.length());
244 	}
245 
246 	/**
247 	 * @return true, if the path is a workspace relative path
248 	 */
249 	public static boolean isWsRelPath(String path) {
250 		return path.startsWith(WS_PREFIX);
251 
252 	}
253 
254 	@Override
255 	public IProject createProject(String projectName, Package modelRoot) {
256 		return createProject(projectName);
257 	}
258 }