Java tutorial
/* * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * This component and the accompanying materials are made available * under the terms of the License "Eclipse Public License v1.0" * which accompanies this distribution, and is available * at the URL "http://www.eclipse.org/legal/epl-v10.html". * * Initial Contributors: * Nokia Corporation - initial contribution. * * Contributors: * * Description: * */ package com.nokia.carbide.cpp.internal.builder.utils.handlers; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.eclipse.cdt.core.model.CModelException; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.CoreModelUtil; import org.eclipse.cdt.core.model.ICElement; import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.cdt.core.resources.FileStorage; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.core.settings.model.ICIncludePathEntry; import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; import org.eclipse.cdt.core.settings.model.ICProjectDescription; import org.eclipse.cdt.core.settings.model.extension.CConfigurationData; import org.eclipse.cdt.core.settings.model.extension.CFolderData; import org.eclipse.cdt.core.settings.model.extension.CLanguageData; import org.eclipse.cdt.internal.ui.util.EditorUtility; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.window.Window; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PartInitException; import org.eclipse.ui.handlers.HandlerUtil; import com.nokia.carbide.cdt.builder.CarbideBuilderPlugin; import com.nokia.carbide.cdt.builder.DefaultMMPViewConfiguration; import com.nokia.carbide.cdt.builder.EMMPPathContext; import com.nokia.carbide.cdt.builder.EpocEngineHelper; import com.nokia.carbide.cdt.builder.EpocEnginePathHelper; import com.nokia.carbide.cdt.builder.MMPViewPathHelper; import com.nokia.carbide.cdt.builder.builder.CarbideCPPBuilder; import com.nokia.carbide.cdt.builder.builder.CarbideCommandLauncher; import com.nokia.carbide.cdt.builder.project.ICarbideBuildConfiguration; import com.nokia.carbide.cdt.builder.project.ICarbideProjectInfo; import com.nokia.carbide.cdt.internal.builder.CarbideBuildConfiguration; import com.nokia.carbide.cpp.epoc.engine.EpocEnginePlugin; import com.nokia.carbide.cpp.epoc.engine.MMPDataRunnableAdapter; import com.nokia.carbide.cpp.epoc.engine.model.mmp.EMMPLanguage; import com.nokia.carbide.cpp.epoc.engine.model.mmp.EMMPStatement; import com.nokia.carbide.cpp.epoc.engine.model.mmp.IMMPData; import com.nokia.carbide.cpp.epoc.engine.model.mmp.IMMPResource; import com.nokia.carbide.cpp.epoc.engine.preprocessor.AcceptedNodesViewFilter; import com.nokia.carbide.cpp.epoc.engine.preprocessor.IDefine; import com.nokia.carbide.cpp.internal.builder.utils.Activator; import com.nokia.carbide.cpp.internal.builder.utils.ui.LanguageSelectionDialog; import com.nokia.carbide.cpp.internal.builder.utils.ui.PreprocessPreferencePage; import com.nokia.cpp.internal.api.utils.core.FileUtils; import com.nokia.cpp.internal.api.utils.core.HostOS; import com.nokia.cpp.internal.api.utils.ui.WorkbenchUtils; public class PreprocessHandler extends AbstractHandler { private static final String MMP_EXTENSION = ".mmp"; //$NON-NLS-1$ private static final String INF_EXTENSION = ".inf"; //$NON-NLS-1$ public Object execute(ExecutionEvent event) throws ExecutionException { ISelection selection = HandlerUtil.getCurrentSelection(event); if (selection == null) { return null; } final IFile selectedFile = getFileToPreprocess(selection); if (selectedFile == null) { return null; } // Save all open editor windows before starting... WorkbenchUtils.saveOpenEditorsIfRequired(); Job buildJob = new Job("Preprocessing file") { protected IStatus run(IProgressMonitor monitor) { try { IProject project = selectedFile.getProject(); monitor.beginTask("Preprocessing " + selectedFile.getName(), 4); final ICarbideProjectInfo cpi = CarbideBuilderPlugin.getBuildManager().getProjectInfo(project); if (cpi != null) { final IPath path = selectedFile.getLocation(); if (path != null) { ICarbideBuildConfiguration buildConfig = cpi.getDefaultConfiguration(); try { CarbideCPPBuilder.removeAllMarkers(project); } catch (CoreException e) { e.printStackTrace(); } CarbideCommandLauncher launcher = new CarbideCommandLauncher(project, monitor, buildConfig.getErrorParserList(), cpi.getINFWorkingDirectory()); launcher.showCommand(true); String cppTool = "cpp" + HostOS.EXE_EXT; //$NON-NLS-1$ for (String var : CarbideCPPBuilder.getResolvedEnvVars(buildConfig)) { if (var.compareTo("ALT_PRE") == 0 || var.startsWith("ALT_PRE=")) { //$NON-NLS-1$ //$NON-NLS-2$ cppTool = "rcpp" + HostOS.EXE_EXT; //$NON-NLS-1$ break; } } List<String> args = new ArrayList<String>(); String cppArgs[] = PreprocessPreferencePage.getCppArguments().split(" "); if (cppArgs != null && cppArgs.length > 0) { for (String arg : cppArgs) { args.add(arg); } } monitor.worked(1); // add the includes and macros List<IPath> userIncludes = new ArrayList<IPath>(); List<IPath> systemIncludes = new ArrayList<IPath>(); if (!getEntriesForConfig(project, userIncludes, systemIncludes)) { launcher.writeToConsole("\n***Stopping. Unable to get includes for project.\n"); CarbideBuilderPlugin.createCarbideProjectMarker(project, IMarker.SEVERITY_ERROR, "Unable to get includes and macros for project.", IMarker.PRIORITY_LOW); return new Status(IStatus.ERROR, "Carbide.c++ builder utils plugin", IStatus.ERROR, "Failed", null); } for (IPath userInclude : userIncludes) { args.add("-I"); //$NON-NLS-1$ args.add("\"" + userInclude.toOSString() + "\""); //$NON-NLS-1$ //$NON-NLS-2$ } // implicit inclusion of the directory where the file being preprocessed is located args.add("-I"); //$NON-NLS-1$ args.add("\"" + selectedFile.getLocation().removeLastSegments(1).toOSString() + "\""); //$NON-NLS-1$ //$NON-NLS-2$ if (systemIncludes.size() > 0) { args.add("-I-"); //$NON-NLS-1$ for (IPath systemInclude : systemIncludes) { args.add("-I"); //$NON-NLS-1$ args.add("\"" + systemInclude.toOSString() + "\""); //$NON-NLS-1$ //$NON-NLS-2$ } } List<String> macros = getMacros(buildConfig, path, monitor); for (String macro : macros) { args.add("-D" + macro); //$NON-NLS-1$ } monitor.worked(1); if (monitor.isCanceled()) { return new Status(IStatus.CANCEL, "Carbide.c++ builder utils plugin", IStatus.CANCEL, "Cancelled", null); } // add the compiler prefix file if any IPath compilerPrefix = buildConfig.getBuildContext().getCompilerPrefixFile(); if (compilerPrefix != null) { args.add("-include"); //$NON-NLS-1$ args.add("\"" + compilerPrefix.toOSString() + "\""); //$NON-NLS-1$ //$NON-NLS-2$ } // add the sdk prefix file if any File sdkPrefix = buildConfig.getBuildContext().getPrefixFromVariantCfg().toFile(); if (sdkPrefix != null && sdkPrefix.exists()) { args.add("-include"); //$NON-NLS-1$ args.add("\"" + sdkPrefix.getAbsolutePath() + "\""); //$NON-NLS-1$ //$NON-NLS-2$ } // now add the path to the file args.add("\"" + path.toOSString() + "\""); //$NON-NLS-1$ //$NON-NLS-2$ // output to a temp file IPath topMakefileDir = new Path(buildConfig.getSDK().getEPOCROOT()) .append("epoc32\\build"); //$NON-NLS-1$ topMakefileDir = topMakefileDir.append(cpi.getINFWorkingDirectory().setDevice(null)); topMakefileDir.toFile().mkdirs(); final IPath tempFilePath = topMakefileDir .append(path.removeFileExtension().lastSegment() + ".ii"); final File tempFile = tempFilePath.toFile(); if (tempFile.exists()) { tempFile.delete(); } try { tempFile.createNewFile(); } catch (IOException e) { CarbideBuilderPlugin.log(e); } args.add("-o"); //$NON-NLS-1$ args.add(tempFile.getAbsolutePath()); launcher.writeToConsole("\n***Preprocessing " + path.toOSString() + "\n"); monitor.worked(1); int retVal = launcher.executeCommand(new Path(cppTool), args.toArray(new String[args.size()]), CarbideCPPBuilder.getResolvedEnvVars(buildConfig), cpi.getINFWorkingDirectory()); if (retVal != 0) { launcher.writeToConsole( "\n=== Preprocess command failed with error code " + retVal + " ==="); launcher.writeToConsole( "\n***Stopping. Check the Problems view or Console output for errors.\n"); CarbideBuilderPlugin.createCarbideProjectMarker(project, IMarker.SEVERITY_ERROR, cppTool + " returned with exit value = " + retVal, IMarker.PRIORITY_LOW); } monitor.worked(1); if (PreprocessPreferencePage.outputToConsole()) { // open the file and pipe the contents to the console try { launcher.writeToConsole("\n"); // take it one line at a time so we don't overwhelm the console view. note that // we send the text pretty fast but it takes a lot longer for the console to actually // render it, so canceling the job may appear to not work String text = new String(FileUtils.readFileContents(tempFile, null)); for (String line : text.split("\n")) { if (monitor.isCanceled()) { return new Status(IStatus.CANCEL, "Carbide.c++ builder utils plugin", IStatus.CANCEL, "Cancelled", null); } launcher.writeToConsole(line); } } catch (CoreException e) { CarbideBuilderPlugin.log(e); } } else { // open file in a new editor window Display.getDefault().asyncExec(new Runnable() { public void run() { try { EditorUtility.openInEditor(new FileStorage(tempFilePath)); } catch (PartInitException e) { CarbideBuilderPlugin.log(e); } catch (CModelException e) { CarbideBuilderPlugin.log(e); } } }); } launcher.writeToConsole(launcher.getTimingStats()); } } if (monitor.isCanceled()) { return new Status(IStatus.CANCEL, "Carbide.c++ builder utils plugin", IStatus.CANCEL, "Cancelled", null); } } finally { monitor.done(); } return new Status(IStatus.OK, "Carbide.c++ builder utils plugin", IStatus.OK, "Complete", null); } }; buildJob.setPriority(Job.BUILD); buildJob.setUser(true); buildJob.schedule(); return null; } /** * If the selected file is a translation unit, bld.inf or mmp file, returns * the IFile, otherwise returns null * @param selection the selection * @return the IFile, or null */ public static IFile getFileToPreprocess(ISelection selection) { IFile selectedFile = null; if (selection instanceof IStructuredSelection) { IStructuredSelection ss = (IStructuredSelection) selection; if (ss.size() == 1) { Object selectionItem = ss.getFirstElement(); if (selectionItem instanceof ITranslationUnit) { ITranslationUnit tu = (ITranslationUnit) selectionItem; if (tu.isSourceUnit() && tu.getResource() instanceof IFile) { selectedFile = (IFile) tu.getResource(); } } else { IFile file = null; if (selectionItem instanceof IFile) { file = (IFile) selectionItem; } else if (selectionItem instanceof IAdaptable) { file = (IFile) ((IAdaptable) selectionItem).getAdapter(IFile.class); } if (file != null) { ITranslationUnit tu = CoreModelUtil.findTranslationUnit(file); if (tu != null && tu.isSourceUnit()) { selectedFile = file; } else { String filename = file.getName().toLowerCase(); if (filename.endsWith(MMP_EXTENSION) || filename.endsWith(INF_EXTENSION)) { selectedFile = file; } } } } } } else if (selection instanceof ITextSelection) { IWorkbenchWindow window = Activator.getActiveWorkbenchWindow(); if (window != null) { IWorkbenchPage page = window.getActivePage(); if (page != null) { IWorkbenchPart part = page.getActivePart(); if (part instanceof IEditorPart) { IEditorPart epart = (IEditorPart) part; IResource resource = (IResource) epart.getEditorInput().getAdapter(IResource.class); ICElement element = CoreModel.getDefault().create(resource); if (element instanceof ITranslationUnit) { ITranslationUnit tu = (ITranslationUnit) element; if (tu.isSourceUnit() && tu.getResource() instanceof IFile) { selectedFile = (IFile) tu.getResource(); } } else { if (resource instanceof IFile) { IFile file = (IFile) resource; String filename = file.getName().toLowerCase(); if (filename.endsWith(MMP_EXTENSION) || filename.endsWith(INF_EXTENSION)) { selectedFile = file; } } } } } } } return selectedFile; } private boolean getEntriesForConfig(IProject project, List<IPath> userIncludes, List<IPath> systemIncludes) { ICProjectDescription projDes = CoreModel.getDefault().getProjectDescription(project); if (projDes != null) { ICConfigurationDescription configDes = projDes.getActiveConfiguration(); if (configDes != null) { CConfigurationData configData = configDes.getConfigurationData(); if (configData != null) { CFolderData rootFolderData = configData.getRootFolderData(); if (rootFolderData != null) { CLanguageData[] languageDatas = rootFolderData.getLanguageDatas(); if (languageDatas != null && languageDatas.length > 0) { CLanguageData languageData = languageDatas[0]; ICLanguageSettingEntry[] includeEntries = languageData .getEntries(ICLanguageSettingEntry.INCLUDE_PATH); if (includeEntries != null) { for (ICLanguageSettingEntry includeEntry : includeEntries) { if (includeEntry instanceof ICIncludePathEntry) { ICIncludePathEntry include = (ICIncludePathEntry) includeEntry; if (include.isLocal()) { userIncludes.add(include.getLocation()); } else { systemIncludes.add(include.getLocation()); } } } return true; } } } } } } return false; } private List<String> getMacros(ICarbideBuildConfiguration buildConfig, final IPath filePath, final IProgressMonitor monitor) { final List<String> macros = new ArrayList<String>(); List<IDefine> buildMacros = buildConfig.getBuildContext().getBuildMacros(); for (IDefine define : buildMacros) { if (define.getName().equals("__PRODUCT_INCLUDE__")) { macros.add(define.getName() + "=" + define.getExpansion()); } else { macros.add(define.getName()); } } List<IDefine> metaDataMacros = buildConfig.getBuildContext().getMetadataMacros(); for (IDefine define : metaDataMacros) { macros.add(define.getName()); } if (((CarbideBuildConfiguration) buildConfig).hasSTDCPPSupport()) { macros.add("__SYMBIAN_STDCPP_SUPPORT__"); } IProject project = buildConfig.getCarbideProject().getProject(); List<IPath> mmps = EpocEngineHelper.getMMPsForSource(project, filePath); if (mmps.size() > 0) { // just use the first mmp I guess... EpocEnginePathHelper helper = new EpocEnginePathHelper(project); IPath workspaceRelativeMMPPath = helper.convertToWorkspace(mmps.get(0)); // target type macro (e.g. __DLL__) EpocEnginePlugin.runWithMMPData( workspaceRelativeMMPPath, new DefaultMMPViewConfiguration(project, buildConfig.getBuildContext(), new AcceptedNodesViewFilter()), new MMPDataRunnableAdapter() { public Object run(IMMPData mmpData) { String targetType = mmpData.getSingleArgumentSettings().get(EMMPStatement.TARGETTYPE); if (targetType != null) { targetType = targetType.toUpperCase(); macros.add("__" + targetType + "__"); } // mmp macros List<String> macroList = mmpData.getListArgumentSettings().get(EMMPStatement.MACRO); for (String macro : macroList) { // Symbian docs say they are converted to upper case always macros.add(macro.toUpperCase()); } // also need to get language macro for resource files if (FileUtils.getSafeFileExtension(filePath).compareTo("rss") == 0) { List<EMMPLanguage> languages = null; MMPViewPathHelper helper = new MMPViewPathHelper(mmpData, (IPath) null); for (IMMPResource resBlock : mmpData.getResourceBlocks()) { IPath fullPath = helper.convertMMPToFilesystem(EMMPPathContext.START_RESOURCE, resBlock.getSource()); if (fullPath.equals(filePath)) { languages = resBlock.getLanguages(); break; } } // if not a resource block or resource block has no language specified, see if there's // an mmp language specified if (languages == null || languages.size() == 0) { languages = mmpData.getLanguages(); if (languages == null || languages.size() == 0) { // default is non-localize languages = Collections.singletonList(EMMPLanguage.SC_NonLocalized); } } final List<String> languageMacro = new ArrayList<String>(1); languageMacro.add("LANGUAGE_" + languages.get(0).getCodeString()); // ask the user which language to preprocess for (if more than one) if (languages.size() > 1) { languageMacro.clear(); final List<EMMPLanguage> finalLanguages = languages; Display.getDefault().syncExec(new Runnable() { public void run() { List<String> langs = new ArrayList<String>(); for (EMMPLanguage lang : finalLanguages) { langs.add(lang.getName()); } LanguageSelectionDialog dlg = new LanguageSelectionDialog( WorkbenchUtils.getSafeShell(), langs); if (Window.OK == dlg.open()) { languageMacro.add("LANGUAGE_" + finalLanguages .get(dlg.getselectedIndex()).getCodeString()); } else { monitor.setCanceled(true); } } }); } if (languageMacro.size() > 0) { macros.add(languageMacro.get(0)); } } return null; } }); } return macros; } }