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:
parent
c2b5e84087
commit
8982ef90e7
12 changed files with 605 additions and 61 deletions
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
cout << "Hello world";
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue