Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add UI for specifying CMake tools and generators' locations #1067

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
*******************************************************************************/
package org.eclipse.cdt.cmake.ui.internal;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
Expand All @@ -20,44 +24,78 @@
import org.eclipse.cdt.cmake.core.ICMakeToolChainFile;
import org.eclipse.cdt.cmake.core.ICMakeToolChainManager;
import org.eclipse.cdt.cmake.core.internal.CMakeToolChainManager;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.build.IToolChain;
import org.eclipse.cdt.core.cdtvariables.CdtVariableException;
import org.eclipse.cdt.core.cdtvariables.ICdtVariable;
import org.eclipse.cdt.core.cdtvariables.ICdtVariableManager;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.ui.newui.BuildVarListDialog;
import org.eclipse.cdt.utils.ui.controls.FileListControl;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
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.DirectoryDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;
import org.osgi.service.prefs.Preferences;

/**
* GUI page to configure workbench preferences for cmake.
*/
public class CMakePreferencePage extends PreferencePage implements IWorkbenchPreferencePage {

private static final String NODENAME = "cmake_environment"; //$NON-NLS-1$
private static final String ENABLE_USE_CMAKE_LOCATION = "enable_use_cmake_location"; //$NON-NLS-1$
private static final String CMAKE_LOCATION = "cmake_location"; //$NON-NLS-1$
private static final String CMAKE_GENERATOR_LOCATION = "cmake_generator_locations"; //$NON-NLS-1$
private static final String VALUE_DELIMITER = " || "; //$NON-NLS-1$
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is some commentary on the design to explain why I have requested changes about serializing and deserializing.

|| was chosen as a value delimiter based on its prior art in CPropertyVarsTab, specifically from

private static final String VALUE_DELIMITER = " || "; //$NON-NLS-1$

However in CPropertyVarsTab this was used strictly as a display convenience when displaying values in the GUI, it is not prior art for what you are doing here because you are using the || to serialize the values.

image

For example, the above setting in the screenshot is stored in .metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.cdt.core.prefs as string escaped XML file:

macros/workspace=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?>\n<macros>\n <stringListMacro name\="jonah" type\="VALUE_TEXT_LIST">\n <value name\="val1"/>\n <value name\="val2"/>\n </stringListMacro>\n</macros>\n

The code that converts the list/array to the serialized form is

for (int i = 0; i < fStringListValue.length; i++) {
ICStorageElement valEl = element.createChild(VALUE_ELEMENT_NAME);
if (fStringListValue[i] != null)
valEl.setAttribute(VALUE_ELEMENT_VALUE, fStringListValue[i]);
}

That ties quite tightly with CDT as it is part of the org.eclipse.cdt.core.settings.model.


private ICMakeToolChainManager manager;
private Table filesTable;
private Button removeButton;
private Button variablesButton;
private Button testButton;
private Button browseButton;
private Button editButton;

private Text cmakeLocationTextBox;
private Text generatorLocationTextBox;

private String[] generatorLocations;
private String cmakeLocation;
private boolean useCmakeToolLocation;

private Map<Path, ICMakeToolChainFile> filesToAdd = new HashMap<>();
private Map<Path, ICMakeToolChainFile> filesToRemove = new HashMap<>();

@Override
public void init(IWorkbench workbench) {
manager = Activator.getService(ICMakeToolChainManager.class);
updateCmakeToolGroupData();
}

@Override
Expand Down Expand Up @@ -141,11 +179,141 @@ public void widgetSelected(SelectionEvent e) {
}
});

// CMake tools section
Group cmakeToolsGroup = new Group(control, SWT.NONE);
cmakeToolsGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
cmakeToolsGroup.setText(Messages.CMakePreferencePage_CMakeTools);
cmakeToolsGroup.setLayout(new GridLayout(1, false));

Composite checkBoxComp = new Composite(cmakeToolsGroup, SWT.NONE);
checkBoxComp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
checkBoxComp.setLayout(new GridLayout());

Button useCMakeToolLocCheckBox = new Button(checkBoxComp, SWT.CHECK);
useCMakeToolLocCheckBox.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 3, 1));
useCMakeToolLocCheckBox.setText(Messages.CMakePreferencePage_UseCMakeToolLocationsInCMakeBuilds);
useCMakeToolLocCheckBox.setToolTipText(Messages.CMakePreferencePage_UseCMakeToolLocationsInCMakeBuildsTooltip);
useCMakeToolLocCheckBox.setSelection(useCmakeToolLocation);
useCMakeToolLocCheckBox.addListener(SWT.Selection, e -> {
useCmakeToolLocation = useCMakeToolLocCheckBox.getSelection();
updateCMakeGroup(useCmakeToolLocation);
});

