diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/resources/builderTests/regressions/README.txt b/build/org.eclipse.cdt.managedbuilder.core.tests/resources/builderTests/regressions/README.txt
index 58b16439453..5368853f439 100644
--- a/build/org.eclipse.cdt.managedbuilder.core.tests/resources/builderTests/regressions/README.txt
+++ b/build/org.eclipse.cdt.managedbuilder.core.tests/resources/builderTests/regressions/README.txt
@@ -3,5 +3,9 @@ helloworldC.zip:
Basic standard Linux GCC C HelloWorld ManagedBuild Project template.
Contains Debug + Release configurations.
+helloworldCPP.zip:
+ Minimal standard Linux GCC C++ HelloWorld ManagedBuild Project template
+ Contains Debug + Release configurations.
+
bug_335476.zip:
Test for noticing environment variable changes.
\ No newline at end of file
diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/resources/builderTests/regressions/helloworldCPP.zip b/build/org.eclipse.cdt.managedbuilder.core.tests/resources/builderTests/regressions/helloworldCPP.zip
new file mode 100644
index 00000000000..c92696a4e14
Binary files /dev/null and b/build/org.eclipse.cdt.managedbuilder.core.tests/resources/builderTests/regressions/helloworldCPP.zip differ
diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/core/tests/CompilationDatabaseGenerationTest.java b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/core/tests/CompilationDatabaseGenerationTest.java
new file mode 100644
index 00000000000..6bb958844b5
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/core/tests/CompilationDatabaseGenerationTest.java
@@ -0,0 +1,170 @@
+/*******************************************************************************
+ * Copyright (c) 2019, 2020 Marc-Andre Laperle.
+ *
+ * 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.managedbuilder.core.tests;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.FileReader;
+
+import org.eclipse.cdt.managedbuilder.core.jsoncdb.CompilationDatabaseInformation;
+import org.eclipse.cdt.managedbuilder.internal.core.CommonBuilder;
+import org.eclipse.cdt.managedbuilder.testplugin.AbstractBuilderTest;
+import org.eclipse.cdt.managedbuilder.testplugin.ManagedBuildTestHelper;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IncrementalProjectBuilder;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.ui.preferences.ScopedPreferenceStore;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+
+public class CompilationDatabaseGenerationTest extends AbstractBuilderTest {
+
+ /**
+ * Tests generation of compile_commands.json in "build" folder
+ */
+ @Test
+ public void testCompilationDatabaseGeneration() throws Exception {
+ setWorkspace("regressions");
+ final IProject app = loadProject("helloworldC");
+ setGenerateFileOptionEnabled(true);
+ app.build(IncrementalProjectBuilder.FULL_BUILD, null);
+ IFile compilationDatabase = app.getFile("Debug/compile_commands.json");
+ assertTrue(compilationDatabase.exists());
+ }
+
+ /**
+ * Tests format for compile_commands.json. JSON array is expected, containing an element for the c file
+ */
+ @Test
+ public void testJsonFormat() throws Exception {
+ setWorkspace("regressions");
+ final IProject app = loadProject("helloworldC");
+ setGenerateFileOptionEnabled(true);
+ app.build(IncrementalProjectBuilder.FULL_BUILD, null);
+ IFile commandsFile = app.getFile("Debug/compile_commands.json");
+ if (commandsFile.exists()) {
+
+ try (FileReader reader = new FileReader(commandsFile.getLocation().toFile())) {
+ Gson gson = new Gson();
+ JsonArray jsonArray = gson.fromJson(reader, JsonArray.class);
+ for (JsonElement element : jsonArray) {
+ CompilationDatabaseInformation compileCommand = gson.fromJson(element,
+ CompilationDatabaseInformation.class);
+
+ assertTrue(compileCommand.directory() != null && !compileCommand.directory().isEmpty());
+ assertTrue(compileCommand.command() != null && !compileCommand.command().isEmpty());
+ assertTrue(compileCommand.file() != null && !compileCommand.file().isEmpty());
+ assertTrue(compileCommand.file().endsWith("src/helloworldC.c"));
+ }
+
+ }
+
+ }
+ }
+
+ /**
+ * Test that compile_commands.json is correctly generated when more than one .c file is present as a source file
+ */
+ @Test
+ public void testMultipleFiles() throws Exception {
+ setWorkspace("regressions");
+ final IProject app = loadProject("helloworldC");
+ IFile aFile = ManagedBuildTestHelper.createFile(app, "src/newFile.c");
+ setGenerateFileOptionEnabled(true);
+ app.build(IncrementalProjectBuilder.FULL_BUILD, null);
+ IFile commandsFile = app.getFile("Debug/compile_commands.json");
+ int numberOfElementsFound = 0;
+ boolean helloworldCIsPresent = false;
+ boolean newFileIsPresent = false;
+ try (FileReader reader = new FileReader(commandsFile.getLocation().toFile())) {
+ Gson gson = new Gson();
+ JsonArray jsonArray = gson.fromJson(reader, JsonArray.class);
+ System.out.println(jsonArray);
+ for (JsonElement element : jsonArray) {
+ CompilationDatabaseInformation compileCommand = gson.fromJson(element,
+ CompilationDatabaseInformation.class);
+ numberOfElementsFound++;
+ if (compileCommand.file().endsWith("helloworldC.c")) {
+ helloworldCIsPresent = true;
+ }
+ if (compileCommand.file().endsWith("newFile.c")) {
+ newFileIsPresent = true;
+ }
+ }
+ assertEquals(2, numberOfElementsFound);
+ assertTrue(helloworldCIsPresent);
+ assertTrue(newFileIsPresent);
+ }
+ }
+
+ /**
+ * Tests that cpp files are handled by compile_commands.json file generator
+ */
+ @Test
+ public void isCPPFileAllowed() throws Exception {
+ setWorkspace("regressions");
+ final IProject app = loadProject("helloworldCPP");
+ setGenerateFileOptionEnabled(true);
+ app.build(IncrementalProjectBuilder.FULL_BUILD, null);
+ IFile commandsFile = app.getFile("Debug/compile_commands.json");
+ if (commandsFile.exists()) {
+
+ try (FileReader reader = new FileReader(commandsFile.getLocation().toFile())) {
+ Gson gson = new Gson();
+ JsonArray jsonArray = gson.fromJson(reader, JsonArray.class);
+ for (JsonElement element : jsonArray) {
+ CompilationDatabaseInformation compileCommand = gson.fromJson(element,
+ CompilationDatabaseInformation.class);
+
+ assertTrue(compileCommand.directory() != null && !compileCommand.directory().isEmpty());
+ assertTrue(compileCommand.command() != null && !compileCommand.command().isEmpty());
+ assertTrue(compileCommand.file() != null && !compileCommand.file().isEmpty());
+ assertTrue(compileCommand.file().endsWith("src/helloworldCPP.cpp"));
+ }
+
+ }
+ }
+ }
+
+ /**
+ * Tests that compilation database is not generated when feature is disabled
+ */
+ @Test
+ public void testCompilationDatabaseGenerationNotEnabled() throws Exception {
+ setWorkspace("regressions");
+ final IProject app = loadProject("helloworldC");
+ setGenerateFileOptionEnabled(false);
+ app.build(IncrementalProjectBuilder.FULL_BUILD, null);
+ IFile compilationDatabase = app.getFile("Debug/compile_commands.json");
+ assertFalse(compilationDatabase.exists());
+ }
+
+ private static void setGenerateFileOptionEnabled(boolean value) {
+ IPreferenceStore preferenceStore = new ScopedPreferenceStore(InstanceScope.INSTANCE,
+ "org.eclipse.cdt.managedbuilder.ui");
+ preferenceStore.setValue(CommonBuilder.COMPILATION_DATABASE_ENABLEMENT, value);
+ }
+
+ @AfterEach
+ public void restoreDefaultForGenerateFile() {
+ IPreferenceStore preferenceStore = new ScopedPreferenceStore(InstanceScope.INSTANCE,
+ "org.eclipse.cdt.managedbuilder.ui");
+ preferenceStore.setToDefault(CommonBuilder.COMPILATION_DATABASE_ENABLEMENT);
+ }
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.core/.project b/build/org.eclipse.cdt.managedbuilder.core/.project
index cab798d8b70..70542d7e9d9 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/.project
+++ b/build/org.eclipse.cdt.managedbuilder.core/.project
@@ -25,6 +25,11 @@
+
+ org.eclipse.pde.ds.core.builder
+
+
+
org.eclipse.jdt.core.javanature
diff --git a/build/org.eclipse.cdt.managedbuilder.core/META-INF/MANIFEST.MF b/build/org.eclipse.cdt.managedbuilder.core/META-INF/MANIFEST.MF
index 413d69ae823..3d59b08efd7 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/META-INF/MANIFEST.MF
+++ b/build/org.eclipse.cdt.managedbuilder.core/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.cdt.managedbuilder.core; singleton:=true
-Bundle-Version: 9.6.300.qualifier
+Bundle-Version: 9.7.0.qualifier
Bundle-Activator: org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin
Bundle-Vendor: %providerName
Bundle-Localization: plugin
@@ -12,9 +12,11 @@ Export-Package: org.eclipse.cdt.build.core.scannerconfig,
org.eclipse.cdt.managedbuilder.buildmodel,
org.eclipse.cdt.managedbuilder.buildproperties,
org.eclipse.cdt.managedbuilder.core,
+ org.eclipse.cdt.managedbuilder.core.jsoncdb,
org.eclipse.cdt.managedbuilder.envvar,
org.eclipse.cdt.managedbuilder.internal.buildmodel;x-friends:="org.eclipse.cdt.managedbuilder.ui",
org.eclipse.cdt.managedbuilder.internal.core;x-friends:="org.eclipse.cdt.managedbuilder.ui,org.eclipse.cdt.managedbuilder.headlessbuilderapp",
+ org.eclipse.cdt.managedbuilder.internal.core.jsoncdb.generator;x-internal:=true,
org.eclipse.cdt.managedbuilder.internal.dataprovider;x-internal:=true,
org.eclipse.cdt.managedbuilder.internal.envvar;x-internal:=true,
org.eclipse.cdt.managedbuilder.internal.language.settings.providers;x-friends:="org.eclipse.cdt.managedbuilder.ui",
@@ -39,7 +41,8 @@ Require-Bundle: org.eclipse.cdt.core;bundle-version="[8.3.0,9.0.0)",
org.eclipse.ui;bundle-version="[3.2.0,4.0.0)",
org.eclipse.core.variables;bundle-version="[3.1.100,4.0.0)",
org.eclipse.cdt.make.core;visibility:=reexport,
- org.eclipse.core.filesystem;bundle-version="1.2.0"
+ org.eclipse.core.filesystem;bundle-version="1.2.0",
+ org.eclipse.jdt.annotation;bundle-version="[2.2.7,3.0.0)";resolution:=optional
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-17
Import-Package: com.google.gson;version="2.8.0"
diff --git a/build/org.eclipse.cdt.managedbuilder.core/plugin.properties b/build/org.eclipse.cdt.managedbuilder.core/plugin.properties
index 05c1695ec50..0e5591443c2 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/plugin.properties
+++ b/build/org.eclipse.cdt.managedbuilder.core/plugin.properties
@@ -78,6 +78,7 @@ extension-point.name.0 = Managed Build Definitions
extension-point.name.1 = Managed Build Project Converter
extension-point.name.2 = Build Properties
extension-point.name.3 = ToolChain Modification Info
+extension-point.name.4 = Compilation Database Contributor
GCCBuildOutputParser.name = CDT GCC Build Output Parser
GCCBuiltinCompilerSettings.name = CDT GCC Built-in Compiler Settings
diff --git a/build/org.eclipse.cdt.managedbuilder.core/plugin.xml b/build/org.eclipse.cdt.managedbuilder.core/plugin.xml
index f4892de8a22..076b3a70cc7 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/plugin.xml
+++ b/build/org.eclipse.cdt.managedbuilder.core/plugin.xml
@@ -7,6 +7,8 @@
+
+
diff --git a/build/org.eclipse.cdt.managedbuilder.core/schema/compilationDatabaseContributor.exsd b/build/org.eclipse.cdt.managedbuilder.core/schema/compilationDatabaseContributor.exsd
new file mode 100644
index 00000000000..ebe86d50583
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.core/schema/compilationDatabaseContributor.exsd
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+ This extension point allows to add specific information to compile_commands.json file.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Compilation Database for C/C++ projects
+
+
+
+
+
+
+ Toolchain ID
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/jsoncdb/CompilationDatabaseInformation.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/jsoncdb/CompilationDatabaseInformation.java
new file mode 100644
index 00000000000..dd3743e8ad0
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/jsoncdb/CompilationDatabaseInformation.java
@@ -0,0 +1,22 @@
+/********************************************************************************
+ * Copyright (c) 2023, 2024 Renesas Electronics Corp. and others.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
+package org.eclipse.cdt.managedbuilder.core.jsoncdb;
+
+/**
+ * The compilation database array of “command objects” members to be used for
+ * the extension point
+ * directory: The working directory of the compilation.
+ * command: The compile command. file: The main translation unit source
+ * processed by this compilation step.
+ * @since 9.7
+ */
+
+public record CompilationDatabaseInformation(String directory, String command, String file) {
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/jsoncdb/ICompilationDatabaseContributor.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/jsoncdb/ICompilationDatabaseContributor.java
new file mode 100644
index 00000000000..e76afa1bb93
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/jsoncdb/ICompilationDatabaseContributor.java
@@ -0,0 +1,33 @@
+/********************************************************************************
+ * Copyright (c) 2023, 2024 Renesas Electronics Europe. and others.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
+package org.eclipse.cdt.managedbuilder.core.jsoncdb;
+
+import java.util.List;
+
+import org.eclipse.cdt.managedbuilder.core.IConfiguration;
+import org.eclipse.jdt.annotation.NonNull;
+
+/**
+ * @since 9.7
+ */
+public interface ICompilationDatabaseContributor {
+
+ /**
+ * @param config
+ * Adds a new list of files to the compilation database
+ * Implementors should provide concrete implementations of this
+ * interface. IConfiguration will be taken as input, accessing the project and will generate a list of
+ * additional files to be added to compile_commands.json
+ * @return A non-null list of files that will be added to compilation database
+ */
+ @NonNull
+ public List getAdditionalFiles(@NonNull IConfiguration config);
+
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/CommonBuilder.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/CommonBuilder.java
index 2d6c149f7ce..58e9bd75771 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/CommonBuilder.java
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/CommonBuilder.java
@@ -57,6 +57,7 @@
import org.eclipse.cdt.managedbuilder.internal.buildmodel.IConfigurationBuildState;
import org.eclipse.cdt.managedbuilder.internal.buildmodel.IProjectBuildState;
import org.eclipse.cdt.managedbuilder.internal.buildmodel.StepBuilder;
+import org.eclipse.cdt.managedbuilder.internal.core.jsoncdb.generator.CompilationDatabaseGenerator;
import org.eclipse.cdt.managedbuilder.macros.BuildMacroException;
import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider;
import org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator;
@@ -85,6 +86,9 @@
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.ui.preferences.ScopedPreferenceStore;
public class CommonBuilder extends ACBuilder implements IIncrementalProjectBuilder2 {
@@ -93,6 +97,7 @@ public class CommonBuilder extends ACBuilder implements IIncrementalProjectBuild
private static final String NEWLINE = System.getProperty("line.separator"); //$NON-NLS-1$
private static final String TRACE_FOOTER = "]: "; //$NON-NLS-1$
private static final String TRACE_HEADER = "GeneratedmakefileBuilder trace ["; //$NON-NLS-1$
+ public static final String COMPILATION_DATABASE_ENABLEMENT = "generateCBDFile"; //$NON-NLS-1$
public static boolean VERBOSE = false;
private static final int PROGRESS_MONITOR_SCALE = 100;
@@ -505,6 +510,10 @@ private IProject[] build(int kind, IProject project, IBuilder[] builders, boolea
}
for (int i = 0; i < num; i++) {
+ if (isGenerateFileOptionEnabled()) {
+ CompilationDatabaseGenerator generator = new CompilationDatabaseGenerator(getProject(), activeCfg);
+ generator.generate();
+ }
//bug 219337
if (kind == INCREMENTAL_BUILD || kind == AUTO_BUILD) {
if (buildConfigResourceChanges()) { //only build projects with project resource changes
@@ -1375,4 +1384,15 @@ public ISchedulingRule getRule(int trigger, Map args) {
// Success!
return null;
}
+
+ public static boolean isGenerateFileOptionEnabled() {
+ try {
+ IPreferenceStore preferenceStore = new ScopedPreferenceStore(InstanceScope.INSTANCE,
+ "org.eclipse.cdt.managedbuilder.ui"); //$NON-NLS-1$
+ return preferenceStore.getBoolean(COMPILATION_DATABASE_ENABLEMENT);
+ } catch (Exception e) {
+ ManagedBuilderCorePlugin.log(e);
+ }
+ return false;
+ }
}
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/jsoncdb/generator/CompilationDatabaseContributionManager.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/jsoncdb/generator/CompilationDatabaseContributionManager.java
new file mode 100644
index 00000000000..b6792ab56a9
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/jsoncdb/generator/CompilationDatabaseContributionManager.java
@@ -0,0 +1,139 @@
+/********************************************************************************
+ * Copyright (c) 2023, 2024 Renesas Electronics Corp. and others.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
+package org.eclipse.cdt.managedbuilder.internal.core.jsoncdb.generator;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.managedbuilder.core.IConfiguration;
+import org.eclipse.cdt.managedbuilder.core.IToolChain;
+import org.eclipse.cdt.managedbuilder.core.jsoncdb.CompilationDatabaseInformation;
+import org.eclipse.cdt.managedbuilder.core.jsoncdb.ICompilationDatabaseContributor;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jdt.annotation.NonNull;
+
+/* package */ final class CompilationDatabaseContributionManager {
+ private static final String ATTRIB_RUNNER = "runner"; //$NON-NLS-1$
+ private static final String ATTRIB_TOOLCHAIN_ID = "toolchainID"; //$NON-NLS-1$
+ private static final String ID_COMPILATIONDATABASE = "compilationDatabase"; //$NON-NLS-1$
+ private static final String EXTENSION_ID = "compilationDatabaseContributor"; //$NON-NLS-1$
+ /**
+ * Map of tool chain IDs (see {@link IToolChain#getId()} to
+ * loaded instances of {@link ICompilationDatabaseContributor}
+ */
+ @NonNull
+ private final Map loadedInstances = new HashMap<>();
+ /**
+ * Map of tool chain IDs (see {@link IToolChain#getId()} to
+ * extension point information for the compilationDatabaseContributor extension.
+ */
+ private final Map factoryExtensions = new HashMap<>();
+
+ private class EmptyCompilationDatabaseContributor implements ICompilationDatabaseContributor {
+
+ @Override
+ public final @NonNull List getAdditionalFiles(@NonNull IConfiguration config) {
+ return Collections.emptyList();
+ }
+ }
+
+ private static CompilationDatabaseContributionManager instance;
+
+ private CompilationDatabaseContributionManager() {
+ initalise();
+ }
+
+ public static synchronized CompilationDatabaseContributionManager getInstance() {
+ if (CompilationDatabaseContributionManager.instance == null) {
+ CompilationDatabaseContributionManager.instance = new CompilationDatabaseContributionManager();
+ }
+ return CompilationDatabaseContributionManager.instance;
+ }
+
+ private void initalise() {
+ IExtensionPoint extension = Platform.getExtensionRegistry().getExtensionPoint(
+ "org.eclipse.cdt.managedbuilder.core", CompilationDatabaseContributionManager.EXTENSION_ID); //$NON-NLS-1$
+ if (extension != null) {
+ IExtension[] extensions = extension.getExtensions();
+ for (IExtension extension2 : extensions) {
+ IConfigurationElement[] configElements = extension2.getConfigurationElements();
+ for (IConfigurationElement configElement : configElements) {
+ if (CompilationDatabaseContributionManager.ID_COMPILATIONDATABASE.equals(configElement.getName())) { // $NON-NLS-1$
+ String toolchainId = configElement
+ .getAttribute(CompilationDatabaseContributionManager.ATTRIB_TOOLCHAIN_ID);
+ String className = configElement
+ .getAttribute(CompilationDatabaseContributionManager.ATTRIB_RUNNER);
+ if (toolchainId != null && className != null) {
+ factoryExtensions.put(toolchainId, configElement);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Get the Code Assist tool with the specified id
+ *
+ * @param id
+ * @return Tool extension or a list with no element if not found.
+ * @throws CoreException
+ */
+
+ @NonNull
+ public synchronized ICompilationDatabaseContributor getCompilationDatabaseContributor(
+ @NonNull IConfiguration config) {
+ IToolChain toolChain = config.getToolChain();
+ while (toolChain != null) {
+ String toolchainId = toolChain.getBaseId();
+ if (loadedInstances.containsKey(toolchainId)) {
+ ICompilationDatabaseContributor contributor = loadedInstances.get(toolchainId);
+ Assert.isNotNull(contributor);
+ return contributor;
+ } else if (factoryExtensions.containsKey(toolchainId)) {
+ return createCdbInstance(toolchainId);
+ } else {
+ toolChain = toolChain.getSuperClass();
+ }
+ }
+ return new EmptyCompilationDatabaseContributor();
+ }
+
+ @NonNull
+ private ICompilationDatabaseContributor createCdbInstance(String toolchainId) {
+ IConfigurationElement ele = factoryExtensions.get(toolchainId);
+ if (ele != null) {
+ ICompilationDatabaseContributor loaded = null;
+ try {
+ loaded = (ICompilationDatabaseContributor) ele
+ .createExecutableExtension(CompilationDatabaseContributionManager.ATTRIB_RUNNER);
+
+ } catch (CoreException e) {
+ Platform.getLog(getClass()).log(Status.error("Not able to create instance", e)); //$NON-NLS-1$
+ }
+ if (loaded == null) {
+ loaded = new EmptyCompilationDatabaseContributor();
+ }
+ loadedInstances.put(toolchainId, loaded);
+ return loaded;
+ }
+
+ return new EmptyCompilationDatabaseContributor();
+ }
+
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/jsoncdb/generator/CompilationDatabaseGenerator.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/jsoncdb/generator/CompilationDatabaseGenerator.java
new file mode 100644
index 00000000000..70382ed667d
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/core/jsoncdb/generator/CompilationDatabaseGenerator.java
@@ -0,0 +1,417 @@
+/********************************************************************************
+ * Copyright (c) 2023, 2024 Renesas Electronics Corp. and others.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
+package org.eclipse.cdt.managedbuilder.internal.core.jsoncdb.generator;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.List;
+
+import org.eclipse.cdt.core.settings.model.ICSourceEntry;
+import org.eclipse.cdt.core.settings.model.util.CDataUtil;
+import org.eclipse.cdt.managedbuilder.core.BuildException;
+import org.eclipse.cdt.managedbuilder.core.IConfiguration;
+import org.eclipse.cdt.managedbuilder.core.IFileInfo;
+import org.eclipse.cdt.managedbuilder.core.IFolderInfo;
+import org.eclipse.cdt.managedbuilder.core.IManagedCommandLineGenerator;
+import org.eclipse.cdt.managedbuilder.core.IManagedCommandLineInfo;
+import org.eclipse.cdt.managedbuilder.core.IOutputType;
+import org.eclipse.cdt.managedbuilder.core.IResourceInfo;
+import org.eclipse.cdt.managedbuilder.core.ITool;
+import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager;
+import org.eclipse.cdt.managedbuilder.core.jsoncdb.CompilationDatabaseInformation;
+import org.eclipse.cdt.managedbuilder.core.jsoncdb.ICompilationDatabaseContributor;
+import org.eclipse.cdt.managedbuilder.internal.macros.FileContextData;
+import org.eclipse.cdt.managedbuilder.macros.BuildMacroException;
+import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceProxy;
+import org.eclipse.core.resources.IResourceProxyVisitor;
+import org.eclipse.core.resources.IResourceStatus;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jdt.annotation.NonNull;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+public final class CompilationDatabaseGenerator {
+
+ private static final String CDB_FILENAME = "compile_commands.json"; //$NON-NLS-1$
+ private static final String ERROR_MESSAGE = "Can not set contents to compile_commands.json file"; //$NON-NLS-1$
+
+ private IProject project;
+ private IConfiguration configuration;
+ private ICSourceEntry[] srcEntries;
+ private Collection fileList;
+
+ public CompilationDatabaseGenerator(IProject proj, IConfiguration config) {
+ project = proj;
+ configuration = config;
+ srcEntries = config.getSourceEntries();
+ }
+
+ /**
+ * @param proj
+ * Creates and populates compilation database file
+ * @param config
+ */
+ public void generate() {
+ IPath buildDirectory = ManagedBuildManager.getBuildFullPath(configuration, configuration.getBuilder());
+ IPath compilationDatabasePath = buildDirectory
+ .append(IPath.SEPARATOR + CompilationDatabaseGenerator.CDB_FILENAME);
+ try {
+ IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ if (!workspace.getRoot().exists(buildDirectory)) {
+ createDirectory(workspace.getRoot().getFolder(buildDirectory).getProjectRelativePath().toString());
+ }
+ IFile compileCommandsFile = createFile(compilationDatabasePath);
+ addToCompilationdatabase(project, compileCommandsFile, configuration);
+
+ } catch (CoreException e) {
+ Platform.getLog(getClass())
+ .log(Status.error("Unable to initialize the creation of compile_commands.json file", e)); //$NON-NLS-1$
+ }
+
+ }
+
+ private IFile createFile(IPath compilationDatabasePath) throws CoreException {
+ IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ IFile newFile = workspace.getRoot().getFile(compilationDatabasePath);
+ try {
+ if (!newFile.exists()) {
+ try (InputStream inputStream = new ByteArrayInputStream("".getBytes())) { //$NON-NLS-1$
+ newFile.create(inputStream, true, null);
+ }
+ } else {
+ try (InputStream inputStream = new ByteArrayInputStream("".getBytes())) { //$NON-NLS-1$
+ newFile.setContents(inputStream, true, false, null);
+ }
+ }
+
+ } catch (Exception e) {
+ IStatus status = new Status(IStatus.ERROR, getClass(), CompilationDatabaseGenerator.ERROR_MESSAGE, e);
+ Platform.getLog(getClass()).log(status);
+ }
+
+ return newFile;
+ }
+
+ private void addToCompilationdatabase(IProject project, IFile compileCommandsFile, @NonNull IConfiguration config)
+ throws CoreException {
+ List objList = new ArrayList<>();
+ Gson gson = new GsonBuilder().setPrettyPrinting().create();
+ ResourceProxyVisitor resourceVisitor = new ResourceProxyVisitor(this, config);
+ project.accept(resourceVisitor, IResource.NONE);
+ try {
+ objList.addAll(populateObjList(project, config));
+ objList.addAll(getRunnerForToolchain(config).getAdditionalFiles(config));
+ CompilationDatabaseGenerator.save(gson.toJson(objList), compileCommandsFile);
+ } catch (Exception e) {
+ IStatus status = new Status(IStatus.ERROR, getClass(), CompilationDatabaseGenerator.ERROR_MESSAGE, e);
+ Platform.getLog(getClass()).log(status);
+ }
+ }
+
+ private static void save(String buffer, IFile file) throws CoreException {
+ byte[] bytes = buffer.getBytes(StandardCharsets.UTF_8);
+ ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
+ boolean force = true;
+ file.setContents(stream, force, false, null); // Don't record history
+ }
+
+ @NonNull
+ private ICompilationDatabaseContributor getRunnerForToolchain(@NonNull IConfiguration config) throws CoreException {
+ return CompilationDatabaseContributionManager.getInstance().getCompilationDatabaseContributor(config);
+ }
+
+ private List populateObjList(IProject project, IConfiguration config)
+ throws CoreException, BuildException {
+ List objList = new ArrayList<>();
+ for (IResource resource : getFileList()) {
+
+ IPath moduleRelativePath = resource.getParent().getProjectRelativePath();
+ String relativePath = moduleRelativePath.toString();
+ IFolder folder = project.getFolder(config.getName());
+ IPath sourceLocation = getPathForResource(resource);
+ String ext = sourceLocation.getFileExtension();
+ IResourceInfo rcInfo = config.getResourceInfo(resource.getProjectRelativePath(), false);
+ ITool tool = null;
+ if (rcInfo instanceof IFileInfo fi) {
+ ITool[] tools = fi.getToolsToInvoke();
+ if (tools != null && tools.length > 0) {
+ tool = tools[0];
+ for (ITool tool2 : tools) {
+ if (!tool2.getCustomBuildStep()) {
+ tool = tool2;
+ break;
+ }
+ }
+ }
+ } else if (rcInfo instanceof IFolderInfo foInfo) {
+ tool = foInfo.getToolFromInputExtension(ext);
+ }
+
+ if (tool != null) {
+
+ ArrayList enumeratedPrimaryOutputs = new ArrayList<>();
+ calculateOutputsForSource(tool, relativePath, sourceLocation, enumeratedPrimaryOutputs);
+ ArrayList inputs = new ArrayList<>();
+ inputs.add(resource.getLocation().toString());
+
+ IPath[] addlInputPaths = tool.getAdditionalDependencies();
+ for (IPath addlInputPath : addlInputPaths) {
+
+ IPath addlPath = addlInputPath;
+ if (!(addlPath.toString().startsWith("$(")) && !addlPath.isAbsolute()) { //$NON-NLS-1$
+ IPath tempPath = getPathForResource(project).append(addlPath);
+ if (tempPath != null) {
+ addlPath = ManagedBuildManager.calculateRelativePath(folder.getLocation(), tempPath);
+ }
+ }
+ inputs.add(addlPath.toString());
+ }
+ String[] inputStrings = inputs.toArray(new String[inputs.size()]);
+ String primaryOutputName = null;
+ String resourceName = sourceLocation.removeFileExtension().lastSegment();
+ if (!enumeratedPrimaryOutputs.isEmpty()) {
+ if (enumeratedPrimaryOutputs.size() > 1) {
+ StringBuilder resultBuilder = new StringBuilder();
+ for (IPath outputPath : enumeratedPrimaryOutputs) {
+ resultBuilder.append(outputPath.toString()).append(" "); //$NON-NLS-1$
+ }
+ primaryOutputName = resultBuilder.toString().trim();
+ } else {
+ primaryOutputName = enumeratedPrimaryOutputs.get(0).toString();
+ }
+ } else {
+ primaryOutputName = relativePath + IPath.SEPARATOR + resourceName + ".o"; //$NON-NLS-1$
+ }
+ IPath outputLocation = Path.fromOSString(primaryOutputName);
+ if (!outputLocation.isAbsolute()) {
+ outputLocation = getPathForResource(project).append(folder.getName()).append(primaryOutputName);
+ }
+ String outflag = tool.getOutputFlag();
+ String outputPrefix = tool.getOutputPrefix();
+ String[] flags = tool.getToolCommandFlags(sourceLocation, folder.getFullPath());
+ IManagedCommandLineInfo cmdLInfo = generateToolCommandLineInfo(tool, flags, outflag, outputPrefix,
+ outputLocation + "", inputStrings, sourceLocation, outputLocation); //$NON-NLS-1$
+
+ IBuildMacroProvider provider = ManagedBuildManager.getBuildMacroProvider();
+ String resolvedOptionFileContents = provider.resolveValueToMakefileFormat(cmdLInfo.getCommandLine(), "", //$NON-NLS-1$
+ " ", IBuildMacroProvider.CONTEXT_FILE, //$NON-NLS-1$
+ new FileContextData(sourceLocation, outputLocation, null, tool));
+
+ objList.add(new CompilationDatabaseInformation(project.getLocation().toString(),
+ resolvedOptionFileContents, resource.getLocation().toString()));
+ }
+
+ }
+ return objList;
+
+ }
+
+ private IManagedCommandLineInfo generateToolCommandLineInfo(ITool tool, String[] flags, String outputFlag,
+ String outputPrefix, String outputName, String[] inputResources, IPath inputLocation,
+ IPath outputLocation) {
+
+ String cmd = tool.getToolCommand();
+ try {
+ String resolvedCommand = null;
+
+ if ((inputLocation != null && inputLocation.toString().indexOf(" ") != -1) || //$NON-NLS-1$
+ (outputLocation != null && outputLocation.toString().indexOf(" ") != -1)) { //$NON-NLS-1$
+ resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValue(cmd, "", //$NON-NLS-1$
+ " ", //$NON-NLS-1$
+ IBuildMacroProvider.CONTEXT_FILE,
+ new FileContextData(inputLocation, outputLocation, null, tool));
+ } else {
+ resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(cmd, "", //$NON-NLS-1$
+ " ", //$NON-NLS-1$
+ IBuildMacroProvider.CONTEXT_FILE,
+ new FileContextData(inputLocation, outputLocation, null, tool));
+ }
+ if ((resolvedCommand = resolvedCommand.trim()).length() > 0) {
+ cmd = resolvedCommand;
+ }
+
+ } catch (BuildMacroException e) {
+ Platform.getLog(getClass()).log(Status.error(CompilationDatabaseGenerator.ERROR_MESSAGE, e));
+ }
+
+ IManagedCommandLineGenerator gen = tool.getCommandLineGenerator();
+ return gen.generateCommandLineInfo(tool, cmd, flags, outputFlag, outputPrefix, outputName, inputResources,
+ tool.getCommandLinePattern());
+
+ }
+
+ private void calculateOutputsForSource(ITool tool, String relativePath, IPath sourceLocation,
+ ArrayList enumeratedPrimaryOutputs) {
+
+ IOutputType[] outTypes = tool.getOutputTypes();
+ if (outTypes != null && outTypes.length > 0) {
+ IOutputType type = tool.getPrimaryOutputType();
+ boolean primaryOutput = (type == tool.getPrimaryOutputType());
+ String[] extensions = type.getOutputExtensions(tool);
+ if (primaryOutput) {
+ for (String extension : extensions) {
+ String prefix = type.getOutputPrefix();
+ String fileName = sourceLocation.removeFileExtension().lastSegment();
+ IPath outPath = Path.fromOSString(relativePath + IPath.SEPARATOR + prefix + fileName);
+ outPath = outPath.addFileExtension(extension);
+ enumeratedPrimaryOutputs.add(0, outPath);
+
+ }
+ }
+ }
+ }
+
+ private IPath getPathForResource(IResource resource) {
+ return new Path(resource.getLocationURI().getPath());
+ }
+
+ private boolean isSource(IPath path) {
+ return !CDataUtil.isExcluded(path, srcEntries);
+ }
+
+ private void appendFileList(IResource resource) {
+ getFileList().add(resource);
+ }
+
+ private Collection getFileList() {
+ if (fileList == null) {
+ fileList = new LinkedHashSet<>();
+ }
+ return fileList;
+ }
+
+ private boolean isGeneratedResource(IResource resource) {
+ // Is this a generated directory ...
+ IPath path = resource.getProjectRelativePath();
+ String[] configNames = ManagedBuildManager.getBuildInfo(project).getConfigurationNames();
+ for (String name : configNames) {
+ IPath root = new Path(name);
+ // It is if it is a root of the resource pathname
+ if (root.isPrefixOf(path)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private IPath createDirectory(String dirName) throws CoreException {
+ // Create or get the handle for the build directory
+ IFolder folder = project.getFolder(dirName);
+ if (!folder.exists()) {
+ // Make sure that parent folders exist
+ IPath parentPath = (new Path(dirName)).removeLastSegments(1);
+ // Assume that the parent exists if the path is empty
+ if (!parentPath.isEmpty()) {
+ IFolder parent = project.getFolder(parentPath);
+ if (!parent.exists()) {
+ createDirectory(parentPath.toString());
+ }
+ }
+
+ // Now make the requested folder
+ try {
+ folder.create(true, true, null);
+ } catch (CoreException e) {
+ if (e.getStatus().getCode() == IResourceStatus.PATH_OCCUPIED) {
+ folder.refreshLocal(IResource.DEPTH_ZERO, null);
+ } else {
+ throw e;
+ }
+ }
+
+ // Make sure the folder is marked as derived so it is not added to CM
+ if (!folder.isDerived()) {
+ folder.setDerived(true, null);
+ }
+ }
+
+ return folder.getFullPath();
+ }
+
+ /**
+ * This class is used to recursively walk the project and determine which
+ * modules contribute buildable source files.
+ */
+ private class ResourceProxyVisitor implements IResourceProxyVisitor {
+ private final CompilationDatabaseGenerator generator;
+ private final IConfiguration config;
+
+ public ResourceProxyVisitor(CompilationDatabaseGenerator generator, IConfiguration cfg) {
+ this.generator = generator;
+ this.config = cfg;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.core.resources.IResourceProxyVisitor#visit(org.eclipse.core.
+ * resources.IResourceProxy)
+ */
+ @Override
+ public boolean visit(IResourceProxy proxy) throws CoreException {
+ // No point in proceeding, is there
+ if (generator == null) {
+ return false;
+ }
+
+ IResource resource = proxy.requestResource();
+ boolean isSource = isSource(resource.getProjectRelativePath());
+
+ // Is this a resource we should even consider
+ if (proxy.getType() == IResource.FILE) {
+ // If this resource has a Resource Configuration and is not excluded or
+ // if it has a file extension that one of the tools builds, add the sudirectory
+ // to the list
+ IResourceInfo rcInfo = config.getResourceInfo(resource.getProjectRelativePath(), false);
+ if (isSource/* && !rcInfo.isExcluded() */) {
+ if (rcInfo instanceof IFolderInfo) {
+ String ext = resource.getFileExtension();
+ boolean buildFile = ((IFolderInfo) rcInfo).buildsFileType(ext);
+ if (buildFile &&
+ // If this file resource is a generated resource, then it is uninteresting
+ !generator.isGeneratedResource(resource)) {
+
+ generator.appendFileList(resource);
+ }
+ } else {
+ generator.appendFileList(resource);
+ }
+ }
+ } else if (proxy.getType() == IResource.FOLDER) {
+
+ if (!isSource || generator.isGeneratedResource(resource)) {
+ return false;
+ }
+ return true;
+ }
+ return true;
+ }
+
+ }
+
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/.project b/build/org.eclipse.cdt.managedbuilder.ui/.project
index 0efa7a6ca87..9724ff19b08 100644
--- a/build/org.eclipse.cdt.managedbuilder.ui/.project
+++ b/build/org.eclipse.cdt.managedbuilder.ui/.project
@@ -25,6 +25,11 @@
+
+ org.eclipse.pde.ds.core.builder
+
+
+
org.eclipse.jdt.core.javanature
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/.settings/org.eclipse.pde.ds.annotations.prefs b/build/org.eclipse.cdt.managedbuilder.ui/.settings/org.eclipse.pde.ds.annotations.prefs
new file mode 100644
index 00000000000..38f9eecff8e
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/.settings/org.eclipse.pde.ds.annotations.prefs
@@ -0,0 +1,7 @@
+dsVersion=V1_3
+eclipse.preferences.version=1
+enabled=true
+generateBundleActivationPolicyLazy=true
+path=OSGI-INF
+validationErrorLevel=error
+validationErrorLevel.missingImplicitUnbindMethod=error
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/META-INF/MANIFEST.MF b/build/org.eclipse.cdt.managedbuilder.ui/META-INF/MANIFEST.MF
index 211ddabea56..9f9770f226e 100644
--- a/build/org.eclipse.cdt.managedbuilder.ui/META-INF/MANIFEST.MF
+++ b/build/org.eclipse.cdt.managedbuilder.ui/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.cdt.managedbuilder.ui; singleton:=true
-Bundle-Version: 9.4.100.qualifier
+Bundle-Version: 9.4.200.qualifier
Bundle-Activator: org.eclipse.cdt.managedbuilder.ui.properties.ManagedBuilderUIPlugin
Bundle-Vendor: %providerName
Bundle-Localization: plugin
@@ -27,3 +27,6 @@ Require-Bundle: org.eclipse.core.resources;bundle-version="[3.2.0,4.0.0)",
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-17
Automatic-Module-Name: org.eclipse.cdt.managedbuilder.ui
+Service-Component: OSGI-INF/org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase.BuiltinPreferedOptionsDefaults.xml,
+ OSGI-INF/org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase.PreferenceConfigurationAccess.xml,
+ OSGI-INF/org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase.PreferenceMetadataDefaults.xml
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/OSGI-INF/org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase.BuiltinPreferedOptionsDefaults.xml b/build/org.eclipse.cdt.managedbuilder.ui/OSGI-INF/org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase.BuiltinPreferedOptionsDefaults.xml
new file mode 100644
index 00000000000..ac26a7bcdae
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/OSGI-INF/org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase.BuiltinPreferedOptionsDefaults.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/OSGI-INF/org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase.PreferenceConfigurationAccess.xml b/build/org.eclipse.cdt.managedbuilder.ui/OSGI-INF/org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase.PreferenceConfigurationAccess.xml
new file mode 100644
index 00000000000..45f61850759
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/OSGI-INF/org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase.PreferenceConfigurationAccess.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/OSGI-INF/org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase.PreferenceMetadataDefaults.xml b/build/org.eclipse.cdt.managedbuilder.ui/OSGI-INF/org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase.PreferenceMetadataDefaults.xml
new file mode 100644
index 00000000000..383524e4d1c
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/OSGI-INF/org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase.PreferenceMetadataDefaults.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/build.properties b/build/org.eclipse.cdt.managedbuilder.ui/build.properties
index a22b5265eb1..dfd8c9af335 100644
--- a/build/org.eclipse.cdt.managedbuilder.ui/build.properties
+++ b/build/org.eclipse.cdt.managedbuilder.ui/build.properties
@@ -16,7 +16,8 @@ bin.includes = plugin.xml,\
about.html,\
icons/,\
.,\
- META-INF/
+ META-INF/,\
+ OSGI-INF/
src.includes = schema/,\
about.html
source.. = src/
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/plugin.properties b/build/org.eclipse.cdt.managedbuilder.ui/plugin.properties
index 14a4812b3e0..1ab240aa55e 100644
--- a/build/org.eclipse.cdt.managedbuilder.ui/plugin.properties
+++ b/build/org.eclipse.cdt.managedbuilder.ui/plugin.properties
@@ -119,3 +119,5 @@ Configurations.menu=Build Configurations
buildDefinitionsUI.ep.name = Build Definitions UI
extension-point.name = Custom MBS New Wizard Pages
+
+JSONCompilatioDatabaseGeneratorPage.name = JSON Compilation Database Generator
\ No newline at end of file
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/plugin.xml b/build/org.eclipse.cdt.managedbuilder.ui/plugin.xml
index 198bcea8041..204de3966ee 100644
--- a/build/org.eclipse.cdt.managedbuilder.ui/plugin.xml
+++ b/build/org.eclipse.cdt.managedbuilder.ui/plugin.xml
@@ -340,6 +340,12 @@
id="org.eclipse.cdt.managedbuilder.ui.preferences.PrefPage_MultiConfig"
name="%multicfg">
+
+
@@ -809,6 +815,12 @@
+
+
@@ -917,5 +929,4 @@
label="%CDTToolchainProperty.keyword.toolchain2">
-
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/BuiltinPreferedOptionsDefaults.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/BuiltinPreferedOptionsDefaults.java
new file mode 100644
index 00000000000..439376d4c0e
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/BuiltinPreferedOptionsDefaults.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Contributors to the Eclipse Foundation.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * See git history
+ *******************************************************************************/
+
+package org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase;
+
+import org.osgi.service.component.annotations.Component;
+
+@Component
+public class BuiltinPreferedOptionsDefaults implements PreferenceOptionsDefaults {
+
+ @Override
+ public boolean generateCDB() {
+ return false;
+ }
+
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/CompilationDatabaseGeneratorBlock.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/CompilationDatabaseGeneratorBlock.java
new file mode 100644
index 00000000000..bfc6e6d6102
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/CompilationDatabaseGeneratorBlock.java
@@ -0,0 +1,259 @@
+/********************************************************************************
+ * Copyright (c) 2023, 2024 Renesas Electronics Corp. and others.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
+package org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase;
+
+import java.util.Optional;
+
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.ProjectScope;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IScopeContext;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.preference.IPreferencePageContainer;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.PreferencesUtil;
+import org.eclipse.ui.dialogs.PropertyPage;
+import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
+import org.eclipse.ui.preferences.IWorkingCopyManager;
+import org.eclipse.ui.preferences.WorkingCopyManager;
+import org.osgi.service.prefs.BackingStoreException;
+
+/**
+
+ * @noextend This class is not intended to be subclasses by clients.
+ * @since 9.5
+ */
+public class CompilationDatabaseGeneratorBlock extends PropertyPage implements IWorkbenchPreferencePage {
+
+ private final String id = "org.eclipse.cdt.managedbuilder.ui.compilationdatabase.JsonCdbPreferencePage"; //$NON-NLS-1$
+
+ protected Configuration configuration;
+ protected IWorkspace workspace;
+
+ protected IWorkingCopyManager manager;
+
+ private Link link;
+ private Button specific;
+ private Control control;
+ protected ConfigurationArea area;
+
+ @Override
+ public void init(IWorkbench workbench) {
+ this.configuration = workbench.getService(Configuration.class);
+ this.workspace = workbench.getService(IWorkspace.class);
+ }
+
+ @Override
+ public void setContainer(IPreferencePageContainer container) {
+ super.setContainer(container);
+ if (manager == null) {
+ manager = Optional.ofNullable(container)//
+ .filter(IWorkbenchPreferenceContainer.class::isInstance)//
+ .map(IWorkbenchPreferenceContainer.class::cast)//
+ .map(IWorkbenchPreferenceContainer::getWorkingCopyManager)//
+ .orElseGet(WorkingCopyManager::new);
+ }
+ if (configuration == null) {
+ configuration = getConfiguration();
+ }
+ if (workspace == null) {
+ workspace = PlatformUI.getWorkbench().getService(IWorkspace.class);
+ }
+ }
+
+ protected Configuration getConfiguration() {
+ return PlatformUI.getWorkbench().getService(Configuration.class);
+ }
+
+ @Override
+ protected Label createDescriptionLabel(Composite parent) {
+ if (projectScope().isPresent()) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setFont(parent.getFont());
+ composite.setLayout(GridLayoutFactory.fillDefaults().numColumns(2).create());
+ composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ specific = new Button(composite, SWT.CHECK);
+ specific.setLayoutData(new GridData(SWT.BEGINNING, SWT.TOP, true, false));
+ specific.setText(Messages.JsonCdbGeneratorPropertyPage_enableProjectSpecific);
+ specific.setFont(JFaceResources.getDialogFont());
+ specific.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> specificSelected()));
+ link = createLink(composite, Messages.JsonCdbGeneratorPropertyPage_configureWorkspace);
+ link.setLayoutData(new GridData(SWT.END, SWT.TOP, false, false));
+ Label line = new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL);
+ line.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false, 2, 1));
+ line.setFont(composite.getFont());
+ }
+ return super.createDescriptionLabel(parent);
+ }
+
+ private void specificSelected() {
+ enableProjectSpecificSettings(specific.getSelection());
+ refreshWidgets(configuration.options(getElement()));
+ }
+
+ private Link createLink(Composite composite, String text) {
+ Link link = new Link(composite, SWT.NONE);
+ link.setFont(composite.getFont());
+ link.setText("" + text + ""); //$NON-NLS-1$ //$NON-NLS-2$
+ link.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (PreferencesUtil.createPreferenceDialogOn(getShell(), getPreferenceId(),
+ new String[] { id, getPreferenceId() }, null).open() == Window.OK) {
+ refreshWidgets(configuration.options(getElement()));
+ }
+ }
+ });
+ return link;
+ }
+
+ protected String getPreferenceId() {
+ return id;
+ }
+
+ @Override
+ protected Control createContents(Composite parent) {
+ var isProjectScope = projectScope().isPresent();
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setLayout(GridLayoutFactory.fillDefaults().numColumns(3).create());
+ composite.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).create());
+ composite.setFont(parent.getFont());
+ control = createPreferenceContent(composite, isProjectScope);
+ control.setLayoutData(new GridData(GridData.FILL_BOTH));
+ if (isProjectScope) {
+ enableProjectSpecificSettings(hasProjectSpecificOptions());
+ }
+ refreshWidgets(configuration.options(getElement()));
+ Dialog.applyDialogFont(composite);
+ return composite;
+ }
+
+ protected ConfigurationArea getConfigurationArea(Composite composite, boolean isProjectScope) {
+ return new PreferenceConfigurationArea(composite, (PreferencesMetadata) configuration.metadata(),
+ isProjectScope);
+ }
+
+ private Control createPreferenceContent(Composite parent, boolean isProjectScope) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setLayout(GridLayoutFactory.fillDefaults().create());
+ composite.setFont(parent.getFont());
+ area = getConfigurationArea(composite, isProjectScope);
+ return composite;
+ }
+
+ protected void refreshWidgets(Object options) {
+ setErrorMessage(null);
+ area.load(options, useProjectSettings() || !projectScope().isPresent());
+
+ }
+
+ protected Optional projectScope() {
+ return new ResolveProjectScope(workspace).apply(getElement());
+ }
+
+ @Override
+ protected void performDefaults() {
+ if (useProjectSettings()) {
+ enableProjectSpecificSettings(false);
+ }
+ IEclipsePreferences prefs = manager.getWorkingCopy(scope().getNode(configuration.qualifier()));
+ try {
+ for (String key : prefs.keys()) {
+ prefs.remove(key);
+ }
+ } catch (BackingStoreException e) {
+ Platform.getLog(getClass()).error("Unable to restore default values.", e); //$NON-NLS-1$
+ }
+ refreshWidgets(configuration.defaults());
+ super.performDefaults();
+ }
+
+ @Override
+ public boolean performOk() {
+ IEclipsePreferences prefs;
+ if (projectScope().isPresent()) {
+ prefs = manager.getWorkingCopy(projectScope().get().getNode(configuration.qualifier()));
+ if (!useProjectSettings()) {
+ try {
+ for (String key : prefs.keys()) {
+ prefs.remove(key);
+ }
+ } catch (BackingStoreException e) {
+ Platform.getLog(getClass()).error("Unable to reset project preferences.", e); //$NON-NLS-1$
+ }
+ prefs = null;
+ }
+ } else {
+ prefs = manager.getWorkingCopy(InstanceScope.INSTANCE.getNode(configuration.qualifier()));
+ }
+ if (prefs != null) {
+ area.store(prefs);
+ }
+ try {
+ manager.applyChanges();
+ } catch (BackingStoreException e) {
+ Platform.getLog(getClass()).error("Unable to save preferences.", e); //$NON-NLS-1$
+ return false;
+ }
+ return true;
+ }
+
+ private IScopeContext scope() {
+ return projectScope().map(IScopeContext.class::cast).orElse(InstanceScope.INSTANCE);
+ }
+
+ protected boolean hasProjectSpecificOptions() {
+ return projectScope()//
+ .map(p -> p.getNode(configuration.qualifier()))//
+ .map(n -> n.get(((PreferencesMetadata) configuration.metadata()).generateCDBFile().identifer(), null))//
+ .isPresent();
+ }
+
+ protected boolean useProjectSettings() {
+ return Optional.ofNullable(specific)//
+ .map(s -> s.getSelection())//
+ .orElse(Boolean.FALSE);
+ }
+
+ protected void enableProjectSpecificSettings(boolean use) {
+ specific.setSelection(use);
+ updateLinkVisibility();
+ }
+
+ private void updateLinkVisibility() {
+ Optional.ofNullable(link)//
+ .filter(l -> !l.isDisposed())//
+ .ifPresent(l -> l.setEnabled(!useProjectSettings()));
+ }
+
+ @Override
+ public void dispose() {
+ Optional.ofNullable(area).ifPresent(ConfigurationArea::dispose);
+ super.dispose();
+ }
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/Configuration.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/Configuration.java
new file mode 100644
index 00000000000..3ca5b288b9d
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/Configuration.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Contributors to the Eclipse Foundation.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * See git history
+ *******************************************************************************/
+package org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase;
+
+import java.net.URI;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.preferences.IPreferenceMetadataStore;
+
+public interface Configuration {
+
+ /**
+ * Returns the defaults
+ *
+ * @return defaults
+ */
+ Object defaults();
+
+ /**
+ * Returns the options for the given context like {@link IResource} or {@link URI}, must not return null
+ * @param context to be adapter to the proper scope
+ *
+ * @return options
+ */
+ Object options(Object context);
+
+ /**
+ * Returns the editor preference store for the given context like {@link IResource} or {@link URI}, must not return null
+ * @param context to be adapter to the proper scope
+ *
+ * @return preference store
+ */
+ IPreferenceMetadataStore storage(Object context);
+
+ /**
+ * Return the metadata for options, must not return null
+ *
+ * @return the option metadata
+ */
+ Object metadata();
+
+ /**
+ * Default qualifier to use for preference storage
+ * @return preference qualifier
+ */
+ String qualifier();
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/ConfigurationAccess.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/ConfigurationAccess.java
new file mode 100644
index 00000000000..a749a783ee2
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/ConfigurationAccess.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Contributors to the Eclipse Foundation.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * See git history
+ *******************************************************************************/
+
+package org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase;
+
+import java.util.Optional;
+
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.ProjectScope;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IScopeContext;
+import org.eclipse.osgi.util.NLS;
+
+public abstract class ConfigurationAccess {
+ protected final String qualifier;
+
+ public ConfigurationAccess(String qualifier) {
+ this.qualifier = qualifier;
+ }
+
+ protected Optional projectScope(IWorkspace workspace, Object context) {
+ return new ResolveProjectScope(workspace).apply(context);
+ }
+
+ protected IEclipsePreferences preferences(IScopeContext scope) {
+ return Optional.ofNullable(scope.getNode(qualifier))//
+ .filter(IEclipsePreferences.class::isInstance)//
+ .map(IEclipsePreferences.class::cast)//
+ .orElseThrow(() -> new IllegalStateException(//
+ NLS.bind("Unable to get preferences for node: {0}", // //$NON-NLS-1$
+ qualifier)));
+ }
+
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/ConfigurationArea.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/ConfigurationArea.java
new file mode 100644
index 00000000000..8c71ba10fbb
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/ConfigurationArea.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Contributors to the Eclipse Foundation.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * See git history
+ *******************************************************************************/
+package org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.PreferenceMetadata;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.TypedEvent;
+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.Group;
+
+public abstract class ConfigurationArea {
+ protected final Map, Button> buttons;
+ protected final List> listeners;
+ protected final int columns;
+
+ public ConfigurationArea(int columns) {
+ this.buttons = new HashMap<>();
+ this.listeners = new ArrayList<>();
+ this.columns = columns;
+
+ }
+
+ protected Group createGroup(Composite parent, String label, int numColumns) {
+ Group group = new Group(parent, SWT.NONE);
+ group.setFont(parent.getFont());
+ group.setText(label);
+ GridLayout layout = new GridLayout();
+ layout.numColumns = numColumns;
+ group.setLayout(layout);
+ group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ return group;
+ }
+
+ protected Button createButton(PreferenceMetadata meta, Composite composite, int style,
+ int horizontalIndent) {
+ Button button = new Button(composite, style);
+ button.setLayoutData(GridDataFactory.fillDefaults().span(columns, 1).indent(horizontalIndent, 0).create());
+ button.setData(meta);
+ button.setText(meta.name());
+ button.setToolTipText(meta.description());
+ buttons.put(meta, button);
+ return button;
+ }
+
+ public void addChangeListener(Consumer listener) {
+ listeners.add(listener);
+ }
+
+ public void removeChangeListener(Consumer listener) {
+ listeners.add(listener);
+ }
+
+ public void changed(TypedEvent event) {
+ listeners.forEach(c -> c.accept(event));
+ }
+
+ public void dispose() {
+ listeners.clear();
+ buttons.clear();
+ }
+
+ public abstract void load(Object options, boolean enable);
+
+ public abstract void store(IEclipsePreferences prefs);
+
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/ExistingResource.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/ExistingResource.java
new file mode 100644
index 00000000000..84b88d3caf0
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/ExistingResource.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2023 ArSysOp and others.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Alexander Fedorov (ArSysOp) - initial API
+ *******************************************************************************/
+package org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase;
+
+import java.net.URI;
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Function;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspace;
+
+public final class ExistingResource implements Function> {
+
+ private final IWorkspace workspace;
+
+ public ExistingResource(IWorkspace workspace) {
+ this.workspace = Objects.requireNonNull(workspace);
+ }
+
+ @Override
+ public Optional apply(URI uri) {
+ return forContainer(uri).or(() -> forFile(uri));
+ }
+
+ private Optional forContainer(URI uri) {
+ return Arrays.stream(workspace.getRoot().findContainersForLocationURI(uri))//
+ .map(IResource.class::cast)//
+ .filter(c -> c.exists())//
+ .findFirst();
+ }
+
+ private Optional forFile(URI uri) {
+ return Arrays.stream(workspace.getRoot().findFilesForLocationURI(uri))//
+ .map(IResource.class::cast)//
+ .filter(c -> c.exists())//
+ .findFirst();
+ }
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/GenerateCDBEnable.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/GenerateCDBEnable.java
new file mode 100644
index 00000000000..d82b320c876
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/GenerateCDBEnable.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Contributors to the Eclipse Foundation.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * See git history
+ *******************************************************************************/
+
+package org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase;
+
+import org.eclipse.core.resources.IProject;
+
+public interface GenerateCDBEnable {
+
+ /**
+ * Checks whether the generation of the compilation database file should be enabled for the given project.
+ * The enable can be linked with certain project properties (e.g. project natures).
+ * @param project
+ * @return true when the generation of compilation database file should be enabled for the given project
+ */
+ public boolean isEnabledFor(IProject project);
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/JsonCdbGeneratorPreferencePage.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/JsonCdbGeneratorPreferencePage.java
new file mode 100644
index 00000000000..6ca2209fa70
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/JsonCdbGeneratorPreferencePage.java
@@ -0,0 +1,82 @@
+/********************************************************************************
+ * Copyright (c) 2023, 2024 Renesas Electronics Corp. and others.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
+package org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase;
+
+import org.eclipse.cdt.ui.dialogs.ICOptionContainer;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+
+/**
+ * Preference page for JSON Compilation Database Generator.
+ */
+public class JsonCdbGeneratorPreferencePage extends PreferencePage
+ implements IWorkbenchPreferencePage, ICOptionContainer {
+
+ private final CompilationDatabaseGeneratorBlock fOptionBlock;
+
+ public JsonCdbGeneratorPreferencePage() {
+ fOptionBlock = new CompilationDatabaseGeneratorBlock();
+ }
+
+ @Override
+ protected Control createContents(Composite parent) {
+ GridLayout gl;
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setLayout(gl = new GridLayout());
+ composite.setLayoutData(new GridData());
+ gl.verticalSpacing = 0;
+ fOptionBlock.createControl(composite);
+ return composite;
+ }
+
+ @Override
+ public void init(IWorkbench workbench) {
+ }
+
+ @Override
+ public void updateContainer() {
+ if (!fOptionBlock.isValid()) {
+ setErrorMessage(fOptionBlock.getErrorMessage());
+ setValid(false);
+ } else {
+ setErrorMessage(null);
+ setValid(true);
+ }
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ public org.eclipse.core.runtime.Preferences getPreferences() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean performOk() {
+ return true;
+ }
+
+ @Override
+ public void performDefaults() {
+ fOptionBlock.performDefaults();
+ }
+
+ @Override
+ public IProject getProject() {
+ return null;
+ }
+
+}
\ No newline at end of file
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/JsonCdbGeneratorPropertyPage.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/JsonCdbGeneratorPropertyPage.java
new file mode 100644
index 00000000000..a5833de00a5
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/JsonCdbGeneratorPropertyPage.java
@@ -0,0 +1,74 @@
+/********************************************************************************
+ * Copyright (c) 2023, 2024 Renesas Electronics Corp. and others.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
+
+package org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase;
+
+import org.eclipse.cdt.ui.dialogs.ICOptionContainer;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.Preferences;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.dialogs.PropertyPage;
+
+/**
+ * Property page for JSON Compilation Database Generator.
+ */
+
+public class JsonCdbGeneratorPropertyPage extends PropertyPage implements ICOptionContainer {
+ private CompilationDatabaseGeneratorBlock optionPage;
+
+ public JsonCdbGeneratorPropertyPage() {
+ super();
+ optionPage = new CompilationDatabaseGeneratorBlock();
+ }
+
+ @Override
+ protected Control createContents(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setLayout(new GridLayout());
+ optionPage.createControl(composite);
+ return composite;
+ }
+
+ @Override
+ protected void performDefaults() {
+ optionPage.performDefaults();
+ }
+
+ @Override
+ public boolean performOk() {
+ return true;
+ }
+
+ @Override
+ public IProject getProject() {
+ IProject project = null;
+ IAdaptable elem = getElement();
+ if (elem instanceof IProject) {
+ project = (IProject) elem;
+ } else if (elem != null) {
+ project = elem.getAdapter(IProject.class);
+ }
+ return project;
+ }
+
+ @Override
+ public void updateContainer() {
+ }
+
+ @Override
+ public Preferences getPreferences() {
+ return null;
+ }
+
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/Messages.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/Messages.java
new file mode 100644
index 00000000000..1836c7e3754
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/Messages.java
@@ -0,0 +1,28 @@
+/********************************************************************************
+ * Copyright (c) 2023, 2024 Renesas Electronics Corp. and others.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
+
+package org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase;
+
+import org.eclipse.osgi.util.NLS;
+
+class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase.messages"; //$NON-NLS-1$
+ public static String JsonCdbGeneratorPreferencePage_description;
+ public static String JsonCdbGeneratorPreferencePage_generateCompilationdatabase;
+ public static String JsonCdbGeneratorPropertyPage_configureWorkspace;
+ public static String JsonCdbGeneratorPropertyPage_enableProjectSpecific;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/PreferenceConfigurationAccess.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/PreferenceConfigurationAccess.java
new file mode 100644
index 00000000000..f3e520eacb8
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/PreferenceConfigurationAccess.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Contributors to the Eclipse Foundation.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * See git history
+ *******************************************************************************/
+
+package org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase;
+
+import java.util.Optional;
+
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.ProjectScope;
+import org.eclipse.core.runtime.preferences.DefaultScope;
+import org.eclipse.core.runtime.preferences.IPreferenceMetadataStore;
+import org.eclipse.core.runtime.preferences.IScopeContext;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.core.runtime.preferences.OsgiPreferenceMetadataStore;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+
+@Component
+public class PreferenceConfigurationAccess extends ConfigurationAccess implements Configuration {
+
+ @Reference
+ private PreferencesMetadata metadata;
+
+ @Reference
+ private IWorkspace workspace;
+
+ @Reference(cardinality = ReferenceCardinality.OPTIONAL)
+ private GenerateCDBEnable enable;
+
+ public PreferenceConfigurationAccess() {
+ super(new Qualifier().get());
+ }
+
+ @Override
+ public PreferenceOptions defaults() {
+ return new PreferencePreferredOptions(qualifier, new IScopeContext[] { DefaultScope.INSTANCE }, metadata,
+ enable);
+ }
+
+ @Override
+ public PreferenceOptions options(Object context) {
+ Optional project = projectScope(workspace, context);
+ IScopeContext[] scopes;
+ if (project.isPresent()) {
+ scopes = new IScopeContext[] { project.get(), InstanceScope.INSTANCE, DefaultScope.INSTANCE };
+ } else {
+ scopes = new IScopeContext[] { InstanceScope.INSTANCE, DefaultScope.INSTANCE };
+ }
+ return new PreferencePreferredOptions(qualifier, scopes, metadata, enable);
+ }
+
+ @Override
+ public IPreferenceMetadataStore storage(Object context) {
+ return new OsgiPreferenceMetadataStore(//
+ preferences(//
+ projectScope(workspace, context)//
+ .map(IScopeContext.class::cast)//
+ .orElse(InstanceScope.INSTANCE)));
+ }
+
+ @Override
+ public PreferencesMetadata metadata() {
+ return metadata;
+ }
+
+ @Override
+ public String qualifier() {
+ return qualifier;
+ }
+
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/PreferenceConfigurationArea.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/PreferenceConfigurationArea.java
new file mode 100644
index 00000000000..61dbccbfa9a
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/PreferenceConfigurationArea.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2023 ArSysOp.
+ *
+ * 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
+ *
+ * Contributors:
+ * Alexander Fedorov (ArSysOp) - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase;
+
+import org.eclipse.cdt.managedbuilder.internal.core.CommonBuilder;
+import org.eclipse.cdt.managedbuilder.ui.properties.ManagedBuilderUIPlugin;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.OsgiPreferenceMetadataStore;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+
+public final class PreferenceConfigurationArea extends ConfigurationArea {
+
+ private final Button generateCDBFileButton;
+ private final String ENABLE_FILE_GENERATION = CommonBuilder.COMPILATION_DATABASE_ENABLEMENT;
+ private IPreferenceStore preferenceStore;
+
+ public PreferenceConfigurationArea(Composite parent, PreferencesMetadata metadata, boolean isProjectScope) {
+ super(1);
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ composite.setLayout(GridLayoutFactory.fillDefaults().numColumns(columns).create());
+ this.generateCDBFileButton = createButton(metadata.generateCDBFile(), composite, SWT.CHECK, 0);
+ preferenceStore = ManagedBuilderUIPlugin.getDefault().getPreferenceStore();
+ }
+
+ @Override
+ public void load(Object options, boolean enable) {
+ if (options instanceof PreferenceOptions editorOptions) {
+ if (generateCDBFileButton != null) {
+ generateCDBFileButton.setSelection(editorOptions.generateCDB());
+ generateCDBFileButton.setEnabled(enable);
+ }
+ }
+
+ }
+
+ @Override
+ public void store(IEclipsePreferences prefs) {
+ OsgiPreferenceMetadataStore store = new OsgiPreferenceMetadataStore(prefs);
+ buttons.entrySet().forEach(e -> store.save(e.getValue().getSelection(), e.getKey()));
+ preferenceStore.setValue(ENABLE_FILE_GENERATION, generateCDBFileButton.getSelection());
+ }
+
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/PreferenceMetadataDefaults.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/PreferenceMetadataDefaults.java
new file mode 100644
index 00000000000..260031a4f08
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/PreferenceMetadataDefaults.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Contributors to the Eclipse Foundation.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * See git history
+ *******************************************************************************/
+package org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase;
+
+import org.eclipse.core.runtime.preferences.PreferenceMetadata;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+
+@Component
+public class PreferenceMetadataDefaults implements PreferencesMetadata {
+
+ @Reference
+ private PreferenceOptionsDefaults defaults;
+
+ @Override
+ public PreferenceMetadata generateCDBFile() {
+ return new PreferenceMetadata<>(Boolean.class, //
+ "generateCDB", defaults.generateCDB(), // //$NON-NLS-1$
+ Messages.JsonCdbGeneratorPreferencePage_generateCompilationdatabase,
+ Messages.JsonCdbGeneratorPreferencePage_description);
+ }
+
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/PreferenceOptions.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/PreferenceOptions.java
new file mode 100644
index 00000000000..e52f5cf430f
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/PreferenceOptions.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Contributors to the Eclipse Foundation.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * See git history
+ *******************************************************************************/
+
+package org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase;
+
+public interface PreferenceOptions {
+
+ /**
+ * Compilation Database Generator needed
+ */
+ boolean generateCDB();
+
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/PreferenceOptionsDefaults.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/PreferenceOptionsDefaults.java
new file mode 100644
index 00000000000..bcb8c3cda1a
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/PreferenceOptionsDefaults.java
@@ -0,0 +1,17 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Contributors to the Eclipse Foundation.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * See git history
+ *******************************************************************************/
+
+package org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase;
+
+public interface PreferenceOptionsDefaults extends PreferenceOptions {
+
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/PreferencePreferredOptions.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/PreferencePreferredOptions.java
new file mode 100644
index 00000000000..667c13cb68b
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/PreferencePreferredOptions.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Contributors to the Eclipse Foundation.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * See git history
+ *******************************************************************************/
+
+package org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase;
+
+import java.util.Objects;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.preferences.IScopeContext;
+
+public class PreferencePreferredOptions extends PreferredOptions implements PreferenceOptions, GenerateCDBEnable {
+ private final PreferencesMetadata metadata;
+ private final GenerateCDBEnable enable;
+
+ public PreferencePreferredOptions(String qualifier, IScopeContext[] scopes, PreferencesMetadata metadata,
+ GenerateCDBEnable enable) {
+ super(qualifier, scopes);
+ this.metadata = Objects.requireNonNull(metadata);
+ this.enable = enable;
+ }
+
+ @Override
+ public boolean generateCDB() {
+ return booleanValue(metadata.generateCDBFile());
+ }
+
+ @Override
+ public boolean isEnabledFor(IProject project) {
+ if (enable != null) {
+ return enable.isEnabledFor(project);
+ }
+ return booleanValue(metadata.generateCDBFile());
+ }
+
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/PreferencesMetadata.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/PreferencesMetadata.java
new file mode 100644
index 00000000000..13805c5ccea
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/PreferencesMetadata.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Contributors to the Eclipse Foundation.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * See git history
+ *******************************************************************************/
+
+package org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase;
+
+import org.eclipse.core.runtime.preferences.PreferenceMetadata;
+
+public interface PreferencesMetadata {
+
+ /**
+ * Returns the metadata for the "Generate compile_commands.json file" option, must not return null
.
+ *
+ * @return the metadata for the "Generate compile_commands.json file" option
+ *
+ * @see PreferenceOptions#generateCDB()
+ */
+ PreferenceMetadata generateCDBFile();
+
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/PreferredOptions.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/PreferredOptions.java
new file mode 100644
index 00000000000..a72dc8f758c
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/PreferredOptions.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Contributors to the Eclipse Foundation.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * See git history
+ *******************************************************************************/
+
+package org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase;
+
+import java.util.Objects;
+import java.util.Optional;
+
+import org.eclipse.core.runtime.preferences.IScopeContext;
+import org.eclipse.core.runtime.preferences.PreferenceMetadata;
+
+public abstract class PreferredOptions {
+ protected final String qualifier;
+ protected final IScopeContext[] scopes;
+
+ public PreferredOptions(String qualifier, IScopeContext[] scopes) {
+ this.qualifier = Objects.requireNonNull(qualifier);
+ this.scopes = Objects.requireNonNull(scopes);
+ }
+
+ protected String stringValue(PreferenceMetadata> meta) {
+ String actual = String.valueOf(meta.defaultValue());
+ for (int i = scopes.length - 1; i >= 0; i--) {
+ IScopeContext scope = scopes[i];
+ String previous = actual;
+ actual = scope.getNode(qualifier).get(meta.identifer(), previous);
+ }
+ return actual;
+ }
+
+ protected boolean booleanValue(PreferenceMetadata meta) {
+ return Optional.of(meta)//
+ .map(this::stringValue)//
+ .map(Boolean::valueOf)//
+ .orElseGet(meta::defaultValue);
+ }
+
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/Qualifier.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/Qualifier.java
new file mode 100644
index 00000000000..1955d2e9094
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/Qualifier.java
@@ -0,0 +1,21 @@
+/********************************************************************************
+ * Copyright (c) 2023, 2024 Renesas Electronics Corp. and others.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
+package org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase;
+
+import java.util.function.Supplier;
+
+public final class Qualifier implements Supplier {
+
+ @Override
+ public String get() {
+ return "org.eclipse.cdt.managedbuilder.ui"; //$NON-NLS-1$
+ }
+
+}
diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/ResolveProject.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/ResolveProject.java
new file mode 100644
index 00000000000..0ebcf815568
--- /dev/null
+++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/compilationdatabase/ResolveProject.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2023 ArSysOp.
+ *
+ * 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
+ *
+ * Contributors:
+ * Alexander Fedorov (ArSysOp) - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.managedbuilder.internal.ui.compilationdatabase;
+
+import java.net.URI;
+import java.util.Optional;
+import java.util.function.Function;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.runtime.Adapters;
+
+public final class ResolveProject implements Function