1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-19 15:05:36 +02:00

Bug 533444 - Add Container Build support to CMake Projects

- fix CMakePropertyPage to check if the active config is
  a Container build in which case dynamically build the page
  using the results of a cmake -LAH call which will give
  the various configuration values that can be changed
- add new CMakePropertyCombo, CMakePropertyText, CMakeUtils
  and ICMakePropertyPageControl classes
- change CMakeBuildConfiguration build methods to use
  startBuildProcess to run commands similar to
  what StandardBuildConfiguration does now
- change CMakeBuildConfigurationProvider to use a container image
  name to form a build directory so that differnt image targets
  are differentiated and easy for the user to figure out what they
  are for
- fix main.cpp sample CMake program to actually be a hello
  world program

Change-Id: Iea9e2b5cc6895bc95194e28b131a3fb7e3b670ca
This commit is contained in:
Jeff Johnston 2018-04-10 14:37:17 -04:00
parent c2b5e84087
commit 8982ef90e7
12 changed files with 605 additions and 61 deletions

View file

@ -26,6 +26,8 @@ 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.envvar.EnvironmentVariable;
import org.eclipse.cdt.core.envvar.IEnvironmentVariable;
import org.eclipse.cdt.core.model.ICModelMarker;
import org.eclipse.cdt.core.resources.IConsole;
import org.eclipse.cdt.utils.Platform;
@ -34,6 +36,7 @@ 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.eclipse.core.runtime.jobs.Job;
import org.osgi.service.prefs.BackingStoreException;
import org.osgi.service.prefs.Preferences;
@ -43,6 +46,7 @@ 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 CMAKE_ENV = "cmake.environment"; //$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$
@ -97,8 +101,9 @@ public class CMakeBuildConfiguration extends CBuildConfiguration {
private boolean isLocal() throws CoreException {
IToolChain toolchain = getToolChain();
return Platform.getOS().equals(toolchain.getProperty(IToolChain.ATTR_OS))
&& Platform.getOSArch().equals(toolchain.getProperty(IToolChain.ATTR_ARCH));
return (Platform.getOS().equals(toolchain.getProperty(IToolChain.ATTR_OS))
|| "linux-container".equals(toolchain.getProperty(IToolChain.ATTR_OS))) //$NON-NLS-1$
&& (Platform.getOSArch().equals(toolchain.getProperty(IToolChain.ATTR_ARCH)));
}
@Override
@ -142,16 +147,10 @@ public class CMakeBuildConfiguration extends CBuildConfiguration {
}
if (runCMake) { // $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("cmake"); //$NON-NLS-1$
command.add("-G"); //$NON-NLS-1$
command.add(generator);
@ -164,8 +163,10 @@ public class CMakeBuildConfiguration extends CBuildConfiguration {
case "debug": //$NON-NLS-1$
command.add("-DCMAKE_BUILD_TYPE=Debug"); //$NON-NLS-1$
break;
case "run": //$NON-NLS-1$
command.add("-DCMAKE_BUILD_TYPE=Release"); //$NON-NLS-1$
break;
}
command.add("-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"); //$NON-NLS-1$
String userArgs = getProperty(CMAKE_ARGUMENTS);
@ -175,31 +176,59 @@ public class CMakeBuildConfiguration extends CBuildConfiguration {
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, console);
Process p = startBuildProcess(command, new IEnvironmentVariable[0], console, monitor);
if (p == null) {
console.getErrorStream().write(String.format(Messages.CMakeBuildConfiguration_Failure, "")); //$NON-NLS-1$
return null;
}
watchProcess(p, console);
}
try (ErrorParserManager epm = new ErrorParserManager(project, getBuildDirectoryURI(), this,
getToolChain().getErrorParserIds())) {
epm.setOutputStream(console.getOutputStream());
List<String> command = new ArrayList<>();
String envStr = getProperty(CMAKE_ENV);
List<IEnvironmentVariable> envVars = new ArrayList<>();
if (envStr != null) {
List<String> envList = CMakeUtils.stripEnvVars(envStr);
for (String s : envList) {
int index = s.indexOf("="); //$NON-NLS-1$
if (index == -1) {
envVars.add(new EnvironmentVariable(s));
} else {
envVars.add(new EnvironmentVariable(s.substring(0, index), s.substring(index + 1)));
}
}
}
String buildCommand = getProperty(BUILD_COMMAND);
String[] command = buildCommand != null && !buildCommand.trim().isEmpty() ? buildCommand.split(" ") //$NON-NLS-1$
: new String[] { "cmake", "--build", "." }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
Path cmdPath = findCommand(command[0]);
if (cmdPath != null) {
command[0] = cmdPath.toString();
if (buildCommand == null) {
command.add("cmake"); //$NON-NLS-1$
command.add("--build"); //$NON-NLS-1$
command.add("."); //$NON-NLS-1$
if ("Ninja".equals(generator)) {
command.add("--"); //$NON-NLS-1$
command.add("-v"); //$NON-NLS-1$
}
} else {
command.addAll(Arrays.asList(buildCommand.split(" "))); //$NON-NLS-1$
}
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 });
Process p = startBuildProcess(command, envVars.toArray(new IEnvironmentVariable[0]), console, monitor);
if (p == null) {
console.getErrorStream().write(String.format(Messages.CMakeBuildConfiguration_Failure, "")); //$NON-NLS-1$
return null;
}
watchProcess(p, new IConsoleParser[] { epm });
project.refreshLocal(IResource.DEPTH_INFINITE, monitor);
@ -233,26 +262,34 @@ public class CMakeBuildConfiguration extends CBuildConfiguration {
return;
}
List<String> command = new ArrayList<>();
String cleanCommand = getProperty(CLEAN_COMMAND);
if (cleanCommand == null) {
if (generator == null || generator.equals("Ninja")) { //$NON-NLS-1$
cleanCommand = "ninja clean"; //$NON-NLS-1$
command.add("ninja"); //$NON-NLS-1$
command.add("clean"); //$NON-NLS-1$
} else {
cleanCommand = "make clean"; //$NON-NLS-1$
command.add("make"); //$NON-NLS-1$
command.add("clean"); //$NON-NLS-1$
}
}
String[] command = cleanCommand.split(" "); //$NON-NLS-1$
} else {
command.addAll(Arrays.asList(cleanCommand.split(" "))); //$NON-NLS-1$
}
IEnvironmentVariable[] env = new IEnvironmentVariable[0];
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, console);
Process p = startBuildProcess(command, env, console, monitor);
if (p == null) {
console.getErrorStream().write(String.format(Messages.CMakeBuildConfiguration_Failure, "")); //$NON-NLS-1$
return;
}
watchProcess(p, console);
outStream.write(Messages.CMakeBuildConfiguration_BuildComplete);
project.refreshLocal(IResource.DEPTH_INFINITE, monitor);
} catch (IOException e) {
throw new CoreException(Activator.errorStatus(String.format(Messages.CMakeBuildConfiguration_Cleaning, project.getName()), e));
@ -263,6 +300,7 @@ public class CMakeBuildConfiguration extends CBuildConfiguration {
IProject project = getProject();
Path commandsFile = getBuildDirectory().resolve("compile_commands.json"); //$NON-NLS-1$
if (Files.exists(commandsFile)) {
List<Job> jobsList = new ArrayList<>();
monitor.setTaskName(Messages.CMakeBuildConfiguration_ProcCompJson);
try (FileReader reader = new FileReader(commandsFile.toFile())) {
Gson gson = new Gson();
@ -272,7 +310,14 @@ public class CMakeBuildConfiguration extends CBuildConfiguration {
dedupedCmds.put(command.getFile(), command);
}
for (CompileCommand command : dedupedCmds.values()) {
processLine(command.getCommand());
processLine(command.getCommand(), jobsList);
}
for (Job j : jobsList) {
try {
j.join();
} catch (InterruptedException e) {
// ignore
}
}
shutdown();
} catch (IOException e) {

View file

@ -108,13 +108,19 @@ public class CMakeBuildConfigurationProvider implements ICBuildConfigurationProv
// create config
StringBuilder configName = new StringBuilder("cmake."); //$NON-NLS-1$
configName.append(launchMode);
if (os != null) {
if ("linux-container".equals(os)) { //$NON-NLS-1$
String osConfigName = toolChain.getProperty("linux-container-id"); //$NON-NLS-1$
configName.append('.');
configName.append(os);
}
if (arch != null && !arch.isEmpty()) {
configName.append('.');
configName.append(arch);
configName.append(osConfigName);
} else {
if (os != null) {
configName.append('.');
configName.append(os);
}
if (arch != null && !arch.isEmpty()) {
configName.append('.');
configName.append(arch);
}
}
String name = configName.toString();
int i = 0;

View file

@ -0,0 +1,57 @@
/*******************************************************************************
* Copyright (c) 2018 Red Hat Inc. 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
*
* Red Hat Inc. - initial version
*******************************************************************************/
package org.eclipse.cdt.cmake.core.internal;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CMakeUtils {
/**
* Parse a string containing environment variables into individual VAR=VALUE pairs.
*
* @param envString - String to parse
* @return List of var=value Strings
*/
public static List<String> stripEnvVars(String envString) {
Pattern p1 = Pattern.compile("(\\w+[=]\\\".*?\\\").*"); //$NON-NLS-1$
Pattern p2 = Pattern.compile("(\\w+[=]'.*?').*"); //$NON-NLS-1$
Pattern p3 = Pattern.compile("(\\w+[=][^\\s]+).*"); //$NON-NLS-1$
boolean finished = false;
List<String> envVars = new ArrayList<>();
while (!finished) {
Matcher m1 = p1.matcher(envString);
if (m1.matches()) {
envString = envString.replaceFirst("\\w+[=]\\\".*?\\\"","").trim(); //$NON-NLS-1$ //$NON-NLS-2$
String s = m1.group(1).trim();
envVars.add(s.replaceAll("\\\"", "")); //$NON-NLS-1$ //$NON-NLS-2$
} else {
Matcher m2 = p2.matcher(envString);
if (m2.matches()) {
envString = envString.replaceFirst("\\w+[=]'.*?'", "").trim(); //$NON-NLS-1$ //$NON-NLS-2$
String s = m2.group(1).trim();
envVars.add(s.replaceAll("'", "")); //$NON-NLS-1$ //$NON-NLS-2$
} else {
Matcher m3 = p3.matcher(envString);
if (m3.matches()) {
envString = envString.replaceFirst("\\w+[=][^\\s]+", "").trim(); //$NON-NLS-1$ //$NON-NLS-2$
envVars.add(m3.group(1).trim());
} else {
finished = true;
}
}
}
}
return envVars;
}
}

View file

@ -14,11 +14,13 @@ public class Messages extends NLS {
public static String CMakeBuildConfiguration_Building;
public static String CMakeBuildConfiguration_BuildingIn;
public static String CMakeBuildConfiguration_BuildingComplete;
public static String CMakeBuildConfiguration_BuildComplete;
public static String CMakeBuildConfiguration_Cleaning;
public static String CMakeBuildConfiguration_NotFound;
public static String CMakeBuildConfiguration_NoToolchainFile;
public static String CMakeBuildConfiguration_ProcCompCmds;
public static String CMakeBuildConfiguration_ProcCompJson;
public static String CMakeBuildConfiguration_Failure;
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);

View file

@ -8,8 +8,10 @@
CMakeBuildConfiguration_Building=Building %s
CMakeBuildConfiguration_BuildingIn=Building in: %s\n
CMakeBuildConfiguration_BuildingComplete=Build complete (%d errors, %d warnings): %s\n
CMakeBuildConfiguration_BuildComplete=Build complete\n
CMakeBuildConfiguration_Cleaning=Cleaning %s
CMakeBuildConfiguration_NotFound=CMakeFiles not found. Assuming clean.
CMakeBuildConfiguration_NoToolchainFile=No CMake toolchain file found for this target.
CMakeBuildConfiguration_ProcCompCmds=Processing compile commands %s
CMakeBuildConfiguration_ProcCompJson=Processing compile_commands.json
CMakeBuildConfiguration_Failure=Failure running cmake: %s\n

View file

@ -1,4 +1,7 @@
#include <iostream>
using namespace std;
int main(int argc, char **argv) {
cout << "Hello world";
return 0;
}

View file

@ -0,0 +1,66 @@
/*******************************************************************************
* Copyright (c) 2018 Red Hat Inc. 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:
* Red Hat Inc. - initial implementation
*******************************************************************************/
package org.eclipse.cdt.cmake.ui.internal;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
public class CMakePropertyCombo implements ICMakePropertyPageControl {
private String name;
private String initialValue;
private Combo combo;
public CMakePropertyCombo(Composite composite, String name, String[] values, String initialValue, String tooltip) {
this.name = name;
this.initialValue = initialValue;
Label label = new Label(composite, SWT.NONE);
label.setText(name);
label.setLayoutData(new GridData());
combo = new Combo(composite, SWT.BORDER | SWT.DROP_DOWN | SWT.READ_ONLY);
GridData data = new GridData(GridData.FILL_BOTH);
data.grabExcessHorizontalSpace = true;
combo.setLayoutData(data);
combo.setItems(values);
combo.setText(initialValue);
combo.setToolTipText(tooltip);
}
@Override
public String getFieldValue() {
return combo.getText();
}
@Override
public String getFieldName() {
return name;
}
@Override
public boolean isValueChanged() {
return !combo.getText().equals(initialValue);
}
@Override
public boolean isValid() {
return true;
}
@Override
public String getErrorMessage() {
return null;
}
}

View file

@ -0,0 +1,66 @@
/*******************************************************************************
* Copyright (c) 2018 Red Hat Inc. 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:
* Red Hat Inc. - initial implementation
*******************************************************************************/
package org.eclipse.cdt.cmake.ui.internal;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
public class CMakePropertyText implements ICMakePropertyPageControl {
private String name;
private String initialValue;
protected Text text;
public CMakePropertyText(Composite composite, String name, String initialValue, String tooltip) {
this.name = name;
if (initialValue == null) {
initialValue = ""; //$NON-NLS-1$
}
this.initialValue = initialValue;
Label label = new Label(composite, SWT.NONE);
label.setText(name);
label.setLayoutData(new GridData());
text = new Text(composite, SWT.SINGLE | SWT.BORDER);
GridData data = new GridData(GridData.FILL_BOTH);
data.grabExcessHorizontalSpace = true;
text.setLayoutData(data);
text.setText(initialValue);
text.setToolTipText(tooltip);
}
@Override
public String getFieldValue() {
return text.getText();
}
@Override
public String getFieldName() {
return name;
}
@Override
public boolean isValueChanged() {
return !text.getText().equals(initialValue);
}
@Override
public boolean isValid() {
return true;
}
@Override
public String getErrorMessage() {
return null;
}
}

View file

@ -0,0 +1,53 @@
/*******************************************************************************
* Copyright (c) 2018 Red Hat Inc. 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:
* Red Hat Inc. - initial implementation
*******************************************************************************/
package org.eclipse.cdt.cmake.ui.internal;
public interface ICMakePropertyPageControl {
/**
* Get the value of the field
* @return field value
*/
String getFieldValue();
/**
* Get the name of the field to set for cmake command
* @return field name
*/
String getFieldName();
/**
* Has the initial value changed
* @return
*/
boolean isValueChanged();
/**
* Is this field valid?
* @return
*/
boolean isValid();
/**
* Get the command line parameter if already configured
* @return String containing command-line for configured build dir
*/
default String getConfiguredString() {
return "-D" + getFieldName() + "=" + getFieldValue(); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* Get any error message for the control
* @return error message
*/
String getErrorMessage();
}

View file

@ -30,6 +30,12 @@ public class Messages extends NLS {
public static String CMakePreferencePage_Toolchain;
public static String CMakePropertyPage_FailedToStartCMakeGui_Body;
public static String CMakePropertyPage_FailedToStartCMakeGui_Title;
public static String CMakePropertyPage_FailedToGetOS_Body;
public static String CMakePropertyPage_FailedToGetOS_Title;
public static String CMakePropertyPage_FailedToGetCMakeConfiguration_Body;
public static String CMakePropertyPage_FailedToGetCMakeConfiguration_Title;
public static String CMakePropertyPage_FailedToConfigure;
public static String CMakePropertyPage_Terminated;
public static String CMakePropertyPage_LaunchCMakeGui;
public static String NewCMakeProjectWizard_Description;

View file

@ -17,6 +17,12 @@ CMakePreferencePage_Remove=Remove
CMakePreferencePage_Toolchain=Toolchain
CMakePropertyPage_FailedToStartCMakeGui_Body=Failed to run the CMake GUI:
CMakePropertyPage_FailedToStartCMakeGui_Title=Failed to run CMake GUI
CMakePropertyPage_FailedToGetOS_Body=Failed to get target OS for CMake project:
CMakePropertyPage_FailedToGetOS_Title=Failed to get target OS
CMakePropertyPage_FailedToFetchCMakeConfiguration_Body=Failed to fetch CMake configuration values
CMakePropertyPage_FailedToFetchCMakeConfiguration_Title=Failed to fetch CMake configuration
CMakePropertyPage_FailedToConfigure=Failed to reconfigure CMake
CMakePropertyPage_Terminated=Command terminated with rc={0}\n
CMakePropertyPage_LaunchCMakeGui=Launch CMake GUI...
NewCMakeProjectWizard_Description=Specify properties of new CMake project.
NewCMakeProjectWizard_PageTitle=New CMake Project

View file

@ -10,12 +10,37 @@
*******************************************************************************/
package org.eclipse.cdt.cmake.ui.properties;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.cdt.cmake.ui.internal.Activator;
import org.eclipse.cdt.cmake.ui.internal.CMakePropertyCombo;
import org.eclipse.cdt.cmake.ui.internal.CMakePropertyText;
import org.eclipse.cdt.cmake.ui.internal.ICMakePropertyPageControl;
import org.eclipse.cdt.cmake.ui.internal.Messages;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.CommandLauncherManager;
import org.eclipse.cdt.core.ICommandLauncher;
import org.eclipse.cdt.core.build.CBuildConfiguration;
import org.eclipse.cdt.core.build.ICBuildCommandLauncher;
import org.eclipse.cdt.core.build.ICBuildConfiguration;
import org.eclipse.cdt.core.build.IToolChain;
import org.eclipse.cdt.core.resources.IConsole;
import org.eclipse.core.resources.IBuildConfiguration;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
@ -24,6 +49,7 @@ import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.dialogs.PropertyPage;
/**
@ -35,32 +61,238 @@ import org.eclipse.ui.dialogs.PropertyPage;
* PATH.
*/
public class CMakePropertyPage extends PropertyPage {
private List<ICMakePropertyPageControl> componentList = new ArrayList<>();
@Override
protected Control createContents(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
composite.setLayout(new GridLayout());
Button b = new Button(composite, SWT.NONE);
b.setText(Messages.CMakePropertyPage_LaunchCMakeGui);
b.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
IProject project = (IProject) getElement();
boolean isContainerBuild = false;
ICBuildConfiguration cconfig = null;
IProject project = (IProject) getElement();
try {
IBuildConfiguration config = project.getActiveBuildConfig();
cconfig = config.getAdapter(ICBuildConfiguration.class);
IToolChain toolChain = cconfig.getToolChain();
String os = toolChain.getProperty(IToolChain.ATTR_OS);
isContainerBuild = os.equals("linux-container"); //$NON-NLS-1$
} catch (CoreException e2) {
MessageDialog.openError(parent.getShell(), Messages.CMakePropertyPage_FailedToGetOS_Title,
Messages.CMakePropertyPage_FailedToGetOS_Body + e2.getMessage());
}
if (isContainerBuild) {
try {
ICommandLauncher launcher = CommandLauncherManager.getInstance().getCommandLauncher(project.getActiveBuildConfig().getAdapter(ICBuildConfiguration.class));
launcher.setProject(project);
if (launcher instanceof ICBuildCommandLauncher) {
((ICBuildCommandLauncher)launcher).setBuildConfiguration(cconfig);
}
IPath buildPath = project.getLocation().append("build").append(((CBuildConfiguration)cconfig).getName());
Process p = launcher.execute(new Path("/bin/sh"), new String[] { "-c", "cmake -LAH ."}, //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
new String[0], buildPath, new NullProgressMonitor());
if (p != null) {
ByteArrayOutputStream stdout = new ByteArrayOutputStream();
ByteArrayOutputStream stderr = new ByteArrayOutputStream();
int rc = -1;
try {
String configName = project.getActiveBuildConfig().getName();
String sourceDir = project.getLocation().toOSString();
String buildDir = project.getLocation().append("build").append(configName).toOSString(); //$NON-NLS-1$
Runtime.getRuntime().exec(new String[] { "cmake-gui", "-H" + sourceDir, "-B" + buildDir }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
} catch (CoreException | IOException e1) {
MessageDialog.openError(parent.getShell(), Messages.CMakePropertyPage_FailedToStartCMakeGui_Title,
Messages.CMakePropertyPage_FailedToStartCMakeGui_Body + e1.getMessage());
if (launcher.waitAndRead(stdout, stderr, new NullProgressMonitor()) == ICommandLauncher.OK) {
p.waitFor();
}
rc = p.exitValue();
} catch (InterruptedException e) {
// ignore for now
}
if (rc == 0) {
componentList = parseConfigureOutput(stdout, composite);
}
}
});
} catch (CoreException e) {
MessageDialog.openError(parent.getShell(), Messages.CMakePropertyPage_FailedToGetCMakeConfiguration_Title,
Messages.CMakePropertyPage_FailedToGetCMakeConfiguration_Body + e.getMessage());
}
} else {
Button b = new Button(composite, SWT.NONE);
b.setText(Messages.CMakePropertyPage_LaunchCMakeGui);
b.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
IProject project = (IProject) getElement();
try {
String configName = project.getActiveBuildConfig().getName();
String sourceDir = project.getLocation().toOSString();
String buildDir = project.getLocation().append("build").append(configName).toOSString(); //$NON-NLS-1$
Runtime.getRuntime().exec(new String[] { "cmake-gui", "-H" + sourceDir, "-B" + buildDir }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
} catch (CoreException | IOException e1) {
MessageDialog.openError(parent.getShell(), Messages.CMakePropertyPage_FailedToStartCMakeGui_Title,
Messages.CMakePropertyPage_FailedToStartCMakeGui_Body + e1.getMessage());
}
}
});
}
return composite;
}
@Override
public boolean performOk() {
List<String> args = new ArrayList<>();
args.add("cmake"); //$NON-NLS-1$
args.add("-LAH"); //$NON-NLS-1$
for (ICMakePropertyPageControl control : componentList) {
if (control.isValueChanged()) {
args.add(control.getConfiguredString()); //$NON-NLS-1$ //$NON-NLS-2$
}
}
if (args.size() == 2) {
return true;
}
try {
IProject project = (IProject) getElement();
ICBuildConfiguration buildConfig = project.getActiveBuildConfig().getAdapter(ICBuildConfiguration.class);
String configName = ((CBuildConfiguration)buildConfig).getName();
IPath buildDir = project.getLocation().append("build").append(configName); //$NON-NLS-1$
ICommandLauncher launcher = CommandLauncherManager.getInstance().getCommandLauncher(project.getActiveBuildConfig().getAdapter(ICBuildConfiguration.class));
launcher.setProject(project);
if (launcher instanceof ICBuildCommandLauncher) {
((ICBuildCommandLauncher)launcher).setBuildConfiguration(buildConfig);
}
StringBuilder b = new StringBuilder();
for (String arg : args) {
b.append(arg);
b.append(" "); //$NON-NLS-1$
}
b.append(".");
Process p = launcher.execute(new Path("/bin/sh"), new String[] { "-c", b.toString() }, new String[0], buildDir, new NullProgressMonitor()); //$NON-NLS-1$ //$NON-NLS-2$
int rc = -1;
IConsole console = CCorePlugin.getDefault().getConsole();
console.start(project);
try (OutputStream stdout = console.getOutputStream()) {
OutputStream stderr = stdout;
StringBuilder buf = new StringBuilder();
for (String arg : args) {
buf.append(arg);
buf.append(" "); //$NON-NLS-1$
}
buf.append(System.lineSeparator());
stdout.write(buf.toString().getBytes());
stdout.flush();
try {
if (launcher.waitAndRead(stdout, stderr, new NullProgressMonitor()) == ICommandLauncher.OK) {
p.waitFor();
}
rc = p.exitValue();
stdout.write(NLS.bind(Messages.CMakePropertyPage_Terminated, rc).getBytes());
stdout.flush();
if (rc != 0) {
Display.getDefault().syncExec(() -> {
MessageDialog.openError(getShell(), null, Messages.CMakePropertyPage_FailedToConfigure);
});
}
} catch (InterruptedException e) {
// ignore for now
}
} catch (IOException e2) {
Activator.log(e2);
return false;
}
} catch (CoreException e3) {
// TODO Auto-generated catch block
Activator.log(e3);
return false;
}
return true;
}
public enum ParseState {
INIT, SEENCOMMENT
};
/**
* Parse output of cmake -LAH call to determine options to show to user
* @param stdout - ByteArrayOutputStream containing output of command
* @param composite - Composite to add Controls to
* @return - list of Controls
*/
List<ICMakePropertyPageControl> parseConfigureOutput(ByteArrayOutputStream stdout, Composite composite) {
List<ICMakePropertyPageControl> controls = new ArrayList<>();
try {
ParseState state = ParseState.INIT;
String output = stdout.toString(StandardCharsets.UTF_8.name());
String[] lines = output.split("\\r?\\n"); //$NON-NLS-1$
Pattern commentPattern = Pattern.compile("//(.*)"); //$NON-NLS-1$
Pattern argPattern = Pattern.compile("(\\w+):([a-zA-Z]+)=(.*)"); //$NON-NLS-1$
Pattern optionPattern = Pattern.compile(".*?options are:((\\s+\\w+(\\(.*\\))?)+).*"); //$NON-NLS-1$
String lastComment = ""; //$NON-NLS-1$
for (String line : lines) {
line = line.trim();
switch (state) {
case INIT:
Matcher commentMatcher = commentPattern.matcher(line);
if (commentMatcher.matches()) {
state = ParseState.SEENCOMMENT;
lastComment = commentMatcher.group(1);
}
break;
case SEENCOMMENT:
Matcher argMatcher = argPattern.matcher(line);
if (argMatcher.matches()) {
String name = argMatcher.group(1);
String type = argMatcher.group(2);
String initialValue = argMatcher.group(3);
Matcher optionMatcher = optionPattern.matcher(lastComment);
if (optionMatcher.matches()) {
String optionString = optionMatcher.group(1).trim();
String[] options = optionString.split("\\s+"); //$NON-NLS-1$
for (int i = 0; i < options.length; ++i) {
options[i] = options[i].replaceAll("\\(.*?\\)", "").trim(); //$NON-NLS-1$
}
ICMakePropertyPageControl control = new CMakePropertyCombo(composite, name, options, initialValue, lastComment);
controls.add(control);
} else {
if ("BOOL".equals(type)) {
if ("ON".equals(initialValue) || ("OFF".equals(initialValue))) {
ICMakePropertyPageControl control = new CMakePropertyCombo(composite, name, new String[] {"ON","OFF"}, //$NON-NLS-1$ //$NON-NLS-2$
initialValue, lastComment);
controls.add(control);
} else if ("YES".equals(initialValue) || "NO".equals(initialValue)) {
ICMakePropertyPageControl control = new CMakePropertyCombo(composite, name, new String[] {"YES","NO"}, //$NON-NLS-1$ //$NON-NLS-2$
initialValue, lastComment);
controls.add(control);
} else {
ICMakePropertyPageControl control = new CMakePropertyCombo(composite, name, new String[] {"TRUE", "FALSE"}, //$NON-NLS-1$ //$NON-NLS-2$
"TRUE".equals(initialValue) ? "TRUE" : "FALSE", lastComment); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
controls.add(control);
}
} else {
ICMakePropertyPageControl control = new CMakePropertyText(composite, name, initialValue, lastComment);
controls.add(control);
}
}
}
state = ParseState.INIT;
break;
}
}
} catch (UnsupportedEncodingException e) {
return controls;
}
return controls;
}
}