Skip to content

Commit

Permalink
Improve CMake build option handling and API
Browse files Browse the repository at this point in the history
Summary:

- Add some new API to make it easier for ISVs to provide defaults.
- Fully connect UI elements to CMake build process
- Add some missing UI elements (such as customizing generator)
- CMake generator default within CDT changed to Ninja

Details:

Add API to set CMake generator default (eg Ninja) ISV can set
their desired CMake generator by overriding
`CMakeBuildConfiguration.getDefaultProperties`. ISVs can also further
fine tune the build process by overriding
`CMakeBuildConfiguration.getDefaultProperties`

Remove API `IOsOverrides` and related code. `IOsOverrides` was a partial
implementation to achieve builds in Docker containers, however the
work was not complete and it the extra code was complicating some
basic use cases of setting defaults

Add support for all generators to CMake build settings UI page by
using a Combo instead of radio buttons. The non-deprecated generators
that are built-in to CDT populate the Combo, but additional generators
can be manually entered in the Combo.

Rename clean command to clean target to better reflect its use as
the argument passed to cmake's --target command line.

Add all target for the argument passed to cmake's --target
command line when doing a normal build.

Clarify usage of UI overrides and change the UI to be "use defaults"
(i.e. invert the checkbox). This is a **breaking** change as it means
user projects that were using UI overrides will revert to using defaults.
This is done on purpose as so many little things have changed in CMake
settings, that reverting to defaults on upgrade seems like a logical
decision. In addition *use defaults* matches the other GUIs in Eclipse,
for example the MBS build command settings.

Populate all defaults in getDefaultProperties() so that all CMake build
settings are displayed as used (greyed out) and can be used as a starting
point when editing settings.

Simplify some of the code in CMakeBuildTab.

Fix parsing of extra args so that quoted strings work.

Refactored manual tests document and brought it up to date.

Correct command line option for CMake's --warn-unused-vars

Correct command line option for CMake's --warn-uninitialized

Overall this is an API breaking change and the CHANGELOG-API.md has been
updated with all the API changes in and around ICMakeProperties,
including fixing typos in WarnUninitialized methods.

Fixes #1055
Part of #1000

Co-authored-by: John Moule <[email protected]>
Co-authored-by: Jonah Graham <[email protected]>
  • Loading branch information
betamaxbandit and jonahgraham committed Jan 26, 2025
1 parent 11dfaa4 commit 517ffab
Show file tree
Hide file tree
Showing 30 changed files with 921 additions and 1,154 deletions.
15 changes: 15 additions & 0 deletions NewAndNoteworthy/CDT-12.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,21 @@ The minimum version of GLIBC required is now 2.31.
This version can be found in Ubuntu 20.04 and later, RHEL 9.0 and later and other distros as well.
CDT's native components will likely work with older versions of glibc too, assuming they provide the required APIs for Eclipse CDT.

# Core Build

## More CMake build settings are now available in the user interface

The CMake build setting GUI has been updated to include more CMake settings, and some of the settings that did not used to do the correct thing have been updated for more consistent behavior.
The way these settings are saved has been slightly modified, meaning workspaces with CMake projects from before CDT 12 will have their build settings restored to defaults.
Build settings can be customized by unchecking "Use default CMake settings".

TODO: Before release add the final screenshot for the build settings here. I am not including it now because the UI keeps changing.

## Default build system generator for CMake changed to Ninja on all platforms

The default for CMake's build system generator is now Ninja on all platforms.
Users who want to use other build system generators can select their desired generator in the build settings.

# Managed Build

## New *C Project* and new *C++ Project* available via *New C/C++ Project* wizard
Expand Down
17 changes: 17 additions & 0 deletions NewAndNoteworthy/CHANGELOG-API.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,23 @@ This section describes API removals that occurred in past releases, and upcoming

Below is the detailed descriptions of API changes and mitigation efforts API consumers need to take.

## API Changes in CDT 12.0.

### org.eclipse.cdt.cmake.core.properties refactored

A significant simplification to the CMake build properties was completed, this included removing some API that was not used.
The following classes have been removed or modified in API breaking ways:

- org.eclipse.cdt.cmake.core.properties.ICMakePropertiesController removed
- org.eclipse.cdt.cmake.core.properties.IGeneralProperties removed
- org.eclipse.cdt.cmake.core.properties.IOsOverrides removed
- org.eclipse.cdt.cmake.core.properties.ICMakeProperties:
- new methods added to compensate for removal of IOsOverrides
- reset method removed
- spelling corrected for methods with Uninitialized in the name
- setWarnUnused renamed to setWarnUnusedVars and isWarnUnused renamed to isWarnUnusedVars


