From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Matt Armstrong Newsgroups: gmane.emacs.devel Subject: Emacs + bear + compile_commands.json + clangd Date: Mon, 10 Oct 2022 21:09:58 -0700 Message-ID: <87pmezvw4p.fsf@rfc20.org> References: Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="3520"; mail-complaints-to="usenet@ciao.gmane.io" Cc: emacs-devel To: =?utf-8?B?Sm/Do28gVMOhdm9yYQ==?= , Gerd =?utf-8?Q?M=C3=B6llmann?= Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Tue Oct 11 06:11:04 2022 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1oi6bg-0000io-1D for ged-emacs-devel@m.gmane-mx.org; Tue, 11 Oct 2022 06:11:04 +0200 Original-Received: from localhost ([::1]:43560 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1oi6bf-0001WG-4J for ged-emacs-devel@m.gmane-mx.org; Tue, 11 Oct 2022 00:11:03 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:55380) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1oi6am-0008VQ-HB for emacs-devel@gnu.org; Tue, 11 Oct 2022 00:10:08 -0400 Original-Received: from relay7-d.mail.gandi.net ([2001:4b98:dc4:8::227]:44955) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1oi6aj-00039P-0b for emacs-devel@gnu.org; Tue, 11 Oct 2022 00:10:07 -0400 Original-Received: (Authenticated sender: matt@rfc20.org) by mail.gandi.net (Postfix) with ESMTPSA id 2B2BB20002; Tue, 11 Oct 2022 04:10:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rfc20.org; s=gm1; t=1665461401; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=eS3II61tvjdQdSiox3+JU/nSyaBMBVUciCF2SNexSQs=; b=DlC6U09bcs9KDR0wRnbyExGOFCpZ+9k8SkIkeh0BydxJiZJ1EXTomhhTezKRwX2evbdbmp xA6dvSdlZdn6L7y/NDxNdiXqYTo5uzTrhifl73NSI8+MevOZfRpa2oXaElRsHxkf0MpfDA u4gf3dK2PMkEnWudoYx7HbX1wuZMLcCTZB3WuWhVrQhVdee/KQlUN3k2sa+tJbUdTvpX4L pReQBWjbZB3tIp53FeBgC9hybmbWkavPoWC2VrYZsTF28uVGEhL95bXMj24eczPszWWuno 7XD/DqNr0TSSSF76ua0TMQyiJzYdTWxkYfbPY3/dvnYWEJTc6W2D0F5hpYsQfw== Original-Received: from matt by naz with local (Exim 4.96) (envelope-from ) id 1oi6ac-009TRJ-1n; Mon, 10 Oct 2022 21:09:58 -0700 In-Reply-To: Received-SPF: pass client-ip=2001:4b98:dc4:8::227; envelope-from=matt@rfc20.org; helo=relay7-d.mail.gandi.net X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.io gmane.emacs.devel:297413 Archived-At: --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Jo=C3=A3o T=C3=A1vora 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 L= SP > server? > > If so, how is that going? Last time I tried to do that, the server (clang= d, > i think) was still very confused in many files. > > Jo=C3=A3o Hey Jo=C3=A3o, 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 for you. I now do this: ./configure 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. --=-=-= Content-Type: text/x-python Content-Disposition: inline; filename=emacs-fixup-compile-commands.py #!/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) --=-=-=--