CompileCommands.vala 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. using GLib;
  2. namespace Spry.Cli {
  3. /**
  4. * Maintains a `compile_commands.json` in the application root for the
  5. * Vala language server: meson emits the database as a build artifact in
  6. * `builddir/`, and it is copied out to the root whenever a build
  7. * happens (the initial build on `spry new`, and every `spry dev`
  8. * build/rebuild). The copied file is generated state — gitignored and
  9. * excluded from packaging.
  10. */
  11. public class CompileCommands : Object {
  12. /**
  13. * Runs the initial meson setup + build of a freshly scaffolded
  14. * application (so the compile database exists) and copies the
  15. * database to the project root. Failures are reported but do not
  16. * fail scaffolding itself.
  17. */
  18. public static void build_initial(string app_dir, string? libdir) {
  19. var launcher = new SubprocessLauncher(SubprocessFlags.NONE);
  20. Tools.apply_env(launcher, libdir);
  21. stdout.printf("[spry] Running initial build (for compile_commands.json)…\n");
  22. if (!run_step(launcher, app_dir, { "meson", "setup", ".", "builddir" })
  23. || !run_step(launcher, app_dir, { "ninja", "-C", "builddir" })) {
  24. return;
  25. }
  26. copy_from_builddir(app_dir);
  27. }
  28. private static bool run_step(SubprocessLauncher launcher, string app_dir, string[] argv) {
  29. try {
  30. var previous = Environment.get_current_dir();
  31. Environment.set_current_dir(app_dir);
  32. var process = launcher.spawnv(argv);
  33. Environment.set_current_dir(previous);
  34. if (!process.wait_check()) {
  35. stderr.printf("[spry] Initial build failed — compile_commands.json not generated\n");
  36. return false;
  37. }
  38. }
  39. catch (Error e) {
  40. stderr.printf("[spry] Initial build could not run: %s\n", e.message);
  41. return false;
  42. }
  43. return true;
  44. }
  45. /**
  46. * Copies `builddir/compile_commands.json` to the project root when
  47. * it exists; a no-op otherwise (e.g. the build failed or produced
  48. * none).
  49. */
  50. public static void copy_from_builddir(string app_dir) {
  51. try {
  52. var source = File.new_for_path(Path.build_filename(app_dir, "builddir", "compile_commands.json"));
  53. if (!source.query_exists()) {
  54. return;
  55. }
  56. var destination = File.new_for_path(Path.build_filename(app_dir, "compile_commands.json"));
  57. if (!destination.query_exists()
  58. || source.query_info("time::modified", FileQueryInfoFlags.NONE).get_modification_date_time()
  59. .difference(destination.query_info("time::modified", FileQueryInfoFlags.NONE).get_modification_date_time()) > 0) {
  60. source.copy(destination, FileCopyFlags.OVERWRITE);
  61. stdout.printf("[spry] compile_commands.json copied to the project root\n");
  62. }
  63. }
  64. catch (Error e) {
  65. }
  66. }
  67. }
  68. }