## API Changes in CDT 11.5.

### org.eclipse.cdt.make.ui.dialogs.DiscoveredPathContainerPage removed
Expand Down
7 changes: 5 additions & 2 deletions cmake/org.eclipse.cdt.cmake.core.tests/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ Bundle-SymbolicName: org.eclipse.cdt.cmake.core.tests
Bundle-Version: 1.0.0.qualifier
Fragment-Host: org.eclipse.cdt.cmake.core;bundle-version="1.5.0"
Import-Package: org.assertj.core.api;version="[3.24.2,4.0.0)",
org.junit.jupiter.api;version="[5.9.3,6.0.0)"
org.junit.jupiter.api;version="[5.9.3,6.0.0)",
org.mockito;version="[5.15.0,6.0.0)",
org.mockito.stubbing;version="[5.15.0,6.0.0)"
Automatic-Module-Name: org.eclipse.cdt.cmake.core.tests
Bundle-Vendor: %Bundle-Vendor
Bundle-Copyright: %Bundle-Copyright
Require-Bundle: org.junit
Require-Bundle: org.junit,
org.eclipse.cdt.core.tests;bundle-version="[5.4.0,6.0.0)"

Original file line number Diff line number Diff line change
@@ -0,0 +1,299 @@
/*******************************************************************************
* Copyright (c) 2025 Renesas Electronics Europe.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.cdt.cmake.core;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.cdt.cmake.core.properties.CMakeGenerator;
import org.eclipse.cdt.cmake.core.properties.ICMakeGenerator;
import org.eclipse.cdt.cmake.core.properties.ICMakeProperties;
import org.eclipse.cdt.core.CCProjectNature;
import org.eclipse.cdt.core.CProjectNature;
import org.eclipse.cdt.core.build.IToolChain;
import org.eclipse.cdt.core.testplugin.ResourceHelper;
import org.eclipse.cdt.core.testplugin.util.BaseTestCase5;
import org.eclipse.cdt.utils.CommandLineUtil;
import org.eclipse.core.resources.IBuildConfiguration;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

/**
* Tests a new API added to the CMake Build Configuration which allows default CMake properties to be set.
* See the new interface {@link ICMakeBuildConfiguration}.
*/
public class CMakeBuildConfigurationTests extends BaseTestCase5 {
private IBuildConfiguration buildConfig;
private IToolChain mockToolchain;

@BeforeEach
public void setup() throws Exception {
// Create a CMake project
IProject project = createCMakeProject();
// Get the default build config from the project (it always has one)
buildConfig = project.getBuildConfig(IBuildConfiguration.DEFAULT_CONFIG_NAME);
// Setup a toolchain ready to use for creating the valid ICBuildConfiguration
mockToolchain = mock(IToolChain.class);
when(mockToolchain.getProperty(IToolChain.ATTR_OS)).thenReturn("osDummy");
when(mockToolchain.getProperty(IToolChain.ATTR_ARCH)).thenReturn("archDummy");
when(mockToolchain.getTypeId()).thenReturn("tc_typeId");
when(mockToolchain.getId()).thenReturn("tcId");
when(mockToolchain.getBuildConfigNameFragment()).thenReturn("buildConfigName");
}

/**
* Test for {@link ICMakeProperties#setGenerator()}.
*
* This test also verifies that what the ISV overrides in getCMakeProperties is what takes effect.
*/
@Test
public void getCMakePropertiesTestSetGenerator() throws Exception {
CMakeBuildConfiguration cmBuildConfig = new CMakeBuildConfiguration(buildConfig, "cmBuildConfigName",
mockToolchain) {

@Override
public ICMakeProperties getCMakeProperties() {
ICMakeProperties properties = super.getCMakeProperties();
properties.setGenerator(CMakeGenerator.WatcomWMake);
return properties;
}
};

// Call the new method on ICMakeBuildConfiguration to get the default CMake properties.
ICMakeProperties cMakeProperties = cmBuildConfig.getCMakeProperties();
assertThat(cMakeProperties.getGenerator(), is(CMakeGenerator.WatcomWMake));
}

/**
* Test for {@link ICMakeProperties#setExtraArguments()}
*
* This test also verifies that what the ISV overrides in getCMakeProperties is what takes effect.
*/
@Test
public void getCMakePropertiesTestSetExtraArguments() throws Exception {
// Create a C Build Configuration using the default build config and an arbitrary name
CMakeBuildConfiguration cmBuildConfig = new CMakeBuildConfiguration(buildConfig, "cmBuildConfigName",
mockToolchain) {

@Override
public ICMakeProperties getCMakeProperties() {
ICMakeProperties properties = super.getCMakeProperties();
properties.setExtraArguments(
new ArrayList<>((List.of("-DplatformAgnosticArgsTest0=0", "-DplatformAgnosticArgsTest1=1"))));
return properties;
}
};
// Call the new method on ICMakeBuildConfiguration to get the default CMake properties.
ICMakeProperties cMakeProperties = cmBuildConfig.getCMakeProperties();
List<String> extraArguments = cMakeProperties.getExtraArguments();
assertThat(extraArguments, contains("-DplatformAgnosticArgsTest0=0", "-DplatformAgnosticArgsTest1=1"));
}

/**
* Test for {@link CMakeBuildConfiguration#getDefaultProperties()}
*/
@Test
public void getDefaultProperties() throws Exception {
// Create a C Build Configuration using the default build config and an arbitrary name
CMakeBuildConfiguration cmBuildConfig = new CMakeBuildConfiguration(buildConfig, "cmBuildConfigName",
mockToolchain) {

@Override
public Map<String, String> getDefaultProperties() {
var defs = new HashMap<>(super.getDefaultProperties());
defs.put(CMAKE_GENERATOR, CMakeGenerator.WatcomWMake.getCMakeName());
return defs;
}
};
// Call the new method on ICMakeBuildConfiguration to get the default CMake properties.
ICMakeProperties cMakeProperties = cmBuildConfig.getCMakeProperties();
assertThat(cMakeProperties.getGenerator(), is(CMakeGenerator.WatcomWMake));
}

@Test
public void getDefaultPropertiesTestExtraArgs() throws Exception {
// Create a C Build Configuration using the default build config and an arbitrary name
CMakeBuildConfiguration cmBuildConfig = new CMakeBuildConfiguration(buildConfig, "cmBuildConfigName",
mockToolchain) {
@Override
public Map<String, String> getDefaultProperties() {
var defs = new HashMap<>(super.getDefaultProperties());
defs.put(CMAKE_ARGUMENTS, "-Dtest0=0 -Dtest1=1");
return defs;
}
};
// Call the new method on ICMakeBuildConfiguration to get the default CMake properties.
ICMakeProperties cMakeProperties = cmBuildConfig.getCMakeProperties();
List<String> extraArguments = cMakeProperties.getExtraArguments();
assertThat(extraArguments, contains("-Dtest0=0", "-Dtest1=1"));
}

/**
* Test that a custom cmake generator can be entered and auto-created
*/
@Test
public void customCMakeGeneratorEntryAuto() throws Exception {
// Create a C Build Configuration using the default build config and an arbitrary name
CMakeBuildConfiguration cmBuildConfig = new CMakeBuildConfiguration(buildConfig, "cmBuildConfigName",
mockToolchain) {
@Override
public Map<String, String> getDefaultProperties() {
var defs = new HashMap<>(super.getDefaultProperties());
// A custom generator for a custom cmake version
defs.put(CMAKE_GENERATOR, "My Personal Generator");
return defs;
}
};

// Call the new method on ICMakeBuildConfiguration to get the default CMake properties.
ICMakeProperties cMakeProperties = cmBuildConfig.getCMakeProperties();
assertThat(cMakeProperties.getGenerator().getCMakeName(), is("My Personal Generator"));
assertThat(cMakeProperties.getGenerator().getIgnoreErrOption(), is(nullValue()));
assertThat(cMakeProperties.getGenerator().getMakefileName(), is(nullValue()));
}

/**
* Test that a custom cmake generator can be entered and manually-created
*/
@Test
public void customCMakeGeneratorEntryManual() throws Exception {
// Create a C Build Configuration using the default build config and an arbitrary name
CMakeBuildConfiguration cmBuildConfig = new CMakeBuildConfiguration(buildConfig, "cmBuildConfigName",
mockToolchain) {
@Override
public Map<String, String> getDefaultProperties() {
var defs = new HashMap<>(super.getDefaultProperties());
// A custom generator for a custom cmake version
defs.put(CMAKE_GENERATOR, "My Personal Generator");
return defs;
}

@Override
public ICMakeProperties getCMakeProperties() {
ICMakeProperties properties = super.getCMakeProperties();
if ("My Personal Generator".equals(properties.getGenerator().getCMakeName())) {
var generator = new ICMakeGenerator() {
@Override
public String getMakefileName() {
return "MyMak.mak";
}

@Override
public String getIgnoreErrOption() {
return "-mycustom";
}

@Override
public String getCMakeName() {
return "My Personal Generator";
}
};
properties.setGenerator(generator);
}
return properties;
}
};

// Call the new method on ICMakeBuildConfiguration to get the default CMake properties.
ICMakeProperties cMakeProperties = cmBuildConfig.getCMakeProperties();
assertThat(cMakeProperties.getGenerator().getCMakeName(), is("My Personal Generator"));
assertThat(cMakeProperties.getGenerator().getIgnoreErrOption(), is("-mycustom"));
assertThat(cMakeProperties.getGenerator().getMakefileName(), is("MyMak.mak"));
}

/**
* Test all and clean targets and cmake command have working defaults
*/
@Test
public void targetsAndCommandDefaults() throws Exception {
// Create a C Build Configuration using the default build config and an arbitrary name
CMakeBuildConfiguration cmBuildConfig = new CMakeBuildConfiguration(buildConfig, "cmBuildConfigName",
mockToolchain);

// Call the new method on ICMakeBuildConfiguration to get the default CMake properties.
ICMakeProperties cMakeProperties = cmBuildConfig.getCMakeProperties();
assertThat(cMakeProperties.getCommand(), is("cmake"));
assertThat(cMakeProperties.getAllTarget(), is("all"));
assertThat(cMakeProperties.getCleanTarget(), is("clean"));
}

/**
* Test all and clean targets and cmake command can be overridden
*/
@Test
public void targetsAndCommand() throws Exception {
// Create a C Build Configuration using the default build config and an arbitrary name
CMakeBuildConfiguration cmBuildConfig = new CMakeBuildConfiguration(buildConfig, "cmBuildConfigName",
mockToolchain) {
@Override
public Map<String, String> getDefaultProperties() {
var defs = new HashMap<>(super.getDefaultProperties());
defs.put(CMAKE_BUILD_COMMAND, "mycmake");
defs.put(CMAKE_ALL_TARGET, "myall");
defs.put(CMAKE_CLEAN_TARGET, "myclean");
return defs;
}
};

// Call the new method on ICMakeBuildConfiguration to get the default CMake properties.
ICMakeProperties cMakeProperties = cmBuildConfig.getCMakeProperties();
assertThat(cMakeProperties.getCommand(), is("mycmake"));
assertThat(cMakeProperties.getAllTarget(), is("myall"));
assertThat(cMakeProperties.getCleanTarget(), is("myclean"));
}

/**
* Test that extra arguments parse correctly, e.g. handles ".
*
* Note that this test is minimal here as the real functionality is in {@link CommandLineUtil}
* and all the special cases are tested in CommandLineUtilTest.
*/
@Test
public void extraArgumentsParseCorrectly() throws Exception {
// Create a C Build Configuration using the default build config and an arbitrary name
CMakeBuildConfiguration cmBuildConfig = new CMakeBuildConfiguration(buildConfig, "cmBuildConfigName",
mockToolchain) {
@Override
public Map<String, String> getDefaultProperties() {
var defs = new HashMap<>(super.getDefaultProperties());
defs.put(CMAKE_ARGUMENTS, "-Da=\"something with space and quotes\" \"-Danother=quoted\"");
return defs;
}
};

// Call the new method on ICMakeBuildConfiguration to get the default CMake properties.
ICMakeProperties cMakeProperties = cmBuildConfig.getCMakeProperties();
assertThat(cMakeProperties.getExtraArguments(),
is(List.of("-Da=something with space and quotes", "-Danother=quoted")));
}

private IProject createCMakeProject() throws Exception {
// Create a plain Eclipse project
IProject project = ResourceHelper.createProject(this.getName());
// Add C/C++ and CMake natures to make it a CMake project
IProjectDescription description = project.getDescription();
description.setNatureIds(
new String[] { CProjectNature.C_NATURE_ID, CCProjectNature.CC_NATURE_ID, CMakeNature.ID });
project.setDescription(description, null);
return project;
}
}
Loading

0 comments on commit 517ffab

Please sign in to comment.