all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Matt Armstrong <matt@rfc20.org>
To: "João Távora" <joaotavora@gmail.com>,
	"Gerd Möllmann" <gerd.moellmann@gmail.com>
Cc: emacs-devel <emacs-devel@gnu.org>
Subject: Emacs + bear + compile_commands.json + clangd
Date: Mon, 10 Oct 2022 21:09:58 -0700	[thread overview]
Message-ID: <87pmezvw4p.fsf@rfc20.org> (raw)
In-Reply-To: <CALDnm53kyL+9XnY9MnH48oGjfjZVR4rsbPho4XWkUZXSiFokFw@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1768 bytes --]

João Távora <joaotavora@gmail.com> writes:

> Hello Gerd. Out of curiosity, and speculation, is your use of 'bear'
> intended to make a compilation database of Emacs sources for use with a LSP
> server?
>
> If so, how is that going? Last time I tried to do that, the server (clangd,
> i think) was still very confused in many files.
>
> João

Hey João, I had issues with Emacs source and clangd, especially with
header files.  The issue is that many of Emacs' C header files are not
"self contained" so they can't be compiled alone.  Also, `bear` will
only generate compile commands for .c files, and clangd uses heuristics
to guess a compile command for nearby .h files.  It does a reasonable
job in some projects, but not Emacs due to the "self contained" issue.
Biggest issue: when editing an .h file clangd won't include <config.h>
for you.

I now do this:

    ./configure <whatever>
    bear --force-wrapper -- make -j$CPUS
    emacs-fixup-compile-commands.py

where emacs-fixup-compile-commands.py is attached.  Bonus to anyone
rewrites it in elisp.  ;-)

The idea is to find the .c file with the most similar name to each .h
file, then form a compile command for the .h by hacking the .c file's
command line, adding:

   -Wno-unused-macros -include config.h

...this way, when clangd "compiles" an Emacs .h file it includes
config.h first (which fixes many issues), and won't complain about
macros going unused in the file.

With this, Emacs + clangd is pretty seamless for me.

P.S. I recently had to start passing "--force-wrapper" to bear.  Some
Emacs builds steps were failing with bear's LD_PRELOAD hack.  Maybe the
Emacs modules stuff?  Or tests?  I didn't look into it, but
"--force-wrapper" fixed it.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: emacs-fixup-compile-commands.py --]
[-- Type: text/x-python, Size: 2448 bytes --]

#!/usr/bin/env python3

import copy
import json
import glob
import os
import sys


def levenshteinDistance(s1, s2):
    if len(s1) > len(s2):
        s1, s2 = s2, s1

    distances = range(len(s1) + 1)
    for i2, c2 in enumerate(s2):
        distances_ = [i2 + 1]
        for i1, c1 in enumerate(s1):
            if c1 == c2:
                distances_.append(distances[i1])
            else:
                distances_.append(
                    1 + min((distances[i1], distances[i1 + 1], distances_[-1]))
                )
        distances = distances_
    return distances[-1]


def Read():
    with open("compile_commands.json") as file:
        return json.load(file)


def Write(compile_commands):
    with open("compile_commands.json", "w") as file:
        json.dump(compile_commands, file, sort_keys=True, indent=2)


def Headers():
    # return [f for f in os.listdir('src') if f.endswith('.h')]
    return glob.glob(os.path.join(os.getcwd(), "src/*.h"))


def NeedsConfigH(header):
    """Returns True if header needs config.h to function"""
    if header.endswith("/config.h"):
        return False
    with open(header) as file:
        return "INLINE_HEADER_BEGIN" in file.read()


def FindSimilarCommand(compile_commands, header):
    header = os.path.join(os.getcwd(), header)
    bestDistance = sys.maxsize
    bestCommand = None
    for command in compile_commands:
        distance = levenshteinDistance(header, command["file"])
        if distance < bestDistance:
            bestDistance = distance
            bestCommand = command
    return bestCommand


def AdaptTemplate(command, header):
    command = copy.deepcopy(command)
    if "output" in command:
        del command["output"]
    src = os.path.relpath(command["file"], command["directory"])
    index = command["arguments"].index(src)
    new_src = os.path.relpath(header, command["directory"])
    command["arguments"][index : index + 1] = [
        "-Wno-unused-macros",
        "-include",
        "config.h",
        new_src,
    ]
    command["file"] = header
    return command


compile_commands = Read()
new_compile_commands = copy.copy(compile_commands)
for header in Headers():
    if NeedsConfigH(header):
        similar = FindSimilarCommand(compile_commands, header)
        if similar["file"] == header:
            continue
        adapted = AdaptTemplate(similar, header)
        new_compile_commands.append(adapted)
Write(new_compile_commands)

  parent reply	other threads:[~2022-10-11  4:09 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-08-19 12:44 Lightning fast build Gerd Möllmann
2022-08-19 12:59 ` Alan Mackenzie
2022-08-21  2:47 ` Pankaj Jangid
2022-08-21  9:36 ` João Távora
2022-08-21 10:24   ` Gerd Möllmann
2022-10-11  4:09   ` Matt Armstrong [this message]
2022-10-11  5:39     ` Emacs + bear + compile_commands.json + clangd Gerd Möllmann
2022-10-11 17:37       ` Matt Armstrong
2022-10-12  4:32         ` Gerd Möllmann

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87pmezvw4p.fsf@rfc20.org \
    --to=matt@rfc20.org \
    --cc=emacs-devel@gnu.org \
    --cc=gerd.moellmann@gmail.com \
    --cc=joaotavora@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.