Composite locationComp = new Composite(cmakeToolsGroup, SWT.NONE);
locationComp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
locationComp.setLayout(new GridLayout(3, false));

Label cmakeLocationLabel = new Label(locationComp, SWT.NONE);
cmakeLocationLabel.setText(Messages.CMakePreferencePage_CMakeLocation);
cmakeLocationLabel.setToolTipText(Messages.CMakePreferencePage_CMakeLocationTooltip);

cmakeLocationTextBox = new Text(locationComp, SWT.BORDER);
cmakeLocationTextBox.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
cmakeLocationTextBox.setText(cmakeLocation);
cmakeLocationTextBox.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent evt) {
cmakeLocation = resolveVariableValue(cmakeLocationTextBox.getText());
testButton.setEnabled(useCmakeToolLocation && cmakeLocationTextBox.getText().trim().length() > 0);

}
});

Composite cmakeLocationButtonComp = new Composite(locationComp, SWT.NONE);
cmakeLocationButtonComp.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
cmakeLocationButtonComp.setLayout(new GridLayout(3, true));

variablesButton = new Button(cmakeLocationButtonComp, SWT.PUSH);
variablesButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
variablesButton.setText(Messages.CMakePreferencePage_Variables);
variablesButton.setData(cmakeLocationTextBox);
variablesButton.addListener(SWT.Selection, e -> {
String x = null;
if (variablesButton.getData() instanceof Text t) {
x = getVariableDialog(getShell(), null);
if (x != null) {
t.insert(x);
}
}
});
Comment on lines +226 to +238
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only getData on this button is in the listener - by doing it this way we need instanceof checks and we lose the natural connection. e.g. doing find references on cmakeLocationTextBox won't show the t on line 232. Also, if you have one access to the field (variablesButton) you may as well directly access the field you really wanted.

Here is a suggestion for this block of code, it does this following:

  • simplifies the code and improves readability by using cmakeLocationTextBox in the listener
  • removes need for instanceof check
  • removes unneeded extra assignment to x
  • renames x to a more descriptive name
Suggested change
variablesButton = new Button(cmakeLocationButtonComp, SWT.PUSH);
variablesButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
variablesButton.setText(Messages.CMakePreferencePage_Variables);
variablesButton.setData(cmakeLocationTextBox);
variablesButton.addListener(SWT.Selection, e -> {
String x = null;
if (variablesButton.getData() instanceof Text t) {
x = getVariableDialog(getShell(), null);
if (x != null) {
t.insert(x);
}
}
});
variablesButton = new Button(cmakeLocationButtonComp, SWT.PUSH);
variablesButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
variablesButton.setText(Messages.CMakePreferencePage_Variables);
variablesButton.addListener(SWT.Selection, e -> {
String variable = getVariableDialog(getShell(), null);
if (variable != null) {
cmakeLocationTextBox.insert(variable);
}
});

You can apply a similar change to the browseButton


The use of set/get data is suitable when there is some reuse of code. For example, if you used the same listener for a bunch of different Variables... buttons and wanted each one to work on its associated text you could do something like this:

/**
 * Opens the variable dialog and applies the result to the text box associated with the
 * widget that issued the selection event.
 */
Listener applyVariableToTextbox = e -> {
	if (e.widget.getData() instanceof Text t) {
		String variable = getVariableDialog(getShell(), null);
		if (variable != null) {
			t.insert(variable);
		}
	}
};

cmakeVariablesButton = new Button(composite, SWT.PUSH);
cmakeVariablesButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
cmakeVariablesButton.setText("Variables...");
cmakeVariablesButton.setData(cmakeLocationTextBox);
cmakeVariablesButton.addListener(SWT.Selection, applyVariableToTextbox);

anotherVariablesButton = new Button(composite, SWT.PUSH);
anotherVariablesButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
anotherVariablesButton.setText("Variables...");
anotherVariablesButton.setData(anotherTextBox);
anotherVariablesButton.addListener(SWT.Selection, applyVariableToTextbox);


