2 * This file has been donated to Jam.
14 # include "variable.h"
17 #ifdef OPT_HEADER_CACHE_EXT
20 * Craig W. McPheeters, Alias|Wavefront.
22 * hcache.c hcache.h - handle cacheing of #includes in source files.
24 * Create a cache of files scanned for headers. When starting jam, look for the
25 * cache file and load it if present. When finished the binding phase, create a
26 * new header cache. The cache contains files, their timestamps and the header
27 * files found in their scan. During the binding phase of jam, look in the
28 * header cache first for the headers contained in a file. If the cache is
29 * present and valid, use its contents. This results in dramatic speedups with
30 * large projects (eg. 3min -> 1min startup for one project.)
33 * hcache_init() - read and parse the local .jamdeps file.
34 * hcache_done() - write a new .jamdeps file.
35 * hcache() - return list of headers on target. Use cache or do a scan.
37 * The dependency file format is an ASCII file with 1 line per target. Each line
38 * has the following fields:
39 * @boundname@ timestamp @file@ @file@ @file@ ... \n
42 typedef struct hcachedata HCACHEDATA ;
49 LIST * hdrscan; /* the HDRSCAN value for this target */
50 int age; /* if too old, we'll remove it from cache */
55 static struct hash * hcachehash = 0;
56 static HCACHEDATA * hcachelist = 0;
58 static int queries = 0;
61 #define CACHE_FILE_VERSION "version 4"
62 #define CACHE_RECORD_HEADER "header"
63 #define CACHE_RECORD_END "end"
67 * Return the name of the header cache file. May return NULL.
69 * The user sets this by setting the HCACHEFILE variable in a Jamfile. We cache
70 * the result so the user can not change the cache file during header scanning.
73 static char * cache_name( void )
75 static char * name = 0;
78 LIST * hcachevar = var_get( "HCACHEFILE" );
82 TARGET * t = bindtarget( hcachevar->string );
84 pushsettings( t->settings );
85 /* Do not expect the cache file to be generated, so pass 0 as the
86 * third argument to search. Expect the location to be specified via
87 * LOCATE, so pass 0 as the fourth arugment.
89 t->boundname = search( t->name, &t->time, 0, 0 );
90 popsettings( t->settings );
93 name = copystr( t->boundname );
101 * Return the maximum age a cache entry can have before it is purged ftom the
105 static int cache_maxage( void )
108 LIST * var = var_get( "HCACHEMAXAGE" );
111 age = atoi( var->string );
120 * Read a netstring. The caveat is that the string can not contain ASCII 0. The
121 * returned value is as returned by newstr(), so it need not be freed.
124 char * read_netstring( FILE * f )
127 static char * buf = NULL;
128 static unsigned long buf_len = 0;
130 if ( fscanf( f, " %9lu", &len ) != 1 )
132 if ( fgetc( f ) != (int)'\t' )
135 if ( len > 1024 * 64 )
136 return NULL; /* sanity check */
140 unsigned long new_len = buf_len * 2;
143 buf = (char *)BJAM_REALLOC( buf, new_len + 1 );
151 if ( fread( buf, 1, len, f ) != len )
153 if ( fgetc( f ) != (int)'\n' )
157 return newstr( buf );
165 void write_netstring( FILE * f, char const * s )
169 fprintf( f, "%lu\t%s\n", (long unsigned)strlen( s ), s );
175 HCACHEDATA cachedata;
179 int header_count = 0;
182 hcachehash = hashinit( sizeof( HCACHEDATA ), "hcache" );
184 if ( !( hcachename = cache_name() ) )
187 if ( !( f = fopen( hcachename, "rb" ) ) )
190 version = read_netstring( f );
191 if ( !version || strcmp( version, CACHE_FILE_VERSION ) )
202 char * includes_count_str;
203 char * hdrscan_count_str;
208 record_type = read_netstring( f );
211 fprintf( stderr, "invalid %s\n", hcachename );
214 if ( !strcmp( record_type, CACHE_RECORD_END ) )
216 if ( strcmp( record_type, CACHE_RECORD_HEADER ) )
218 fprintf( stderr, "invalid %s with record separator <%s>\n",
219 hcachename, record_type ? record_type : "<null>" );
225 c->boundname = read_netstring( f );
226 time_str = read_netstring( f );
227 age_str = read_netstring( f );
228 includes_count_str = read_netstring( f );
230 if ( !c->boundname || !time_str || !age_str || !includes_count_str )
232 fprintf( stderr, "invalid %s\n", hcachename );
236 c->time = atoi( time_str );
237 c->age = atoi( age_str ) + 1;
239 count = atoi( includes_count_str );
240 for ( l = 0, i = 0; i < count; ++i )
242 char * s = read_netstring( f );
245 fprintf( stderr, "invalid %s\n", hcachename );
248 l = list_new( l, s );
252 hdrscan_count_str = read_netstring( f );
253 if ( !includes_count_str )
255 list_free( c->includes );
256 fprintf( stderr, "invalid %s\n", hcachename );
260 count = atoi( hdrscan_count_str );
261 for ( l = 0, i = 0; i < count; ++i )
263 char * s = read_netstring( f );
266 fprintf( stderr, "invalid %s\n", hcachename );
269 l = list_new( l, s );
273 if ( !hashenter( hcachehash, (HASHDATA * *)&c ) )
275 fprintf( stderr, "can't insert header cache item, bailing on %s\n",
280 c->next = hcachelist;
287 printf( "hcache read from file %s\n", hcachename );
298 int header_count = 0;
305 if ( !( hcachename = cache_name() ) )
308 if ( !( f = fopen( hcachename, "wb" ) ) )
311 maxage = cache_maxage();
313 /* Print out the version. */
314 write_netstring( f, CACHE_FILE_VERSION );
317 for ( c = hcachelist; c; c = c->next )
322 char includes_count_str[ 30 ];
323 char hdrscan_count_str[ 30 ];
327 else if ( c->age > maxage )
330 sprintf( includes_count_str, "%lu", (long unsigned) list_length( c->includes ) );
331 sprintf( hdrscan_count_str, "%lu", (long unsigned) list_length( c->hdrscan ) );
332 sprintf( time_str, "%lu", (long unsigned) c->time );
333 sprintf( age_str, "%lu", (long unsigned) c->age );
335 write_netstring( f, CACHE_RECORD_HEADER );
336 write_netstring( f, c->boundname );
337 write_netstring( f, time_str );
338 write_netstring( f, age_str );
339 write_netstring( f, includes_count_str );
340 for ( l = c->includes; l; l = list_next( l ) )
341 write_netstring( f, l->string );
342 write_netstring( f, hdrscan_count_str );
343 for ( l = c->hdrscan; l; l = list_next( l ) )
344 write_netstring( f, l->string );
348 write_netstring( f, CACHE_RECORD_END );
351 printf( "hcache written to %s. %d dependencies, %.0f%% hit rate\n",
352 hcachename, header_count, queries ? 100.0 * hits / queries : 0 );
358 LIST * hcache( TARGET * t, int rec, regexp * re[], LIST * hdrscan )
360 HCACHEDATA cachedata;
361 HCACHEDATA * c = &cachedata;
367 c->boundname = t->boundname;
369 if (hashcheck (hcachehash, (HASHDATA **) &c))
371 if (c->time == t->time)
373 LIST *l1 = hdrscan, *l2 = c->hdrscan;
375 if (l1->string != l2->string) {
384 printf("HDRSCAN out of date in cache for %s\n",
387 printf("HDRSCAN out of date for %s\n", t->boundname);
390 printf("\n cached: ");
391 list_print(c->hdrscan);
394 list_free(c->includes);
395 list_free(c->hdrscan);
400 printf ("using header cache for %s\n", t->boundname);
403 l = list_copy (0, c->includes);
408 printf ("header cache out of date for %s\n", t->boundname);
409 list_free (c->includes);
410 list_free(c->hdrscan);
415 if (hashenter (hcachehash, (HASHDATA **)&c)) {
416 c->boundname = newstr (c->boundname);
417 c->next = hcachelist;
422 /* 'c' points at the cache entry. Its out of date. */
424 l = headers1 (0, t->boundname, rec, re);
428 c->includes = list_copy (0, l);
429 c->hdrscan = list_copy(0, hdrscan);