From 7b20b4673d8cf46ff61898eb19569007d55c854a Mon Sep 17 00:00:00 2001 From: Chengzhong Wu Date: Mon, 1 Apr 2024 18:05:29 +0800 Subject: [PATCH] feat: generate compile_commands.json with ninja (#228) --- .github/workflows/python_tests.yml | 1 + data/ninja/build.ninja | 4 ++++ pylib/gyp/generator/ninja.py | 31 ++++++++++++++++++++++++++++++ pylib/gyp/generator/ninja_test.py | 12 ++++++++++++ 4 files changed, 48 insertions(+) create mode 100644 data/ninja/build.ninja diff --git a/.github/workflows/python_tests.yml b/.github/workflows/python_tests.yml index 096f38ac..e4a5fd02 100644 --- a/.github/workflows/python_tests.yml +++ b/.github/workflows/python_tests.yml @@ -24,6 +24,7 @@ jobs: with: python-version: ${{ matrix.python-version }} allow-prereleases: true + - uses: seanmiddleditch/gha-setup-ninja@v4 - name: Install dependencies run: | python -m pip install --upgrade pip setuptools diff --git a/data/ninja/build.ninja b/data/ninja/build.ninja new file mode 100644 index 00000000..2400dbb1 --- /dev/null +++ b/data/ninja/build.ninja @@ -0,0 +1,4 @@ +rule cc + command = cc $in $out + +build my.out: cc my.in diff --git a/pylib/gyp/generator/ninja.py b/pylib/gyp/generator/ninja.py index 8ba341e9..0146c499 100644 --- a/pylib/gyp/generator/ninja.py +++ b/pylib/gyp/generator/ninja.py @@ -11,6 +11,7 @@ import os.path import re import signal +import shutil import subprocess import sys import gyp @@ -2210,6 +2211,7 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params, config_name options = params["options"] flavor = gyp.common.GetFlavor(params) generator_flags = params.get("generator_flags", {}) + generate_compile_commands = generator_flags.get("compile_commands", False) # build_dir: relative path from source root to our output files. # e.g. "out/Debug" @@ -2878,6 +2880,35 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params, config_name master_ninja_file.close() + if generate_compile_commands: + compile_db = GenerateCompileDBWithNinja(toplevel_build) + compile_db_file = OpenOutput( + os.path.join(toplevel_build, "compile_commands.json") + ) + compile_db_file.write(json.dumps(compile_db, indent=2)) + compile_db_file.close() + + +def GenerateCompileDBWithNinja(path, targets=["all"]): + """Generates a compile database using ninja. + + Args: + path: The build directory to generate a compile database for. + targets: Additional targets to pass to ninja. + + Returns: + List of the contents of the compile database. + """ + ninja_path = shutil.which("ninja") + if ninja_path is None: + raise Exception("ninja not found in PATH") + json_compile_db = subprocess.check_output( + [ninja_path, "-C", path] + + targets + + ["-t", "compdb", "cc", "cxx", "objc", "objcxx"] + ) + return json.loads(json_compile_db) + def PerformBuild(data, configurations, params): options = params["options"] diff --git a/pylib/gyp/generator/ninja_test.py b/pylib/gyp/generator/ninja_test.py index 7d180685..15cddfdf 100644 --- a/pylib/gyp/generator/ninja_test.py +++ b/pylib/gyp/generator/ninja_test.py @@ -6,6 +6,7 @@ """ Unit tests for the ninja.py file. """ +from pathlib import Path import sys import unittest @@ -50,6 +51,17 @@ def test_BinaryNamesLinux(self): writer.ComputeOutputFileName(spec, "static_library").endswith(".a") ) + def test_GenerateCompileDBWithNinja(self): + build_dir = ( + Path(__file__).resolve().parent.parent.parent.parent / "data" / "ninja" + ) + compile_db = ninja.GenerateCompileDBWithNinja(build_dir) + assert len(compile_db) == 1 + assert compile_db[0]["directory"] == str(build_dir) + assert compile_db[0]["command"] == "cc my.in my.out" + assert compile_db[0]["file"] == "my.in" + assert compile_db[0]["output"] == "my.out" + if __name__ == "__main__": unittest.main()