-
Notifications
You must be signed in to change notification settings - Fork 556
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generate compile_commands.json for Improved Language Server Support #1982
Comments
Thanks @StoneLin0708, what's complexity of your |
Thanks for the feedback, @enjoy-digital The patch_litex_builder_for_compile_commands is straightforward in my setup but might require additional testing and some error handling to ensure it works universally for other users. Here’s the core part of the patch that captures the make commands and takes dry run results for later parsing: from litex.soc.integration.builder import Builder
import os
import subprocess
def patch_litex_builder_for_compile_commands(builder: Builder):
make_compile_commands = []
# most of the code is from litex.soc.integration.builder.Builder._generate_rom_software
def _generate_rom_software(self: Builder, compile_bios=True):
for name, src_dir in self.software_packages:
if name == "bios" and not compile_bios:
continue
dst_dir = os.path.join(self.software_dir, name)
makefile = os.path.join(src_dir, "Makefile")
if self.compile_software:
dry_command = ["make", "--dry-run", "V=1", "-C", dst_dir, "-f", makefile]
make_compile_commands.extend(
subprocess.check_output(dry_command).decode('utf-8').splitlines()
)
subprocess.check_call(["make", "-C", dst_dir, "-f", makefile])
builder._generate_rom_software = _generate_rom_software.__get__(builder)
return make_compile_commands Additionally, here's the parse_compile_commands function that processes the results to generate the compile commands format: import re
from typing import List
def parse_compile_commands(make_compile_commands: List[str]) -> List:
compile_commands = []
make_cwd = None
for i in make_compile_commands:
if i.startswith('make: Entering directory'):
m_output = re.search(r"'(.+)'", i)
if m_output:
make_cwd = m_output.group(1)
else:
make_cwd = None
continue
if i.startswith('make: Leaving directory'):
make_cwd = None
continue
if not i.startswith('riscv64-unknown-elf-gcc'):
continue
# extract output file
m_output = re.search(r'-o\s+(\S+)', i)
# extract input file (with/without -c)
m_input = re.search(r'(-c\s+)?(\S+\.[cS])', i)
# add to compile_commands if both output and input are found
if m_output and m_input:
# remove output from command
i = i.replace(m_output.group(0), '')
# remove -march=... -mabi=... if present
i = re.sub(r'-march=\S+', ' ', i)
i = re.sub(r'-mabi=\S+', ' ', i)
i = re.sub(r'\s+', ' ', i)
compile_commands.append(
{
'output': m_output.group(1),
'file': m_input.group(2),
'command': i.strip(),
'directory': make_cwd
}
)
return compile_commands |
Thanks to the LiteX team for this great project!
Issue:
The current LiteX build system does not generate
compile_commands.json
, limiting functionality of language servers such asclangd
, and affecting features like code completion.Questions:
compile_commands.json
during the build?Proposed Solutions:
*Note: Both methods require post-processing to remove target-specific flags (-march=, -mabi=), which are necessary for my clangd setup to function correctly.
I am considering two approaches and would appreciate community input on both:
litex.soc.integration.builder.Builder._generate_rom_software
to perform a--dry-run
, capture the commands, and do post-processing*. This method integrates directly into the build process without requiring additional dependencies but may require more maintenance.Current Implementation:
I’ve implemented a working solution by modifying the LiteX Builder and using it in the build process of my project.
Which approach would better suit our community’s needs, or are there other methods you’d suggest? Thanks for any feedback.
The text was updated successfully, but these errors were encountered: