mirror of
https://review.haiku-os.org/buildtools
synced 2024-11-23 07:18:49 +01:00
19aaa79362
There was a comma in compile_commands.json after the last entry what prevented from using file directly in some tools. Test plan: verified new compile_commands.json with "python3 -m json.tool compile_commands.json" Change-Id: I6c2582f7285a3409d95081a93f3c05b5cc9322b9 Reviewed-on: https://review.haiku-os.org/c/buildtools/+/4671 Reviewed-by: Jérôme Duval <jerome.duval@gmail.com>
464 lines
11 KiB
C
464 lines
11 KiB
C
/*
|
|
* /+\
|
|
* +\ Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
|
* \+/
|
|
*
|
|
* This file is part of jam.
|
|
*
|
|
* License is hereby granted to use this software and distribute it
|
|
* freely, as long as this copyright notice is retained and modifications
|
|
* are clearly marked.
|
|
*
|
|
* ALL WARRANTIES ARE HEREBY DISCLAIMED.
|
|
*/
|
|
|
|
/*
|
|
* jam.c - make redux
|
|
*
|
|
* See Jam.html for usage information.
|
|
*
|
|
* These comments document the code.
|
|
*
|
|
* The top half of the code is structured such:
|
|
*
|
|
* jam
|
|
* / | \
|
|
* +---+ | \
|
|
* / | \
|
|
* jamgram option \
|
|
* / | \ \
|
|
* / | \ \
|
|
* / | \ |
|
|
* scan | compile make
|
|
* | | / | \ / | \
|
|
* | | / | \ / | \
|
|
* | | / | \ / | \
|
|
* jambase parse | rules search make1
|
|
* | | | \
|
|
* | | | \
|
|
* | | | \
|
|
* builtins timestamp command execute
|
|
* |
|
|
* |
|
|
* |
|
|
* filesys
|
|
*
|
|
*
|
|
* The support routines are called by all of the above, but themselves
|
|
* are layered thus:
|
|
*
|
|
* variable|expand
|
|
* / | | |
|
|
* / | | |
|
|
* / | | |
|
|
* lists | | pathsys
|
|
* \ | |
|
|
* \ | |
|
|
* \ | |
|
|
* newstr |
|
|
* \ |
|
|
* \ |
|
|
* \ |
|
|
* hash
|
|
*
|
|
* Roughly, the modules are:
|
|
*
|
|
* builtins.c - jam's built-in rules
|
|
* command.c - maintain lists of commands
|
|
* compile.c - compile parsed jam statements
|
|
* execunix.c - execute a shell script on UNIX
|
|
* execvms.c - execute a shell script, ala VMS
|
|
* expand.c - expand a buffer, given variable values
|
|
* file*.c - scan directories and archives on *
|
|
* hash.c - simple in-memory hashing routines
|
|
* headers.c - handle #includes in source files
|
|
* jambase.c - compilable copy of Jambase
|
|
* jamgram.y - jam grammar
|
|
* lists.c - maintain lists of strings
|
|
* make.c - bring a target up to date, once rules are in place
|
|
* make1.c - execute command to bring targets up to date
|
|
* newstr.c - string manipulation routines
|
|
* option.c - command line option processing
|
|
* parse.c - make and destroy parse trees as driven by the parser
|
|
* path*.c - manipulate file names on *
|
|
* hash.c - simple in-memory hashing routines
|
|
* regexp.c - Henry Spencer's regexp
|
|
* rules.c - access to RULEs, TARGETs, and ACTIONs
|
|
* scan.c - the jam yacc scanner
|
|
* search.c - find a target along $(SEARCH) or $(LOCATE)
|
|
* timestamp.c - get the timestamp of a file or archive member
|
|
* variable.c - handle jam multi-element variables
|
|
*
|
|
* 05/04/94 (seiwald) - async multiprocess (-j) support
|
|
* 02/08/95 (seiwald) - -n implies -d2.
|
|
* 02/22/95 (seiwald) - -v for version info.
|
|
* 09/11/00 (seiwald) - PATCHLEVEL folded into VERSION.
|
|
* 01/10/01 (seiwald) - pathsys.h split from filesys.h
|
|
* 01/21/02 (seiwald) - new -q to quit quickly on build failure
|
|
* 03/16/02 (seiwald) - support for -g (reorder builds by source time)
|
|
* 09/19/02 (seiwald) - new -d displays
|
|
* 10/22/02 (seiwald) - list_new() now does its own newstr()/copystr()
|
|
* 11/04/02 (seiwald) - const-ing for string literals
|
|
*/
|
|
|
|
# include "jam.h"
|
|
# include "option.h"
|
|
# include "patchlevel.h"
|
|
|
|
/* These get various function declarations. */
|
|
|
|
# include "lists.h"
|
|
# include "parse.h"
|
|
# include "variable.h"
|
|
# include "compile.h"
|
|
# include "builtins.h"
|
|
# include "jcache.h"
|
|
# include "rules.h"
|
|
# include "newstr.h"
|
|
# include "scan.h"
|
|
# include "timestamp.h"
|
|
# include "make.h"
|
|
|
|
/* Macintosh is "special" */
|
|
|
|
# ifdef OS_MAC
|
|
# include <QuickDraw.h>
|
|
# endif
|
|
|
|
/* And UNIX for this */
|
|
|
|
# ifdef unix
|
|
# include <sys/utsname.h>
|
|
# endif
|
|
|
|
struct globs globs = {
|
|
0, /* noexec */
|
|
1, /* jobs */
|
|
0, /* quitquick */
|
|
0, /* newestfirst */
|
|
# ifdef OS_MAC
|
|
{ 0 }, /* display - suppress actions output */
|
|
# else
|
|
{ 0, 1 }, /* display actions */
|
|
# endif
|
|
0, /* output compilation db here */
|
|
0 /* output commands, not run them */
|
|
} ;
|
|
|
|
/* Symbols to be defined as true for use in Jambase */
|
|
|
|
static const char *othersyms[] = { OSMAJOR, OSMINOR, OSPLAT, JAMVERSYM, 0 } ;
|
|
|
|
/* Known for sure:
|
|
* mac needs arg_enviro
|
|
* OS2 needs extern environ
|
|
*/
|
|
|
|
# ifdef OS_MAC
|
|
# define use_environ arg_environ
|
|
# ifdef MPW
|
|
QDGlobals qd;
|
|
# endif
|
|
# endif
|
|
|
|
# ifndef use_environ
|
|
# define use_environ environ
|
|
# if !defined( __WATCOM__ ) && !defined( OS_OS2 ) && !defined( OS_NT )
|
|
extern char **environ;
|
|
# endif
|
|
# endif
|
|
|
|
int main( int argc, char **argv, char **arg_environ )
|
|
{
|
|
int n;
|
|
const char *s;
|
|
struct option optv[N_OPTS];
|
|
const char *all = "all";
|
|
int anyhow = 0;
|
|
int status;
|
|
|
|
# ifdef OS_MAC
|
|
InitGraf(&qd.thePort);
|
|
# endif
|
|
|
|
argc--, argv++;
|
|
|
|
if( ( n = getoptions( argc, argv, "d:j:f:gs:t:ano:cqv", optv ) ) < 0 )
|
|
{
|
|
printf( "\nusage: jam [ options ] targets...\n\n" );
|
|
|
|
printf( "-a Build all targets, even if they are current.\n" );
|
|
printf( "-dx Display (a)actions (c)causes (d)dependencies\n" );
|
|
printf( " (m)make tree (x)commands (0-9) debug levels.\n" );
|
|
# ifdef OPT_RULE_PROFILING_EXT
|
|
printf( " (p)profile rules.\n" );
|
|
# endif
|
|
printf( "-fx Read x instead of Jambase.\n" );
|
|
printf( "-g Build from newest sources first.\n" );
|
|
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" );
|
|
printf( "-v Print the version of jam and exit.\n\n" );
|
|
|
|
exit( EXITBAD );
|
|
}
|
|
|
|
argc -= n, argv += n;
|
|
|
|
/* Version info. */
|
|
|
|
if( ( s = getoptval( optv, 'v', 0 ) ) )
|
|
{
|
|
printf( "Jam %s. %s. ", VERSION, OSMINOR );
|
|
printf( "Copyright 1993-2002 Christopher Seiwald.\n" );
|
|
|
|
return EXITOK;
|
|
}
|
|
|
|
/* Pick up interesting options */
|
|
|
|
if( ( s = getoptval( optv, 'n', 0 ) ) )
|
|
globs.noexec++, DEBUG_MAKE = DEBUG_MAKEQ = DEBUG_EXEC = 1;
|
|
|
|
if( ( s = getoptval( optv, 'q', 0 ) ) )
|
|
globs.quitquick = 1;
|
|
|
|
if( ( s = getoptval( optv, 'a', 0 ) ) )
|
|
anyhow++;
|
|
|
|
if( ( s = getoptval( optv, 'j', 0 ) ) )
|
|
{
|
|
globs.jobs = atoi( s );
|
|
var_set( "JAMJOBS", list_new( L0, s, 0 ), VAR_SET );
|
|
}
|
|
|
|
if( ( s = getoptval( optv, 'g', 0 ) ) )
|
|
globs.newestfirst = 1;
|
|
|
|
/* Turn on/off debugging */
|
|
|
|
for( n = 0; s = getoptval( optv, 'd', n ); n++ )
|
|
{
|
|
int i = atoi( s );
|
|
|
|
/* First -d, turn off defaults. */
|
|
|
|
if( !n )
|
|
DEBUG_MAKE = DEBUG_MAKEQ = DEBUG_EXEC = 0;
|
|
|
|
/* n turns on levels 1-n */
|
|
/* +n turns on level n */
|
|
/* c turns on named display c */
|
|
|
|
if( i < 0 || i >= DEBUG_MAX )
|
|
{
|
|
printf( "Invalid debug level '%s'.\n", s );
|
|
}
|
|
else if( *s == '+' )
|
|
{
|
|
globs.debug[i] = 1;
|
|
}
|
|
else if( i ) while( i )
|
|
{
|
|
globs.debug[i--] = 1;
|
|
}
|
|
else while( *s ) switch( *s++ )
|
|
{
|
|
case 'a': DEBUG_MAKE = DEBUG_MAKEQ = 1; break;
|
|
case 'c': DEBUG_CAUSES = 1; break;
|
|
case 'd': DEBUG_DEPENDS = 1; break;
|
|
case 'm': DEBUG_MAKEPROG = 1; break;
|
|
case 'x': DEBUG_EXEC = 1; break;
|
|
# ifdef OPT_RULE_PROFILING_EXT
|
|
case 'p': DEBUG_PROFILE_RULES = 1; break;
|
|
# endif
|
|
case '0': break;
|
|
default: printf( "Invalid debug flag '%c'.\n", s[-1] );
|
|
}
|
|
}
|
|
|
|
/* 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 */
|
|
|
|
{
|
|
char buf[ 128 ];
|
|
time_t clock;
|
|
time( &clock );
|
|
strcpy( buf, ctime( &clock ) );
|
|
|
|
/* Trim newline from date */
|
|
|
|
if( strlen( buf ) == 25 )
|
|
buf[ 24 ] = 0;
|
|
|
|
var_set( "JAMDATE", list_new( L0, buf, 0 ), VAR_SET );
|
|
}
|
|
|
|
/* And JAMUNAME */
|
|
# ifdef unix
|
|
{
|
|
struct utsname u;
|
|
|
|
if( uname( &u ) >= 0 )
|
|
{
|
|
LIST *l = L0;
|
|
l = list_new( l, u.machine, 0 );
|
|
l = list_new( l, u.version, 0 );
|
|
l = list_new( l, u.release, 0 );
|
|
l = list_new( l, u.nodename, 0 );
|
|
l = list_new( l, u.sysname, 0 );
|
|
var_set( "JAMUNAME", l, VAR_SET );
|
|
}
|
|
}
|
|
# endif /* unix */
|
|
|
|
/*
|
|
* Jam defined variables OS, OSPLAT
|
|
*/
|
|
|
|
var_defines( othersyms );
|
|
|
|
/* load up environment variables */
|
|
|
|
var_defines( (const char **)use_environ );
|
|
|
|
#ifdef OPT_JAM_TARGETS_VARIABLE_EXT
|
|
/* define the variable JAM_TARGETS containing the targets specified on
|
|
the command line */
|
|
{
|
|
LIST *l = L0;
|
|
int i;
|
|
char **targets = argv;
|
|
int targetCount = argc;
|
|
if (targetCount == 0) {
|
|
targets = (char**)&all;
|
|
targetCount = 1;
|
|
}
|
|
|
|
for (i = 0; i < targetCount; i++)
|
|
l = list_new( l, targets[i], 0 );
|
|
|
|
var_set( "JAM_TARGETS", l, VAR_SET );
|
|
}
|
|
#endif
|
|
|
|
/* Load up variables set on command line. */
|
|
|
|
for( n = 0; s = getoptval( optv, 's', n ); n++ )
|
|
{
|
|
const char *symv[2];
|
|
symv[0] = s;
|
|
symv[1] = 0;
|
|
var_defines( symv );
|
|
}
|
|
|
|
/* Initialize built-in rules */
|
|
|
|
load_builtins();
|
|
|
|
/* Parse ruleset */
|
|
#ifdef OPT_JAMFILE_CACHE_EXT
|
|
jcache_init();
|
|
#endif
|
|
|
|
for( n = 0; s = getoptval( optv, 'f', n ); n++ )
|
|
parse_file( s );
|
|
|
|
if( !n )
|
|
parse_file( "+" );
|
|
|
|
#ifdef OPT_JAMFILE_CACHE_EXT
|
|
jcache_done();
|
|
#endif
|
|
|
|
status = yyanyerrors();
|
|
|
|
/* Manually touch -t targets */
|
|
|
|
for( n = 0; s = getoptval( optv, 't', n ); n++ )
|
|
touchtarget( s );
|
|
|
|
/* If an output file is specified, set globs.cmdout to that */
|
|
|
|
if( s = getoptval( optv, 'o', 0 ) )
|
|
{
|
|
if( !( globs.cmdout = fopen( s, "w" ) ) )
|
|
{
|
|
printf( "Failed to write to '%s'\n", s );
|
|
exit( EXITBAD );
|
|
}
|
|
globs.noexec++;
|
|
}
|
|
|
|
#ifdef OPT_JAM_TARGETS_VARIABLE_EXT
|
|
/* get value of variable JAM_TARGETS and build the targets */
|
|
{
|
|
LIST *l = var_get( "JAM_TARGETS" );
|
|
int targetCount = list_length(l);
|
|
char **targets;
|
|
int i;
|
|
|
|
if (targetCount == 0) {
|
|
/* No targets. Nothing to do. */
|
|
exit( EXITOK );
|
|
}
|
|
|
|
targets = malloc(targetCount * sizeof(char*));
|
|
if (!targets) {
|
|
printf( "Memory allocation failed!\n" );
|
|
exit( EXITBAD );
|
|
}
|
|
|
|
for (i = 0; i < targetCount; i++) {
|
|
targets[i] = (char*)l->string;
|
|
l = l->next;
|
|
}
|
|
|
|
argv = targets;
|
|
argc = targetCount;
|
|
}
|
|
#endif
|
|
|
|
/* Now make target */
|
|
|
|
if( !argc )
|
|
status |= make( 1, &all, anyhow );
|
|
else
|
|
status |= make( argc, (const char **)argv, anyhow );
|
|
|
|
/* Widely scattered cleanup */
|
|
|
|
var_done();
|
|
donerules();
|
|
donestamps();
|
|
donestr();
|
|
|
|
/* close cmdout */
|
|
|
|
if( globs.cmdout )
|
|
fclose( globs.cmdout );
|
|
|
|
/* close compilation database output file */
|
|
if ( globs.comp_db )
|
|
{
|
|
fprintf(globs.comp_db, "\n]\n");
|
|
fclose( globs.comp_db );
|
|
}
|
|
|
|
return status ? EXITBAD : EXITOK;
|
|
}
|