[haiku-commits] Change in buildtools[master]: jam: add an option to generate compile_commands.json

  • From: Gerrit <review@xxxxxxxxxxxxxxxxxxx>
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Tue, 22 Sep 2020 18:32:16 +0000

From Adrien Destugues <pulkomandy@xxxxxxxxx>:

Adrien Destugues has uploaded this change for review. ( 
https://review.haiku-os.org/c/buildtools/+/3260 ;)


Change subject: jam: add an option to generate compile_commands.json
......................................................................

jam: add an option to generate compile_commands.json

Based on Boost Jam patch: https://github.com/boostorg/build/pull/133
retrofitted to our version. Only the ruels whose name contains Cc or Cxx
are stored there. This can be improved if it's not good enough.

The commands are generated only as they are run. Unfortunately I think
with Jam there isn't really a way to do otherwise.
---
M jam/jam.c
M jam/jam.h
M jam/make1.c
3 files changed, 110 insertions(+), 2 deletions(-)



  git pull ssh://git.haiku-os.org:22/buildtools refs/changes/60/3260/1

diff --git a/jam/jam.c b/jam/jam.c
index 2bbf1ae..cf51d44 100644
--- a/jam/jam.c
+++ b/jam/jam.c
@@ -141,7 +141,8 @@
 # else
        { 0, 1 },               /* display actions  */
 # endif
-       0                       /* output commands, not run them */
+       0,                      /* output commands, not run them */
+       0                       /* output compilation db here */
 } ;

 /* Symbols to be defined as true for use in Jambase */
@@ -182,7 +183,7 @@

        argc--, argv++;

-       if( ( n = getoptions( argc, argv, "d:j:f:gs:t:ano:qv", optv ) ) < 0 )
+       if( ( n = getoptions( argc, argv, "d:j:f:gs:t:ano:cqv", optv ) ) < 0 )
        {
            printf( "\nusage: jam [ options ] targets...\n\n" );

@@ -197,6 +198,7 @@
             printf( "-jx     Run up to x shell commands concurrently.\n" );
             printf( "-n      Don't actually execute the updating actions.\n" );
             printf( "-ox     Write the updating actions to file x.\n" );
+            printf( "-c      Output JSON compilation database to 
compile_commands.json.\n" );
             printf( "-q      Quit quickly as soon as a target fails.\n" );
            printf( "-sx=y   Set variable x=y, overriding environment.\n" );
             printf( "-tx     Rebuild x, even if it is up-to-date.\n" );
@@ -279,6 +281,17 @@
            }
        }

+       /* If we're asked to produce a compilation database, open the file. */
+       if ( ( s = getoptval( optv, 'c', 0 ) ) )
+       {
+               if ( !( globs.comp_db = fopen( "compile_commands.json", "w" ) ) 
)
+               {
+                       printf( "Failed to write to 'compile_commands.json'\n");
+                       exit( EXITBAD );
+               }
+               fprintf(globs.comp_db, "[\n");
+       }
+
        /* Set JAMDATE first */

        {
@@ -439,5 +452,12 @@
        if( globs.cmdout )
            fclose( globs.cmdout );

+       /* close compilation database output file */
+       if ( globs.comp_db )
+       {
+               fprintf(globs.comp_db, "]\n");
+               fclose( globs.comp_db );
+       }
+
        return status ? EXITBAD : EXITOK;
 }
diff --git a/jam/jam.h b/jam/jam.h
index da3db48..6e509d5 100644
--- a/jam/jam.h
+++ b/jam/jam.h
@@ -500,6 +500,7 @@
        int     quitquick;
        int     newestfirst;            /* build newest sources first */
        char    debug[DEBUG_MAX];
+       FILE    *comp_db;                       /* output compilation db here */
        FILE    *cmdout;                /* print cmds, not run them */
 } ;

