-
-
Notifications
You must be signed in to change notification settings - Fork 42.1k
New CLI subcommand to create clang-compatible compilation database (compile_commands.json
)
#14370
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
Merged
Merged
Changes from 43 commits
Commits
Show all changes
44 commits
Select commit
Hold shift + click to select a range
47365ae
pulled source from dev branch
e0bff4d
missed a file from origin
5a51eaa
formatting
d817b7d
revised argument names. relaxed matching rules to work for avr too
30b564f
add docstrings
849a12f
added docs. tightened up regex
b671c40
remove unused imports
f42cadc
cleaning up command file. use existing qmk dir constant
e768fac
rename parser library file
21c5b63
move lib functions into command file. there are only 2 and they aren'…
3fe7817
currently debugging...
ec3739b
more robustly find config
bf2aef2
updated docs
10171f8
remove unused imports
697ca67
reuse make executable from the main make command
82a8be3
pulled source from dev branch
3a95195
missed a file from origin
3ed55aa
formatting
c9a4d97
revised argument names. relaxed matching rules to work for avr too
9226ba5
add docstrings
764f35d
added docs. tightened up regex
b0a5e1a
remove unused imports
67c08c6
cleaning up command file. use existing qmk dir constant
c0fc66e
rename parser library file
2f103f5
move lib functions into command file. there are only 2 and they aren'…
c03da56
currently debugging...
8db4e13
more robustly find config
67ae7d8
updated docs
976b0b1
remove unused imports
7ab3465
reuse make executable from the main make command
16c47fd
Merge branch 'compile_commands' of https://github.com/xton/qmk_firmwa…
70dfd86
Merge branch 'master' into compile_commands
c558c5d
remove MAKEFLAGS from environment for better control over process man…
afb2527
Update .gitignore
xton f64f64a
add a usage line to docs
3830823
Merge branch 'compile_commands' of https://github.com/xton/qmk_firmwa…
6cbcc9c
doc change as suggested
xton bae3306
Merge remote-tracking branch 'xton/compile_commands' into develop
baodrate 13044e0
rename command
baodrate ecffaa4
Merge branch 'develop' into compile_commands
baodrate 42014f0
remove debug print statements
baodrate d8d0f25
generate-compilation-database: fix arg handling
baodrate 7df7b9e
generate-comilation-db: improve error handling
baodrate 66e090d
use cli.run() instead of Popen()
baodrate File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
"""Creates a compilation database for the given keyboard build. | ||
""" | ||
|
||
import itertools | ||
import json | ||
import os | ||
import re | ||
import shlex | ||
import shutil | ||
import subprocess | ||
from functools import lru_cache | ||
from pathlib import Path | ||
from typing import Dict, Iterator, List | ||
|
||
from milc import cli | ||
|
||
from qmk.commands import create_make_command | ||
from qmk.constants import QMK_FIRMWARE | ||
from qmk.decorators import automagic_keyboard, automagic_keymap | ||
|
||
|
||
@lru_cache(maxsize=10) | ||
def system_libs(binary: str) -> List[Path]: | ||
"""Find the system include directory that the given build tool uses. | ||
""" | ||
cli.log.debug("searching for system library directory for binary: %s", binary) | ||
bin_path = shutil.which(binary) | ||
return list(Path(bin_path).resolve().parent.parent.glob("*/include")) if bin_path else [] | ||
|
||
|
||
file_re = re.compile(r'printf "Compiling: ([^"]+)') | ||
cmd_re = re.compile(r'LOG=\$\((.+?)&&') | ||
|
||
|
||
def parse_make_n(f: Iterator[str]) -> List[Dict[str, str]]: | ||
"""parse the output of `make -n <target>` | ||
|
||
This function makes many assumptions about the format of your build log. | ||
This happens to work right now for qmk. | ||
""" | ||
|
||
state = 'start' | ||
this_file = None | ||
records = [] | ||
for line in f: | ||
if state == 'start': | ||
m = file_re.search(line) | ||
if m: | ||
this_file = m.group(1) | ||
state = 'cmd' | ||
|
||
if state == 'cmd': | ||
assert this_file | ||
m = cmd_re.search(line) | ||
if m: | ||
# we have a hit! | ||
this_cmd = m.group(1) | ||
args = shlex.split(this_cmd) | ||
args += ['-I%s' % s for s in system_libs(args[0])] | ||
new_cmd = ' '.join(shlex.quote(s) for s in args if s != '-mno-thumb-interwork') | ||
records.append({"directory": str(QMK_FIRMWARE.resolve()), "command": new_cmd, "file": this_file}) | ||
state = 'start' | ||
|
||
return records | ||
|
||
|
||
@cli.argument('-kb', '--keyboard', help='The keyboard to build a firmware for. Ignored when a configurator export is supplied.') | ||
@cli.argument('-km', '--keymap', help='The keymap to build a firmware for. Ignored when a configurator export is supplied.') | ||
@cli.subcommand('Create a compilation database.') | ||
@automagic_keyboard | ||
@automagic_keymap | ||
def generate_compilation_database(cli): | ||
"""Creates a compilation database for the given keyboard build. | ||
|
||
Does a make clean, then a make -n for this target and uses the dry-run output to create | ||
a compilation database (compile_commands.json). This file can help some IDEs and | ||
IDE-like editors work better. For more information about this: | ||
|
||
https://clang.llvm.org/docs/JSONCompilationDatabase.html | ||
""" | ||
command = None | ||
# check both config domains: the magic decorator fills in `generate_compilation_database` but the user is | ||
# more likely to have set `compile` in their config file. | ||
current_keyboard = cli.config.generate_compilation_database.keyboard or cli.config.user.keyboard | ||
current_keymap = cli.config.generate_compilation_database.keymap or cli.config.user.keymap | ||
|
||
if current_keyboard and current_keymap: | ||
# Generate the make command for a specific keyboard/keymap. | ||
command = create_make_command(current_keyboard, current_keymap, dry_run=True) | ||
|
||
elif not current_keyboard: | ||
cli.log.error('Could not determine keyboard!') | ||
elif not current_keymap: | ||
cli.log.error('Could not determine keymap!') | ||
|
||
if command: | ||
# remove any environment variable overrides which could trip us up | ||
env = os.environ.copy() | ||
env.pop("MAKEFLAGS", None) | ||
|
||
# re-use same executable as the main make invocation (might be gmake) | ||
clean_command = [command[0], 'clean'] | ||
cli.log.info('Making clean with {fg_cyan}%s', ' '.join(clean_command)) | ||
subprocess.run(clean_command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, env=env, check=True) | ||
|
||
cli.log.info('Gathering build instructions from {fg_cyan}%s', ' '.join(command)) | ||
with subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, env=env) as proc: | ||
stdout1, stdout2 = itertools.tee(proc.stdout or []) | ||
db = parse_make_n(stdout1) | ||
proc.wait() | ||
if not db: | ||
cli.log.error("Failed to parse output from make output:\n%s", ''.join(stdout2)) | ||
return False | ||
|
||
cli.log.info("Found %s compile commands", len(db)) | ||
|
||
dbpath = QMK_FIRMWARE / 'compile_commands.json' | ||
|
||
cli.log.info(f"Writing build database to {dbpath}") | ||
dbpath.write_text(json.dumps(db, indent=4)) | ||
|
||
else: | ||
cli.log.error('You must supply both `--keyboard` and `--keymap`, or be in a directory for a keyboard or keymap.') | ||
cli.echo('usage: qmk compiledb [-kb KEYBOARD] [-km KEYMAP]') | ||
return False |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.