testButton = new Button(cmakeLocationButtonComp, SWT.PUSH);
testButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
testButton.setText(Messages.CMakePreferencePage_Test);
testButton.setToolTipText(Messages.CMakePreferencePage_TestTooltip);
testButton.setData(cmakeLocationTextBox);
testButton.addListener(SWT.Selection, e -> {
try {
Process p = Runtime.getRuntime()
.exec(new String[] { cmakeLocation + File.separatorChar + "cmake", "--version" }); //$NON-NLS-1$ //$NON-NLS-2$
List<String> buf = new ArrayList<>();
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = br.readLine()) != null) {
buf.add(line);
}
MessageDialog.openInformation(getShell(), Messages.CMakePreferencePage_TestCmakeLocation_Title,
Messages.CMakePreferencePage_TestCmakeLocation_Body + String.join(System.lineSeparator(), buf));
} catch (IOException e1) {
MessageDialog.openError(getShell(), Messages.CMakePreferencePage_FailToTestCmakeLocation_Title,
Messages.CMakePreferencePage_FailToTestCmakeLocation_Body + e1.getMessage());
Activator.log(e1);
}
});

browseButton = new Button(cmakeLocationButtonComp, SWT.PUSH);
browseButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
browseButton.setText(Messages.CMakePreferencePage_Browse);
browseButton.setData(cmakeLocationTextBox);
browseButton.addListener(SWT.Selection, e -> {
DirectoryDialog dirDialog = new DirectoryDialog(getShell());
String browsedDirectory = dirDialog.open();
if (browsedDirectory != null && browseButton.getData() instanceof Text t) {
t.setText(browsedDirectory);
}
});

Label generatorLocationsLabel = new Label(locationComp, SWT.NONE);
generatorLocationsLabel.setText(Messages.CMakePreferencePage_GeneratorLocation);
generatorLocationsLabel.setToolTipText(Messages.CMakePreferencePage_GeneratorLocationTooltip);

generatorLocationTextBox = new Text(locationComp, SWT.BORDER);
generatorLocationTextBox.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
generatorLocationTextBox.setEditable(false);
generatorLocationTextBox.setText(String.join(VALUE_DELIMITER, generatorLocations));

Composite generatorLocationButtonComp = new Composite(locationComp, SWT.NONE);
generatorLocationButtonComp.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
generatorLocationButtonComp.setLayout(new GridLayout(3, true));

editButton = new Button(generatorLocationButtonComp, SWT.PUSH);
editButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
editButton.setText(Messages.CMakePreferencePage_Edit);
editButton.setData(generatorLocationTextBox);
editButton.addListener(SWT.Selection, e -> {
EditGeneratorLocationDialog dialog = new EditGeneratorLocationDialog(getShell(),
Messages.CMakePreferencePage_EditGeneratorLocations_Title, generatorLocations);
if (dialog.open() == Window.OK && editButton.getData() instanceof Text t) {
generatorLocations = dialog.getValues();
t.setText(String.join(VALUE_DELIMITER, generatorLocations));
}
});

updateTable();
updateCMakeGroup(useCmakeToolLocation);

return control;
}

protected void updateCMakeGroup(boolean enable) {
cmakeLocationTextBox.setEnabled(enable);
generatorLocationTextBox.setEnabled(enable);
variablesButton.setEnabled(enable);
testButton.setEnabled(enable && cmakeLocationTextBox.getText().trim().length() > 0);
browseButton.setEnabled(enable);
editButton.setEnabled(enable);
}