diff --git a/jam/make1.c b/jam/make1.c
index ffb7831..888ea5c 100644
--- a/jam/make1.c
+++ b/jam/make1.c
@@ -73,6 +73,12 @@
 static SETTINGS *make1settings( LIST *vars );
 static void make1bind( TARGET *t, int warn );

+void out_compile_database(
+     char const * const action,
+     char const * const source,
+     char const * const command
+ );
+
 /* Ugly static - it's too hard to carry it through the callbacks. */

 static struct {
@@ -295,6 +301,17 @@
            if( globs.cmdout )
                fprintf( globs.cmdout, "%s", cmd->buf );

+               if ( globs.comp_db != NULL )
+               {
+                       const char* rule_name = cmd->rule->name;
+                       const char* target_name = lol_get( (LOL *)&cmd->args, 0 
)->string;
+                       const char* source_name = NULL;
+                       LIST* sources = lol_get( (LOL *)&cmd->args, 1);
+                       if (sources != NULL)
+                               source_name = lol_get((LOL *)&cmd->args, 1 
)->string;
+                       out_compile_database( rule_name, source_name, cmd->buf 
);
+               }
+
            if( globs.noexec )
            {
                make1d( t, EXEC_CMD_OK );
@@ -671,3 +688,73 @@
        t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING;
        popsettings( t->settings );
 }
+
+
+static void out_json(char const* str, FILE* f)
+{
+     char const* escape_src = "\"\\\b\n\r\t";
+     char const* escape_subst[] = {
+         "\\\"", "\\\\", "\\b", "\\n", "\\r", "\\t"
+     };
+     char buffer[1024];
+     int i = 0;
+
+     /* trim leading whitespace */
+     while (*str != 0 && strchr(" \t\n\r\t", *str) != NULL)
+        ++str;
+
+     for (; *str != 0; ++str)
+     {
+         char const* ch;
+         char const* subst;
+         if (i >= sizeof(buffer) - 10)
+         {
+             buffer[i] = 0;
+             fputs(buffer, f);
+             i = 0;
+         }
+
+         /* skip non-printable characters */
+         if (*str < ' ' || *str > 127) continue;
+
+         ch = strchr(escape_src, *str);
+         if (ch == NULL)
+         {
+             buffer[i++] = *str;
+             continue;
+         }
+         subst = escape_subst[ch - escape_src];
+         strcpy(&buffer[i], subst);
+         i += strlen(subst);
+     }
+
+     buffer[i] = 0;
+     fputs(buffer, f);
+}
+
+
+void out_compile_database
+(
+     char const * const action,
+     char const * const source,
+     char const * const command
+)
+{
+     /* file format defined here:
+      * http://clang.llvm.org/docs/JSONCompilationDatabase.html
+      * we're not interested in link, mkdir, rm or any non-compile action
+      */
+     if (source
+        && (strstr(action, "Cc") != NULL || strstr(action, "Cxx") != NULL))
+     {
+         char buffer[256];
+         fputs("{ \"directory\": \"", globs.comp_db);
+         out_json(getcwd(buffer, sizeof(buffer)), globs.comp_db);
+         fputs("\", \"command\": \"", globs.comp_db);
+         out_json(command, globs.comp_db);
+         fputs("\", \"file\": \"", globs.comp_db);
+         out_json(source, globs.comp_db);
+         fputs("\" },\n", globs.comp_db);
+     }
+
+}

--
To view, visit https://review.haiku-os.org/c/buildtools/+/3260
To unsubscribe, or for help writing mail filters, visit 
https://review.haiku-os.org/settings

Gerrit-Project: buildtools
Gerrit-Branch: master
Gerrit-Change-Id: Ic5d44dc27baa2a2e4157324f6c5a228ab0366afe
Gerrit-Change-Number: 3260
Gerrit-PatchSet: 1
Gerrit-Owner: Adrien Destugues <pulkomandy@xxxxxxxxx>
Gerrit-MessageType: newchange

Other related posts: