You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by vi...@apache.org on 2022/02/19 08:15:54 UTC

[netbeans] branch cnd updated: [cnd] 3.1 makeproject compile_commands.json

This is an automated email from the ASF dual-hosted git repository.

vieiro pushed a commit to branch cnd
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/cnd by this push:
     new ae52a9b  [cnd] 3.1 makeproject compile_commands.json
     new 8115eec  Merge pull request #3553 from vieiro/feature/cnd-lsp
ae52a9b is described below

commit ae52a9b9ce28984a9fa7f223f79193c76966d78f
Author: Antonio Vieiro <vi...@apache.org>
AuthorDate: Tue Feb 1 21:39:38 2022 +0100

    [cnd] 3.1 makeproject compile_commands.json
    
    Automatically generate compile_commands.json for make based projects.
---
 cnd/cnd.api.project/nbproject/project.xml          |   3 +-
 cnd/cnd.lsp/build.xml                              |  25 ++
 cnd/cnd.lsp/manifest.mf                            |   6 +
 cnd/cnd.lsp/nbproject/project.properties           |  20 ++
 cnd/cnd.lsp/nbproject/project.xml                  | 141 +++++++++
 .../lsp/compilationdb/ClangCDBGenerationCause.java |  53 ++++
 .../lsp/compilationdb/ClangCDBGenerationTask.java  | 341 +++++++++++++++++++++
 .../cnd/lsp/compilationdb/ClangCDBSupport.java     | 219 +++++++++++++
 .../lsp/compilationdb/CommandObjectBuilder.java    | 131 ++++++++
 .../makeproject/LSPMakeProjectLookupProvider.java  |  40 +++
 .../modules/cnd/lsp/resources/Bundle.properties    |  22 ++
 cnd/cnd.makeproject/nbproject/project.xml          |   1 +
 cnd/cnd.toolchain/nbproject/project.xml            |   3 +-
 ide/dlight.nativeexecution/nbproject/project.xml   |   1 +
 nbbuild/cluster.properties                         |   1 +
 15 files changed, 1005 insertions(+), 2 deletions(-)

diff --git a/cnd/cnd.api.project/nbproject/project.xml b/cnd/cnd.api.project/nbproject/project.xml
index 0d1cdd8..c78efff 100644
--- a/cnd/cnd.api.project/nbproject/project.xml
+++ b/cnd/cnd.api.project/nbproject/project.xml
@@ -111,7 +111,6 @@
                 <friend>org.netbeans.modules.cnd.analysis.impl</friend>
                 <friend>org.netbeans.modules.cnd.apt</friend>
                 <friend>org.netbeans.modules.cnd.audit</friend>
-                <friend>org.netbeans.modules.cnd.jconvertwizard</friend>
                 <friend>org.netbeans.modules.cnd.classview</friend>
                 <friend>org.netbeans.modules.cnd.codemodel.bridge</friend>
                 <friend>org.netbeans.modules.cnd.codemodel.utils</friend>
@@ -122,6 +121,8 @@
                 <friend>org.netbeans.modules.cnd.gizmo</friend>
                 <friend>org.netbeans.modules.cnd.gotodeclaration</friend>
                 <friend>org.netbeans.modules.cnd.highlight</friend>
+                <friend>org.netbeans.modules.cnd.jconvertwizard</friend>
+                <friend>org.netbeans.modules.cnd.lsp</friend>
                 <friend>org.netbeans.modules.cnd.makeproject</friend>
                 <friend>org.netbeans.modules.cnd.makeproject.source.bridge</friend>
                 <friend>org.netbeans.modules.cnd.makeproject.ui</friend>
diff --git a/cnd/cnd.lsp/build.xml b/cnd/cnd.lsp/build.xml
new file mode 100644
index 0000000..9f9e3c3
--- /dev/null
+++ b/cnd/cnd.lsp/build.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<project basedir="." default="netbeans" name="cnd/cnd.lsp">
+    <description>Builds, tests, and runs the project org.netbeans.modules.cnd.lsp</description>
+    <import file="../../nbbuild/templates/projectized.xml"/>
+</project>
diff --git a/cnd/cnd.lsp/manifest.mf b/cnd/cnd.lsp/manifest.mf
new file mode 100644
index 0000000..ad635bf
--- /dev/null
+++ b/cnd/cnd.lsp/manifest.mf
@@ -0,0 +1,6 @@
+Manifest-Version: 1.0
+AutoUpdate-Show-In-Client: false
+OpenIDE-Module: org.netbeans.modules.cnd.lsp
+OpenIDE-Module-Implementation-Version: 1
+OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/cnd/lsp/resources/Bundle.properties
+
diff --git a/cnd/cnd.lsp/nbproject/project.properties b/cnd/cnd.lsp/nbproject/project.properties
new file mode 100644
index 0000000..355b38a
--- /dev/null
+++ b/cnd/cnd.lsp/nbproject/project.properties
@@ -0,0 +1,20 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+is.eager=true
+javac.source=1.8
+javac.compilerargs=-Xlint -Xlint:-serial
+spec.version.base=1.0.0
diff --git a/cnd/cnd.lsp/nbproject/project.xml b/cnd/cnd.lsp/nbproject/project.xml
new file mode 100644
index 0000000..adfac30
--- /dev/null
+++ b/cnd/cnd.lsp/nbproject/project.xml
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<project xmlns="http://www.netbeans.org/ns/project/1">
+    <type>org.netbeans.modules.apisupport.project</type>
+    <configuration>
+        <data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
+            <code-name-base>org.netbeans.modules.cnd.lsp</code-name-base>
+            <module-dependencies>
+                <dependency>
+                    <code-name-base>org.netbeans.libs.json_simple</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>0.27</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.netbeans.modules.cnd.api.project</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>1.37.9</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.netbeans.modules.cnd.makeproject</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>2</release-version>
+                        <specification-version>2.59.20</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.netbeans.modules.cnd.makeproject.ui</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>1.1.8</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.netbeans.modules.cnd.toolchain</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>1.35.14</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.netbeans.modules.dlight.nativeexecution</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>1.54</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.netbeans.modules.projectapi</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>1.85</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.netbeans.modules.projectuiapi.base</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>1.101</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.awt</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>7.83</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.filesystems</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>9.27</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.nodes</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>7.60</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.util</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>9.23</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.util.lookup</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>8.49</specification-version>
+                    </run-dependency>
+                </dependency>
+            </module-dependencies>
+            <public-packages/>
+        </data>
+    </configuration>
+</project>
diff --git a/cnd/cnd.lsp/src/org/netbeans/modules/cnd/lsp/compilationdb/ClangCDBGenerationCause.java b/cnd/cnd.lsp/src/org/netbeans/modules/cnd/lsp/compilationdb/ClangCDBGenerationCause.java
new file mode 100644
index 0000000..fa963e2
--- /dev/null
+++ b/cnd/cnd.lsp/src/org/netbeans/modules/cnd/lsp/compilationdb/ClangCDBGenerationCause.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.cnd.lsp.compilationdb;
+
+/**
+ * ClangCDBGenerationCause represents possible causes that require a Clang
+ * compilation database to be regenerated.
+ *
+ * @author antonio
+ */
+enum ClangCDBGenerationCause {
+    /**
+     * Some files were added to the project
+     */
+    FILES_ADDED,
+    /**
+     * Some files were removed from the project
+     */
+    FILES_REMOVED,
+    /**
+     * Some files were renamed in the project
+     */
+    FILES_RENAMED,
+    /**
+     * Project configuration changed
+     */
+    PROJECT_CONFIGURATION_CHANGED,
+    /**
+     * Project is opened.
+     */
+    PROJECT_OPENED, 
+    /**
+     * Include paths or macro defintions have changed for
+     * some files or for the whole project.
+     */
+    INCLUDES_MACROS_CHANGED
+}
diff --git a/cnd/cnd.lsp/src/org/netbeans/modules/cnd/lsp/compilationdb/ClangCDBGenerationTask.java b/cnd/cnd.lsp/src/org/netbeans/modules/cnd/lsp/compilationdb/ClangCDBGenerationTask.java
new file mode 100644
index 0000000..04739cc
--- /dev/null
+++ b/cnd/cnd.lsp/src/org/netbeans/modules/cnd/lsp/compilationdb/ClangCDBGenerationTask.java
@@ -0,0 +1,341 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.cnd.lsp.compilationdb;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.json.simple.JSONObject;
+import org.netbeans.modules.cnd.api.project.NativeFileItem.Language;
+import static org.netbeans.modules.cnd.api.project.NativeFileItem.Language.CPP;
+import static org.netbeans.modules.cnd.api.project.NativeFileItem.Language.C_HEADER;
+import static org.netbeans.modules.cnd.api.project.NativeFileItem.Language.FORTRAN;
+import static org.netbeans.modules.cnd.api.project.NativeFileItem.Language.OTHER;
+import org.netbeans.modules.cnd.api.project.NativeProject;
+import org.netbeans.modules.cnd.api.toolchain.AbstractCompiler;
+import org.netbeans.modules.cnd.api.toolchain.CompilerSet;
+import org.netbeans.modules.cnd.api.toolchain.PredefinedToolKind;
+import org.netbeans.modules.cnd.api.toolchain.Tool;
+import org.netbeans.modules.cnd.makeproject.api.MakeProject;
+import org.netbeans.modules.cnd.makeproject.api.configurations.BasicCompilerConfiguration;
+import org.netbeans.modules.cnd.makeproject.api.configurations.CCCompilerConfiguration;
+import org.netbeans.modules.cnd.makeproject.api.configurations.CCompilerConfiguration;
+import org.netbeans.modules.cnd.makeproject.api.configurations.ConfigurationDescriptorProvider;
+import org.netbeans.modules.cnd.makeproject.api.configurations.Item;
+import org.netbeans.modules.cnd.makeproject.api.configurations.ItemConfiguration;
+import org.netbeans.modules.cnd.makeproject.api.configurations.MakeConfiguration;
+import org.netbeans.modules.cnd.makeproject.api.configurations.MakeConfigurationDescriptor;
+import org.openide.filesystems.FileUtil;
+import org.openide.util.Cancellable;
+
+/**
+ * ClangCDBGenerationTask creates/updates a Clang compilation database as
+ * defined https://clang.llvm.org/docs/JSONCompilationDatabase.html
+ *
+ * @author antonio
+ */
+final class ClangCDBGenerationTask implements Callable<Void>, Cancellable {
+
+    private static final String CDB_NAME = "compile_commands.json"; // NOI18N
+    private static final Logger LOG
+            = Logger.getLogger(ClangCDBGenerationTask.class.getName());
+
+    protected boolean cancelled;
+    private final ClangCDBSupport support;
+    private final BlockingQueue<ClangCDBGenerationCause> pendingCauses;
+    private final MakeProject makeProject;
+    private final NativeProject nativeProject;
+    private final MakeConfiguration activeMakeConfiguration;
+    private final CompilerSet compilerSet;
+    private final ConfigurationDescriptorProvider configurationDescriptorProvider;
+    private final MakeConfigurationDescriptor makeConfigurationDescriptor;
+
+    ClangCDBGenerationTask(ClangCDBSupport support, BlockingQueue<ClangCDBGenerationCause> pendingCauses)
+            throws IllegalArgumentException {
+        this.support = support;
+        this.makeProject = support.getMakeProject();
+        this.pendingCauses = pendingCauses;
+        this.cancelled = false;
+
+        // Prepare some required objects
+        nativeProject = makeProject.getLookup().lookup(NativeProject.class);
+        if (nativeProject == null) {
+            throw new IllegalArgumentException("No native project found");
+        }
+
+        if (makeProject.getDevelopmentHost() != null && !makeProject.getDevelopmentHost().isLocal()) {
+            throw new IllegalArgumentException("Not a local project");
+        }
+
+        activeMakeConfiguration = makeProject.getActiveConfiguration();
+        if (activeMakeConfiguration == null) {
+            throw new IllegalArgumentException("No active make configuration");
+        }
+
+        compilerSet = activeMakeConfiguration.getCompilerSet().getCompilerSet();
+        if (compilerSet == null) {
+            throw new IllegalArgumentException("No compilerset defined");
+        }
+
+        configurationDescriptorProvider
+                = makeProject.getLookup().lookup(ConfigurationDescriptorProvider.class);
+        if (configurationDescriptorProvider == null) {
+            throw new IllegalArgumentException("No configuration descriptor found");
+        }
+
+        makeConfigurationDescriptor = configurationDescriptorProvider.getConfigurationDescriptor();
+        if (makeConfigurationDescriptor == null) {
+            throw new IllegalArgumentException("No MakeConfigurationDescriptor");
+        }
+
+    }
+
+    @Override
+    public Void call() throws Exception {
+
+        try {
+            updateCompilationDatabase();
+        } catch (Exception e) {
+            LOG.log(Level.SEVERE, String.format("Error updating compilation database:%s:%s", e.getMessage(), e.getClass().getName()), e);
+            throw e;
+        }
+        return null;
+    }
+
+    public void updateCompilationDatabase() throws Exception {
+        LOG.log(Level.FINE, "Updating compilation database");
+
+        if (cancelled) {
+            LOG.log(Level.FINE, "Task was cancelled.");
+            return;
+        }
+
+        if (!support.isOpen()) {
+            LOG.log(Level.FINE, "Project is not open, bailing out.");
+            return;
+        }
+
+        if (pendingCauses.isEmpty()) {
+            LOG.log(Level.FINE, "No pending causes, bailing out");
+            return;
+        }
+
+        ArrayList<ClangCDBGenerationCause> coalescedCauses = new ArrayList<>(pendingCauses.size());
+        pendingCauses.drainTo(coalescedCauses);
+
+        File projectDirectory = FileUtil.toFile(makeProject.getProjectDirectory());
+        File compilationDatabase = new File(projectDirectory, CDB_NAME);
+        LOG.log(Level.FINE, "Updating compilation database {0} because {1}",
+                new Object[]{compilationDatabase.getPath(), coalescedCauses.toString()});
+
+        // Get the project items,
+        Item[] items = makeConfigurationDescriptor.getProjectItems();
+        if (items == null || items.length == 0) {
+            LOG.log(Level.FINE, "No items in project.");
+            return;
+        }
+
+        if (cancelled) {
+            LOG.log(Level.FINE, "Task cancelled");
+            return;
+        }
+
+        long startTime = System.currentTimeMillis();
+
+        // Use a temporary file to create the compilation database.
+        File tempFile = Files.createTempFile("CDB", ".json").toFile(); // NOI18N
+
+        try ( FileOutputStream outputStream = new FileOutputStream(tempFile); //
+                  PrintWriter writer = new PrintWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8))) {
+            FileChannel channel = outputStream.getChannel();
+            FileLock lock = channel.lock();
+            writeCompilationDatabase(writer, lock, items);
+        }
+
+        // Only update the compilation database if we're done with all items.
+        if (!cancelled) {
+            try {
+                Files.move(tempFile.toPath(), compilationDatabase.toPath(), StandardCopyOption.REPLACE_EXISTING);
+            } catch (Throwable e) {
+                LOG.log(Level.SEVERE, String.format("Error updating compilation database %s:%s", e.getMessage(), e.getClass().getName()), e);
+            }
+        }
+
+        // And delete the temporary file
+        tempFile.delete();
+
+        long endTime = System.currentTimeMillis();
+        LOG.log(Level.INFO, "Regeneration of {0} took {1} ms.", new Object[]{
+            compilationDatabase.getAbsolutePath(),
+            endTime - startTime
+        });
+    }
+
+    private void writeCompilationDatabase(PrintWriter writer, FileLock lock, Item[] items)
+            throws Exception {
+
+        // We don't want to hold all command objects in memory, but write
+        // them sequentially.
+        writer.println("[");
+        boolean firstItem = true;
+        for (Item item : items) {
+            if (cancelled) {
+                return;
+            }
+            LOG.log(Level.FINE, "Updating compilation db for item {0}", item.getName());
+            Language language = item.getLanguage();
+            ItemConfiguration itemConfiguration = item.getItemConfiguration(activeMakeConfiguration);
+            JSONObject commandObject = null;
+            switch (language) {
+                case C_HEADER:
+                    // C headers are not included in compilation databases
+                    continue;
+                case C:
+                case CPP:
+                case OTHER: // Assembler?
+                    // C and C++ files (and possibly assembler) are included in the compilation database
+                    commandObject = getCommandObjectForItem(
+                            language, item, itemConfiguration);
+                    break;
+                case FORTRAN:
+                    // Fortran is not supported in clang-style compilation databases, AFAIK
+                    break;
+            }
+            if (commandObject != null) {
+                if (firstItem) {
+                    firstItem = false;
+                } else {
+                    writer.print(",");
+                }
+                commandObject.writeJSONString(writer);
+                writer.println();
+            }
+        }
+        writer.println("]");
+    }
+
+    /**
+     * Returns a Command Object required to compile an item.
+     *
+     * @param makeProject The project
+     * @param activeMakeConfiguration The active make configuration.
+     * @param compilerSet The compiler set.
+     * @param item The item being compiled.
+     * @param itemConfiguration The item configuration of the item.
+     * @return A JSON String with this command object.
+     * @throws Exception If an I/O error happens.
+     */
+    private JSONObject getCommandObjectForItem(
+            Language language, Item item, ItemConfiguration itemConfiguration)
+            throws Exception {
+
+        if (itemConfiguration.getExcluded().getValue()) {
+            LOG.log(Level.FINE, "Skipping excluded item {0}",
+                    item.getName());
+            return null;
+        }
+
+        CommandObjectBuilder builder = new CommandObjectBuilder(makeProject);
+
+        // 0. 'directory' entry in the command object is automatically added.
+        // 1. 'file' entry in the command object.
+        LOG.log(Level.FINE, "Creating command object for item: {0} in file: {1}", new Object[]{item.getName(), item.getAbsolutePath()});
+        builder.setFile(item.getAbsolutePath());
+
+        // 2. 'command' entry in the command object
+        PredefinedToolKind toolKind = itemConfiguration.getTool();
+        Tool compilerTool = compilerSet.getTool(toolKind);
+        if (!(compilerTool instanceof AbstractCompiler)) {
+            LOG.log(Level.FINE, "Cannot find an AbstractCompiler for item {0}",
+                    item.getName());
+            return null;
+        }
+        AbstractCompiler compiler = (AbstractCompiler) compilerTool;
+        // 2.1 compiler path ("/usr/bin/gcc", for instance).
+        builder.addCommandItem(compiler.getPath());
+
+        // 2.2 "-c" flag. This is currently hardcoded in NetBeans CND... :-(
+        builder.addCommandItem("-c");
+
+        // 2.3 The full path of the file to compile ("/home/users/user/project/myfile.c")
+        builder.addCommandItem(builder.getFile());
+
+        // 2.3 language specific flags
+        // C Options
+        {
+            CCompilerConfiguration cConfiguration = itemConfiguration.getCCompilerConfiguration();
+            if (cConfiguration != null) {
+                String cFlags = cConfiguration.getCFlags(compiler);
+                builder.addCommandItem(cFlags);
+                String allOptions = cConfiguration.getAllOptions2(compiler);
+                builder.addCommandItem(allOptions);
+                LOG.log(Level.FINE, "C: CFLAGS {0} options {1}", new Object[]{cFlags, allOptions});
+            }
+        }
+
+        // C++ options
+        {
+            CCCompilerConfiguration cppConfiguration = itemConfiguration.getCCCompilerConfiguration();
+            if (cppConfiguration != null) {
+                String cppFlags = cppConfiguration.getCCFlags(compiler);
+                builder.addCommandItem(cppFlags);
+                String allOptions = cppConfiguration.getAllOptions2(compiler);
+                builder.addCommandItem(allOptions);
+                LOG.log(Level.FINE, "C++: CFLAGS {0} options {1}", new Object[]{cppFlags, allOptions});
+            }
+        }
+
+        // 3. output file ("/home/users/user/project/build/Linux/X86/myfile.o", for instance)
+        // Note that "output" is optional in CommandObjects
+        BasicCompilerConfiguration basicCompilerConfiguration = itemConfiguration.getCompilerConfiguration();
+        String outputFile = basicCompilerConfiguration.getOutputFile(item, activeMakeConfiguration, true);
+
+        if (outputFile != null) {
+            // outputFile is constructed with Makefile macros, like these:
+            // "/home/antonio/tmp/${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM}/main.o
+            // We want to expand these
+            outputFile = activeMakeConfiguration.expandMacros(outputFile);
+            builder.setOutput(outputFile);
+
+            // We also include a '-o outputfile' to the command
+            builder.addCommandItem("-o");
+            builder.addCommandItem(outputFile);
+        }
+
+        return builder.build();
+    }
+
+    @Override
+    public boolean cancel() {
+        this.cancelled = true;
+        return true;
+    }
+
+}
diff --git a/cnd/cnd.lsp/src/org/netbeans/modules/cnd/lsp/compilationdb/ClangCDBSupport.java b/cnd/cnd.lsp/src/org/netbeans/modules/cnd/lsp/compilationdb/ClangCDBSupport.java
new file mode 100644
index 0000000..e7ca389
--- /dev/null
+++ b/cnd/cnd.lsp/src/org/netbeans/modules/cnd/lsp/compilationdb/ClangCDBSupport.java
@@ -0,0 +1,219 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.cnd.lsp.compilationdb;
+
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.netbeans.modules.cnd.api.project.NativeFileItem;
+import org.netbeans.modules.cnd.api.project.NativeProject;
+import org.netbeans.modules.cnd.api.project.NativeProjectItemsListener;
+import org.netbeans.modules.cnd.makeproject.api.MakeProject;
+import org.netbeans.modules.cnd.makeproject.api.support.MakeProjectEvent;
+import org.netbeans.modules.cnd.makeproject.api.support.MakeProjectListener;
+import org.netbeans.spi.project.ui.ProjectOpenedHook;
+import org.openide.util.RequestProcessor;
+
+/**
+ * ClangCDBSupport is responsible for detecting and generating a JSON
+ * compilation database, as defined in
+ * https://clang.llvm.org/docs/JSONCompilationDatabase.html
+ *
+ * When "ProjectOpenedHook.projectOpened" is fired, i.e., when the project is
+ * opened, we start listening to NativeProjectItemsListener and
+ * MakeProjectListener.
+ *
+ * We remove these listeners when the project is closed or deleted.
+ *
+ * The compilation database is regenerated after COALESCING_DELAY_MS
+ * milliseconds. Requests are coalesced using a "pendingCauses" blocking queue.
+ */
+public final class ClangCDBSupport
+        extends ProjectOpenedHook
+        implements
+        NativeProjectItemsListener, MakeProjectListener {
+
+    private static final Logger LOG = Logger.getLogger(ClangCDBSupport.class.getName());
+    private static final RequestProcessor CLANG_CDB_PROCESSOR = new RequestProcessor(ClangCDBSupport.class.getName());
+    private static final long COALESCING_DELAY_MS = 1000;
+    private final MakeProject makeProject;
+    private final BlockingQueue<ClangCDBGenerationCause> pendingCauses;
+    private boolean projectOpen;
+
+    public ClangCDBSupport(final MakeProject makeProject) {
+        this.makeProject = makeProject;
+        this.projectOpen = false;
+        this.pendingCauses = new LinkedBlockingQueue<>();
+    }
+
+    /**
+     * Called when multiple files are added to the project.
+     *
+     * @param fileItems the list of file items that was added.
+     */
+    @Override
+    public void filesAdded(List<NativeFileItem> fileItems) {
+        updateCompilationDatabase(ClangCDBGenerationCause.FILES_ADDED);
+    }
+
+    /**
+     * Called when multiple files are removed from the project.
+     *
+     * @param fileItems the list of file items that was added.
+     */
+    @Override
+    public void filesRemoved(List<NativeFileItem> fileItems) {
+        updateCompilationDatabase(ClangCDBGenerationCause.FILES_REMOVED);
+    }
+
+    /**
+     * Called when include paths or macro definitions have changed (and files
+     * needs to be re-parsed) for multiple files.
+     *
+     * @param fileItems the list of file items that has changed.
+     */
+    @Override
+    public void filesPropertiesChanged(List<NativeFileItem> fileItems) {
+        updateCompilationDatabase(ClangCDBGenerationCause.INCLUDES_MACROS_CHANGED);
+    }
+
+    /**
+     * Called when include paths or macro definitions have changed (and files
+     * needs to be re-parsed) for all files in project.
+     *
+     * @param nativeProject project whose properties have changed
+     */
+    @Override
+    public void filesPropertiesChanged(NativeProject nativeProject) {
+        updateCompilationDatabase(ClangCDBGenerationCause.INCLUDES_MACROS_CHANGED);
+    }
+
+    @Override
+    public void fileRenamed(String oldPath, NativeFileItem newFileIetm) {
+        updateCompilationDatabase(ClangCDBGenerationCause.FILES_RENAMED);
+    }
+
+    /**
+     * notifies about intensive file operations to be started. We ignore these.
+     *
+     * @param nativeProject
+     */
+    @Override
+    public void fileOperationsStarted(NativeProject nativeProject) {
+        LOG.log(Level.FINE, "File operations started.");
+    }
+
+    /**
+     * notifies about intensive file operations finished. We ignore these
+     *
+     * @param nativeProject
+     */
+    @Override
+    public void fileOperationsFinished(NativeProject nativeProject) {
+        LOG.log(Level.FINE, "File operations finished.");
+    }
+
+    @Override
+    public void configurationXmlChanged(MakeProjectEvent ev) {
+        updateCompilationDatabase(ClangCDBGenerationCause.PROJECT_CONFIGURATION_CHANGED);
+    }
+
+    /**
+     * Ignored. See javadoc
+     * @param ev 
+     */
+    @Override
+    public void propertiesChanged(MakeProjectEvent ev) {
+        LOG.log(Level.FINE, "Some project properties changed {0}",
+                ev.getPath());
+    }
+
+    @Override
+    protected void projectOpened() {
+        LOG.log(Level.FINE, "Project opened");
+        projectOpen = true;
+        makeProject.getHelper().addMakeProjectListener(this);
+        NativeProject nativeProject = makeProject.getLookup().lookup(NativeProject.class);
+        if (nativeProject != null) {
+            nativeProject.addProjectItemsListener(this);
+        } else {
+            LOG.log(Level.FINE, "Cannot attach to native project events.");
+        }
+        updateCompilationDatabase(ClangCDBGenerationCause.PROJECT_OPENED);
+    }
+
+    @Override
+    protected void projectClosed() {
+        LOG.log(Level.FINE, "Project closed");
+        removeListenersOnCloseOrDelete();
+    }
+
+    @Override
+    public void projectDeleted(NativeProject nativeProject) {
+        LOG.log(Level.FINE, "Project deleted");
+        removeListenersOnCloseOrDelete();
+    }
+
+    private void removeListenersOnCloseOrDelete() {
+        projectOpen = false;
+        makeProject.getHelper().removeMakeProjectListener(this);
+        NativeProject nativeProject = makeProject.getLookup().lookup(NativeProject.class);
+        if (nativeProject != null) {
+            nativeProject.removeProjectItemsListener(this);
+        } else {
+            LOG.log(Level.FINE, "Cannot detach from native project events.");
+        }
+    }
+
+    /**
+     * Updates the compilation database "[project]/compile_commands.json". If a
+     * task is already running then the request is silently ignored.
+     *
+     * @param cause The cause that originated the need to recreate the
+     * compilation database.
+     */
+    private void updateCompilationDatabase(ClangCDBGenerationCause cause) {
+        LOG.log(Level.FINE, "Update compilation database project is open: {0}", projectOpen);
+        if (projectOpen) {
+            pendingCauses.add(cause);
+            ClangCDBGenerationTask task = null;
+            try {
+                task = new ClangCDBGenerationTask(this, pendingCauses);
+            } catch (IllegalArgumentException iae) {
+                LOG.log(Level.SEVERE, "Unable to create ClangCDBGenerationTask: {0}", iae.getMessage());
+                return;
+            }
+            // We fire the regeneration task after a COALESCING_DELAY_MS milliseconds, to
+            // coalesce requests (for instance, when many files are added or removed).
+            CLANG_CDB_PROCESSOR.schedule(task, COALESCING_DELAY_MS, TimeUnit.MILLISECONDS);
+        }
+    }
+
+    MakeProject getMakeProject() {
+        return makeProject;
+    }
+
+    boolean isOpen() {
+        return projectOpen;
+    }
+
+}
diff --git a/cnd/cnd.lsp/src/org/netbeans/modules/cnd/lsp/compilationdb/CommandObjectBuilder.java b/cnd/cnd.lsp/src/org/netbeans/modules/cnd/lsp/compilationdb/CommandObjectBuilder.java
new file mode 100644
index 0000000..10d0a4d
--- /dev/null
+++ b/cnd/cnd.lsp/src/org/netbeans/modules/cnd/lsp/compilationdb/CommandObjectBuilder.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.cnd.lsp.compilationdb;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.json.simple.JSONObject;
+import org.netbeans.api.project.Project;
+import org.openide.filesystems.FileObject;
+
+/**
+ * CommandObjectBuilder builds a JSONObject representing a CommandObject as
+ * defined in https://clang.llvm.org/docs/JSONCompilationDatabase.html
+ */
+final class CommandObjectBuilder {
+
+    private static final Logger LOG = Logger.getLogger(CommandObjectBuilder.class.getName());
+
+    private final Project project;
+    private final StringBuilder command;
+    private String file;
+    private String output;
+
+    CommandObjectBuilder(Project project) {
+        this.project = project;
+        this.command = new StringBuilder();
+    }
+
+    /**
+     * Appends another piece of the 'command' entry in the command object. For
+     * instance, you can add "-strip" or "-std=ansi".
+     *
+     * @param part The part to append at the end of the command line.
+     * @return this
+     */
+    CommandObjectBuilder addCommandItem(String part) {
+        if (part != null) {
+            command.append(' ').append(part).append(' ');
+        }
+        return this;
+    }
+
+    /**
+     * Sets the 'file' entry in the command object. For instance,
+     * "/usr/home/user/project/folder/file.c"
+     *
+     * @param file The file. Absolute paths are recommended, but can be relative
+     * to the project.getProjectDirectory().
+     * @return this
+     */
+    CommandObjectBuilder setFile(String file) {
+        this.file = Paths.get(file).toAbsolutePath().toString();
+        return this;
+    }
+
+    /**
+     * Sets the 'output' entry in the command object. For instance,
+     * "/usr/home/user/project/build/platform/file.o"
+     *
+     * @param output The file. Absolute paths are recommended, but can be
+     * relative to the project.getProjectDirectory().
+     * @return this.
+     */
+    CommandObjectBuilder setOutput(String output) {
+        this.output = Paths.get(output).toAbsolutePath().toString();
+        return this;
+    }
+
+    String getFile() {
+        return file;
+    }
+
+    /**
+     * Builds a JSONObject representing this command object. NOTE: 'directory'
+     * entry is automatically set to project.getProjectDirectory().
+     *
+     * @return The JSONObject representing this command object.
+     * @throws IllegalStateException if a mandatory entri in the command object
+     * is not present.
+     */
+    JSONObject build() throws IllegalStateException {
+        if (file == null) {
+            throw new IllegalStateException("Missing file");
+        }
+        if (command.length() == 0) {
+            throw new IllegalStateException("No command");
+        }
+
+        JSONObject object = new JSONObject();
+
+        // directory
+        FileObject projectDirectory = project.getProjectDirectory();
+        Path directory = Paths.get(projectDirectory.toURI());
+        directory = directory.toAbsolutePath();
+        LOG.log(Level.FINE, "Directory {0}", directory.toString());
+        object.put("directory", directory.toString());
+
+        // file
+        LOG.log(Level.FINE, "File {0}", file);
+        object.put("file", file);
+
+        // command
+        object.put("command", command.toString().trim());
+        LOG.log(Level.FINE, "Command {0}", command.toString());
+
+        // output (this one is optional)
+        if (output != null) {
+            object.put("output", output);
+        }
+        return object;
+    }
+
+}
diff --git a/cnd/cnd.lsp/src/org/netbeans/modules/cnd/lsp/makeproject/LSPMakeProjectLookupProvider.java b/cnd/cnd.lsp/src/org/netbeans/modules/cnd/lsp/makeproject/LSPMakeProjectLookupProvider.java
new file mode 100644
index 0000000..0913516
--- /dev/null
+++ b/cnd/cnd.lsp/src/org/netbeans/modules/cnd/lsp/makeproject/LSPMakeProjectLookupProvider.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.cnd.lsp.makeproject;
+
+import java.util.ArrayList;
+import org.netbeans.modules.cnd.lsp.compilationdb.ClangCDBSupport;
+import org.netbeans.modules.cnd.makeproject.api.MakeProject;
+import org.netbeans.modules.cnd.makeproject.api.MakeProjectLookupProvider;
+import org.openide.util.lookup.ServiceProvider;
+
+/**
+ * Adds stuff to MakeProject Lookup.
+ * @author antonio
+ */
+@ServiceProvider(service = MakeProjectLookupProvider.class)
+public class LSPMakeProjectLookupProvider implements MakeProjectLookupProvider {
+
+    @Override
+    public void addLookup(MakeProject owner, ArrayList<Object> ic) {
+        ClangCDBSupport support = new ClangCDBSupport(owner);
+        ic.add(support);
+    }
+    
+}
diff --git a/cnd/cnd.lsp/src/org/netbeans/modules/cnd/lsp/resources/Bundle.properties b/cnd/cnd.lsp/src/org/netbeans/modules/cnd/lsp/resources/Bundle.properties
new file mode 100644
index 0000000..caf1327
--- /dev/null
+++ b/cnd/cnd.lsp/src/org/netbeans/modules/cnd/lsp/resources/Bundle.properties
@@ -0,0 +1,22 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+OpenIDE-Module-Display-Category=C/C++
+# Should not be translated
+OpenIDE-Module-Long-Description=\
+    C/C++ Language Server Protocol support
+OpenIDE-Module-Name=C/C++ LSP
+OpenIDE-Module-Short-Description=Language Server Protocol Support for C/C++
diff --git a/cnd/cnd.makeproject/nbproject/project.xml b/cnd/cnd.makeproject/nbproject/project.xml
index 8bb88b4..17d2750 100644
--- a/cnd/cnd.makeproject/nbproject/project.xml
+++ b/cnd/cnd.makeproject/nbproject/project.xml
@@ -345,6 +345,7 @@
                 <friend>org.netbeans.modules.cnd.gizmo</friend>
                 <friend>org.netbeans.modules.cnd.highlight</friend>
                 <friend>org.netbeans.modules.cnd.jconvertwizard</friend>
+                <friend>org.netbeans.modules.cnd.lsp</friend>
                 <friend>org.netbeans.modules.cnd.make2netbeans</friend>
                 <friend>org.netbeans.modules.cnd.makeproject.source.bridge</friend>
                 <friend>org.netbeans.modules.cnd.makeproject.ui</friend>
diff --git a/cnd/cnd.toolchain/nbproject/project.xml b/cnd/cnd.toolchain/nbproject/project.xml
index f3088b5..aece047 100644
--- a/cnd/cnd.toolchain/nbproject/project.xml
+++ b/cnd/cnd.toolchain/nbproject/project.xml
@@ -246,7 +246,6 @@
                 <friend>org.netbeans.modules.cnd.analysis.impl</friend>
                 <friend>org.netbeans.modules.cnd.api.remote</friend>
                 <friend>org.netbeans.modules.cnd.audit</friend>
-                <friend>org.netbeans.modules.cnd.jconvertwizard</friend>
                 <friend>org.netbeans.modules.cnd.classview</friend>
                 <friend>org.netbeans.modules.cnd.cncppunit</friend>
                 <friend>org.netbeans.modules.cnd.completion</friend>
@@ -259,6 +258,8 @@
                 <friend>org.netbeans.modules.cnd.dwarfdiscovery</friend>
                 <friend>org.netbeans.modules.cnd.gizmo</friend>
                 <friend>org.netbeans.modules.cnd.highlight</friend>