private void updateTable() {
List<ICMakeToolChainFile> sorted = new ArrayList<>(getFiles().values());
Collections.sort(sorted, (o1, o2) -> o1.getPath().toString().compareToIgnoreCase(o2.getPath().toString()));
Expand Down Expand Up @@ -205,7 +373,89 @@ public boolean performOk() {
filesToAdd.clear();
filesToRemove.clear();

// Update Preferences for cmakeSupplier
getPreferences().putBoolean(ENABLE_USE_CMAKE_LOCATION, useCmakeToolLocation);
getPreferences().put(CMAKE_LOCATION, cmakeLocation);
getPreferences().put(CMAKE_GENERATOR_LOCATION, String.join(VALUE_DELIMITER, generatorLocations));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please serialize the list using XML or propose another serialization format that has no ambiguity.

For example, to reuse the CDT infrastructure to do this see org.eclipse.cdt.internal.core.cdtvariables.UserDefinedVariableSupplier.storeMacrosToStream(StorableCdtVariables)

Note that the CDT Variables GUI + backend is pretty complicated and it can be hard to see how the variable serialize connects to the preference tab. Here is a call hierarchy that shows how they are connected:

  • StorableCdtVariables.serialize(ICStorageElement)
    • UserDefinedVariableSupplier.storeMacrosToStream(StorableCdtVariables)
      • UserDefinedVariableSupplier.storeWorkspaceMacros(StorableCdtVariables, boolean)
        • UserDefinedVariableSupplier.storeWorkspaceVariables(boolean)
          • UserVarSupplier.storeWorkspaceVariables(boolean)
            • CPropertyVarsTab.performApply(ICResourceDescription, ICResourceDescription) line 648


return true;
}

private void updateCmakeToolGroupData() {
useCmakeToolLocation = getPreferences().getBoolean(ENABLE_USE_CMAKE_LOCATION, false);
cmakeLocation = getPreferences().get(CMAKE_LOCATION, ""); //$NON-NLS-1$
String genLocations = getPreferences().get(CMAKE_GENERATOR_LOCATION, ""); //$NON-NLS-1$
generatorLocations = genLocations.length() > 0 ? genLocations.split(" \\|\\| ") : new String[0]; //$NON-NLS-1$
}

private String resolveVariableValue(String value) {
try {
ICdtVariableManager vm = CCorePlugin.getDefault().getCdtVariableManager();
return vm.resolveValue(value, null, "", null); //$NON-NLS-1$
} catch (CdtVariableException e) {
Activator.log(e);
}
return null;
}

private String getVariableDialog(Shell shell, ICConfigurationDescription cfgd) {
ICdtVariableManager vm = CCorePlugin.getDefault().getCdtVariableManager();
BuildVarListDialog dialog = new BuildVarListDialog(shell, vm.getVariables(cfgd));
dialog.setTitle(Messages.VariablesDialog_Title);
if (dialog.open() == Window.OK) {
Object[] selected = dialog.getResult();
if (selected.length > 0) {
String s = ((ICdtVariable) selected[0]).getName();
return "${" + s.trim() + "}"; //$NON-NLS-1$//$NON-NLS-2$
}
}
return null;
}

private class EditGeneratorLocationDialog extends Dialog {

private String fTitle;
private FileListControl fListEditor;
private String[] fGeneratorLocations;

public EditGeneratorLocationDialog(Shell parentShell, String title, String[] generatorLocations) {
super(parentShell);
this.fGeneratorLocations = generatorLocations;
}

@Override
protected void configureShell(Shell shell) {
super.configureShell(shell);
if (fTitle != null) {
shell.setText(fTitle);
}
}

@Override
protected Control createDialogArea(Composite parent) {
Composite comp = new Composite(parent, SWT.NULL);
comp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
comp.setLayout(new GridLayout());
fListEditor = new FileListControl(comp,
Messages.CMakePreferencePage_EditGeneratorLocations_GeneratorLocation, 0);
if (fGeneratorLocations != null) {
fListEditor.setList(fGeneratorLocations);
}
return comp;
}

@Override
protected void okPressed() {
fGeneratorLocations = fListEditor.getItems();
super.okPressed();
}

public String[] getValues() {
return fGeneratorLocations;
}
}

private Preferences getPreferences() {
return InstanceScope.INSTANCE.getNode(CCorePlugin.PLUGIN_ID).node(NODENAME);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,31 @@ public class Messages extends NLS {
public static String CMakeBuildTab_useDefaultCmakeSettings;
public static String CMakeBuildTab_useDefaultCmakeSettingsTip;
public static String CMakePreferencePage_Add;
public static String CMakePreferencePage_Browse;
public static String CMakePreferencePage_CMakeLocation;
public static String CMakePreferencePage_CMakeLocationTooltip;
public static String CMakePreferencePage_CMakeTools;
public static String CMakePreferencePage_ConfirmRemoveDesc;
public static String CMakePreferencePage_ConfirmRemoveTitle;
public static String CMakePreferencePage_Delete;
public static String CMakePreferencePage_Edit;
public static String CMakePreferencePage_EditGeneratorLocations_Title;
public static String CMakePreferencePage_EditGeneratorLocations_GeneratorLocation;
public static String CMakePreferencePage_FailToTestCmakeLocation_Body;
public static String CMakePreferencePage_FailToTestCmakeLocation_Title;
public static String CMakePreferencePage_Files;
public static String CMakePreferencePage_GeneratorLocation;
public static String CMakePreferencePage_GeneratorLocationTooltip;
public static String CMakePreferencePage_Path;
public static String CMakePreferencePage_Remove;
public static String CMakePreferencePage_Test;
public static String CMakePreferencePage_TestCmakeLocation_Body;
public static String CMakePreferencePage_TestCmakeLocation_Title;
public static String CMakePreferencePage_TestTooltip;
public static String CMakePreferencePage_Toolchain;
public static String CMakePreferencePage_UseCMakeToolLocationsInCMakeBuilds;
public static String CMakePreferencePage_UseCMakeToolLocationsInCMakeBuildsTooltip;
public static String CMakePreferencePage_Variables;
public static String CMakePropertyPage_FailedToStartCMakeGui_Body;
public static String CMakePropertyPage_FailedToStartCMakeGui_Title;
public static String CMakePropertyPage_FailedToGetOS_Body;
Expand All @@ -53,6 +72,8 @@ public class Messages extends NLS {
public static String NewCMakeToolChainFilePage_Title;
public static String NewCMakeToolChainFilePage_Toolchain;

public static String VariablesDialog_Title;

static {
// initialize resource bundle
NLS.initializeMessages("org.eclipse.cdt.cmake.ui.internal.messages", Messages.class); //$NON-NLS-1$
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,31 @@ CMakeBuildTab_Toolchain=Toolchain
CMakeBuildTab_useDefaultCmakeSettings=Use default CMake settings
CMakeBuildTab_useDefaultCmakeSettingsTip=Use the default CMake settings that are provided by the toolchain and Core Build System
CMakePreferencePage_Add=Add...
CMakePreferencePage_Browse=Browse...
CMakePreferencePage_CMakeLocation=CMake location:
CMakePreferencePage_CMakeLocationTooltip=The directory containing the CMake tool.
CMakePreferencePage_CMakeTools=CMake Tools
CMakePreferencePage_ConfirmRemoveDesc=Do you wish to deregister the selected files?
CMakePreferencePage_ConfirmRemoveTitle=Deregister CMake ToolChain File
CMakePreferencePage_Delete=Delete
CMakePreferencePage_Edit=Edit...
CMakePreferencePage_EditGeneratorLocations_Title=Edit generator locations
CMakePreferencePage_EditGeneratorLocations_GeneratorLocation=Generator location:
CMakePreferencePage_FailToTestCmakeLocation_Body=Fail to test CMake in selected location:\u000a
CMakePreferencePage_FailToTestCmakeLocation_Title=Fail to test CMake location
CMakePreferencePage_Files=Toolchain Files
CMakePreferencePage_GeneratorLocation=Generator location(s):
CMakePreferencePage_GeneratorLocationTooltip=The directory(s) containing the CMake generators (eg Ninja, Makefiles). To add or modify the list, use "Edit..." button.
CMakePreferencePage_Path=Toolchain File
CMakePreferencePage_Remove=Remove
CMakePreferencePage_Test=Test...
CMakePreferencePage_TestCmakeLocation_Body=Found:\u0020
CMakePreferencePage_TestCmakeLocation_Title=Test result
CMakePreferencePage_TestTooltip=Tests that the CMake binary is found and executable.
CMakePreferencePage_Toolchain=Toolchain
CMakePreferencePage_UseCMakeToolLocationsInCMakeBuilds=Use CMake tool locations in CMake builds
CMakePreferencePage_UseCMakeToolLocationsInCMakeBuildsTooltip=The listed directories are added to the CMake execution environment so the CMake tool and generators are available for building and debugging. Uncheck to use locations already specified on system PATH environment.
CMakePreferencePage_Variables=Variables...
CMakePropertyPage_FailedToStartCMakeGui_Body=Failed to run the CMake GUI:\u0020
CMakePropertyPage_FailedToStartCMakeGui_Title=Failed to run CMake GUI
CMakePropertyPage_FailedToGetOS_Body=Failed to get target OS for CMake project:
Expand All @@ -34,3 +53,4 @@ NewCMakeToolChainFilePage_Path=Path:
NewCMakeToolChainFilePage_Select=Select location for CMake toolchain file
NewCMakeToolChainFilePage_Title=New CMake ToolChain File
NewCMakeToolChainFilePage_Toolchain=Toolchain:
VariablesDialog_Title=Select CMake variable
Loading
Loading