/* * Get a filename in cache for given md5sum. */ const char *filecache_getfilename(TARGET *t, MD5SUM sum, const char* extension) { BUFFER buff; size_t pos; const char *cachedir; const char* result; cachedir = filecache_getpath(t); /* if no cachedir, no cachefiles */ if (cachedir==NULL) { return NULL; } /* put the cachedir in front of buffer */ buffer_init(&buff); buffer_addstring(&buff, cachedir, strlen(cachedir)); buffer_addchar(&buff, '/'); pos = buffer_pos(&buff); buffer_addstring(&buff, "000/", 4); /* add use md5 as filename */ buffer_addstring(&buff, md5tostring(sum), 32); if (extension) buffer_addstring(&buff, extension, strlen(extension)); buffer_addchar(&buff, 0); buffer_setpos(&buff, pos); buffer_putstring(&buff, buffer_ptr(&buff) + pos + 4, 3); result = newstr(buffer_ptr(&buff)); buffer_free(&buff); return result; }
void checksum_update(TARGET *t, MD5SUM buildmd5sum) { CHECKSUMDATA cachedata, *c = &cachedata; char buildmd5sumstring[33]; /* If the buildmd5sum is empty, then the file doesn't exist. */ if (ismd5empty(buildmd5sum)) return; /* if the target is available in the cache */ strcpy(buildmd5sumstring, md5tostring(buildmd5sum)); c->boundname = buildmd5sumstring; /* Search for the appropriate .link file that matches the target. */ if (!hashcheck(checksumhash, (HASHDATA **)&c)) { if (hashenter(checksumhash, (HASHDATA **)&c)) { c->boundname = newstr( c->boundname ); c->next = checksumdatalist; checksumdatalist = c; } } memcpy(&c->contentmd5sum, t->contentchecksum->contentmd5sum, MD5_SUMSIZE); c->mtime = 1; c->age = 0; checksumsdirty = 1; }
int checksum_retrieve(TARGET *t, MD5SUM buildmd5sum) { CHECKSUMDATA cachedata, *c = &cachedata; char buildmd5sumstring[33]; checksums_readfile(); strcpy(buildmd5sumstring, md5tostring(buildmd5sum)); c->boundname = buildmd5sumstring; if (!hashcheck(checksumhash, (HASHDATA **)&c)) { return 0; } getcachedmd5sum(t, 0); if (t->contentchecksum && t->contentchecksum->mtime != 0 && memcmp( c->contentmd5sum, t->contentchecksum->contentmd5sum, MD5_SUMSIZE ) == 0 ) { time_t time; #ifdef _MSC_VER _utime(t->boundname, NULL); #else utime(t->boundname, NULL); #endif file_time(t->boundname, &time); t->contentchecksum->mtime = time; t->contentchecksum->age = 0; checksumsdirty = 1; //printf("JAMDEBUG: %s is already the proper cached target.\n", t->name); return 1; } else { memset(&c->contentmd5sum, 0, MD5_SUMSIZE); } return 0; }
/* * Get cached md5sum of a file. If none found, or not up to date, if the file is source * try to recalculate the sum. If not, then return empty sum (all zeroes). */ int getcachedmd5sum( TARGET *t, int source ) { HCACHEDATA cachedata, *c = &cachedata; int use_cache = 1; HCACHEFILE *file; const char *target = t->boundname; # ifdef DOWNSHIFT_PATHS char path[ MAXJPATH ]; char *p; #endif if ( t->contentmd5sum_calculated ) return t->contentmd5sum_changed; if (!source) { memset(&t->buildmd5sum, 0, sizeof(t->buildmd5sum)); memset(&t->contentmd5sum, 0, sizeof(t->contentmd5sum)); t->contentmd5sum_calculated = 1; t->contentmd5sum_changed = 0; return t->contentmd5sum_changed; } file = hcachefile_get( t ); ++queries; # ifdef DOWNSHIFT_PATHS p = path; do *p++ = (char)tolower( *target ); while( *target++ ); target = path; # endif c->boundname = target; if( hashcheck( file->hcachehash, (HASHDATA **) &c ) ) { if ( t->time == 0 ) { /* This file was generated. Grab its timestamp. */ file_time( c->boundname, &c->mtime ); } else if( c->mtime != t->time ) use_cache = 0; if ( use_cache ) { use_cache = memcmp(md5sumempty, &c->contentmd5sum, sizeof(c->contentmd5sum)) != 0; } if( use_cache ) { if( DEBUG_MD5HASH ) printf( "- content md5: %s (%s)\n", t->boundname, md5tostring(c->contentmd5sum)); c->age = 0; /* The entry has been used, its young again */ ++hits; t->contentmd5sum_changed = 0; memcpy(&t->contentmd5sum, &c->contentmd5sum, sizeof(t->contentmd5sum)); t->contentmd5sum_calculated = 1; return t->contentmd5sum_changed; } else { if( DEBUG_MD5HASH ) printf( "md5 cache out of date for %s (time %d, md5time %d)\n", t->boundname , (int)t->time, (int)c->mtime ); } } else { if( hashenter( file->hcachehash, (HASHDATA **)&c ) ) { c->boundname = newstr( c->boundname ); c->next = file->hcachelist; file->hcachelist = c; c->time = 0; c->includes = NULL; c->hdrscan = NULL; } } file->dirty = 1; /* 'c' points at the cache entry. Its out of date. */ { MD5SUM origmd5sum; #ifdef OPT_BUILTIN_LUA_SUPPORT_EXT LIST *md5callback; #endif memcpy( &origmd5sum, &c->contentmd5sum, sizeof( MD5SUM ) ); #ifdef OPT_BUILTIN_LUA_SUPPORT_EXT pushsettings( t->settings ); md5callback = var_get( "MD5CALLBACK" ); popsettings( t->settings ); if ( md5callback ) { luahelper_md5callback(t->boundname, c->contentmd5sum, md5callback->string); } else { #endif md5file( t->boundname, c->contentmd5sum ); #ifdef OPT_BUILTIN_LUA_SUPPORT_EXT } #endif t->contentmd5sum_changed = memcmp( &origmd5sum, &c->contentmd5sum, sizeof( MD5SUM ) ) != 0; } if( DEBUG_MD5HASH ) printf( "- content md5: %s (%s)\n", t->boundname, md5tostring(c->contentmd5sum)); c->mtime = t->time; if ( c->mtime == 0 ) { /* This file was generated. Grab its timestamp. */ file_time( c->boundname, &c->mtime ); } c->age = 0; memcpy(&t->contentmd5sum, &c->contentmd5sum, sizeof(t->contentmd5sum)); t->contentmd5sum_calculated = (char)(memcmp(md5sumempty, &t->contentmd5sum, sizeof(t->contentmd5sum)) != 0); memset(&t->buildmd5sum, 0, sizeof(t->buildmd5sum)); return t->contentmd5sum_changed; }
void filecache_update(TARGET *t) { MD5SUM blobmd5sum; int haveblobmd5sum = 0; const char *cachedname; const char *blobname; int cacheerror; if (!t->filecache_generate) return; /* If the buildmd5sum is empty, then the file doesn't exist. */ cacheerror = ismd5empty(t->buildmd5sum); if (cacheerror) return; haveblobmd5sum = 0; cachedname = filecache_getfilename(t, t->buildmd5sum, NULL); if (!cachedname) return; /* Search for the appropriate .link file that matches the target. */ haveblobmd5sum = filecache_findlink(cachedname, blobmd5sum); /* If we weren't able to determine the target md5sum, do it now. */ if (!haveblobmd5sum) { #ifdef OPT_BUILTIN_LUA_SUPPORT_EXT LIST *md5callback; pushsettings( t->settings ); md5callback = var_get( "MD5CALLBACK" ); popsettings( t->settings ); if ( md5callback ) { luahelper_md5callback(t->boundname, blobmd5sum, md5callback->string); } else { #endif md5file(t->boundname, blobmd5sum); #ifdef OPT_BUILTIN_LUA_SUPPORT_EXT } #endif memcpy(t->contentmd5sum, blobmd5sum, sizeof(MD5SUM)); if (ismd5empty(t->contentmd5sum)) return; } { /* Is the blob already there? */ time_t blobtime; blobname = filecache_getfilename(t, blobmd5sum, ".blob"); if (file_time(blobname, &blobtime) == -1) { time_t blobpartialtime; const char *blobpartialname; if(DEBUG_MD5HASH) printf("Caching %s as %s\n", t->name, cachedname); else printf("Caching %s\n", t->name); /* Write the new .blob to the cache. */ blobpartialname = filecache_getfilename(t, blobmd5sum, ".blob.partial"); if (file_time(blobpartialname, &blobpartialtime) == -1) { if (copyfile(blobpartialname, t->boundname, &blobmd5sum) == 0 || rename(blobpartialname, blobname) != 0) { printf("** Unable to write %s to cache.\n", t->name, cachedname); filecache_disable(t); return; } } } } /* Write the new .link file to the cache. */ { FILE *file; BUFFER linknamebuff; buffer_init(&linknamebuff); buffer_addstring(&linknamebuff, cachedname, strlen(cachedname)); buffer_addchar(&linknamebuff, '-'); buffer_addstring(&linknamebuff, md5tostring(blobmd5sum), 32); buffer_addstring(&linknamebuff, ".link", 5); buffer_addchar(&linknamebuff, 0); file_mkdir(buffer_ptr(&linknamebuff)); file = fopen(buffer_ptr(&linknamebuff), "wb"); if (file) { write_md5sum(file, blobmd5sum); write_string(file, t->name); fclose(file); } buffer_free(&linknamebuff); } }
static CMD * make1cmds( ACTIONS *a0 ) #endif { CMD *cmds = 0; LIST *shell = var_get( "JAMSHELL" ); /* shell is per-target */ /* Step through actions */ /* Actions may be shared with other targets or grouped with */ /* RULE_TOGETHER, so actions already seen are skipped. */ for( ; a0; a0 = a0->next ) { RULE *rule = a0->action->rule; SETTINGS *boundvars; LIST *nt, *ns; ACTIONS *a1; int start, chunk, length, maxline; TARGETS *autosettingsreverse = 0; TARGETS *autot; #ifdef OPT_MULTIPASS_EXT if ( a0->action->pass != actionpass ) continue; #endif /* Only do rules with commands to execute. */ /* If this action has already been executed, use saved status */ #ifdef OPT_DEBUG_MAKE1_LOG_EXT if (DEBUG_MAKE1) { printf( "make1cmds\t--\t%s (actions %s, running %s)\n" , rule->name, rule->actions ? "yes" : "no", a0->action->running ? "yes" : "no" ); } #endif if( !rule->actions || a0->action->running ) continue; #ifdef OPT_REMOVE_EMPTY_DIRS_EXT if ( rule->flags & RULE_REMOVEEMPTYDIRS ) { for( a1 = a0; a1; a1 = a1->next ) { TARGETS* sources; for ( sources = a1->action->sources; sources; sources = sources->next ) { emptydirtargets = list_new( emptydirtargets, sources->target->name, 1 ); } } } #endif for ( autot = a0->action->autosettings; autot; autot = autot->next ) { if ( autot->target != t ) pushsettings( autot->target->settings ); autosettingsreverse = targetentryhead( autosettingsreverse, autot->target, 0 ); } pushsettings( t->settings ); a0->action->running = 1; #ifdef OPT_ACTIONS_WAIT_FIX a0->action->run_tgt = t; #endif /* Make LISTS of targets and sources */ /* If `execute together` has been specified for this rule, tack */ /* on sources from each instance of this rule for this target. */ #ifdef OPT_DEBUG_MAKE1_LOG_EXT if (DEBUG_MAKE1) { LIST *list = make1list(L0, a0->action->targets, 0); printf("make1cmds\t--\ttargets: "); list_print(list); list_free(list); printf("\n"); list = make1list(L0, a0->action->sources, 0); printf("make1cmds\t--\tsources: "); list_print(list); list_free(list); printf("\n"); } #endif #ifdef OPT_BUILTIN_MD5CACHE_EXT if (t->filecache_generate || t->filecache_use) { LIST* targets = make1list_unbound( L0, a0->action->targets, 0 ); LIST* sources = make1list_unbound( L0, a0->action->sources, rule->flags ); nt = L0; ns = L0; if ( strncmp( rule->name, "batched_", 8 ) == 0 ) { int anycacheable = 0; for( ; targets; targets = targets->next, sources = ( sources == NULL ? sources : sources->next ) ) { TARGET *t = bindtarget(targets->string); TARGET *s = sources!=NULL ? bindtarget(sources->string) : NULL; /* if this target could be cacheable */ if ( (t->flags & T_FLAG_USEFILECACHE) && (t->filecache_generate || t->filecache_use) ) { /* find its final md5sum */ MD5_CTX context; MD5SUM buildsumorg; anycacheable = 1; memcpy(&buildsumorg, &t->buildmd5sum, sizeof(t->buildmd5sum)); MD5Init( &context ); MD5Update( &context, t->buildmd5sum, sizeof( t->buildmd5sum ) ); { TARGET *outt = bindtarget( t->boundname ); outt->flags |= T_FLAG_USEFILECACHE; MD5Final( outt->buildmd5sum, &context ); memcpy(&t->buildmd5sum, &outt->buildmd5sum, sizeof(t->buildmd5sum)); } if (DEBUG_MD5HASH) { printf( "Cacheable: %s buildmd5: %s org: %s\n", t->boundname, md5tostring(t->buildmd5sum), md5tostring(buildsumorg) ); } /* if using cache is allowed */ if (t->filecache_use) { const char *cachedname; /* if the target is available in the cache */ cachedname = filecache_getfilename(t, t->buildmd5sum, ".doesntwork"); if (cachedname!=NULL) { time_t cachedtime; if ( file_time( cachedname, &cachedtime ) == 0 ) { /* try to get it from the cache */ if (copyfile(t->boundname, cachedname, NULL)) { printf( "Using cached %s\n", t->name ); continue; } else { printf( "Cannot retrieve %s from cache (will build normally)\n", t->name ); } } else { if( DEBUG_MD5HASH) { printf( "Cannot find %s in cache as %s\n", t->name, cachedname ); } } } } /* Build new lists */ nt = list_new( nt, t->boundname, 1 ); if (s) ns = list_new( ns, s->boundname, 1 ); } } if ( !anycacheable ) { nt = make1list( L0, a0->action->targets, 0 ); ns = make1list( L0, a0->action->sources, rule->flags ); } } else { int allcached = 1; popsettings( t->settings ); for( ; targets; targets = list_next(targets) ) { TARGET *t = bindtarget(targets->string); // TARGET *s = sources!=NULL ? bindtarget(sources->string) : NULL; TARGETS *c; TARGET *outt; LIST *filecache = 0; if ( t->flags & T_FLAG_USEFILECACHE ) { pushsettings( t->settings ); filecache = filecache_fillvalues( t ); popsettings( t->settings ); } /* if this target could be cacheable */ if ( (t->flags & T_FLAG_USEFILECACHE) && (t->filecache_generate || t->filecache_use) ) { /* find its final md5sum */ MD5_CTX context; if( DEBUG_MD5HASH ) { printf( "------------------------------------------------\n" ); printf( "------------------------------------------------\n" ); printf( "------------------------------------------------\n" ); } /* sort all dependents by name, so we can make reliable md5sums */ t->depends = make0sortbyname( t->depends ); MD5Init( &context ); /* add the path of the file to the sum - it is significant because one command can create more than one file */ MD5Update( &context, (unsigned char*)t->name, (unsigned int)strlen( t->name ) ); /* add in the COMMANDLINE */ if ( t->flags & T_FLAG_USECOMMANDLINE ) { SETTINGS *vars; for ( vars = t->settings; vars; vars = vars->next ) { if ( vars->symbol[0] == 'C' && strcmp( vars->symbol, "COMMANDLINE" ) == 0 ) { LIST *list; for ( list = vars->value; list; list = list->next ) { MD5Update( &context, (unsigned char*)list->string, (unsigned int)strlen( list->string ) ); if( DEBUG_MD5HASH ) printf( "\t\tCOMMANDLINE: %s\n", list->string ); } break; } } } /* for each dependencies */ for( c = t->depends; c; c = c->next ) { /* If this is a "Needs" dependency, don't care about its contents. */ if (c->needs) { continue; } /* add name of the dependency and its contents */ make0calcmd5sum( c->target, 1 ); if ( c->target->buildmd5sum_calculated ) { MD5Update( &context, (unsigned char*)c->target->name, (unsigned int)strlen( c->target->name ) ); MD5Update( &context, c->target->buildmd5sum, sizeof( c->target->buildmd5sum ) ); } } outt = bindtarget( t->boundname ); outt->flags |= T_FLAG_USEFILECACHE; outt->filecache_generate = t->filecache_generate; outt->filecache_use = t->filecache_use; outt->settings = addsettings( outt->settings, VAR_SET, "FILECACHE", list_new( L0, filecache->string, 1 ) ); MD5Final( outt->buildmd5sum, &context ); if (DEBUG_MD5HASH) { printf( "Cacheable: %s buildmd5: %s\n", t->boundname, md5tostring(outt->buildmd5sum) ); } /* if using cache is allowed */ if ( t->filecache_use && allcached ) { allcached = filecache_retrieve( t, outt->buildmd5sum ); } else { allcached = 0; } } else { allcached = 0; } } pushsettings( t->settings ); if ( !allcached ) { nt = make1list( L0, a0->action->targets, 0 ); ns = make1list( L0, a0->action->sources, rule->flags ); } } list_free( targets ); list_free( sources ); /* if no targets survived (all were retrieved from the cache) or no sources survived (all are up to date) */ if (nt==NULL) { // || ns==NULL) { /* skip this action */ list_free(ns); popsettings( t->settings ); for ( autot = autosettingsreverse; autot; autot = autot->next ) { if ( autot->target != t ) pushsettings( autot->target->settings ); } continue; } } else { #if 0 if ( strncmp( rule->name, "batched_", 8 ) == 0 ) { TARGETS* targets = a0->action->targets; TARGETS* sources = a0->action->sources; int anycacheable = 0; nt = L0; ns = L0; /* walk sources and targets simultaneously */ for( ; targets; targets = targets->next, sources = (sources==NULL?sources:sources->next) ) { TARGET *t = targets->target; TARGET *s = sources!=NULL ? sources->target : NULL; /* Sources to 'actions existing' are never in the dependency */ /* graph (if they were, they'd get built and 'existing' would */ /* be superfluous, so throttle warning message about independent */ /* targets. */ if( t->binding == T_BIND_UNBOUND ) make1bind( t, 0 ); if( s!=NULL) { if ( s->binding == T_BIND_UNBOUND ) make1bind( s, !( rule->flags & RULE_EXISTING ) ); if ( s->binding == T_BIND_UNBOUND ) printf("Warning using unbound source %s for batched action.\n", s->name); } if( ( rule->flags & RULE_EXISTING ) && s!=NULL && s->binding != T_BIND_EXISTS ) continue; if( t->fate < T_FATE_BUILD ) continue; /* Build new lists */ nt = list_new( nt, t->boundname, 1 ); if (s!=NULL) { ns = list_new( ns, s->boundname, 1 ); } } if (sources!=NULL) { printf("warning: more sources than targets in a batched action!\n"); } } else { #endif nt = make1list( L0, a0->action->targets, 0 ); ns = make1list( L0, a0->action->sources, rule->flags ); #if 0 } #endif } #else nt = make1list( L0, a0->action->targets, 0 ); ns = make1list( L0, a0->action->sources, rule->flags ); #endif if( rule->flags & RULE_TOGETHER ) for( a1 = a0->next; a1; a1 = a1->next ) #ifdef OPT_MULTIPASS_EXT if( a1->action->pass == actionpass && a1->action->rule == rule && !a1->action->running ) #else if( a1->action->rule == rule && !a1->action->running ) #endif { ns = make1list( ns, a1->action->sources, rule->flags ); a1->action->running = 1; #ifdef OPT_ACTIONS_WAIT_FIX a1->action->run_tgt = t; #endif } /* If doing only updated (or existing) sources, but none have */ /* been updated (or exist), skip this action. */ if( !ns && ( rule->flags & ( RULE_UPDATED | RULE_EXISTING ) ) ) { list_free( nt ); #ifdef OPT_DEBUG_MAKE1_LOG_EXT if (DEBUG_MAKE1) { const char* desc = 0; if ((rule->flags & (RULE_UPDATED | RULE_EXISTING)) == (RULE_UPDATED | RULE_EXISTING)) { desc = "updated/existing"; } else if (rule->flags & RULE_UPDATED) { desc = "updated"; } else if (rule->flags & RULE_EXISTING) { desc = "existing"; } printf( "make1cmds\t--\t%s (skipping actions by %s)\n" , rule->name, desc ); } #endif /* OPT_DEBUG_MAKE1_LOG_EXT */ popsettings( t->settings ); for ( autot = autosettingsreverse; autot; autot = autot->next ) { if ( autot->target != t ) pushsettings( autot->target->settings ); } continue; } /* If we had 'actions xxx bind vars' we bind the vars now */ boundvars = make1settings( rule->bindlist ); pushsettings( boundvars ); /* * Build command, starting with all source args. * * If cmd_new returns 0, it's because the resulting command * length is > MAXLINE. In this case, we'll slowly reduce * the number of source arguments presented until it does * fit. This only applies to actions that allow PIECEMEAL * commands. * * While reducing slowly takes a bit of compute time to get * things just right, it's worth it to get as close to MAXLINE * as possible, because launching the commands we're executing * is likely to be much more compute intensive! * * Note we loop through at least once, for sourceless actions. * * Max line length is the action specific maxline or, if not * given or bigger than MAXLINE, MAXLINE. */ start = 0; chunk = length = list_length( ns ); /* commented out so jamgram.y can compile #ifdef OPT_ACTION_MAXTARGETS_EXT */ maxline = rule->maxline; /* commented so jamgram.y can compile #else maxline = rule->flags / RULE_MAXLINE; #endif */ #ifdef OPT_PIECEMEAL_PUNT_EXT maxline = maxline && maxline < CMDBUF ? maxline : CMDBUF; #else maxline = maxline && maxline < MAXLINE ? maxline : MAXLINE; #endif do { /* Build cmd: cmd_new consumes its lists. */ /* commented out so jamgram.y can compile #ifdef OPT_ACTION_MAXTARGETS_EXT */ int thischunk = rule->maxtargets != 0 ? (chunk < rule->maxtargets ? chunk : rule->maxtargets) : chunk; CMD *cmd = cmd_new( rule, list_copy( L0, nt ), list_sublist( ns, start, thischunk ), list_copy( L0, shell ), maxline ); /* commented so jamgram.y can compile #else CMD *cmd = cmd_new( rule, list_copy( L0, nt ), list_sublist( ns, start, chunk ), list_copy( L0, shell ), maxline ); #endif */ if( cmd ) { /* It fit: chain it up. */ if( !cmds ) cmds = cmd; else cmds->tail->next = cmd; cmds->tail = cmd; /* commented out so jamgram.y can compile #ifdef OPT_ACTION_MAXTARGETS_EXT */ start += thischunk; /* commented out so jamgram.y can compile #else start += chunk; #endif */ } else if( ( rule->flags & RULE_PIECEMEAL ) && chunk > 1 ) { /* Reduce chunk size slowly. */ chunk = chunk * 9 / 10; } else { /* Too long and not splittable. */ #ifdef OPT_PIECEMEAL_PUNT_EXT if (maxline < CMDBUF) { maxline = CMDBUF; continue; } #endif printf( "%s actions too long (max %d)!\n", rule->name, maxline ); exit( EXITBAD ); } } while( start < length ); /* These were always copied when used. */ list_free( nt ); list_free( ns ); /* Free the variables whose values were bound by */ /* 'actions xxx bind vars' */ popsettings( boundvars ); freesettings( boundvars ); popsettings( t->settings ); for ( autot = autosettingsreverse; autot; autot = autot->next ) { if ( autot->target != t ) pushsettings( autot->target->settings ); } } return cmds; }
static void make1list_batched( MD5SUM *md5forcmd, LIST**plt, LIST**pls, TARGETS *targets, TARGETS *sources, int flags ) { /* walk sources and targets simultaneously */ for( ; targets; targets = targets->next, sources = (sources==NULL?sources:sources->next) ) { TARGET *t = targets->target; TARGET *s = sources!=NULL ? sources->target : NULL; if ( t->flags & T_FLAG_USEFILECACHE ) { LIST *filecache; pushsettings( t->settings ); filecache = var_get( "FILECACHE" ); if ( filecache ) { LIST *l; char *ptr; strcpy( filecache_buffer, "FILECACHE." ); strcat( filecache_buffer, filecache->string ); ptr = filecache_buffer + strlen( filecache_buffer ); strcat( ptr, ".USE" ); l = var_get( filecache_buffer ); if ( l && atoi( l->string ) != 0) { t->filecache_use = 1; } strcat( ptr, ".GENERATE" ); l = var_get( filecache_buffer ); if ( l && atoi( l->string ) != 0) { t->filecache_generate = 1; } } popsettings( t->settings ); } /* Sources to 'actions existing' are never in the dependency */ /* graph (if they were, they'd get built and 'existing' would */ /* be superfluous, so throttle warning message about independent */ /* targets. */ if( t->binding == T_BIND_UNBOUND ) make1bind( t, 0 ); if( s!=NULL) { if ( s->binding == T_BIND_UNBOUND ) make1bind( s, !( flags & RULE_EXISTING ) ); if ( s->binding == T_BIND_UNBOUND ) printf("Warning using unbound source %s for batched action.\n", s->name); } if( ( flags & RULE_EXISTING ) && s!=NULL && s->binding != T_BIND_EXISTS ) continue; if( t->fate < T_FATE_BUILD ) continue; /* if this target could be cacheable */ if ( (t->flags & T_FLAG_USEFILECACHE) && (t->filecache_generate || t->filecache_use) ) { /* find its final md5sum */ MD5_CTX context; MD5SUM buildsumorg; memcpy(&buildsumorg, &t->buildmd5sum, sizeof(t->buildmd5sum)); MD5Init( &context ); /* add the path of the file to the sum - it is significant because one command can create more than one file */ MD5Update( &context, t->name, strlen( t->name ) ); MD5Final( t->buildmd5sum, &context ); if (DEBUG_MD5HASH) { printf( "Cacheable: %s buildmd5: %s org: %s\n", t->boundname, md5tostring(t->buildmd5sum), md5tostring(buildsumorg) ); } } /* if this target could be cacheable */ if ( (t->flags & T_FLAG_USEFILECACHE) && (t->filecache_generate || t->filecache_use) ) { const char *cachedname; time_t cachedtime; /* if using cache is allowed */ if (t->filecache_use) { /* if the target is available in the cache */ cachedname = filecache_getfilename(t, t->buildmd5sum, ""); if (cachedname!=NULL) { if ( file_time( cachedname, &cachedtime ) == 0 ) { /* try to get it from the cache */ if (copyfile(t->boundname, cachedname, NULL)) { printf( "Using cached %s\n", t->boundname ); continue; } else { printf( "Cannot retrieve %s from cache (will build normally)\n", t->boundname ); } } else { if( DEBUG_MD5HASH) { printf( "Cannot find %s in cache as %s\n", t->boundname, cachedname ); } } } } } /* Build new lists */ *plt = list_new( *plt, t->boundname, 1 ); if (s!=NULL) { *pls = list_new( *pls, s->boundname, 1 ); } } if (sources!=NULL) { printf("warning: more sources than targets in a batched action!\n"); } }
void filecache_update(TARGET *t, MD5SUM buildmd5sum) { MD5SUM blobmd5sum; int haveblobmd5sum = 0; const char *cachedname; const char *blobname; int cacheerror; if (!t->filecache_generate) return; /* If the buildmd5sum is empty, then the file doesn't exist. */ cacheerror = ismd5empty(buildmd5sum); if (cacheerror) return; haveblobmd5sum = 0; cachedname = filecache_getfilename(t, buildmd5sum, NULL); if (!cachedname) return; /* Search for the appropriate .link file that matches the target. */ haveblobmd5sum = filecache_findlink(cachedname, blobmd5sum); /* If we weren't able to determine the target md5sum, do it now. */ if (!haveblobmd5sum) { getcachedmd5sum( t, 1 ); memcpy(blobmd5sum, t->contentchecksum->contentmd5sum, MD5_SUMSIZE); if (ismd5empty(t->contentchecksum->contentmd5sum)) return; } { /* Is the blob already there? */ time_t blobtime; blobname = filecache_getfilename(t, blobmd5sum, ".blob"); if (file_time(blobname, &blobtime) == -1) { time_t blobpartialtime; const char *blobpartialname; if(DEBUG_MD5HASH) printf("Caching %s as %s\n", t->name, cachedname); else printf("Caching %s\n", t->name); /* Write the new .blob to the cache. */ blobpartialname = filecache_getfilename(t, blobmd5sum, ".blob.partial"); if (file_time(blobpartialname, &blobpartialtime) == -1) { if (copyfile(blobpartialname, t->boundname, &blobmd5sum) == 0 || rename(blobpartialname, blobname) != 0) { printf("** Unable to write %s to cache.\n", t->name); filecache_disable(t); return; } } } } /* Write the new .link file to the cache. */ { FILE *file; BUFFER linknamebuff; buffer_init(&linknamebuff); buffer_addstring(&linknamebuff, cachedname, strlen(cachedname)); buffer_addchar(&linknamebuff, '-'); buffer_addstring(&linknamebuff, md5tostring(blobmd5sum), 32); buffer_addstring(&linknamebuff, ".link", 5); buffer_addchar(&linknamebuff, 0); file_mkdir(buffer_ptr(&linknamebuff)); file = fopen(buffer_ptr(&linknamebuff), "wb"); if (file) { write_md5sum(file, blobmd5sum); write_string(file, t->name); fclose(file); } buffer_free(&linknamebuff); } }