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.cdt.internal.builder; import java.io.BufferedInputStream; import java.io.File; import java.io.FileFilter; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.RandomAccessFile; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import org.eclipse.cdt.make.core.makefile.ICommand; import org.eclipse.cdt.make.core.makefile.IMacroDefinition; import org.eclipse.cdt.make.core.makefile.IRule; import org.eclipse.cdt.make.core.makefile.ITargetRule; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import com.nokia.carbide.cdt.builder.BuilderPreferenceConstants; import com.nokia.carbide.cdt.builder.CarbideBuilderPlugin; import com.nokia.carbide.cdt.builder.DefaultGNUMakefileViewConfiguration; import com.nokia.carbide.cdt.builder.DefaultMMPViewConfiguration; import com.nokia.carbide.cdt.builder.DefaultViewConfiguration; import com.nokia.carbide.cdt.builder.EpocEngineHelper; import com.nokia.carbide.cdt.builder.EpocEnginePathHelper; 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.ui.MMPChangedActionDialog; import com.nokia.carbide.cdt.internal.builder.ui.MMPChangedActionDialog.MMPChangedAction; import com.nokia.carbide.cdt.internal.builder.ui.TrackDependenciesQueryDialog; import com.nokia.carbide.cpp.epoc.engine.BldInfViewRunnableAdapter; import com.nokia.carbide.cpp.epoc.engine.EpocEnginePlugin; import com.nokia.carbide.cpp.epoc.engine.MMPDataRunnableAdapter; import com.nokia.carbide.cpp.epoc.engine.model.IModel; import com.nokia.carbide.cpp.epoc.engine.model.IModelProvider; import com.nokia.carbide.cpp.epoc.engine.model.bldinf.IBldInfView; import com.nokia.carbide.cpp.epoc.engine.model.makefile.IMakefileView; 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.internal.api.sdk.ISBSv1BuildContext; import com.nokia.carbide.cpp.internal.api.sdk.ISBSv1BuildInfo; import com.nokia.carbide.cpp.internal.qt.core.QtCorePlugin; import com.nokia.carbide.cpp.sdk.core.IBSFPlatform; import com.nokia.carbide.cpp.sdk.core.ISBVPlatform; import com.nokia.carbide.cpp.sdk.core.ISDKBuildInfo; import com.nokia.carbide.cpp.sdk.core.ISymbianBuildContext; import com.nokia.carbide.cpp.sdk.core.ISymbianBuilderID; import com.nokia.carbide.cpp.sdk.core.ISymbianSDK; 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 CarbideSBSv1Builder implements ICarbideBuilder { private static final String EPOC_BUILD_DIR = "epoc32\\build"; //$NON-NLS-1$ private static final String BUILD_CMD = "build"; //$NON-NLS-1$ private static final String CLEAN_CMD = "clean"; //$NON-NLS-1$ private static final String FREEZE_CMD = "freeze"; //$NON-NLS-1$ private static final String REALLYCLEAN_CMD = "reallyclean"; //$NON-NLS-1$ private static final String EXPORT_CMD = "export"; //$NON-NLS-1$ private static final String LIBRARY_CMD = "library"; //$NON-NLS-1$ private static final String MAKEFILE_CMD = "makefile"; //$NON-NLS-1$ private static final String RESOURCE_CMD = "resource"; //$NON-NLS-1$ private static final String TARGET_CMD = "target"; //$NON-NLS-1$ private static final String FINAL_CMD = "final"; //$NON-NLS-1$ private static final String TEST_CMD = "test"; //$NON-NLS-1$ private static final IPath MAKE = new Path("make" + HostOS.EXE_EXT); //$NON-NLS-1$ private static final IPath PERL = new Path("perl" + HostOS.EXE_EXT); //$NON-NLS-1$ private static final String ABLD_BAT_NAME = "abld.bat"; //$NON-NLS-1$ private static final String CARBIDE_MAKEFILE_TEXT = "# Managed by Carbide - do not modify"; //$NON-NLS-1$ private static boolean areWeManagingTheMakeFiles = false; // workaround for bug #4728. we don't want to pass -j when building resources // or the library stage (bug #4827) private static boolean removeMakeVariableOneTime = false; private static FileFilter objectCodeDirectoryFileFilter = new FileFilter() { public boolean accept(File file) { if (file.getName().endsWith(".d") || file.getName().endsWith(".dep") || file.getName().endsWith(".o") || file.getName().endsWith(".obj")) { return true; } return false; } }; private static final String CARBIDE_CHANGES_FILE = "CARBIDE_CHANGES.TXT"; //$NON-NLS-1$ private static final String FIXUP_DEPFILES_FILE = "fix_dep_file_paths.pl"; //$NON-NLS-1$ public void preBuildStep(ICarbideBuildConfiguration buildConfig, CarbideCommandLauncher launcher) { areWeManagingTheMakeFiles = shouldManageMakeFiles(buildConfig); // if variant BSF, let them know the other platforms that will be built as a result ISymbianSDK sdk = buildConfig.getSDK(); ISBSv1BuildInfo sbsv1BuildInfo = (ISBSv1BuildInfo) sdk.getBuildInfo(ISymbianBuilderID.SBSV1_BUILDER); if (sbsv1BuildInfo != null) { IBSFPlatform[] bsfPlatforms = sbsv1BuildInfo.getBSFCatalog() .getAdditionalBuiltPlatforms(buildConfig.getPlatformString()); if (bsfPlatforms.length > 0) { String plats = ""; for (IBSFPlatform plat : bsfPlatforms) { plats = ", " + plat.getName(); } plats = plats.replaceFirst(", ", ""); launcher.writeToConsole("\n***Additionally built platforms: " + plats + "\n"); } } } public void preCleanStep(ICarbideBuildConfiguration buildConfig) { areWeManagingTheMakeFiles = shouldManageMakeFiles(buildConfig); } public boolean buildComponent(ICarbideBuildConfiguration buildConfig, IPath componentPath, boolean isTest, CarbideCommandLauncher launcher, IProgressMonitor monitor) { areWeManagingTheMakeFiles = shouldManageMakeFiles(buildConfig); ISBSv1BuildContext sbsv1Context = (ISBSv1BuildContext) buildConfig.getBuildContext(); if (!CarbideCPPBuilder.generateBldmakeMakefilesIfNecessary(buildConfig, launcher)) { return false; } String componentName = componentPath.removeFileExtension().lastSegment(); String buildPlatform = ""; if (buildConfig.getPlatformString().startsWith(ISBSv1BuildContext.ARMV5_PLATFORM) && EpocEngineHelper.hasFeatureVariantKeyword(buildConfig.getCarbideProject(), componentPath)) { buildPlatform = buildConfig.getPlatformString().toLowerCase(); } else if (buildConfig.getBuildContext() instanceof ISBSv1BuildContext) { buildPlatform = ((ISBSv1BuildContext) buildConfig.getBuildContext()).getBasePlatformForVariation() .toLowerCase(); } // need to run individual build steps when managing makefiles or doing concurrent builds if (areWeManagingTheMakeFiles || buildConfig.getCarbideProject().isConcurrentBuildingEnabled()) { SubMonitor progress = SubMonitor.convert(monitor, 7); progress.setTaskName(CarbideBuildManagerUtils.getBuildLabel(buildConfig, componentName)); // run abld export or test export List<String> args = new ArrayList<String>(); if (isTest) { args.add(TEST_CMD); } args.add(EXPORT_CMD); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldExportArgs().split(" ")) { args.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, args.toArray(new String[args.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } if (!runMMPChangeCheck(buildConfig, componentPath, isTest, launcher)) { return false; } // run abld makefile platform for each component to be built if needed if (!generateAbldMakefileIfNecessary(buildConfig, launcher, componentPath, isTest, progress)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } // run abld library platform args.clear(); if (isTest) { args.add(TEST_CMD); } args.add(LIBRARY_CMD); args.add(buildPlatform); args.add(componentName); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldLibraryArgs().split(" ")) { args.add(arg); } removeMakeVariableOneTime = true; if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, args.toArray(new String[args.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } // run abld resource platform target args.clear(); if (isTest) { args.add(TEST_CMD); } args.add(RESOURCE_CMD); args.add(buildPlatform); args.add(buildConfig.getTargetString().toLowerCase()); args.add(componentName); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldResourceArgs().split(" ")) { args.add(arg); } removeMakeVariableOneTime = true; if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, args.toArray(new String[args.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } // run abld target platform target args.clear(); if (isTest) { args.add(TEST_CMD); } args.add(TARGET_CMD); args.add(buildPlatform); args.add(buildConfig.getTargetString().toLowerCase()); args.add(componentName); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldTargetArgs().split(" ")) { args.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, args.toArray(new String[args.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } // run abld final platform target args.clear(); if (isTest) { args.add(TEST_CMD); } args.add(FINAL_CMD); args.add(buildPlatform); args.add(buildConfig.getTargetString().toLowerCase()); args.add(componentName); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldFinalArgs().split(" ")) { args.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, args.toArray(new String[args.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } } else { SubMonitor progress = SubMonitor.convert(monitor, 1); progress.setTaskName(CarbideBuildManagerUtils.getBuildLabel(buildConfig, componentName)); List<String> argsList = new ArrayList<String>(); if (isTest) { argsList.add(TEST_CMD); } argsList.add(BUILD_CMD); argsList.add(buildPlatform); argsList.add(buildConfig.getTargetString().toLowerCase()); argsList.add(componentName); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldBuildArgs().split(" ")) { argsList.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } } launcher.writeToConsole("\n***Build Complete\n"); return true; } public boolean cleanComponent(ICarbideBuildConfiguration buildConfig, IPath componentPath, boolean isTest, CarbideCommandLauncher launcher, IProgressMonitor monitor) { areWeManagingTheMakeFiles = shouldManageMakeFiles(buildConfig); ISBSv1BuildContext sbsv1Context = (ISBSv1BuildContext) buildConfig.getBuildContext(); if (!CarbideCPPBuilder.generateBldmakeMakefilesIfNecessary(buildConfig, launcher)) { return false; } String componentName = componentPath.removeFileExtension().lastSegment(); String buildPlatform = ""; if (buildConfig.getPlatformString().startsWith(ISBSv1BuildContext.ARMV5_PLATFORM) && EpocEngineHelper.hasFeatureVariantKeyword(buildConfig.getCarbideProject(), componentPath)) { buildPlatform = buildConfig.getPlatformString().toLowerCase(); } else if (buildConfig.getBuildContext() instanceof ISBSv1BuildContext) { buildPlatform = ((ISBSv1BuildContext) buildConfig.getBuildContext()).getBasePlatformForVariation() .toLowerCase(); } SubMonitor progress = SubMonitor.convert(monitor, 2); progress.setTaskName("Cleaning " + componentName); // run abld makefile platform for each component to be built if needed if (!generateAbldMakefileIfNecessary(buildConfig, launcher, componentPath, isTest, progress)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } int cleanLevel = buildConfig.getCarbideProject().getCleanLevel(); String abldCleanCmd = REALLYCLEAN_CMD; if (0 == cleanLevel) { abldCleanCmd = CLEAN_CMD; } List<String> argsList = new ArrayList<String>(); if (isTest) { argsList.add(TEST_CMD); } argsList.add(abldCleanCmd); argsList.add(buildPlatform); argsList.add(buildConfig.getTargetString().toLowerCase()); argsList.add(componentName); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldCleanArgs().split(" ")) { argsList.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } launcher.writeToConsole("\n***Clean Complete\n"); return true; } public boolean freezeComponent(ICarbideBuildConfiguration buildConfig, IPath componentPath, boolean isTest, CarbideCommandLauncher launcher, IProgressMonitor monitor) { areWeManagingTheMakeFiles = shouldManageMakeFiles(buildConfig); ISBSv1BuildContext sbsv1Context = (ISBSv1BuildContext) buildConfig.getBuildContext(); if (!CarbideCPPBuilder.generateBldmakeMakefilesIfNecessary(buildConfig, launcher)) { return false; } String componentName = componentPath.removeFileExtension().lastSegment(); String buildPlatform = ""; if (buildConfig.getPlatformString().startsWith(ISBSv1BuildContext.ARMV5_PLATFORM) && EpocEngineHelper.hasFeatureVariantKeyword(buildConfig.getCarbideProject(), componentPath)) { buildPlatform = buildConfig.getPlatformString().toLowerCase(); } else if (buildConfig.getBuildContext() instanceof ISBSv1BuildContext) { buildPlatform = ((ISBSv1BuildContext) buildConfig.getBuildContext()).getBasePlatformForVariation() .toLowerCase(); } // run abld makefile platform for each component to be built if needed if (!generateAbldMakefileIfNecessary(buildConfig, launcher, componentPath, isTest, monitor)) { return false; } monitor.worked(1); if (monitor.isCanceled()) { return false; } List<String> argsList = new ArrayList<String>(); if (isTest) { argsList.add(TEST_CMD); } argsList.add(FREEZE_CMD); argsList.add(buildPlatform); argsList.add(componentName); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldFreezeArgs().split(" ")) { argsList.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false)) { return false; } monitor.worked(1); if (monitor.isCanceled()) { return false; } launcher.writeToConsole("\n***Freeze Complete\n"); return true; } public void compileFile(IPath file, ICarbideBuildConfiguration buildConfig, IPath fullMMPPath, CarbideCommandLauncher launcher, IProgressMonitor monitor) throws CoreException { ICarbideProjectInfo cpi = buildConfig.getCarbideProject(); if (!CarbideCPPBuilder.generateBldmakeMakefilesIfNecessary(buildConfig, launcher)) { return; } monitor.worked(1); if (monitor.isCanceled()) { return; } List<ISymbianBuildContext> buildConfigList = new ArrayList<ISymbianBuildContext>(1); buildConfigList.add(buildConfig.getBuildContext()); List<IPath> normalMakMakePaths = new ArrayList<IPath>(); List<IPath> testMakMakePaths = new ArrayList<IPath>(); EpocEngineHelper.getMakMakeFiles(cpi.getAbsoluteBldInfPath(), buildConfigList, normalMakMakePaths, testMakMakePaths, new NullProgressMonitor()); monitor.worked(1); if (monitor.isCanceled()) { return; } boolean found = false; boolean isTest = false; // see if we can find the component for (IPath path : normalMakMakePaths) { if (path.equals(fullMMPPath)) { found = true; break; } } if (!found) { // try the test components for (IPath path : testMakMakePaths) { if (path.equals(fullMMPPath)) { found = true; isTest = true; break; } } } if (!found) { throw new CoreException(new Status(IStatus.ERROR, CarbideBuilderPlugin.PLUGIN_ID, 0, "Unable to find mmp file " + fullMMPPath.toOSString(), null)); //$NON-NLS-1$ } areWeManagingTheMakeFiles = shouldManageMakeFiles(buildConfig); if (!runMMPChangeCheck(buildConfig, fullMMPPath, isTest, launcher)) { return; } if (!generateAbldMakefileIfNecessary(buildConfig, launcher, fullMMPPath, isTest, monitor)) { return; } monitor.worked(1); if (monitor.isCanceled()) { return; } List<IPath> objectFilePaths = new ArrayList<IPath>(); File makeFile = getMakefileForMMP(buildConfig, fullMMPPath); if (FileUtils.getSafeFileExtension(file).toLowerCase().compareTo("rss") == 0) { // rss files can be compiled for multiple languages, e.g. .R01, .R02, etc. EpocEnginePathHelper helper = new EpocEnginePathHelper(cpi.getProject()); objectFilePaths = getMakeRulesForResource(buildConfig, helper.convertFilesystemToWorkspace(fullMMPPath), helper.convertPathToView(file)); } else { // assume source file (or .s file or .cia file). we need to get the path to the output file // that matches the one in the makefile. we could normally do this without parsing the makefile // itself, but there are cases where we can't determine if the path with be absolute or relative // to the bld.inf directory. for example, my tests on EKA1 kits show that it's relative except for // WINSCW builds. For EKA1, they are always absolute, except in the UIQ3 SDK where they are similar // to EKA1. since this is a little iffy, we'll get the real path from the makefile itself so we know // we're right. this will be a little slower but... IPath makefilePath = new Path(makeFile.getAbsolutePath()); IModelProvider modelProvider = EpocEnginePlugin.getMakefileModelProvider(); IModel model = modelProvider.getSharedModel(makefilePath); if (model == null) { launcher.writeToConsole("\nERROR: Unable to create model for " + makefilePath.toOSString() + "\n"); return; } IMakefileView view = (IMakefileView) model.createView(new DefaultGNUMakefileViewConfiguration( buildConfig.getCarbideProject(), new AcceptedNodesViewFilter())); if (view == null) { launcher.writeToConsole("\nERROR: Unable to create view for " + makefilePath.toOSString() + "\n"); return; } IMacroDefinition[] epocBldMacros = view.getAllMacroDefinitions("EPOCBLD"); if (epocBldMacros.length != 1) { launcher.writeToConsole( "\nERROR: Unable to locate EPOCBLD macro in " + makefilePath.toOSString() + "\n"); return; } view.dispose(); modelProvider.releaseSharedModel(model); IPath objectDir = null; if (buildConfig.getPlatformString().startsWith(ISBSv1BuildContext.ARMV5_PLATFORM) && EpocEngineHelper.hasFeatureVariantKeyword(cpi, fullMMPPath)) { // if symbian binary variation, then the object file dir will be in sub-directory with <md5>/udeb/<obj> // The platform can only be a variant if the MMP file has FEATUREVARIANT keyword && The platform is ARMV5-based. String MD5Name = EpocEngineHelper.getMD5HashForBinaryVariant(buildConfig, fullMMPPath); if (MD5Name != null && MD5Name.length() > 0) { objectDir = new Path(epocBldMacros[0].getValue().toString()).append(MD5Name) .append(buildConfig.getTargetString()); } } if (objectDir == null) { objectDir = new Path(epocBldMacros[0].getValue().toString()).append(buildConfig.getTargetString()); } IPath path = objectDir.append(file.removeFileExtension().lastSegment() + ".o") .removeTrailingSeparator(); if (FileUtils.getSafeFileExtension(file).toLowerCase().compareTo("cia") == 0) { // .cia objects have an _ appended to them path = objectDir.append(file.removeFileExtension().lastSegment() + "_.o").removeTrailingSeparator(); } objectFilePaths.add(path); } IPath workingDirectory = cpi.getINFWorkingDirectory(); for (IPath objectPath : objectFilePaths) { // verify object file directory. the make target cannot build unless the output folder exists File objDir = objectPath.removeLastSegments(1).toFile(); if (!objDir.exists()) { objDir.mkdirs(); } // delete the object file if it exists so make will actually compile it IPath objectToDelete = objectPath; if (objectToDelete.toOSString().startsWith("..")) { // relative paths are relative to the bld.inf directory objectToDelete = workingDirectory.append(objectToDelete); } else if (objectToDelete.isAbsolute() && objectToDelete.getDevice() == null) { objectToDelete = objectToDelete.setDevice(workingDirectory.getDevice()); } try { File outputFile = objectToDelete.toFile().getCanonicalFile(); if (outputFile.exists()) { outputFile.delete(); } } catch (IOException e) { e.printStackTrace(); CarbideBuilderPlugin.log(e); } // strip off the drive to match the makefile rules String[] makeArgs = new String[] { "-f", makeFile.getAbsolutePath(), objectPath.setDevice(null).toOSString() }; launcher.setErrorParserManager(buildConfig.getCarbideProject().getINFWorkingDirectory(), buildConfig.getErrorParserList()); int retVal = launcher.executeCommand(MAKE, makeArgs, getResolvedEnvVars(buildConfig), workingDirectory); if (retVal != 0) { launcher.writeToConsole("\n=== make failed with error code " + retVal + " ==="); launcher.writeToConsole("\n***Stopping. Check the Problems view or Console output for errors.\n"); CarbideBuilderPlugin.createCarbideProjectMarker(cpi.getProject(), IMarker.SEVERITY_ERROR, "make returned with exit value = " + retVal, IMarker.PRIORITY_LOW); return; } monitor.worked(1); if (monitor.isCanceled()) { return; } } } protected List<IPath> getMakeRulesForResource(final ICarbideBuildConfiguration buildConfig, final IPath workspaceRelativeMMPPath, final IPath projectRelativeResourcePath) { final List<IPath> rules = new ArrayList<IPath>(); EpocEnginePlugin.runWithMMPData(workspaceRelativeMMPPath, new DefaultMMPViewConfiguration(buildConfig.getCarbideProject().getProject(), buildConfig.getBuildContext(), new AcceptedNodesViewFilter()), new MMPDataRunnableAdapter() { public Object run(IMMPData mmpData) { // read the project-wide target path String targetPath = mmpData.getSingleArgumentSettings().get(EMMPStatement.TARGETPATH); if (targetPath != null) { // make sure it doesn't start with a "\" but ends with one IPath targetP = new Path(targetPath).makeRelative().addTrailingSeparator(); targetPath = targetP.toOSString(); } else { // for EKA2 use sys\bin\ targetPath = "sys\\bin\\"; //$NON-NLS-1$ } String dataZDir = buildConfig.getSDK().getReleaseRoot().removeLastSegments(1).toOSString() + "\\Data\\z\\"; //$NON-NLS-1$ IPath rezPath = null; List<EMMPLanguage> languages = null; // check the user resources List<IPath> userResources = mmpData.getUserResources(); for (IPath userRes : userResources) { if (userRes.equals(projectRelativeResourcePath)) { rezPath = new Path(dataZDir).removeLastSegments(1) .append(userRes.removeFileExtension().lastSegment()); break; } } if (rezPath == null) { // check the system resources List<IPath> systemResources = mmpData.getSystemResources(); for (IPath systemRes : systemResources) { if (systemRes.equals(projectRelativeResourcePath)) { // target path for system resources is \z\system\data\ rezPath = new Path(dataZDir + "system\\data\\" + systemRes.removeFileExtension().lastSegment()); break; } } } if (rezPath == null) { // check the resource blocks List<IMMPResource> resourceBlocks = mmpData.getResourceBlocks(); for (IMMPResource resourceBlock : resourceBlocks) { if (resourceBlock.getSource().equals(projectRelativeResourcePath)) { IPath resPath = resourceBlock.getTargetPath(); if (resPath == null) { // if not specified in the resource block then get the global // target path String targetP = mmpData.getSingleArgumentSettings() .get(EMMPStatement.TARGETPATH); if (targetP != null) { resPath = new Path(targetP); } } if (resPath != null) { resPath = resPath.makeRelative().addTrailingSeparator(); String filename = resourceBlock.getTargetFile(); if (filename == null) { filename = resourceBlock.getSource().removeFileExtension() .lastSegment(); } else { filename = new Path(filename).removeFileExtension().toOSString(); } rezPath = new Path(dataZDir + resPath.toOSString() + filename); languages = resourceBlock.getLanguages(); if (languages.size() == 0) languages = null; break; } } } } if (rezPath != null) { if (languages == null) { languages = mmpData.getLanguages(); if (languages.size() == 0) { // default is non-localize languages = Collections.singletonList(EMMPLanguage.SC_NonLocalized); } } for (EMMPLanguage language : languages) { String extension = "R" + language.getCodeString(); //$NON-NLS-1$ rules.add(rezPath.addFileExtension(extension)); } } return null; } }); return rules; } protected boolean shouldManageMakeFiles(ICarbideBuildConfiguration buildConfig) { // check the project pref to see if we should manage the make files ICarbideProjectInfo cpi = buildConfig.getCarbideProject(); if (cpi.areMakefilesManaged()) { return true; } return false; } protected boolean updateMakDepsFile(ISymbianSDK sdk) { // add the following to the top of the the Deps_GenDependsL subroutine in makdeps.pm String change = "\r\n\t# Carbide.c++ change. See CARBIDE_CHANGES.TXT for more details.\r\n\tif ($ENV{CARBIDE_NO_DEPENDENCIES}) {\r\n\t\treturn;\r\n\t}\r\n"; IPath toolsPath = sdk.getToolsPath(); boolean updated = false; try { File mdFile = toolsPath.append("makdeps.pm").toFile(); RandomAccessFile makDepsFile = new RandomAccessFile(mdFile, "rw"); // back up the file first File backupFile = toolsPath.append("makdeps.pmbak").toFile(); if (backupFile.createNewFile()) { FileUtils.copyFile(mdFile, backupFile); } // now scan for the line we're interested in String line = makDepsFile.readLine(); while (line != null) { if (line.startsWith("sub Deps_GenDependsL")) { // now insert our text long fp = makDepsFile.getFilePointer(); byte[] bytes = new byte[(int) (makDepsFile.length() - fp)]; makDepsFile.readFully(bytes); makDepsFile.seek(fp); String newText = new String(bytes); newText = change + newText; makDepsFile.write(newText.getBytes()); updated = true; break; } line = makDepsFile.readLine(); } makDepsFile.close(); } catch (Exception e) { CarbideBuilderPlugin.log(e); e.printStackTrace(); } if (!updated) { return false; } // now create the CARBIDE_CHANGES.TXT file File ourFile = toolsPath.append(CARBIDE_CHANGES_FILE).toFile(); try { if (!ourFile.createNewFile()) { return false; } // now write the content String content = "In order to improve build performance, we need to tell the Symbian build tools not to generate dependency\r\n" + "information for sources and resources in the make files. The dependency information will still be generated and\r\n" + "tracked, but will be done on a per-file basis. In order to do this, we needed to add a few lines to the makdeps.pm\r\n" + "file. This change will not affect command line builds. The previous file was backed up and named makdeps.pmbak.\r\n"; FileWriter writer = new FileWriter(ourFile); writer.write(content); writer.flush(); writer.close(); } catch (IOException e) { CarbideBuilderPlugin.log(e); e.printStackTrace(); return false; } return true; } public boolean buildAllComponents(ICarbideBuildConfiguration buildConfig, List<IPath> normalMakMakePaths, List<IPath> testMakMakePaths, CarbideCommandLauncher launcher, IProgressMonitor monitor) { ISBSv1BuildContext sbsv1Context = (ISBSv1BuildContext) buildConfig.getBuildContext(); //TODO: do we really want to bail if abld returns an error? is this the keepgoing flag? see what the command line builds do. // they bail on an individual build step, but keep building the other steps even if there's an error and keepgoing is not specified // need to run individual build steps when managing makefiles or doing concurrent builds if (!areWeManagingTheMakeFiles && !buildConfig.getCarbideProject().isConcurrentBuildingEnabled()) { // not using our dependency stuff. just call abld [test] build. note that we need // to do this because the makefile step needs to happen even if the mmp hasn't changed // because the dependency info is in the makefiles. SubMonitor progress = SubMonitor.convert(monitor, 3); progress.setTaskName(CarbideBuildManagerUtils.getBuildLabel(buildConfig, null)); if (!CarbideCPPBuilder.generateBldmakeMakefilesIfNecessary(buildConfig, launcher)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } // run abld build for normal components if there are any if (normalMakMakePaths.size() > 0) { List<String> argsList = new ArrayList<String>(); argsList.add(BUILD_CMD); argsList.add(buildConfig.getPlatformString().toLowerCase()); argsList.add(buildConfig.getTargetString().toLowerCase()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldBuildArgs().split(" ")) { argsList.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false)) { return false; } } progress.worked(1); if (progress.isCanceled()) { return false; } // run abld build for test components if there are any if (buildConfig.getCarbideProject().isBuildingTestComps()) { if (testMakMakePaths.size() > 0) { List<String> argsList = new ArrayList<String>(); argsList.add(TEST_CMD); argsList.add(BUILD_CMD); argsList.add(buildConfig.getPlatformString().toLowerCase()); argsList.add(buildConfig.getTargetString().toLowerCase()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldBuildArgs().split(" ")) { argsList.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false)) { return false; } } } progress.worked(1); if (progress.isCanceled()) { return false; } return true; } // figure out exactly how much work we have to do int unitsOfWork = 3; if (normalMakMakePaths.size() > 0) { unitsOfWork += 4; } if (buildConfig.getCarbideProject().isBuildingTestComps()) { unitsOfWork += 1; } if (testMakMakePaths.size() > 0) { unitsOfWork += 4; } SubMonitor progress = SubMonitor.convert(monitor, unitsOfWork); progress.setTaskName(CarbideBuildManagerUtils.getBuildLabel(buildConfig, null)); if (!CarbideCPPBuilder.generateBldmakeMakefilesIfNecessary(buildConfig, launcher)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } // run abld export even if there are no mmps List<String> args = new ArrayList<String>(); args.add(EXPORT_CMD); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldExportArgs().split(" ")) { args.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, args.toArray(new String[args.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } if (!runMMPChangeCheck(buildConfig, normalMakMakePaths, testMakMakePaths, launcher)) { return false; } // run abld makefile platform for each component to be built if needed if (!CarbideCPPBuilder.generateAbldMakefilesIfNecessary(buildConfig, launcher, false, progress)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } // build the normal components if there are any if (normalMakMakePaths.size() > 0) { // run abld library platform args.clear(); args.add(LIBRARY_CMD); args.add(buildConfig.getPlatformString().toLowerCase()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldLibraryArgs().split(" ")) { args.add(arg); } removeMakeVariableOneTime = true; if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, args.toArray(new String[args.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } // run abld resource platform target args.clear(); args.add(RESOURCE_CMD); args.add(buildConfig.getPlatformString().toLowerCase()); args.add(buildConfig.getTargetString().toLowerCase()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldResourceArgs().split(" ")) { args.add(arg); } removeMakeVariableOneTime = true; if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, args.toArray(new String[args.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } // run abld target platform target args.clear(); args.add(TARGET_CMD); args.add(buildConfig.getPlatformString().toLowerCase()); args.add(buildConfig.getTargetString().toLowerCase()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldTargetArgs().split(" ")) { args.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, args.toArray(new String[args.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } // run abld final platform target args.clear(); args.add(FINAL_CMD); args.add(buildConfig.getPlatformString().toLowerCase()); args.add(buildConfig.getTargetString().toLowerCase()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldFinalArgs().split(" ")) { args.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, args.toArray(new String[args.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } } // run abld test export even if there are no mmps // only do this if building test components is checked. note we do this // even if there are no test mmps. there could still be test exports. if (buildConfig.getCarbideProject().isBuildingTestComps()) { args.clear(); args.add(TEST_CMD); args.add(EXPORT_CMD); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldExportArgs().split(" ")) { args.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, args.toArray(new String[args.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } } // build the test components if there are any if (testMakMakePaths.size() > 0) { // run abld library platform args.clear(); args.add(TEST_CMD); args.add(LIBRARY_CMD); args.add(buildConfig.getPlatformString().toLowerCase()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldLibraryArgs().split(" ")) { args.add(arg); } removeMakeVariableOneTime = true; if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, args.toArray(new String[args.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } // run abld resource platform target args.clear(); args.add(TEST_CMD); args.add(RESOURCE_CMD); args.add(buildConfig.getPlatformString().toLowerCase()); args.add(buildConfig.getTargetString().toLowerCase()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldResourceArgs().split(" ")) { args.add(arg); } removeMakeVariableOneTime = true; if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, args.toArray(new String[args.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } // run abld target platform target args.clear(); args.add(TEST_CMD); args.add(TARGET_CMD); args.add(buildConfig.getPlatformString().toLowerCase()); args.add(buildConfig.getTargetString().toLowerCase()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldTargetArgs().split(" ")) { args.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, args.toArray(new String[args.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } // run abld final platform target args.clear(); args.add(TEST_CMD); args.add(FINAL_CMD); args.add(buildConfig.getPlatformString().toLowerCase()); args.add(buildConfig.getTargetString().toLowerCase()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldFinalArgs().split(" ")) { args.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, args.toArray(new String[args.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } } return true; } public boolean buildComponentSubset(ICarbideBuildConfiguration buildConfig, List<IPath> normalMakMakePaths, List<IPath> testMakMakePaths, CarbideCommandLauncher launcher, IProgressMonitor monitor) { ISBSv1BuildContext sbsv1Context = (ISBSv1BuildContext) buildConfig.getBuildContext(); // need to run individual build steps when managing makefiles or doing concurrent builds if (!areWeManagingTheMakeFiles && !buildConfig.getCarbideProject().isConcurrentBuildingEnabled()) { // not using our dependency stuff. just call abld [test] build. note that we need // to do this because the makefile step needs to happen even if the mmp hasn't changed // because the dependency info is in the makefiles. SubMonitor progress = SubMonitor.convert(monitor, 1 + normalMakMakePaths.size() + testMakMakePaths.size()); progress.setTaskName(CarbideBuildManagerUtils.getBuildLabel(buildConfig, null)); if (!CarbideCPPBuilder.generateBldmakeMakefilesIfNecessary(buildConfig, launcher)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } // run abld build platform for each component for (IPath path : normalMakMakePaths) { String buildPlatform = ""; if (buildConfig.getPlatformString().startsWith(ISBSv1BuildContext.ARMV5_PLATFORM) && EpocEngineHelper.hasFeatureVariantKeyword(buildConfig.getCarbideProject(), path)) { buildPlatform = buildConfig.getPlatformString().toLowerCase(); } else if (buildConfig.getBuildContext() instanceof ISBSv1BuildContext) { buildPlatform = ((ISBSv1BuildContext) buildConfig.getBuildContext()) .getBasePlatformForVariation().toLowerCase(); } List<String> argsList = new ArrayList<String>(); argsList.add(BUILD_CMD); argsList.add(buildPlatform); argsList.add(buildConfig.getTargetString().toLowerCase()); argsList.add(path.removeFileExtension().lastSegment()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldBuildArgs().split(" ")) { argsList.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } } // run abld build platform target for each test component for (IPath path : testMakMakePaths) { String buildPlatform = ""; if (buildConfig.getPlatformString().startsWith(ISBSv1BuildContext.ARMV5_PLATFORM) && EpocEngineHelper.hasFeatureVariantKeyword(buildConfig.getCarbideProject(), path)) { buildPlatform = buildConfig.getPlatformString().toLowerCase(); } else if (buildConfig.getBuildContext() instanceof ISBSv1BuildContext) { buildPlatform = ((ISBSv1BuildContext) buildConfig.getBuildContext()) .getBasePlatformForVariation().toLowerCase(); } List<String> argsList = new ArrayList<String>(); argsList.add(TEST_CMD); argsList.add(BUILD_CMD); argsList.add(buildPlatform); argsList.add(buildConfig.getTargetString().toLowerCase()); argsList.add(path.removeFileExtension().lastSegment()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldBuildArgs().split(" ")) { argsList.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } } // in case there are no components selected, we still need to do an export if (normalMakMakePaths.size() == 0) { if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, new String[] { EXPORT_CMD }, false)) { return false; } } if (testMakMakePaths.size() == 0) { if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, new String[] { TEST_CMD, EXPORT_CMD }, false)) { return false; } } return true; } SubMonitor progress = SubMonitor.convert(monitor, 4 + (normalMakMakePaths.size() * 4) + (testMakMakePaths.size() * 4)); progress.setTaskName(CarbideBuildManagerUtils.getBuildLabel(buildConfig, null)); if (!CarbideCPPBuilder.generateBldmakeMakefilesIfNecessary(buildConfig, launcher)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } // run abld export even if there are no mmps - note, this is not mmp specific List<String> argsList = new ArrayList<String>(); argsList.add(EXPORT_CMD); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldExportArgs().split(" ")) { argsList.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } if (!runMMPChangeCheck(buildConfig, normalMakMakePaths, testMakMakePaths, launcher)) { return false; } // run abld makefile platform for each component to be built if needed if (!CarbideCPPBuilder.generateAbldMakefilesIfNecessary(buildConfig, launcher, false, progress)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } // build the normal components if there are any. do each abld step for all components. if (normalMakMakePaths.size() > 0) { // run abld library platform for each component for (IPath path : normalMakMakePaths) { String buildPlatform = ""; if (buildConfig.getPlatformString().startsWith(ISBSv1BuildContext.ARMV5_PLATFORM) && EpocEngineHelper.hasFeatureVariantKeyword(buildConfig.getCarbideProject(), path)) { buildPlatform = buildConfig.getPlatformString().toLowerCase(); } else if (buildConfig.getBuildContext() instanceof ISBSv1BuildContext) { buildPlatform = ((ISBSv1BuildContext) buildConfig.getBuildContext()) .getBasePlatformForVariation().toLowerCase(); } argsList.clear(); argsList.add(LIBRARY_CMD); argsList.add(buildPlatform); argsList.add(path.removeFileExtension().lastSegment()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldLibraryArgs().split(" ")) { argsList.add(arg); } removeMakeVariableOneTime = true; if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } } // run abld resource platform target for each component for (IPath path : normalMakMakePaths) { String buildPlatform = ""; if (buildConfig.getPlatformString().startsWith(ISBSv1BuildContext.ARMV5_PLATFORM) && EpocEngineHelper.hasFeatureVariantKeyword(buildConfig.getCarbideProject(), path)) { buildPlatform = buildConfig.getPlatformString().toLowerCase(); } else if (buildConfig.getBuildContext() instanceof ISBSv1BuildContext) { buildPlatform = ((ISBSv1BuildContext) buildConfig.getBuildContext()) .getBasePlatformForVariation().toLowerCase(); } argsList.clear(); argsList.add(RESOURCE_CMD); argsList.add(buildPlatform); argsList.add(buildConfig.getTargetString().toLowerCase()); argsList.add(path.removeFileExtension().lastSegment()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldResourceArgs().split(" ")) { argsList.add(arg); } removeMakeVariableOneTime = true; if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } } // run abld target platform target for each component for (IPath path : normalMakMakePaths) { String buildPlatform = ""; if (buildConfig.getPlatformString().startsWith(ISBSv1BuildContext.ARMV5_PLATFORM) && EpocEngineHelper.hasFeatureVariantKeyword(buildConfig.getCarbideProject(), path)) { buildPlatform = buildConfig.getPlatformString().toLowerCase(); } else if (buildConfig.getBuildContext() instanceof ISBSv1BuildContext) { buildPlatform = ((ISBSv1BuildContext) buildConfig.getBuildContext()) .getBasePlatformForVariation().toLowerCase(); } argsList.clear(); argsList.add(TARGET_CMD); argsList.add(buildPlatform); argsList.add(buildConfig.getTargetString().toLowerCase()); argsList.add(path.removeFileExtension().lastSegment()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldTargetArgs().split(" ")) { argsList.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } } // run abld final platform target for each component for (IPath path : normalMakMakePaths) { String buildPlatform = ""; if (buildConfig.getPlatformString().startsWith(ISBSv1BuildContext.ARMV5_PLATFORM) && EpocEngineHelper.hasFeatureVariantKeyword(buildConfig.getCarbideProject(), path)) { buildPlatform = buildConfig.getPlatformString().toLowerCase(); } else if (buildConfig.getBuildContext() instanceof ISBSv1BuildContext) { buildPlatform = ((ISBSv1BuildContext) buildConfig.getBuildContext()) .getBasePlatformForVariation().toLowerCase(); } argsList.clear(); argsList.add(FINAL_CMD); argsList.add(buildPlatform); argsList.add(buildConfig.getTargetString().toLowerCase()); argsList.add(path.removeFileExtension().lastSegment()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldFinalArgs().split(" ")) { argsList.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } } } // run abld test export even if there are no mmps - note, this is not mmp specific argsList.clear(); argsList.add(TEST_CMD); argsList.add(EXPORT_CMD); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldExportArgs().split(" ")) { argsList.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } // build the test components if there are any. do each abld step for all components. if (testMakMakePaths.size() > 0) { // run abld library platform for each component for (IPath path : testMakMakePaths) { String buildPlatform = ""; if (buildConfig.getPlatformString().startsWith(ISBSv1BuildContext.ARMV5_PLATFORM) && EpocEngineHelper.hasFeatureVariantKeyword(buildConfig.getCarbideProject(), path)) { buildPlatform = buildConfig.getPlatformString().toLowerCase(); } else if (buildConfig.getBuildContext() instanceof ISBSv1BuildContext) { buildPlatform = ((ISBSv1BuildContext) buildConfig.getBuildContext()) .getBasePlatformForVariation().toLowerCase(); } argsList.clear(); argsList.add(TEST_CMD); argsList.add(LIBRARY_CMD); argsList.add(buildPlatform); argsList.add(path.removeFileExtension().lastSegment()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldLibraryArgs().split(" ")) { argsList.add(arg); } removeMakeVariableOneTime = true; if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } } // run abld resource platform target for each component for (IPath path : testMakMakePaths) { String buildPlatform = ""; if (buildConfig.getPlatformString().startsWith(ISBSv1BuildContext.ARMV5_PLATFORM) && EpocEngineHelper.hasFeatureVariantKeyword(buildConfig.getCarbideProject(), path)) { buildPlatform = buildConfig.getPlatformString().toLowerCase(); } else if (buildConfig.getBuildContext() instanceof ISBSv1BuildContext) { buildPlatform = ((ISBSv1BuildContext) buildConfig.getBuildContext()) .getBasePlatformForVariation().toLowerCase(); } argsList.clear(); argsList.add(TEST_CMD); argsList.add(RESOURCE_CMD); argsList.add(buildPlatform); argsList.add(buildConfig.getTargetString().toLowerCase()); argsList.add(path.removeFileExtension().lastSegment()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldResourceArgs().split(" ")) { argsList.add(arg); } removeMakeVariableOneTime = true; if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } } // run abld target platform target for each component for (IPath path : testMakMakePaths) { String buildPlatform = ""; if (buildConfig.getPlatformString().startsWith(ISBSv1BuildContext.ARMV5_PLATFORM) && EpocEngineHelper.hasFeatureVariantKeyword(buildConfig.getCarbideProject(), path)) { buildPlatform = buildConfig.getPlatformString().toLowerCase(); } else { buildPlatform = ((ISBSv1BuildContext) buildConfig.getBuildContext()) .getBasePlatformForVariation().toLowerCase(); } argsList.clear(); argsList.add(TEST_CMD); argsList.add(TARGET_CMD); argsList.add(buildPlatform); argsList.add(buildConfig.getTargetString().toLowerCase()); argsList.add(path.removeFileExtension().lastSegment()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldTargetArgs().split(" ")) { argsList.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } } // run abld final platform target for each component for (IPath path : testMakMakePaths) { String buildPlatform = ""; if (buildConfig.getPlatformString().startsWith(ISBSv1BuildContext.ARMV5_PLATFORM) && EpocEngineHelper.hasFeatureVariantKeyword(buildConfig.getCarbideProject(), path)) { buildPlatform = buildConfig.getPlatformString().toLowerCase(); } else if (buildConfig.getBuildContext() instanceof ISBSv1BuildContext) { buildPlatform = ((ISBSv1BuildContext) buildConfig.getBuildContext()) .getBasePlatformForVariation().toLowerCase(); } argsList.clear(); argsList.add(TEST_CMD); argsList.add(FINAL_CMD); argsList.add(buildPlatform); argsList.add(buildConfig.getTargetString().toLowerCase()); argsList.add(path.removeFileExtension().lastSegment()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldFinalArgs().split(" ")) { argsList.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false)) { return false; } progress.worked(1); if (progress.isCanceled()) { return false; } } } return true; } public void cleanAllComponents(ICarbideBuildConfiguration buildConfig, List<IPath> normalMakMakePaths, List<IPath> testMakMakePaths, CarbideCommandLauncher launcher, IProgressMonitor monitor) { SubMonitor progress = SubMonitor.convert(monitor, 5); progress.setTaskName("Cleaning " + buildConfig.getDisplayString()); ISBSv1BuildContext sbsv1Context = (ISBSv1BuildContext) buildConfig.getBuildContext(); if (!CarbideCPPBuilder.generateBldmakeMakefilesIfNecessary(buildConfig, launcher)) { return; } progress.worked(1); if (progress.isCanceled()) { return; } if (!CarbideCPPBuilder.generateAbldMakefilesIfNecessary(buildConfig, launcher, false, progress)) { return; } progress.worked(1); if (progress.isCanceled()) { return; } CarbideProjectInfo cpi = (CarbideProjectInfo) buildConfig.getCarbideProject(); int cleanLevel = cpi.getCleanLevel(); String abldCleanCmd = REALLYCLEAN_CMD; if (0 == cleanLevel) { abldCleanCmd = CLEAN_CMD; } // clean the normal components if there are any if (normalMakMakePaths.size() > 0) { List<String> argsList = new ArrayList<String>(); argsList.add(abldCleanCmd); argsList.add(buildConfig.getPlatformString().toLowerCase()); argsList.add(buildConfig.getTargetString().toLowerCase()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldCleanArgs().split(" ")) { argsList.add(arg); } // run abld clean/reallyclean if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false)) { return; } } progress.worked(1); if (progress.isCanceled()) { return; } // clean the test components if there are any if (testMakMakePaths.size() > 0) { List<String> argsList = new ArrayList<String>(); argsList.add(TEST_CMD); argsList.add(abldCleanCmd); argsList.add(buildConfig.getPlatformString().toLowerCase()); argsList.add(buildConfig.getTargetString().toLowerCase()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldCleanArgs().split(" ")) { argsList.add(arg); } // run abld test clean/reallyclean if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false)) { return; } } progress.worked(1); if (progress.isCanceled()) { return; } if (2 == cleanLevel) { // clean level 2 so we need to run bldmake clean as well List<String> argsList = new ArrayList<String>(); argsList.add(CLEAN_CMD); argsList.add(buildConfig.getPlatformString().toLowerCase()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getBldmakeCleanArgs().split(" ")) { argsList.add(arg); } CarbideCPPBuilder.invokeBldmakeCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false); } progress.worked(1); if (progress.isCanceled()) { return; } } public void cleanComponentSubset(ICarbideBuildConfiguration buildConfig, List<IPath> normalMakMakePaths, List<IPath> testMakMakePaths, CarbideCommandLauncher launcher, IProgressMonitor monitor) { SubMonitor progress = SubMonitor.convert(monitor, 3 + normalMakMakePaths.size() + testMakMakePaths.size()); progress.setTaskName("Cleaning " + buildConfig.getDisplayString()); ISBSv1BuildContext sbsv1Context = (ISBSv1BuildContext) buildConfig.getBuildContext(); if (!CarbideCPPBuilder.generateBldmakeMakefilesIfNecessary(buildConfig, launcher)) { return; } progress.worked(1); if (progress.isCanceled()) { return; } if (!CarbideCPPBuilder.generateAbldMakefilesIfNecessary(buildConfig, launcher, false, progress)) { return; } progress.worked(1); if (progress.isCanceled()) { return; } CarbideProjectInfo cpi = (CarbideProjectInfo) buildConfig.getCarbideProject(); int cleanLevel = cpi.getCleanLevel(); String abldCleanCmd = REALLYCLEAN_CMD; if (0 == cleanLevel) { abldCleanCmd = CLEAN_CMD; } // clean the normal components if there are any if (normalMakMakePaths.size() > 0) { // run abld clean/reallyclean for each component for (IPath path : normalMakMakePaths) { String buildPlatform = ""; if (buildConfig.getPlatformString().startsWith(ISBSv1BuildContext.ARMV5_PLATFORM) && EpocEngineHelper.hasFeatureVariantKeyword(buildConfig.getCarbideProject(), path)) { buildPlatform = buildConfig.getPlatformString().toLowerCase(); } else if (buildConfig.getBuildContext() instanceof ISBSv1BuildContext) { buildPlatform = ((ISBSv1BuildContext) buildConfig.getBuildContext()) .getBasePlatformForVariation().toLowerCase(); } List<String> argsList = new ArrayList<String>(); argsList.add(abldCleanCmd); argsList.add(buildPlatform); argsList.add(buildConfig.getTargetString().toLowerCase()); argsList.add(path.removeFileExtension().lastSegment()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldCleanArgs().split(" ")) { argsList.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false)) { return; } progress.worked(1); if (progress.isCanceled()) { return; } } } // clean the test components if there are any if (testMakMakePaths.size() > 0) { // run abld test clean/reallyclean for each component for (IPath path : testMakMakePaths) { List<String> argsList = new ArrayList<String>(); argsList.add(TEST_CMD); argsList.add(abldCleanCmd); argsList.add(buildConfig.getPlatformString().toLowerCase()); argsList.add(buildConfig.getTargetString().toLowerCase()); argsList.add(path.removeFileExtension().lastSegment()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldCleanArgs().split(" ")) { argsList.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false)) { return; } progress.worked(1); if (progress.isCanceled()) { return; } } } if (2 == cleanLevel) { // clean level 2 so we need to run bldmake clean as well List<String> argsList = new ArrayList<String>(); argsList.add(CLEAN_CMD); argsList.add(buildConfig.getPlatformString().toLowerCase()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getBldmakeCleanArgs().split(" ")) { argsList.add(arg); } CarbideCPPBuilder.invokeBldmakeCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false); } progress.worked(1); if (progress.isCanceled()) { return; } } public void freezeAllComponents(ICarbideBuildConfiguration buildConfig, List<IPath> normalMakMakePaths, List<IPath> testMakMakePaths, CarbideCommandLauncher launcher, IProgressMonitor monitor) { SubMonitor progress = SubMonitor.convert(monitor, 4); progress.setTaskName("Freezing " + buildConfig.getDisplayString()); ISBSv1BuildContext sbsv1Context = (ISBSv1BuildContext) buildConfig.getBuildContext(); if (!CarbideCPPBuilder.generateBldmakeMakefilesIfNecessary(buildConfig, launcher)) { return; } progress.worked(1); if (progress.isCanceled()) { return; } if (!CarbideCPPBuilder.generateAbldMakefilesIfNecessary(buildConfig, launcher, false, progress)) { return; } progress.worked(1); if (progress.isCanceled()) { return; } // freeze the normal components if there are any if (normalMakMakePaths.size() > 0) { List<String> argsList = new ArrayList<String>(); argsList.add(FREEZE_CMD); argsList.add(buildConfig.getPlatformString().toLowerCase()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldFreezeArgs().split(" ")) { argsList.add(arg); } // run abld freeze if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false)) { return; } } progress.worked(1); if (progress.isCanceled()) { return; } // freeze the test components if there are any if (testMakMakePaths.size() > 0) { List<String> argsList = new ArrayList<String>(); argsList.add(TEST_CMD); argsList.add(FREEZE_CMD); argsList.add(buildConfig.getPlatformString().toLowerCase()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldFreezeArgs().split(" ")) { argsList.add(arg); } // run abld test freeze if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false)) { return; } } progress.worked(1); if (progress.isCanceled()) { return; } } public void freezeComponentSubset(ICarbideBuildConfiguration buildConfig, List<IPath> normalMakMakePaths, List<IPath> testMakMakePaths, CarbideCommandLauncher launcher, IProgressMonitor monitor) { SubMonitor progress = SubMonitor.convert(monitor, 2 + normalMakMakePaths.size() + testMakMakePaths.size()); progress.setTaskName("Freezing " + buildConfig.getDisplayString()); ISBSv1BuildContext sbsv1Context = (ISBSv1BuildContext) buildConfig.getBuildContext(); if (!CarbideCPPBuilder.generateBldmakeMakefilesIfNecessary(buildConfig, launcher)) { return; } progress.worked(1); if (progress.isCanceled()) { return; } if (!CarbideCPPBuilder.generateAbldMakefilesIfNecessary(buildConfig, launcher, false, progress)) { return; } progress.worked(1); if (progress.isCanceled()) { return; } // freeze the normal components if there are any if (normalMakMakePaths.size() > 0) { // run abld freeze for each component for (IPath path : normalMakMakePaths) { String buildPlatform = ""; if (buildConfig.getPlatformString().startsWith(ISBSv1BuildContext.ARMV5_PLATFORM) && EpocEngineHelper.hasFeatureVariantKeyword(buildConfig.getCarbideProject(), path)) { buildPlatform = buildConfig.getPlatformString().toLowerCase(); } else if (buildConfig.getBuildContext() instanceof ISBSv1BuildContext) { buildPlatform = ((ISBSv1BuildContext) buildConfig.getBuildContext()) .getBasePlatformForVariation().toLowerCase(); } List<String> argsList = new ArrayList<String>(); argsList.add(FREEZE_CMD); argsList.add(buildPlatform); argsList.add(path.removeFileExtension().lastSegment()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldFreezeArgs().split(" ")) { argsList.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false)) { return; } progress.worked(1); if (progress.isCanceled()) { return; } } } // freeze the test components if there are any if (testMakMakePaths.size() > 0) { // run abld test freeze for each component for (IPath path : testMakMakePaths) { List<String> argsList = new ArrayList<String>(); argsList.add(TEST_CMD); argsList.add(FREEZE_CMD); argsList.add(buildConfig.getPlatformString().toLowerCase()); argsList.add(path.removeFileExtension().lastSegment()); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldFreezeArgs().split(" ")) { argsList.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false)) { return; } progress.worked(1); if (progress.isCanceled()) { return; } } } } protected boolean runMMPChangeCheck(final ICarbideBuildConfiguration buildConfig, IPath componentPath, boolean isTest, final CarbideCommandLauncher launcher) { // don't worry about it for tests if (WorkbenchUtils.isJUnitRunning()) { return true; } // ignore this for Qt projects since the mmp will be regenerated before each build. final IProject project = buildConfig.getCarbideProject().getProject(); if (QtCorePlugin.isQtProject(project)) { return true; } // we used to ignore this for emulator builds, thinking everything of interest was in the .uid.cpp file. well, a lot of // the things are, but not all. see bug #5504 for more details. if (!buildConfig.getCarbideProject().promptForMMPChangedAction() && buildConfig.getCarbideProject().defaultMMPChangedAction() == ICarbideProjectInfo.ACTION_NONE) { // don't need to do anything return true; } final List<MMPChangedAction> mmpList = new ArrayList<MMPChangedAction>(); int defaultAction = 0; ICarbideProjectInfo cpi = CarbideBuilderPlugin.getBuildManager().getProjectInfo(project); if (cpi != null) { defaultAction = cpi.defaultMMPChangedAction(); } if (hasMMPMakefileChanged(buildConfig, componentPath)) { mmpList.add(new MMPChangedAction(componentPath, defaultAction, isTest)); } return mmpsChanged(buildConfig, mmpList, launcher); } protected boolean runMMPChangeCheck(final ICarbideBuildConfiguration buildConfig, List<IPath> normalMakMakePaths, List<IPath> testMakMakePaths, final CarbideCommandLauncher launcher) { // don't worry about it for tests if (WorkbenchUtils.isJUnitRunning()) { return true; } // ignore this for Qt projects since the mmp will be regenerated before each build. final IProject project = buildConfig.getCarbideProject().getProject(); if (QtCorePlugin.isQtProject(project)) { return true; } // we used to ignore this for emulator builds, thinking everything of interest was in the .uid.cpp file. well, a lot of // the things are, but not all. see bug #5504 for more details. if (!buildConfig.getCarbideProject().promptForMMPChangedAction() && buildConfig.getCarbideProject().defaultMMPChangedAction() == ICarbideProjectInfo.ACTION_NONE) { // don't need to do anything return true; } final List<MMPChangedAction> mmpList = new ArrayList<MMPChangedAction>(); int defaultAction = 0; ICarbideProjectInfo cpi = CarbideBuilderPlugin.getBuildManager().getProjectInfo(project); if (cpi != null) { defaultAction = cpi.defaultMMPChangedAction(); } // check all mmps for (IPath path : normalMakMakePaths) { if (hasMMPMakefileChanged(buildConfig, path)) { mmpList.add(new MMPChangedAction(path, defaultAction, false)); } } for (IPath path : testMakMakePaths) { if (hasMMPMakefileChanged(buildConfig, path)) { mmpList.add(new MMPChangedAction(path, defaultAction, true)); } } return mmpsChanged(buildConfig, mmpList, launcher); } protected boolean mmpsChanged(final ICarbideBuildConfiguration buildConfig, final List<MMPChangedAction> mmpList, final CarbideCommandLauncher launcher) { if (mmpList.size() < 1) { // no changed mmps return true; } if (!buildConfig.getCarbideProject().promptForMMPChangedAction()) { // just apply the default action to each mmp switch (buildConfig.getCarbideProject().defaultMMPChangedAction()) { case ICarbideProjectInfo.ACTION_NONE: // do nothing break; case ICarbideProjectInfo.ACTION_LINK_ONLY: for (MMPChangedAction action : mmpList) { // force re-link forceRelink(buildConfig, action.fullMMPPath); } break; case ICarbideProjectInfo.ACTION_COMPILE_AND_LINK: for (MMPChangedAction action : mmpList) { // force re-compile forceRecompile(buildConfig, action.fullMMPPath, action.isTest, launcher); } break; } return true; } // run in the UI thread IWorkbench workbench = PlatformUI.getWorkbench(); IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); if (window == null) { IWorkbenchWindow windows[] = workbench.getWorkbenchWindows(); window = windows[0]; } final Shell shell = window.getShell(); final IProject project = buildConfig.getCarbideProject().getProject(); final MMPChangedActionDialog dlg = new MMPChangedActionDialog(shell, project, mmpList); // trick to get return value final List<Boolean> retVal = new ArrayList<Boolean>(1); shell.getDisplay().syncExec(new Runnable() { public void run() { if (Dialog.OK == dlg.open()) { // check the don't bug me option if (dlg.dontAskAgain()) { // uncheck the project or workspace setting CarbideProjectModifier cpm = (CarbideProjectModifier) CarbideBuilderPlugin.getBuildManager() .getProjectModifier(project); if (cpm != null) { // if there's only one mmp then change the default action to what they selected. // ideally when "don't ask me again" is checked we'd remember their decision, but // since they can decide different actions for different mmp files, we can't really // do it. so only remember their decision when there's one mmp file. boolean saveAction = (mmpList.size() == 1); if (cpm.overrideWorkspaceBuildSettingsProjectValue()) { cpm.writeProjectSetting(CarbideProjectInfo.PROMPT_FOR_MMP_CHANGED_ACTION, "false"); if (saveAction) { cpm.writeProjectSetting(CarbideProjectInfo.DEFAULT_MMP_CHANGED_ACTION, Integer.toString(mmpList.get(0).mmpAction)); } cpm.saveChanges(); } else { IPreferenceStore store = CarbideBuilderPlugin.getDefault().getPreferenceStore(); store.setValue(BuilderPreferenceConstants.PREF_MMP_CHANGED_ACTION_PROMPT, false); if (saveAction) { store.setValue(BuilderPreferenceConstants.PREF_DEFAULT_MMP_CHANGED_ACTION, mmpList.get(0).mmpAction); } } } } for (MMPChangedAction action : mmpList) { if (action.mmpAction == 1) { // force re-link forceRelink(buildConfig, action.fullMMPPath); } else if (action.mmpAction == 2) { // force re-compile or clean forceRecompile(buildConfig, action.fullMMPPath, action.isTest, launcher); } } // need to return true retVal.add(Boolean.TRUE); } else { // need to return false retVal.add(Boolean.FALSE); } } }); return retVal.get(0).booleanValue(); } protected void forceRecompile(ICarbideBuildConfiguration buildConfig, IPath mmpPath, boolean isTest, CarbideCommandLauncher launcher) { // we could delete the entire object code directory and any .rsc files generated by // the mmp, but it's easier to just clean the component String componentName = mmpPath.removeFileExtension().lastSegment(); launcher.writeToConsole("\n***Cleaning component \"" + componentName + "\" for configuration \"" + buildConfig.getDisplayString() + "\"\n"); // only do a basic clean since we just want the object code and output files removed, nothing else List<String> argsList = new ArrayList<String>(); if (isTest) { argsList.add(TEST_CMD); } argsList.add(CLEAN_CMD); argsList.add(buildConfig.getPlatformString().toLowerCase()); argsList.add(buildConfig.getTargetString().toLowerCase()); argsList.add(componentName); ISBSv1BuildContext sbsv1Context = (ISBSv1BuildContext) buildConfig.getBuildContext(); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldCleanArgs().split(" ")) { argsList.add(arg); } if (!CarbideCPPBuilder.invokeAbldCommand(buildConfig, launcher, argsList.toArray(new String[argsList.size()]), false)) { return; } launcher.writeToConsole("\n***Clean Complete\n"); } protected void forceRelink(ICarbideBuildConfiguration buildConfig, IPath mmpPath) { // just want to re-link but not compile anything. we need to delete some linker // dependency. the most reliable is the output of the build. IPath outputPath = EpocEngineHelper.getHostPathForExecutable(buildConfig, mmpPath); if (outputPath != null) { File outputFile = outputPath.toFile(); if (outputFile.exists()) { outputFile.delete(); } } } public boolean invokeBldmakeCommand(ICarbideBuildConfiguration buildConfig, CarbideCommandLauncher launcher, String[] bldmakeArgs) { ICarbideProjectInfo cpi = buildConfig.getCarbideProject(); IProject project = cpi.getProject(); List<String> args = new ArrayList<String>(bldmakeArgs.length + 2); args.addAll(Arrays.asList(bldmakeArgs)); args.add(0, "bldmake.pl"); //$NON-NLS-1$ args.add(0, "-S"); //$NON-NLS-1$ bldmakeArgs = args.toArray(new String[args.size()]); launcher.setErrorParserManager(buildConfig.getCarbideProject().getINFWorkingDirectory(), CarbideCPPBuilder.getParserIdArray(ICarbideBuildConfiguration.ERROR_PARSERS_BLDMAKE_MAKE)); launcher.writeToConsole("\n***Invoking bldmake command\n"); int retVal = launcher.executeCommand(PERL, bldmakeArgs, getResolvedEnvVars(buildConfig), cpi.getINFWorkingDirectory()); if (retVal != 0) { launcher.writeToConsole("\n=== BLDMAKE 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, "bldmake returned with exit value = " + retVal, IMarker.PRIORITY_LOW); return false; } launcher.writeToConsole(launcher.getTimingStats()); return true; } public boolean invokeAbldCommand(ICarbideBuildConfiguration buildConfig, CarbideCommandLauncher launcher, String[] abldArgs) { ICarbideProjectInfo cpi = buildConfig.getCarbideProject(); IProject project = cpi.getProject(); List<String> args = new ArrayList<String>(abldArgs.length + 2); args.addAll(Arrays.asList(abldArgs)); args.add(0, launcher.getWorkingDirectory().setDevice(null).addTrailingSeparator().toOSString()); args.add(0, "ABLD.PL"); //$NON-NLS-1$ args.add(0, "-S"); //$NON-NLS-1$ abldArgs = args.toArray(new String[args.size()]); launcher.setErrorParserManager(buildConfig.getCarbideProject().getINFWorkingDirectory(), buildConfig.getErrorParserList()); launcher.writeToConsole("\n***Invoking abld command\n"); int retVal = launcher.executeCommand(PERL, abldArgs, getResolvedEnvVars(buildConfig), cpi.getINFWorkingDirectory()); if (retVal != 0) { launcher.writeToConsole("\n=== ABLD 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, "abld returned with exit value = " + retVal, IMarker.PRIORITY_LOW); return false; } launcher.writeToConsole(launcher.getTimingStats()); return true; } public String[] getResolvedEnvVars(ICarbideBuildConfiguration config) { String[] vars = config.getEnvironmentVarsInfo().getResolvedEnvironmentVariables(); if (removeMakeVariableOneTime) { removeMakeVariableOneTime = false; List<String> newVars = new ArrayList<String>(); newVars.addAll(Arrays.asList(vars)); // start at the end as it's probably there for (int i = newVars.size() - 1; i >= 0; i--) { String var = newVars.get(i); if (var.startsWith("MAKE=make -j")) { newVars.remove(var); break; } } vars = newVars.toArray(new String[newVars.size()]); } return vars; } public boolean needsBldmakeMakefileGeneration(ICarbideBuildConfiguration config) { ICarbideProjectInfo cpi = config.getCarbideProject(); IPath bldInfPath = cpi.getAbsoluteBldInfPath(); IPath bldInfDir = bldInfPath.removeLastSegments(1); if (!bldInfDir.toFile().exists()) { return true; // try to generate and let the build process flag the error } if (!bldInfDir.append(ABLD_BAT_NAME).toFile().exists()) { return true; // abld.bat does not exist, generate it } // check for the makefiles dir... IPath prjBuildPath = getMakefileDirectory(config); if (!prjBuildPath.toFile().exists()) { return true; // no build dir } else { // there should always be EXPORT.MAKE and EXPORTTEST.MAKE, PLATFORM.PM, and then {plat}.MAKE and {plat}TEST.MAKE, where // {plat} is the platform string, e.g. WINSCW, ARMV5. if one of these doesn't exist then we need to run // bldmake bldfiles platform. if they all exist, we need to get the oldest time stamp. if that time stamp is // older than the bld.inf or any of its includes then we need to regenerate the makefiles. File makeFile = prjBuildPath.append("EXPORT.MAKE").toFile(); if (!makeFile.exists()) { return true; } long oldestMakefileTimestamp = makeFile.lastModified(); makeFile = prjBuildPath.append("EXPORTTEST.MAKE").toFile(); if (!makeFile.exists()) { return true; } if (makeFile.lastModified() < oldestMakefileTimestamp) { oldestMakefileTimestamp = makeFile.lastModified(); } makeFile = prjBuildPath.append("PLATFORM.PM").toFile(); if (!makeFile.exists()) { return true; } if (makeFile.lastModified() < oldestMakefileTimestamp) { oldestMakefileTimestamp = makeFile.lastModified(); } makeFile = prjBuildPath.append(config.getPlatformString() + ".MAKE").toFile(); if (!makeFile.exists()) { return true; } if (makeFile.lastModified() < oldestMakefileTimestamp) { oldestMakefileTimestamp = makeFile.lastModified(); } makeFile = prjBuildPath.append(config.getPlatformString() + "TEST.MAKE").toFile(); if (!makeFile.exists()) { return true; } if (makeFile.lastModified() < oldestMakefileTimestamp) { oldestMakefileTimestamp = makeFile.lastModified(); } // we need to check the variant hrh files as well File prefixFile = config.getBuildContext().getPrefixFromVariantCfg().toFile(); if (prefixFile != null && prefixFile.lastModified() > oldestMakefileTimestamp) { return true; } for (File file : config.getBuildContext().getVariantHRHIncludes()) { if (file.lastModified() > oldestMakefileTimestamp) { return true; } } // all make files exist. now make sure the oldest of them is newer than the bld.inf or any of its includes final long finalOldestMakefileTimestamp = oldestMakefileTimestamp; Boolean regenerate = (Boolean) EpocEnginePlugin.runWithBldInfView(bldInfPath, new DefaultViewConfiguration(config.getBuildContext(), bldInfPath, new AcceptedNodesViewFilter()), new BldInfViewRunnableAdapter() { public Object run(IBldInfView view) { for (IPath file : view.getReferencedFiles()) { if (file.toFile().lastModified() > finalOldestMakefileTimestamp) { return Boolean.TRUE; } } return Boolean.FALSE; } }); return regenerate.booleanValue(); } } public boolean generateAbldMakefileIfNecessary(ICarbideBuildConfiguration config, CarbideCommandLauncher launcher, IPath componentPath, boolean isTest) { return generateAbldMakefileIfNecessary(config, launcher, componentPath, isTest, new NullProgressMonitor()); } public boolean generateAbldMakefileIfNecessary(ICarbideBuildConfiguration config, CarbideCommandLauncher launcher, IPath componentPath, boolean isTest, IProgressMonitor progress) { // generate the makefile if necessary if (needsAbldMakefileGeneration(config, componentPath)) { ICarbideProjectInfo cpi = config.getCarbideProject(); IPath workingDir = cpi.getINFWorkingDirectory(); launcher.setErrorParserManager(workingDir, config.getErrorParserList()); launcher.writeToConsole("\n***Generating abld makefile.\n"); // delete the *.uid.cpp file if it exists so it gets regenerated. makmake won't regenerate it if only an mmp include // file has changed. see bug #4590 for details. if (config.getPlatformString().equals(ISBSv1BuildContext.EMULATOR_PLATFORM)) { File uidFile = new Path(getMakefileForMMP(config, componentPath).getAbsolutePath()) .removeFileExtension().addFileExtension("UID.CPP").toFile(); if (uidFile.exists()) { uidFile.delete(); } } List<String> abldArgs = new ArrayList<String>(); abldArgs.add(0, "ABLD.PL"); //$NON-NLS-1$ abldArgs.add(0, "-S"); //$NON-NLS-1$ abldArgs.add(launcher.getWorkingDirectory().setDevice(null).addTrailingSeparator().toOSString()); if (isTest) { abldArgs.add(TEST_CMD); //$NON-NLS-1$ } String buildPlatform = ""; if (config.getPlatformString().startsWith(ISBSv1BuildContext.ARMV5_PLATFORM) && EpocEngineHelper.hasFeatureVariantKeyword(config.getCarbideProject(), componentPath)) { buildPlatform = config.getPlatformString().toLowerCase(); } else if (config.getBuildContext() instanceof ISBSv1BuildContext) { buildPlatform = ((ISBSv1BuildContext) config.getBuildContext()).getBasePlatformForVariation() .toLowerCase(); } abldArgs.add(MAKEFILE_CMD); //$NON-NLS-1$ abldArgs.add(buildPlatform); abldArgs.add(componentPath.removeFileExtension().lastSegment()); ISBSv1BuildContext sbsv1Context = (ISBSv1BuildContext) config.getBuildContext(); for (String arg : sbsv1Context.getBuildArgumentsInfo().getAbldMakefileArgs().split(" ")) { abldArgs.add(arg); } launcher.writeToConsole("\n***Invoking abld command\n"); int retVal = launcher.executeCommand(PERL, abldArgs.toArray(new String[abldArgs.size()]), getResolvedEnvVars(config), workingDir); launcher.writeToConsole(launcher.getTimingStats()); if (retVal != 0) { launcher.writeToConsole("\n***Abld returned with exit value = " + retVal); launcher.writeToConsole("\n***Stopping.\n"); return false; } // now make our changes to the generated makefile if (areWeManagingTheMakeFiles) { try { updateMakefile(config, componentPath, progress); } catch (CoreException e) { CarbideBuilderPlugin.log(e); e.printStackTrace(); } } } return true; } protected boolean needsAbldMakefileGeneration(final ICarbideBuildConfiguration config, IPath componentPath) { // if this is an extension makefile then we always do the makefile step. if (isExtensionMakefile(componentPath)) { return true; } ICarbideProjectInfo cpi = config.getCarbideProject(); File makefile = getMakefileForMMP(config, componentPath); if (!makefile.exists()) { return true; } final long makefileTimestamp = makefile.lastModified(); // we need to check the variant hrh files as well File prefixFile = config.getBuildContext().getPrefixFromVariantCfg().toFile(); if (prefixFile != null && prefixFile.lastModified() > makefileTimestamp) { return true; } for (File file : config.getBuildContext().getVariantHRHIncludes()) { if (file.lastModified() > makefileTimestamp) { return true; } } // see if the makefile is newer than the mmp and all of its includes Boolean regenerate = (Boolean) EpocEnginePlugin.runWithMMPData(componentPath, new DefaultMMPViewConfiguration(cpi.getProject(), config.getBuildContext(), new AcceptedNodesViewFilter()), new MMPDataRunnableAdapter() { public Object run(IMMPData data) { for (IPath path : data.getReferencedFiles()) { if (path.toFile().lastModified() > makefileTimestamp) { return Boolean.TRUE; } } return Boolean.FALSE; } }); if (regenerate.booleanValue()) { return true; } // now check to see if our makefile changes are there final IPreferenceStore prefsStore = CarbideBuilderPlugin.getDefault().getPreferenceStore(); if (prefsStore.getBoolean(BuilderPreferenceConstants.PREF_DONT_PROMPT_FOR_DEPENDENCY_MISMATCH) == false && areWeManagingTheMakeFiles && !makeFileHasOurChanges(makefile) && !WorkbenchUtils.isJUnitRunning()) { // if they are not then the user must have been building from the command line. this means that // any dependency files that exist could be stale so we need to delete them. we also need to // remove any object code since the corresponding dependency info will not be available. final int manageDeps[] = { IDialogConstants.OK_ID }; Display.getDefault().syncExec(new Runnable() { public void run() { // ask the user if they want to update now TrackDependenciesQueryDialog dlg = new TrackDependenciesQueryDialog( WorkbenchUtils.getSafeShell(), config.getCarbideProject()); manageDeps[0] = dlg.open(); } }); try { if (manageDeps[0] == IDialogConstants.OK_ID) { cleanupObjectCodeDirectory(new Path(makefile.getAbsolutePath()).removeLastSegments(1)); } } catch (Exception e) { CarbideBuilderPlugin.log(e); e.printStackTrace(); } if (manageDeps[0] == IDialogConstants.OK_ID) { return true; } else { return false; } } return false; } protected boolean hasMMPMakefileChanged(ICarbideBuildConfiguration config, IPath componentPath) { if (isExtensionMakefile(componentPath)) { return false; } ICarbideProjectInfo cpi = config.getCarbideProject(); // only return true when it exists and the mmp or any of its includes is newer File makefile = getMakefileForMMP(config, componentPath); if (!makefile.exists()) { return false; } final long makefileTimestamp = makefile.lastModified(); // we need to check the variant hrh files as well File prefixFile = config.getBuildContext().getPrefixFromVariantCfg().toFile(); if (prefixFile != null && prefixFile.lastModified() > makefileTimestamp) { return true; } for (File file : config.getBuildContext().getVariantHRHIncludes()) { if (file.lastModified() > makefileTimestamp) { return true; } } // see if the makefile is newer than the mmp and all of its includes Boolean regenerate = (Boolean) EpocEnginePlugin.runWithMMPData(componentPath, new DefaultMMPViewConfiguration(cpi.getProject(), config.getBuildContext(), new AcceptedNodesViewFilter()), new MMPDataRunnableAdapter() { public Object run(IMMPData data) { for (IPath path : data.getReferencedFiles()) { if (path.toFile().lastModified() > makefileTimestamp) { return Boolean.TRUE; } } return Boolean.FALSE; } }); return regenerate.booleanValue(); } protected boolean makeFileHasOurChanges(File makefile) { // check the first line of our file for the CARBIDE_MAKEFILE_TEXT comment try { String text = new String(FileUtils.readFileContents(makefile, null)); if (text.startsWith(CARBIDE_MAKEFILE_TEXT)) { return true; } } catch (CoreException e) { } return false; } protected void cleanupObjectCodeDirectory(IPath makefileDir) { // delete any .d, .dep, .o and .obj files in the makefile directory File files[] = makefileDir.toFile().listFiles(objectCodeDirectoryFileFilter); if (files != null) { for (File file : files) { file.delete(); } } // now delete any .d or .dep files in the udeb/urel directories files = makefileDir.append("udeb").toFile().listFiles(objectCodeDirectoryFileFilter); if (files != null) { for (File file : files) { file.delete(); } } files = makefileDir.append("urel").toFile().listFiles(objectCodeDirectoryFileFilter); if (files != null) { for (File file : files) { file.delete(); } } } public File getMakefileForMMP(ICarbideBuildConfiguration config, IPath componentPath) { // create a path to the directory where the make files live IPath makefilePath = new Path(config.getSDK().getEPOCROOT()).append(EPOC_BUILD_DIR); makefilePath = makefilePath.append(config.getCarbideProject().getINFWorkingDirectory().setDevice(null)); // each mmp file has its own directory String mmpName = componentPath.removeFileExtension().lastSegment().toUpperCase(); makefilePath = makefilePath.append(mmpName); // each platform has its own directory String platformName = ""; if (EpocEngineHelper.hasFeatureVariantKeyword(config.getCarbideProject(), componentPath)) { platformName = config.getPlatformString().toUpperCase(); } else if (config.getBuildContext() instanceof ISBSv1BuildContext) { platformName = ((ISBSv1BuildContext) config.getBuildContext()).getBasePlatformForVariation(); } makefilePath = makefilePath.append( ((ISBSv1BuildContext) config.getBuildContext()).getBasePlatformForVariation().toUpperCase()); // and the makefile has the form MMPNAME.PLATFORM makefilePath = makefilePath.append(mmpName + "." + platformName); if (!makefilePath.toFile().exists()) { makefilePath = makefilePath.removeLastSegments(1); makefilePath = makefilePath.append(mmpName + "." + platformName + ".DEFAULT"); } return makefilePath.toFile(); } protected void updateMakefile(ICarbideBuildConfiguration config, IPath componentPath, IProgressMonitor progress) throws CoreException { // ignore extension makefiles. if (isExtensionMakefile(componentPath)) { return; } if (progress.isCanceled()) { return; } File makefile = getMakefileForMMP(config, componentPath); if (!makefile.exists()) { throw new CoreException(new Status(IStatus.ERROR, CarbideBuilderPlugin.PLUGIN_ID, 0, "Makefile " + makefile.getAbsolutePath() + " doesn't exist.", null)); //$NON-NLS-1$ } IPath makefilePath = new Path(makefile.getAbsolutePath()); IModelProvider modelProvider = EpocEnginePlugin.getMakefileModelProvider(); IModel model = modelProvider.getSharedModel(makefilePath); if (model == null) { throw new CoreException(new Status(IStatus.ERROR, CarbideBuilderPlugin.PLUGIN_ID, 0, "Unable to create model for makefile " + makefile.getAbsolutePath(), null)); //$NON-NLS-1$ } IMakefileView view = (IMakefileView) model.createView( new DefaultGNUMakefileViewConfiguration(config.getCarbideProject(), new AcceptedNodesViewFilter())); if (view == null) { throw new CoreException(new Status(IStatus.ERROR, CarbideBuilderPlugin.PLUGIN_ID, 0, "Unable to create view for makefile " + makefile.getAbsolutePath(), null)); //$NON-NLS-1$ } // copy the fix_dep_file_paths.pl file to the makefile directory IPath makefileDirPath = makefilePath.removeLastSegments(1).addTrailingSeparator(); createFixupDepsFile(makefileDirPath); // insert our tag string - note, this will be at the top of the file view.insertText(null, CARBIDE_MAKEFILE_TEXT + view.getEOL()); // insert the includes after the macros so we can use them. IMacroDefinition[] lastMacro = view.getAllMacroDefinitions("EPOCASSPLINKUREL"); if (lastMacro.length != 1) { throw new CoreException(new Status(IStatus.ERROR, CarbideBuilderPlugin.PLUGIN_ID, 0, "Unable to include dependencies in makefile " + makefile.getAbsolutePath(), null)); //$NON-NLS-1$ } // .d for everything but WINSCW String dependencyFileExt = "d"; if (config.getPlatformString().equals(ISBSv1BuildContext.EMULATOR_PLATFORM)) { dependencyFileExt = "dep"; } IPath udebDirPath = makefilePath.removeLastSegments(1).append("udeb").addTrailingSeparator(); IPath urelDirPath = makefilePath.removeLastSegments(1).append("urel").addTrailingSeparator(); view.insertText(lastMacro[0], "-include " + urelDirPath + "*." + dependencyFileExt + view.getEOL()); view.insertText(lastMacro[0], "-include " + udebDirPath + "*." + dependencyFileExt + view.getEOL()); view.insertText(lastMacro[0], "-include " + makefileDirPath + "*.d" + view.getEOL()); view.insertText(lastMacro[0], view.getEOL() + "# Include dependency files" + view.getEOL()); view.insertText(lastMacro[0], ".DELETE_ON_ERROR:" + view.getEOL()); view.insertText(lastMacro[0], view.getEOL() + "# Delete targets if/when updating them fails." + view.getEOL()); // now add the -MD switch to the compiler args final String platform = config.getPlatformString(); if (platform.equals(ISBSv1BuildContext.EMULATOR_PLATFORM)) { // append the -MD and -gccdep switches to the CWFLAGS macro IMacroDefinition[] macros = view.getAllMacroDefinitions("CWFLAGS"); if (macros.length < 1) { throw new CoreException(new Status(IStatus.ERROR, CarbideBuilderPlugin.PLUGIN_ID, 0, "CWFLAGS macro not found in makefile", null)); //$NON-NLS-1$ } IMacroDefinition macro = macros[macros.length - 1]; // add the switches before to the end of the macro. toString may add a line delimiter to the end so strip that off String macroText = macro.toString(); if (macroText.endsWith("\n")) { macroText = macroText.substring(0, macroText.length() - 1); } macroText = macroText + " -MD -gccdep" + view.getEOL(); view.replaceDirective(macro, macroText); } else if (platform.equals(ISBSv1BuildContext.GCCE_PLATFORM)) { // append the -MD switch to the CCFLAGS macro. there may be more than one so take the last one IMacroDefinition[] macros = view.getAllMacroDefinitions("CCFLAGS"); if (macros.length < 1) { throw new CoreException(new Status(IStatus.ERROR, CarbideBuilderPlugin.PLUGIN_ID, 0, "CCFLAGS macro not found in makefile", null)); //$NON-NLS-1$ } IMacroDefinition macro = macros[macros.length - 1]; // add the switches before to the end of the macro. toString may add a line delimiter to the end so strip that off String macroText = macro.toString(); if (macroText.endsWith("\n")) { macroText = macroText.substring(0, macroText.length() - 1); } macroText = macroText + " -MD" + view.getEOL(); view.replaceDirective(macro, macroText); } else { // assuming some version of RVCT IMacroDefinition[] macros = view.getAllMacroDefinitions("ARMCCFLAGS"); if (macros.length > 0) { IMacroDefinition macro = macros[macros.length - 1]; // add the switches before to the end of the macro. toString may add a line delimiter to the end so strip that off String macroText = macro.toString(); if (macroText.endsWith("\n")) { macroText = macroText.substring(0, macroText.length() - 1); } macroText = macroText + " --md" + view.getEOL(); view.replaceDirective(macro, macroText); } else { // newer kits (it looks like 9.4 and later) use different make variables macros = view.getAllMacroDefinitions("CCFLAGS"); if (macros.length > 0) { // there may be more than one CCFLAGS macro so take the last one IMacroDefinition macro = macros[macros.length - 1]; // add the switches before to the end of the macro. toString may add a line delimiter to the end so strip that off String macroText = macro.toString(); if (macroText.endsWith("\n")) { macroText = macroText.substring(0, macroText.length() - 1); } macroText = macroText + " --md" + view.getEOL(); view.replaceDirective(macro, macroText); } else { throw new CoreException(new Status(IStatus.ERROR, CarbideBuilderPlugin.PLUGIN_ID, 0, "Compiler flags macro (ARMCCFLAGS/CCFLAGS) not found in makefile", null)); //$NON-NLS-1$ } } } final String dep_file_paths_perl_script = "\"" + makefileDirPath.append(FIXUP_DEPFILES_FILE).toOSString() + "\""; // now add preprocess commands to the resource file rules. if ALT_PRE env variable is set then // use scpp.exe, otherwise use cpp.exe. pipe the output to a dependency file in the makefile directory. String cpp = "cpp" + HostOS.EXE_EXT; for (String var : getResolvedEnvVars(config)) { if (var.compareTo("ALT_PRE") == 0 || var.startsWith("ALT_PRE=")) { cpp = "rcpp" + HostOS.EXE_EXT; break; } } for (ICommand resourceCmd : view.findCommandsInvoking("perl -S epocrc.pl")) { Object parent = resourceCmd.getParent(); if (parent instanceof ITargetRule) { ITargetRule rule = (ITargetRule) parent; // need to get a new copy of the rule. when we make changes, they are committed and // the makefile is re-parsed so the line number get updated in case any lines were added // or removed. if we use the "stale" copy we'd be making the changes to the wrong lines! rule = view.findRuleForTarget(rule.getTarget().toString(), true); if (rule == null) { throw new CoreException(new Status(IStatus.ERROR, CarbideBuilderPlugin.PLUGIN_ID, 0, "Resource rule not found in makefile", null)); //$NON-NLS-1$ } // figure out the dependency file name String depFileName = rule.getTarget().toString(); int lastdelimiter = depFileName.lastIndexOf("\\"); if (lastdelimiter < 0) { throw new CoreException(new Status(IStatus.ERROR, CarbideBuilderPlugin.PLUGIN_ID, 0, "Failed trying to build cpp command", null)); //$NON-NLS-1$ } depFileName = depFileName.substring(lastdelimiter) + ".d"; // now update the rule so it uses our dependency macro String changedRule = rule.toString(); // now replace the $(DEPEND) with $(DEPENDdepfilename) changedRule = changedRule.replaceFirst("DEPEND", "DEPEND" + depFileName) + view.getEOL(); // fix up line endings. IDirective#toString uses \n whereas the rest of the makefile // uses \r\n\. CDT could change though so check the line endings before changing them. changedRule = changedRule.replaceAll("(?<!\r)\n", view.getEOL()); // now replace the old rule with our new one view.replaceDirective(rule, changedRule); // calculate the full path to the dependency file String depFilePath = makefileDirPath.append(depFileName).toOSString(); // now create a dependency on the .rsc to the .rsc.d String newRule = view.getEOL() + "# Create the dependency on the resource dependency file" + view.getEOL(); newRule = newRule + rule.getTarget().toString() + ": " + depFilePath + view.getEOL(); // now create the rule to create the .rsc.d file newRule = newRule + view.getEOL() + "# Create the rule to generate the actual dependency file" + view.getEOL(); newRule = newRule + depFilePath + ":" + view.getEOL(); // now add the cpp command to our new rule newRule = newRule + "\t" + cpp + " -undef -M -nostdinc "; // add the compiler prefix file if any IPath compilerPrefix = config.getBuildContext().getCompilerPrefixFile(); if (compilerPrefix != null) { newRule = newRule + "-include \"" + compilerPrefix.toOSString() + "\" "; } // get the includes and any resource macros from the actual call to epocrc.pl String rcompCmd = resourceCmd.toString(); int firstInclude = rcompCmd.indexOf("-I"); int dashU = rcompCmd.lastIndexOf("-u"); int dashO = rcompCmd.lastIndexOf("-o$@"); if (dashO < 0) { dashO = rcompCmd.lastIndexOf("-o\"$@\""); } if (firstInclude < 0 || dashU < 0 || dashO < 0) { throw new CoreException(new Status(IStatus.ERROR, CarbideBuilderPlugin.PLUGIN_ID, 0, "Failed trying to build cpp command", null)); //$NON-NLS-1$ } // strip off everything before the first -I and everything after the .rss path rcompCmd = rcompCmd.substring(firstInclude, dashO); // strip off any uid switches after the rss file - see bug #5196 int uidSwitch = rcompCmd.indexOf("-uid"); if (uidSwitch >= 0) { rcompCmd = rcompCmd.substring(0, uidSwitch); } newRule += rcompCmd; // find the macros we need to pass, and replace the -u switch with them String macros = null; if (platform.equals(ISBSv1BuildContext.EMULATOR_PLATFORM)) { // the macros are listed in the CWDEFS macro IMacroDefinition[] defs = view.getAllMacroDefinitions("CWDEFS"); if (defs.length != 1) { throw new CoreException(new Status(IStatus.ERROR, CarbideBuilderPlugin.PLUGIN_ID, 0, "CWDEFS macro not found in makefile", null)); //$NON-NLS-1$ } // need to expand macros here macros = defs[0].getValue().toString(); macros = view.expandAllMacrosInString(macros); // remove quotes, and change -d to -D macros = macros.replaceAll("\"", ""); macros = macros.replaceAll("-d ", "-D"); } else if (platform.equals(ISBSv1BuildContext.GCCE_PLATFORM)) { // the macros are listed in the CCDEFS macro IMacroDefinition[] defs = view.getAllMacroDefinitions("CCDEFS"); if (defs.length != 1) { throw new CoreException(new Status(IStatus.ERROR, CarbideBuilderPlugin.PLUGIN_ID, 0, "CCDEFS macro not found in makefile", null)); //$NON-NLS-1$ } // need to expand macros here macros = defs[0].getValue().toString(); macros = view.expandAllMacrosInString(macros); } else { // assuming some version of RVCT // the macros are listed in the ARMCCDEFS macro IMacroDefinition[] defs = view.getAllMacroDefinitions("ARMCCDEFS"); if (defs.length != 1) { // newer kits (it looks like 9.4 and later) use different make variables defs = view.getAllMacroDefinitions("CCDEFS"); if (defs.length != 1) { throw new CoreException(new Status(IStatus.ERROR, CarbideBuilderPlugin.PLUGIN_ID, 0, "Compiler defines macro (ARMCCDEFS/CCDEFS) not found in makefile", null)); //$NON-NLS-1$ } } // need to expand macros here macros = defs[0].getValue().toString(); macros = view.expandAllMacrosInString(macros); } if (macros != null) { // now strip off any macros that were'nt resolved macros = macros.replaceAll("\\$\\(.*?\\)", ""); // cleanup the __PRODUCT_INCLUDE__ macro if necessary macros = macros.replaceFirst("\\\\\"", "\"<" + makefilePath.getDevice()); macros = macros.replaceFirst("\\\\\"", ">\""); macros = macros.replaceAll("\\\\", "/"); newRule = newRule.replaceFirst("-u ", macros); } // add the compiler prefix file if any ISymbianSDK sdk = config.getSDK(); ISBSv1BuildInfo sbsv1BuildInfo = (ISBSv1BuildInfo) sdk .getBuildInfo(ISymbianBuilderID.SBSV1_BUILDER); ISBVPlatform sbvPlatform = sbsv1BuildInfo.getSBVCatalog().findPlatform(config.getPlatformString()); File sdkPrefix = config.getBuildContext().getPrefixFromVariantCfg().toFile(); if (sbvPlatform != null) { // might be an alternate HRH file to use IPath varVarHRH = sbvPlatform.getBuildVariantHRHFile(); if (!varVarHRH.toFile().equals(sdkPrefix) && varVarHRH.toFile().exists()) { sdkPrefix = varVarHRH.toFile(); } } if (sdkPrefix != null && sdkPrefix.exists()) { newRule = newRule + "-include \"" + sdkPrefix.getAbsolutePath() + "\" "; } newRule += " -o " + depFilePath + view.getEOL(); // for some reason cpp.exe doesn't like paths without the drive letter when working on a subst'ed drive. newRule = newRule.replaceAll("\"\\\\", "\"" + makefilePath.getDevice() + "\\\\"); // now add the call to cleanup the dependency file newRule = newRule + "\tperl -S " + dep_file_paths_perl_script + " " + depFilePath + " cpp" + view.getEOL() + view.getEOL(); view.insertTextBefore(newRule, rule); } } // we need to cleanup the dependency files IRule[] rules = view.getMakefile().getRules(); if (rules != null && rules.length > 0) { for (IRule rule : rules) { // some old kits like S60 1.2 used .obj for winscw builds if (rule.getTarget().toString().endsWith(".o") || rule.getTarget().toString().endsWith(".obj")) { // .s files will not have dependency files ICommand[] cmds = rule.getCommands(); if (cmds.length > 0) { String cmd = cmds[0].toString().toLowerCase(); if (cmd.endsWith(".s") || cmd.endsWith(".s\n")) { continue; } } // need to get a new copy of the rule. when we make changes, they are committed and // the makefile is reparsed so the line number get updated in case any lines were added // or removed. if we use the "stale" copy we'd be making the changes to the wrong lines! rule = view.findRuleForTarget(rule.getTarget().toString(), true); if (rule == null) { throw new CoreException(new Status(IStatus.ERROR, CarbideBuilderPlugin.PLUGIN_ID, 0, "Rule not found in makefile", null)); //$NON-NLS-1$ } String newRule = rule.toString(); IPath destPath = new Path(rule.getTarget().toString()).removeFileExtension() .addFileExtension(dependencyFileExt); String sourcePath = config.getCarbideProject().getINFWorkingDirectory().addTrailingSeparator() .toOSString() + destPath.lastSegment(); // RVCT and GCC98 generate the dependency files in the bld.inf directory. create a command to move // them to the object code directory in the object file rules. note that we do this from within the // makefile rather than outside of it for two reasons: // 1) There could be source files with the same name in different mmp files, so when building from // the bld.inf you could wind up overwriting dependency files. // 2) This will keep the makefiles we alter working from the command line as well (if the user does abld target) // // The Symbian GCC Improvement project updated the GCC for EKA1 kits to GCC 3.0. This behaves much like GCCE. Rather than // running gcc to get the version (which could be tricky), we can just check for the folder // \epoc32\gcc\lib\gcc-lib\arm-epoc-pe\3.0-psion-98r2. If it exists, we'll assume GCC 3.0 and treat it like GCCE. boolean isGCC30 = false; if (config.getSDK().getToolsPath().removeLastSegments(1) .append("gcc\\lib\\gcc-lib\\arm-epoc-pe\\3.0-psion-98r2").toFile().exists()) { isGCC30 = true; } boolean moveDepFile = false; if (!platform.equals(ISBSv1BuildContext.EMULATOR_PLATFORM) && !platform.equals(ISBSv1BuildContext.GCCE_PLATFORM)) { // some form of ARMV5|6 moveDepFile = true; } if (moveDepFile) { newRule = newRule + "\tperl -S ecopyfile.pl " + sourcePath + " " + destPath.toOSString() + view.getEOL(); newRule = newRule + "\tdel " + sourcePath + view.getEOL() + view.getEOL(); } String plat = ""; if (platform.equals(ISBSv1BuildContext.EMULATOR_PLATFORM)) { plat = "winscw"; } else if (platform.equals(ISBSv1BuildContext.GCCE_PLATFORM)) { plat = "gcce"; } if (plat.length() > 0) { newRule = newRule + "\tperl -S " + dep_file_paths_perl_script + " " + destPath.toOSString() + " " + plat + view.getEOL() + view.getEOL(); } // fix up line endings. IDirective#toString uses \n whereas the rest of the makefile // uses \r\n\. CDT could change though so check the line endings before changing them. newRule = newRule.replaceAll("(?<!\r)\n", view.getEOL()); // now replace the old rule with our new one view.replaceDirective(rule, newRule); // fix for bug #7748. we may need to update the listing rule as well since it could generate // a dependency file if (!platform.equals(ISBSv1BuildContext.EMULATOR_PLATFORM)) { // only non-WINSCW platforms are affected rule = view.findRuleForTarget(new Path(rule.getTarget().toString()).removeFileExtension() .addFileExtension("lis").toOSString(), true); if (rule != null) { newRule = rule.toString(); if (moveDepFile) { newRule = newRule + "\tperl -S ecopyfile.pl " + sourcePath + " " + destPath.toOSString() + view.getEOL(); newRule = newRule + "\tdel " + sourcePath + view.getEOL() + view.getEOL(); } if (plat.length() > 0) { newRule = newRule + "\tperl -S " + dep_file_paths_perl_script + " " + destPath.toOSString() + " " + plat + view.getEOL() + view.getEOL(); } // fix up line endings. IDirective#toString uses \n whereas the rest of the makefile // uses \r\n\. CDT could change though so check the line endings before changing them. newRule = newRule.replaceAll("(?<!\r)\n", view.getEOL()); // now replace the old rule with our new one view.replaceDirective(rule, newRule); } } } } } // armcc will not generated an output file when -E is passed (preprocess) along with --md (see bug #4873) // find all rules for .pre files and expand the macros and remove --md rules = view.getMakefile().getRules(); if (rules != null && rules.length > 0) { for (IRule rule : rules) { if (rule.getTarget().toString().endsWith(".pre")) { // sanity check that it's a preprocess command // some kits will use a PREPROCESSOR_OPTION macro which is in the #included compilation config file, so expand the // macros first. String expandedRule = view.expandAllMacrosInString(rule.toString()); if (expandedRule.indexOf("-E ") > 0) { // need to get a new copy of the rule. when we make changes, they are committed and // the makefile is re-parsed so the line number get updated in case any lines were added // or removed. if we use the "stale" copy we'd be making the changes to the wrong lines! rule = view.findRuleForTarget(rule.getTarget().toString(), true); if (rule == null) { throw new CoreException(new Status(IStatus.ERROR, CarbideBuilderPlugin.PLUGIN_ID, 0, "Rule not found in makefile", null)); //$NON-NLS-1$ } String newRule = expandedRule.replaceFirst("--md ", ""); // fix up line endings. IDirective#toString uses \n whereas the rest of the makefile // uses \r\n\. CDT could change though so check the line endings before changing them. newRule = newRule.replaceAll("(?<!\r)\n", view.getEOL()); // now replace the old rule with our new one view.replaceDirective(rule, newRule); } } } } // append the default rule. this is the catch-all rule for anything it doesn't find a rule for elsewhere in the // makefile. this basically tells make to not complain when a source or header doesn't exist, but execute the // commands for the rule in question and let the tool (like a compiler) handle the error. view.appendText(".DEFAULT: ;" + view.getEOL()); // now commit the changes and release the file while (true) { try { view.commit(); break; } catch (IllegalStateException e) { if (!view.merge()) { view.revert(); } } } view.dispose(); modelProvider.releaseSharedModel(model); } private void createFixupDepsFile(IPath directory) throws CoreException { File file = directory.append(FIXUP_DEPFILES_FILE).toFile(); try { if (!file.exists() && !file.createNewFile()) { throw new CoreException(new Status(IStatus.ERROR, CarbideBuilderPlugin.PLUGIN_ID, 0, "Unable to create fix_dep_file_paths.pl in " + directory.toOSString(), null)); //$NON-NLS-1$ } BufferedInputStream in = new BufferedInputStream( FileLocator.openStream(CarbideBuilderPlugin.getDefault().getBundle(), new Path("data").append(FIXUP_DEPFILES_FILE), false)); //$NON-NLS-1$ FileOutputStream out = new FileOutputStream(file); byte[] buf = new byte[1024]; int len; while ((len = in.read(buf)) > 0) { out.write(buf, 0, len); } in.close(); out.close(); } catch (IOException e) { CarbideBuilderPlugin.log(e); throw new CoreException(new Status(IStatus.ERROR, CarbideBuilderPlugin.PLUGIN_ID, 0, "Unable to create fix_dep_file_paths.pl contents in " + directory.toOSString(), null)); //$NON-NLS-1$ } } protected boolean isExtensionMakefile(IPath componenetPath) { // mmp files will always have the mmp extension, even if they have a different extension // in the bld.inf file if (FileUtils.getSafeFileExtension(componenetPath).compareToIgnoreCase("mmp") == 0) { return false; } return true; } public IPath getMakefileDirectory(ICarbideBuildConfiguration config) { return new Path(config.getSDK().getEPOCROOT()).append(EPOC_BUILD_DIR) .append(config.getCarbideProject().getAbsoluteBldInfPath().removeLastSegments(1).setDevice(null)); } }