/******************************************************************************* * Copyright (c) 2015, 2016 QNX Software Systems 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 *******************************************************************************/ package org.eclipse.cdt.cmake.core.internal; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.eclipse.cdt.cmake.core.ICMakeToolChainFile; import org.eclipse.cdt.cmake.core.ICMakeToolChainManager; import org.eclipse.cdt.core.ConsoleOutputStream; import org.eclipse.cdt.core.ErrorParserManager; import org.eclipse.cdt.core.IConsoleParser; import org.eclipse.cdt.core.build.CBuildConfiguration; import org.eclipse.cdt.core.build.IToolChain; import org.eclipse.cdt.core.model.ICModelMarker; import org.eclipse.cdt.core.resources.IConsole; import org.eclipse.core.resources.IBuildConfiguration; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.osgi.service.prefs.BackingStoreException; import org.osgi.service.prefs.Preferences; import com.google.gson.Gson; public class CMakeBuildConfiguration extends CBuildConfiguration { public static final String CMAKE_GENERATOR = "cmake.generator"; //$NON-NLS-1$ public static final String CMAKE_ARGUMENTS = "cmake.arguments"; //$NON-NLS-1$ public static final String BUILD_COMMAND = "cmake.command.build"; //$NON-NLS-1$ public static final String CLEAN_COMMAND = "cmake.command.clean"; //$NON-NLS-1$ private static final String TOOLCHAIN_FILE = "cdt.cmake.toolchainfile"; //$NON-NLS-1$ private ICMakeToolChainFile toolChainFile; public CMakeBuildConfiguration(IBuildConfiguration config, String name) throws CoreException { super(config, name); ICMakeToolChainManager manager = Activator.getService(ICMakeToolChainManager.class); Preferences settings = getSettings(); String pathStr = settings.get(TOOLCHAIN_FILE, ""); //$NON-NLS-1$ if (!pathStr.isEmpty()) { Path path = Paths.get(pathStr); toolChainFile = manager.getToolChainFile(path); } } public CMakeBuildConfiguration(IBuildConfiguration config, String name, IToolChain toolChain) { this(config, name, toolChain, null, "run"); //$NON-NLS-1$ } public CMakeBuildConfiguration(IBuildConfiguration config, String name, IToolChain toolChain, ICMakeToolChainFile toolChainFile, String launchMode) { super(config, name, toolChain, launchMode); this.toolChainFile = toolChainFile; if (toolChainFile != null) { Preferences settings = getSettings(); settings.put(TOOLCHAIN_FILE, toolChainFile.getPath().toString()); try { settings.flush(); } catch (BackingStoreException e) { Activator.log(e); } } } public ICMakeToolChainFile getToolChainFile() { return toolChainFile; } @Override public IProject[] build(int kind, Map<String, String> args, IConsole console, IProgressMonitor monitor) throws CoreException { IProject project = getProject(); try { Map<String, String> properties = getProperties(); String generator = properties.get(CMAKE_GENERATOR); if (generator == null) { generator = "Unix Makefiles"; //$NON-NLS-1$ } project.deleteMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE); ConsoleOutputStream outStream = console.getOutputStream(); Path buildDir = getBuildDirectory(); outStream.write(String.format(Messages.CMakeBuildConfiguration_BuildingIn, buildDir.toString())); if (!Files.exists(buildDir.resolve("CMakeFiles"))) { //$NON-NLS-1$ List<String> command = new ArrayList<>(); // TODO location of CMake out of preferences if not found here Path cmakePath = findCommand("cmake"); //$NON-NLS-1$ if (cmakePath != null) { command.add(cmakePath.toString()); } else { command.add("cmake"); //$NON-NLS-1$ } command.add("-G"); //$NON-NLS-1$ command.add(generator); if (toolChainFile != null) { command.add("-DCMAKE_TOOLCHAIN_FILE=" + toolChainFile.getPath().toString()); //$NON-NLS-1$ } switch (getLaunchMode()) { // TODO what to do with other modes case "debug": //$NON-NLS-1$ command.add("-DCMAKE_BUILD_TYPE=Debug"); //$NON-NLS-1$ break; } command.add("-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"); //$NON-NLS-1$ command.add(new File(project.getLocationURI()).getAbsolutePath()); ProcessBuilder processBuilder = new ProcessBuilder(command).directory(buildDir.toFile()); setBuildEnvironment(processBuilder.environment()); Process process = processBuilder.start(); outStream.write(String.join(" ", command) + '\n'); //$NON-NLS-1$ watchProcess(process, new IConsoleParser[0], console); } try (ErrorParserManager epm = new ErrorParserManager(project, getBuildDirectoryURI(), this, getToolChain().getErrorParserIds())) { String buildCommand = properties.get(BUILD_COMMAND); if (buildCommand == null) { if (generator.equals("Ninja")) { //$NON-NLS-1$ buildCommand = "ninja"; //$NON-NLS-1$ } else { buildCommand = "make"; //$NON-NLS-1$ } } String[] command = buildCommand.split(" "); //$NON-NLS-1$ Path cmdPath = findCommand(command[0]); if (cmdPath != null) { command[0] = cmdPath.toString(); } ProcessBuilder processBuilder = new ProcessBuilder(command).directory(buildDir.toFile()); setBuildEnvironment(processBuilder.environment()); Process process = processBuilder.start(); outStream.write(String.join(" ", command) + '\n'); //$NON-NLS-1$ watchProcess(process, new IConsoleParser[] { epm }, console); } project.refreshLocal(IResource.DEPTH_INFINITE, monitor); // Load compile_commands.json file processCompileCommandsFile(monitor); return new IProject[] { project }; } catch (IOException e) { throw new CoreException(Activator.errorStatus(String.format(Messages.CMakeBuildConfiguration_Building, project.getName()), e)); } } @Override public void clean(IConsole console, IProgressMonitor monitor) throws CoreException { IProject project = getProject(); try { Map<String, String> properties = getProperties(); String generator = properties.get(CMAKE_GENERATOR); project.deleteMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE); ConsoleOutputStream outStream = console.getOutputStream(); Path buildDir = getBuildDirectory(); if (!Files.exists(buildDir.resolve("CMakeFiles"))) { //$NON-NLS-1$ outStream.write(Messages.CMakeBuildConfiguration_NotFound); return; } String cleanCommand = properties.get(CLEAN_COMMAND); if (cleanCommand == null) { if (generator != null && generator.equals("Ninja")) { //$NON-NLS-1$ cleanCommand = "ninja clean"; //$NON-NLS-1$ } else { cleanCommand = "make clean"; //$NON-NLS-1$ } } String[] command = cleanCommand.split(" "); //$NON-NLS-1$ Path cmdPath = findCommand(command[0]); if (cmdPath != null) { command[0] = cmdPath.toString(); } ProcessBuilder processBuilder = new ProcessBuilder(command).directory(buildDir.toFile()); Process process = processBuilder.start(); outStream.write(String.join(" ", command) + '\n'); //$NON-NLS-1$ watchProcess(process, new IConsoleParser[0], console); project.refreshLocal(IResource.DEPTH_INFINITE, monitor); } catch (IOException e) { throw new CoreException(Activator.errorStatus(String.format(Messages.CMakeBuildConfiguration_Cleaning, project.getName()), e)); } } private void processCompileCommandsFile(IProgressMonitor monitor) throws CoreException { IProject project = getProject(); Path commandsFile = getBuildDirectory().resolve("compile_commands.json"); //$NON-NLS-1$ if (Files.exists(commandsFile)) { monitor.setTaskName(Messages.CMakeBuildConfiguration_ProcCompJson); try (FileReader reader = new FileReader(commandsFile.toFile())) { Gson gson = new Gson(); CompileCommand[] commands = gson.fromJson(reader, CompileCommand[].class); for (CompileCommand command : commands) { processLine(command.getCommand()); } shutdown(); } catch (IOException e) { throw new CoreException( Activator.errorStatus(String.format(Messages.CMakeBuildConfiguration_ProcCompCmds, project.getName()), e)); } } } }