/******************************************************************************* * Copyright (c) 2014 Rohde & Schwarz GmbH & Co. KG and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Martin Runge - initial implementation of cmake support *******************************************************************************/ package org.eclipse.cdt.cmake; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.URI; import java.util.ArrayList; import java.util.List; import org.eclipse.cdt.cmake.ui.CMakePropertyConstants; import org.eclipse.cdt.cmake.ui.PreferenceConstants; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.ErrorParserManager; import org.eclipse.cdt.core.ICommandLauncher; import org.eclipse.cdt.core.IConsoleParser; import org.eclipse.cdt.core.envvar.IContributedEnvironment; import org.eclipse.cdt.core.envvar.IEnvironmentVariable; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.resources.IConsole; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.internal.core.BuildRunnerHelper; import org.eclipse.cdt.managedbuilder.core.IConfiguration; import org.eclipse.cdt.managedbuilder.core.IManagedBuildInfo; import org.eclipse.cdt.managedbuilder.core.ITool; import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin; import org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator; import org.eclipse.core.filesystem.URIUtil; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IncrementalProjectBuilder; import org.eclipse.core.resources.ProjectScope; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.variables.IStringVariableManager; import org.eclipse.core.variables.IValueVariable; import org.eclipse.core.variables.VariablesPlugin; public class CMakeMakefileGenerator implements IManagedBuilderMakefileGenerator { Path workspacePath; String projectName; IManagedBuildInfo buildInfo; IProject project; IProgressMonitor monitor; public static final String CMAKE_TOOL_ID = "org.eclipse.cdt.cmake.cmake"; @Override public void generateDependencies() throws CoreException { // TODO Auto-generated method stub } @Override public MultiStatus generateMakefiles(IResourceDelta delta) throws CoreException { // MultiStatus mstatus = regenerateMakefiles(); MultiStatus mstatus = new MultiStatus("org.eclipse.cdt.cmake.builder", 0, "success", null ); return mstatus; } @Override public IPath getBuildWorkingDir() { return CMakeOutputPath.getPath(project, buildInfo.getConfigurationName()); // return new Path(buildInfo.getConfigurationName()); } @Override public String getMakefileName() { // @TODO get settings for selected CMake generator and adjust Makefile Name (e.g. in case of ninja make) return "Makefile"; } @Override public void initialize(IProject project, IManagedBuildInfo info, IProgressMonitor monitor) { this.project = project; this.buildInfo = info; this.monitor = monitor; } @Override public boolean isGeneratedResource(IResource resource) { return true; } @Override public void regenerateDependencies(boolean force) throws CoreException { // TODO Auto-generated method stub } @Override public MultiStatus regenerateMakefiles() throws CoreException { MultiStatus mstatus = new MultiStatus("org.eclipse.cdt.cmake.builder", 0, "success", null ); return mstatus; } @SuppressWarnings("restriction") public MultiStatus runCMake() throws CoreException { MultiStatus mstatus = new MultiStatus("org.eclipse.cdt.cmake.builder", 0, "success", null ); // IConfiguration = buildInfo.getDefaultConfiguration() // currentCon getToolById String currentConf = buildInfo.getConfigurationName(); String currentArch = Platform.getPreferencesService().getString("org.eclipse.cdt.multiarch", PreferenceConstants.P_CURRENT_TARGET_ARCH, "native", null); //String currentArch = Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.P_CURRENT_TARGET_ARCH); String currentInstrument = Platform.getPreferencesService().getString("org.eclipse.cdt.multiarch", PreferenceConstants.P_CURRENT_TARGET_DEVICE, "host", null); // String currentInstrument = Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.P_CURRENT_TARGET_DEVICE); IConsole cmakeConsole = CCorePlugin.getDefault().getConsole("org.eclipse.cdt.cmake.ui.CMakeConsole"); //$NON-NLS-1$ cmakeConsole.start(project); @SuppressWarnings("restriction") BuildRunnerHelper buildRunnerHelper = new BuildRunnerHelper(this.project); ICommandLauncher launcher = new CommandLauncherRC(); IStringVariableManager varMgr = VariablesPlugin.getDefault().getStringVariableManager(); try { if (monitor == null) { monitor = new NullProgressMonitor(); } monitor.beginTask("Invoking CMake for '" + project.getName() + "'", 100);//$NON-NLS-1$ //$NON-NLS-2$ IPath buildDir = null; IEclipsePreferences projectProperties = new ProjectScope(project).getNode("org.eclipse.cdt.cmake.scope"); //$NON-NLS-1$ boolean deviceSpecific = false; boolean useWorkspaceBuidDirSettings = true; if (projectProperties != null) { deviceSpecific = projectProperties.getBoolean(CMakePropertyConstants.P_IS_DEVICE_SPECIFIC, false); useWorkspaceBuidDirSettings = projectProperties.getBoolean(CMakePropertyConstants.P_USE_WORKSPACE_BUILDDIR_SETTINGS, true); } buildDir = getBuildWorkingDir(); IContainer outDirContainer = ResourcesPlugin.getWorkspace().getRoot().getContainerForLocation(buildDir); if( outDirContainer instanceof IFolder) { IFolder outFolder = (IFolder)outDirContainer; if (!outFolder.exists()) { outFolder.create(IResource.NONE, true, monitor); } if(!outFolder.isDerived()) { outFolder.setDerived(true, monitor); } } // if(!buildDir.toFile().exists()) { // boolean retval = buildDir.toFile().mkdir(); // if(retval == false) { // String msg = new String("Could not create build output dir: '" + buildDir.toOSString() + "'"); // throw new CoreException(new Status(IStatus.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID, msg, new Exception())); // } // } // IValueVariable destdirVar = varMgr.getValueVariable("CMake_DESTDIR"); //$NON-NLS-1$ String destDirStr = Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.P_DESTDIR); destDirStr = varMgr.performStringSubstitution(destDirStr); destdirVar.setValue( destDirStr ); ICConfigurationDescription cfgDesc = CoreModel.getDefault().getProjectDescription(project).getConfigurationByName(currentConf); IConfiguration cfg = ManagedBuildManager.getConfigurationForDescription(cfgDesc); ITool[] cmakeTools = cfg.getToolsBySuperClassId(CMAKE_TOOL_ID); ITool cmakeTool = null; if(cmakeTools.length > 0) { cmakeTool = cmakeTools[0]; } List<String> cmakeArgs = new ArrayList<String>(); String[] flags = cmakeTool.getToolCommandFlags(null, null); for(int i = 0; i < flags.length; i++) { cmakeArgs.add(flags[i]); } // cmakeArgs.add("-DCMAKE_BUILD_TYPE=" + currentConf); // if(!currentToolchainFile.equals("<none>")) { // cmakeArgs.add("-DCMAKE_TOOLCHAIN_FILE=" + currentToolchainFile); // } String generator = Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.P_CMAKE_GENERATOR); cmakeArgs.add("-G"); cmakeArgs.add(generator); cmakeArgs.add("-DCMAKE_EXPORT_COMPILE_COMMANDS=On"); IPath pathToSource = project.getLocation(); cmakeArgs.add(pathToSource.toOSString()); // add cmake extra FLAGS // add some cmake options IContributedEnvironment ice = CCorePlugin.getDefault().getBuildEnvironmentManager().getContributedEnvironment(); IEnvironmentVariable[] envvars = ice.getVariables( cfgDesc ); String[] envp = new String[envvars.length]; for(int i = 0; i < envvars.length; i++ ) { envp[i] = envvars[i].getName() + "=" + envvars[i].getValue(); //$NON-NLS-1$ } File buildDirFile = buildDir.toFile(); if(buildDirFile.exists()) { if(!buildDirFile.isDirectory()) { throw new RuntimeException( "The path that is to be used for the build: '" + buildDir + "' exists, but is no directory."); //$NON-NLS-1$ //$NON-NLS-2$ } } else { boolean success = buildDirFile.mkdirs(); if(success = false) { throw new RuntimeException("Could not create build dir: '" + buildDir + "'."); } } URI workingDirectoryURI = new URI(null, null, buildDir.toString(), null ); //$NON-NLS-1$ String cmakeExe = null; boolean cmakeViaPath = Activator.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.P_CMAKE_VIA_PATH); if(cmakeViaPath == true) { cmakeExe = "cmake"; } else { cmakeExe = Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.P_CMAKE_EXE); } IPath cmakePath = new Path( cmakeExe ); String[] a = new String[cmakeArgs.size()]; buildRunnerHelper.setLaunchParameters(launcher, cmakePath, cmakeArgs.toArray(a), workingDirectoryURI, null); // Dummy builder only used for marker generation CMakeProjectBuilderImpl markerGenerator = new CMakeProjectBuilderImpl() { { setCurrentProject(project); } }; ErrorParserManager epm = new ErrorParserManager(project, URIUtil.toURI(pathToSource), markerGenerator, new String[] { CMakeErrorParserStdErr.ID, CMakeErrorParserStdOut.ID }); List<IConsoleParser> consoleParsers = new ArrayList<IConsoleParser>(); buildRunnerHelper.prepareStreams(epm, consoleParsers, (org.eclipse.cdt.core.resources.IConsole) cmakeConsole, new SubProgressMonitor(monitor, 20)); buildRunnerHelper.removeOldMarkers(project, new SubProgressMonitor(monitor, 50, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK)); buildRunnerHelper.greeting(IncrementalProjectBuilder.FULL_BUILD, currentConf, "Running CMake ...", true); //$NON-NLS-1$ int state = buildRunnerHelper.build(new SubProgressMonitor(monitor, 60, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK)); buildRunnerHelper.close(); buildRunnerHelper.goodbye(); if (state != ICommandLauncher.ILLEGAL_COMMAND) { if(state == ICommandLauncher.OK) { buildRunnerHelper.refreshProject(currentConf, new SubProgressMonitor(monitor, 90, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK)); } else { mstatus = new MultiStatus("org.eclipse.cdt.cmake.builder", IStatus.ERROR, "CMake failed to generate Makefile. Please see CMake Console for Details.", null ); } } else { String msg = ""; //$NON-NLS-1$ throw new CoreException(new Status(IStatus.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID, msg, new Exception())); } } catch (CoreException ce) { logToConsole(cmakeConsole, ce.getStatus()); mstatus = new MultiStatus("org.eclipse.cdt.cmake.builder", -1, ce.getStatus().getMessage(), null ); } catch (Exception e) { String msg = "Error running CMake for project: '" + project.getName() +"' in configuration '" + currentConf + "'."; IStatus status = new Status(IStatus.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID, msg, e); logToConsole(cmakeConsole, status); throw new CoreException(status); } finally { try { buildRunnerHelper.close(); } catch (IOException e) { ManagedBuilderCorePlugin.log(e); } monitor.done(); } return mstatus; } public void logToConsole(IConsole console, IStatus status) { String errmsg = new String(); OutputStream cos; try { cos = console.getOutputStream(); StringBuffer buf = new StringBuffer(errmsg); buf.append(System.getProperty("line.separator", "\n")); //$NON-NLS-1$ //$NON-NLS-2$ buf.append(status.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$ try { cos.write(buf.toString().getBytes()); cos.flush(); cos.close(); } catch (IOException e) { ResourcesPlugin.getPlugin().getLog().log(status); } } catch (CoreException e1) { e1.printStackTrace(); } } private String inputStream2String(InputStream is) { /* * To convert the InputStream to String we use the BufferedReader.readLine() * method. We iterate until the BufferedReader return null which means * there's no more data to read. Each line will appended to a StringBuilder * and returned as String. */ BufferedReader reader = new BufferedReader(new InputStreamReader(is)); StringBuilder sb = new StringBuilder(); String line = null; try { while ((line = reader.readLine()) != null) { sb.append(line + "\n"); //$NON-NLS-1$ } } catch (IOException e) { e.printStackTrace(); } finally { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } return sb.toString(); } }