+                <friend>org.netbeans.modules.cnd.jconvertwizard</friend>
+                <friend>org.netbeans.modules.cnd.lsp</friend>
                 <friend>org.netbeans.modules.cnd.make2netbeans</friend>
                 <friend>org.netbeans.modules.cnd.makeproject</friend>
                 <friend>org.netbeans.modules.cnd.makeproject.ui</friend>
diff --git a/ide/dlight.nativeexecution/nbproject/project.xml b/ide/dlight.nativeexecution/nbproject/project.xml
index db4cb91..885590a 100644
--- a/ide/dlight.nativeexecution/nbproject/project.xml
+++ b/ide/dlight.nativeexecution/nbproject/project.xml
@@ -259,6 +259,7 @@
                 <friend>org.netbeans.modules.cnd.dwarfdiscovery</friend>
                 <friend>org.netbeans.modules.cnd.gizmo</friend>
                 <friend>org.netbeans.modules.cnd.highlight</friend>
+                <friend>org.netbeans.modules.cnd.lsp</friend>
                 <friend>org.netbeans.modules.cnd.makeproject</friend>
                 <friend>org.netbeans.modules.cnd.makeproject.ui</friend>
                 <friend>org.netbeans.modules.cnd.mixeddev</friend>
diff --git a/nbbuild/cluster.properties b/nbbuild/cluster.properties
index 9120a242..97aabf4 100644
--- a/nbbuild/cluster.properties
+++ b/nbbuild/cluster.properties
@@ -1089,6 +1089,7 @@ nb.cluster.cnd=\
         cnd.editor,\
         cnd.kit,\
         cnd.lexer,\
+        cnd.lsp,\
         cnd.makeproject,\
         cnd.makeproject.source.bridge,\
         cnd.makeproject.ui,\

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists