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..b6fe5bbf499 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..c723e9668c4 --- /dev/null +++ b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/core/tests/CompilationDatabaseGenerationTest.java @@ -0,0 +1,187 @@ +/******************************************************************************* + * 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 java.io.IOException; + +import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin; +import org.eclipse.cdt.managedbuilder.core.jsoncdb.CompilationDatabaseInformation; +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.CoreException; +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.ui.preferences.ScopedPreferenceStore; +import org.junit.Test; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonIOException; + +public class CompilationDatabaseGenerationTest extends AbstractBuilderTest { + + /** + * Tests generation of compile_commands.json in "build" folder + * @throws CoreException + */ + @Test + public void testCompilationDatabaseGeneration() throws CoreException { + setWorkspace("regressions"); + final IProject app = loadProject("helloworldC"); + isGenerateFileOptionEnabled(true); + app.build(IncrementalProjectBuilder.FULL_BUILD, null); + IFile compilationDatabase = app.getFile("build/compile_commands.json"); + assertTrue(compilationDatabase.exists()); + } + + /** + * Tests format for compile_commands.json. JSON array is expected, containing an element for the c file + * @throws JsonIOException + * @throws CoreException + */ + @Test + public void testJsonFormat() throws JsonIOException, CoreException { + setWorkspace("regressions"); + final IProject app = loadProject("helloworldC"); + isGenerateFileOptionEnabled(true); + app.build(IncrementalProjectBuilder.FULL_BUILD, null); + IFile commandsFile = app.getFile("build/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); + System.out.println(jsonArray); + 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")); + } + + } catch (IOException e) { + assertTrue(false); + } + + } + } + + /** + * Test that compile_commands.json is correctly generated when more than one .c file is present as a source file + * @throws CoreException + */ + @Test + public void testMultipleFiles() throws CoreException { + setWorkspace("regressions"); + final IProject app = loadProject("helloworldC"); + IFile aFile = ManagedBuildTestHelper.createFile(app, "src/newFile.c"); + isGenerateFileOptionEnabled(true); + app.build(IncrementalProjectBuilder.FULL_BUILD, null); + IFile commandsFile = app.getFile("build/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); + } catch (IOException e) { + assertTrue(false); + } + + } + + /** + * Tests that cpp files are handled by compile_commands.json file generator + * @throws CoreException + */ + @Test + public void isCPPFileAllowed() throws CoreException { + setWorkspace("regressions"); + final IProject app = loadProject("helloworldCPP"); + isGenerateFileOptionEnabled(true); + app.build(IncrementalProjectBuilder.FULL_BUILD, null); + System.out.println(app.getLocation()); + IFile commandsFile = app.getFile("build/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); + System.out.println(jsonArray); + 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")); + } + + } catch (IOException e) { + assertTrue(false); + } + } + } + + /** + * Tests that compilation database is not generated when feature is disabled + * @throws CoreException + */ + @Test + public void testCompilationDatabaseGenerationNotEnabled() throws CoreException { + setWorkspace("regressions"); + final IProject app = loadProject("helloworldC"); + isGenerateFileOptionEnabled(false); + app.build(IncrementalProjectBuilder.FULL_BUILD, null); + IFile compilationDatabase = app.getFile("build/compile_commands.json"); + assertFalse(compilationDatabase.exists()); + } + + public static boolean isGenerateFileOptionEnabled(boolean value) { + try { + IPreferenceStore preferenceStore = new ScopedPreferenceStore(InstanceScope.INSTANCE, + "org.eclipse.cdt.managedbuilder.ui"); //$NON-NLS-1$ + preferenceStore.setDefault("generateFile", value); + return preferenceStore.getBoolean("generateFile"); + } catch (Exception e) { + ManagedBuilderCorePlugin.log(e); + } + return false; + } +} diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/jsoncdb/generator/CompilationDatabaseContributionManager.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/jsoncdb/generator/CompilationDatabaseContributionManager.java index aa53f3a3961..5e154ce823b 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/jsoncdb/generator/CompilationDatabaseContributionManager.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/core/jsoncdb/generator/CompilationDatabaseContributionManager.java @@ -32,9 +32,17 @@ 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; - private final Map factoryExtensions; + 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 { @@ -47,8 +55,6 @@ private class EmptyCompilationDatabaseContributor implements ICompilationDatabas private static CompilationDatabaseContributionManager instance; private CompilationDatabaseContributionManager() { - this.factoryExtensions = new HashMap<>(); - this.loadedInstances = new HashMap<>(); initalise(); } @@ -60,8 +66,6 @@ public static synchronized CompilationDatabaseContributionManager getInstance() } private void initalise() { - Map loadedExtension = new HashMap<>(); - IExtensionPoint extension = Platform.getExtensionRegistry().getExtensionPoint( "org.eclipse.cdt.managedbuilder.core", CompilationDatabaseContributionManager.EXTENSION_ID); //$NON-NLS-1$ if (extension != null) { @@ -75,14 +79,12 @@ private void initalise() { String className = configElement .getAttribute(CompilationDatabaseContributionManager.ATTRIB_RUNNER); if (toolchainId != null && className != null) { - loadedExtension.put(toolchainId, configElement); + factoryExtensions.put(toolchainId, configElement); } } } } } - - this.factoryExtensions.putAll(loadedExtension); } /** 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 e470b70ab08..54bdc2d7115 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 @@ -86,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 { @@ -94,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$ + private static final String COMPILATION_DATABASE_ENABLEMENT = "generateFile"; //$NON-NLS-1$ public static boolean VERBOSE = false; private static final int PROGRESS_MONITOR_SCALE = 100; @@ -506,8 +510,10 @@ private IProject[] build(int kind, IProject project, IBuilder[] builders, boolea } for (int i = 0; i < num; i++) { - CompilationDatabaseGenerator generator = new CompilationDatabaseGenerator(getProject(), activeCfg); - generator.generate(); + 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 @@ -1378,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.ui/plugin.xml b/build/org.eclipse.cdt.managedbuilder.ui/plugin.xml index 198bcea8041..75b6d44df51 100644 --- a/build/org.eclipse.cdt.managedbuilder.ui/plugin.xml +++ b/build/org.eclipse.cdt.managedbuilder.ui/plugin.xml @@ -917,5 +917,14 @@ label="%CDTToolchainProperty.keyword.toolchain2"> + + + + diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/compilationdatabase/JsonCdbGeneratorPreferencePage.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/compilationdatabase/JsonCdbGeneratorPreferencePage.java new file mode 100644 index 00000000000..02d1db6f22a --- /dev/null +++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/compilationdatabase/JsonCdbGeneratorPreferencePage.java @@ -0,0 +1,70 @@ +/******************************************************************************** + * 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.ui.compilationdatabase; + +import org.eclipse.cdt.managedbuilder.ui.properties.ManagedBuilderUIPlugin; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.preference.PreferencePage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Group; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPreferencePage; + +/** + * Preference page for JSON Compilation Database Generator. + */ +public class JsonCdbGeneratorPreferencePage extends PreferencePage implements IWorkbenchPreferencePage { + private static final String ENABLE_FILE_GENERATION = "generateFile"; //$NON-NLS-1$ + private Button generateFileCheckbox; + private IPreferenceStore preferenceStore; + + public JsonCdbGeneratorPreferencePage() { + preferenceStore = ManagedBuilderUIPlugin.getDefault().getPreferenceStore(); + } + + @Override + protected Control createContents(Composite parent) { + final Composite composite = new Composite(parent, SWT.NONE); + composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + composite.setLayout(new GridLayout(1, false)); + Group cdbGeneratorOptions = new Group(composite, SWT.NONE); + cdbGeneratorOptions.setLayout(new FillLayout(SWT.HORIZONTAL)); + cdbGeneratorOptions.setText(Messages.JsonCdbGeneratorPreferencePage_description); + cdbGeneratorOptions.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + generateFileCheckbox = new Button(cdbGeneratorOptions, SWT.CHECK); + generateFileCheckbox.setSelection(preferenceStore.getBoolean(ENABLE_FILE_GENERATION)); + generateFileCheckbox.setText(Messages.JsonCdbGeneratorPreferencePage_generateCompilationdatabase); + generateFileCheckbox.addListener(SWT.Selection, e -> { + boolean newValue = generateFileCheckbox.getSelection(); + preferenceStore.setValue(ENABLE_FILE_GENERATION, newValue); + }); + return composite; + } + + /** + * Initializes the default values of this page in the preference bundle. + */ + @Override + protected void performDefaults() { + super.performDefaults(); + preferenceStore.setDefault(ENABLE_FILE_GENERATION, false); + } + + @Override + public void init(IWorkbench workbench) { + } + +} \ No newline at end of file diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/compilationdatabase/Messages.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/compilationdatabase/Messages.java new file mode 100644 index 00000000000..d4f3574ba56 --- /dev/null +++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/compilationdatabase/Messages.java @@ -0,0 +1,26 @@ +/******************************************************************************** + * 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.ui.compilationdatabase; + +import org.eclipse.osgi.util.NLS; + +class Messages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.cdt.managedbuilder.ui.compilationdatabase.messages"; //$NON-NLS-1$ + public static String JsonCdbGeneratorPreferencePage_description; + public static String JsonCdbGeneratorPreferencePage_generateCompilationdatabase; + 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/ui/compilationdatabase/messages.properties b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/compilationdatabase/messages.properties new file mode 100644 index 00000000000..e9d671ea720 --- /dev/null +++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/compilationdatabase/messages.properties @@ -0,0 +1,11 @@ +############################################################################### +# 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 +############################################################################### +JsonCdbGeneratorPreferencePage_description=Enables default generation of compile_commands.json file on build process +JsonCdbGeneratorPreferencePage_generateCompilationdatabase=Generate compile_commands.json file \ No newline at end of file