Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / tools / MetaMake / cache.c
bloba0760fa9141a805bcf5029bd11673caa7eadef2f
1 /* MetaMake - A Make extension
2 Copyright © 1995-2008, The AROS Development Team. All rights reserved.
4 This file is part of MetaMake.
6 MetaMake is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 MetaMake is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU CC; see the file COPYING. If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 //#define DEBUG_CACHE
23 #include "config.h"
25 #ifdef HAVE_STRING_H
26 # include <string.h>
27 #else
28 # include <strings.h>
29 #endif
30 #ifdef HAVE_SYS_STAT_H
31 # include <sys/stat.h>
32 #endif
33 #ifdef HAVE_NETINET_IN_H
34 # include <netinet/in.h> /* for htonl/ntohl() */
35 #endif
36 #include <errno.h>
37 #include <assert.h>
38 #include <unistd.h>
39 #include <stdlib.h>
40 #ifndef PATH_MAX
41 #include <limits.h>
42 #endif
44 #include "cache.h"
45 #include "mem.h"
46 #include "io.h"
47 #include "var.h"
48 #include "dep.h"
49 #include "mmake.h"
51 #if defined(DEBUG_CACHE)
52 #define debug(a) a
53 #else
54 #define debug(v)
55 #endif
57 #define MAJOR 0L
58 #define MINOR 9L
59 #define REVISION 0L
60 #define ID ((MAJOR << 24) | (MINOR << 16) | REVISION)
61 #define CHECK_ID(id) (((id) & 0xFFFF0000) == ((ID) & 0xFFFF0000))
63 extern char *mm_srcdir;
64 extern char *mm_builddir;
66 typedef struct {
67 Cache publicpart;
69 Project * project;
71 DirNode * topdir;
73 List addedfiles;
75 Cache_priv;
77 typedef struct
79 Node node;
81 char *dir;
82 char *src;
83 char *dest;
85 Regenerate;
88 static void
89 freetarget (Target * target)
91 xfree (target->node.name);
93 freelist (&target->makefiles);
95 xfree (target);
98 static void
99 freetargetlist (Cache_priv * cache)
101 Node * node, * next;
103 ForeachNodeSafe(&cache->publicpart.targets,node,next)
105 Remove (node);
106 freetarget ((Target *)node);
110 static void
111 printtargetlist (List * l)
113 Target * n;
115 ForeachNode (l,n)
117 List deps;
118 MakefileRef * mfref;
119 MakefileTarget * mftarget;
120 Node * node;
122 printf ("target %s:\n", n->node.name);
123 printf (" updated=%d\n", n->updated);
124 printf (" makefiles=\n");
125 ForeachNode (&n->makefiles, mfref)
126 printf(" \"%s/%s\"\n",
127 buildpath(mfref->makefile->dir),
128 mfref->makefile->node.name
131 printf (" deps=\n");
132 NewList (&deps);
133 ForeachNode (&n->makefiles, mfref)
135 mftarget = FindNode (&mfref->makefile->targets, n->node.name);
136 ForeachNode (&mftarget->deps, node)
137 addnodeonce (&deps, node->name);
140 printlist (&deps);
141 freelist (&deps);
146 static int progcount;
147 static int token;
148 static char tokens[]="|/-\\";
150 static void
151 progress_reset (FILE * fh)
153 progcount = 0;
154 token = 0;
155 fprintf (fh, "\r|\r");
156 fflush (fh);
159 static void
160 progress (FILE * fh)
162 progcount++;
163 if (progcount == 13)
165 progcount = 0;
166 token++;
167 if (token == 4)
168 token = 0;
169 fprintf (fh, "%c\r", tokens[token]);
170 fflush (fh);
175 void
176 readcache (Cache_priv * cache)
178 char path[256];
179 FILE * fh;
180 uint32_t id;
182 strcpy (path, cache->project->buildtop);
183 strcat (path, "/mmake.cache");
184 assert (strlen(path) < sizeof(path));
186 fh = fopen (path, "r");
188 if (fh)
190 if (!readuint32 (fh, &id) || !CHECK_ID(id))
192 fclose (fh);
193 fh = NULL;
197 if (fh)
199 char * name;
203 if (!readstring (fh, &name))
205 fh = NULL;
206 break;
209 if (name == NULL)
210 continue;
212 addnodeonce (&cache->addedfiles, name);
213 xfree (name);
215 while (name != NULL);
217 if (!(cache->topdir = readcachedir (fh)))
219 fclose (fh);
220 fh = NULL;
224 if (!fh)
226 cache->topdir = newnodesize (cache->project->srctop, sizeof (DirNode));
227 cache->topdir->parent = NULL;
228 NewList(&cache->topdir->subdirs);
229 NewList(&cache->topdir->makefiles);
231 /* Force a check the first time */
232 cache->topdir->time = 0;
235 if (fh)
236 fclose (fh);
238 if (debug)
240 printf ("readcache()\n");
241 printdirnode (cache->topdir, 1);
245 void
246 writecache (Cache_priv * cache)
248 int ok = 1;
249 char path[256];
250 FILE * fh = NULL;
251 uint32_t id;
252 Node *addedfile;
254 debug(printf("MMAKE:cache.c->writecache()\n"));
256 if (!cache->topdir)
257 return;
259 strcpy (path, cache->project->buildtop);
260 strcat (path, "/mmake.cache");
261 assert (strlen(path) < sizeof(path));
263 fh = fopen (path, "w");
265 if (!fh)
267 ok = 0;
268 goto writecacheend;
271 ok = writeuint32 (fh, ID);
272 if (!ok)
273 goto writecacheend;
275 ForeachNode (&cache->addedfiles, addedfile)
277 ok = writestring (fh, addedfile->name);
278 if (!ok)
280 error ("writecache/writestring():%d", __LINE__);
281 goto writecacheend;
285 ok = writestring (fh, NULL);
286 if (!ok)
288 error("writecache/fwrite():%d", __LINE__);
289 goto writecacheend;
292 ok = writecachedir (fh, cache->topdir);
294 writecacheend:
295 if (fh)
296 fclose (fh);
298 if (!ok)
300 unlink (path);
302 printf ("Warning: Creating the cache failed\n");
307 void
308 checknewsrc (Cache_priv * cache, Makefile * makefile, List * regeneratefiles)
310 char * mfsrc = xmalloc (strlen (makefile->node.name) + 5);
311 char * mfdst = xmalloc (strlen (mm_builddir) + 1 + strlen (buildpath(makefile->dir)) + 1 + strlen (makefile->node.name) + 1);
312 struct stat sst, dst;
314 debug(printf("MMAKE:cache.c->checknewsrc('%s')\n", makefile->node.name));
316 strcpy (mfsrc, makefile->node.name);
317 strcat (mfsrc, ".src");
319 if (stat (mfsrc, &sst) == -1)
321 xfree (mfsrc);
322 return;
325 strcpy (mfdst, mm_builddir);
326 strcat (mfdst, "/");
327 strcat (mfdst, buildpath(makefile->dir));
328 strcat (mfdst, "/");
329 strcat (mfdst, makefile->node.name);
331 if (stat (mfdst, &dst) == -1
332 || sst.st_mtime > dst.st_mtime
333 || checkdeps (&cache->project->genmakefiledeps, dst.st_mtime)
336 static char currdir[PATH_MAX];
337 Regenerate *reg = new (Regenerate);
339 getcwd(currdir, PATH_MAX);
340 reg->dir = xstrdup (buildpath(makefile->dir));
341 reg->src = mfsrc;
342 reg->dest = xstrdup (makefile->node.name);
344 AddTail (regeneratefiles, reg);
346 else
348 xfree (mfsrc);
354 updatemflist (Cache_priv * cache, DirNode * node, List * regeneratefiles)
356 DirNode * subdir;
357 Makefile * makefile;
358 int goup = 0, reread = 0;
359 char curdir[1024];
361 debug(printf("MMAKE:cache.c->updatemflist()\n"));
363 if (strlen(node->node.name) != 0)
365 if (getcwd(curdir, sizeof(curdir)) == NULL)
367 error("Could not get current directory");
368 exit (20);
370 if (chdir(node->node.name) < 0)
372 error("Could not change to dir '%s'", node->node.name);
373 exit (20);
375 goup = 1;
378 if (scandirnode(node, cache->project->defaultmakefilename, &cache->project->ignoredirs))
379 reread ++;
381 ForeachNode(&node->subdirs, subdir)
383 debug(printf("MMAKE:cache.c->updatemflist: checking subdir ..\n"));
384 reread += updatemflist(cache, subdir, regeneratefiles);
387 ForeachNode(&node->makefiles, makefile)
389 debug(printf("MMAKE:cache.c->updatemflist: checking makefile ..\n"));
390 checknewsrc(cache, makefile, regeneratefiles);
393 if (goup)
394 chdir(curdir);
396 progress (stdout);
398 return reread;
402 updatetargetlist (Cache_priv * cache, DirNode * node)
404 DirNode * subdir;
405 int reread = 0;
407 debug(printf("MMAKE:cache.c->updatetargetlist('%s')\n", node->node.name));
409 reread = scanmakefiles(node, &cache->project->vars);
411 ForeachNode(&node->subdirs, subdir)
412 reread += updatetargetlist(cache, subdir);
414 progress (stdout);
416 return reread;
420 void
421 regeneratemf (Cache_priv * cache, List * regeneratefiles)
423 Regenerate * reg,* reg2;
424 char tmpname[20];
425 int fd;
426 FILE *f;
428 debug(printf("MMAKE:cache.c->regeneratemf()\n"));
430 if (GetHead (regeneratefiles) == NULL)
431 return;
433 strcpy (tmpname, "/tmp/genmfXXXXXX");
434 fd = mkstemp (tmpname);
435 if (fd < 0)
437 error ("Could not create temporary file %s", tmpname);
438 exit (10);
440 else
442 f = fdopen (fd, "w");
443 if (f == NULL)
445 error ("Could not open temporary file %s", tmpname);
446 exit (10);
450 ForeachNodeSafe (regeneratefiles, reg, reg2)
452 char * mfsrc = xmalloc (strlen(cache->project->srctop) + strlen(reg->dir) + strlen(reg->src) + 3);
453 char * mfdst = xmalloc (strlen(cache->project->buildtop) + strlen(reg->dir) + strlen(reg->dest) + 3);
455 strcpy (mfsrc, cache->project->srctop);
456 if (strlen(reg->dir) > 0)
458 strcat (mfsrc, "/");
459 strcat (mfsrc, reg->dir);
461 strcat (mfsrc, "/");
462 strcat (mfsrc, reg->src);
464 strcpy (mfdst, cache->project->buildtop);
465 if (strlen(reg->dir) > 0)
467 strcat (mfdst, "/");
468 strcat (mfdst, reg->dir);
470 strcat (mfdst, "/");
471 strcat (mfdst, reg->dest);
473 debug(printf("MMAKE:cache.c->regeneratemf: regenerate '%s' as '%s'\n", mfsrc, mfdst));
475 fprintf (f, "%s %s\n", mfsrc, mfdst);
476 Remove (reg);
477 xfree (mfsrc);
478 xfree (mfdst);
480 xfree (reg->dir);
481 xfree (reg->src);
482 xfree (reg->dest);
483 xfree (reg);
486 fclose (f);
488 setvar (&cache->project->vars, "MMLIST", tmpname);
489 if (!execute (cache->project, cache->project->genmakefilescript,"-","-",""))
491 error ("Error regenerating makefile");
492 exit (10);
495 debug(printf("MMAKE:cache.c->regeneratemf: Finished\n"));
497 unlink (tmpname);
500 void
501 buildtargetlist (Cache_priv * cache, DirNode * node)
503 Makefile * makefile;
504 MakefileRef * mfref;
505 MakefileTarget * mftarget;
506 DirNode * subdir;
507 Target * target;
508 Node * n;
510 debug(printf("MMAKE:cache.c->buildtargetlist()\n"));
512 ForeachNode (&node->makefiles, makefile)
514 ForeachNode (&makefile->targets, mftarget)
516 if (strchr (mftarget->node.name, '$') != NULL)
518 char * s = substvars(&cache->project->vars, mftarget->node.name);
519 SETSTR (mftarget->node.name, s);
522 ForeachNode (&mftarget->deps, n)
524 if (strchr (n->name, '$') != NULL)
526 char * s = substvars(&cache->project->vars, n->name);
527 SETSTR (n->name, s);
531 target = FindNode (&cache->publicpart.targets, mftarget->node.name);
533 if (target == NULL)
535 target = newnodesize (mftarget->node.name, sizeof(Target));
536 target->updated = 0;
537 NewList (&target->makefiles);
538 AddTail (&cache->publicpart.targets, target);
541 mfref = newnodesize ("", sizeof(MakefileRef));
542 mfref->virtualtarget = mftarget->virtualtarget;
543 mfref->makefile = makefile;
544 AddTail (&target->makefiles, mfref);
548 ForeachNode (&node->subdirs, subdir)
549 buildtargetlist (cache, subdir);
552 Cache *
553 activatecache (Project *prj)
555 Cache_priv * cache;
556 List regeneratefiles;
557 Node * addedfile, * extrafile;
558 Makefile * makefile;
559 List newadded;
560 int reread;
562 debug(printf("MMAKE:cache.c->activatecache(Project @ %x)\n", prj));
564 cache = new (Cache_priv);
565 if (!cache)
566 return NULL;
567 NewList (&regeneratefiles);
569 cache->project = prj;
571 debug(printf("MMAKE:cache.c->activatecache: Cache @ %x for Project @ %x\n", cache, prj));
573 NewList (&cache->addedfiles);
574 NewList (&cache->publicpart.targets);
576 readcache (cache);
578 debug(printf("MMAKE:cache.c->activatecache: Cache read.\n"));
580 progress_reset (stdout);
581 printf ("Scanning dirs...\n");
582 reread = updatemflist (cache, cache->topdir, &regeneratefiles);
584 debug(printf("MMAKE:cache.c->activatecache: Updated MF list.\n"));
586 if (verbose)
587 printf ("Reread %d dirs\n", reread);
589 if (debug)
591 printf ("Directory tree for project %s\n", prj->node.name);
592 printdirnode (cache->topdir, 0);
595 /* Add the extra makefiles to the tree if needed */
596 chdir (cache->project->buildtop);
597 NewList (&newadded);
598 ForeachNode (&cache->project->extramakefiles, extrafile)
600 addedfile = FindNode (&cache->addedfiles, extrafile->name);
601 if (addedfile == NULL)
603 makefile = addmakefile (cache->topdir, extrafile->name);
605 if (makefile == NULL)
607 error("Could not add makefile \"%s\"", extrafile->name);
608 exit (20);
611 addnodeonce (&newadded, extrafile->name);
613 else /* addedfile != NULL => was already added before */
615 makefile = findmakefile (cache->topdir, extrafile->name);
617 if (makefile == NULL)
619 error("Makefile \"%s\" has disappeared", extrafile->name);
620 exit (20);
623 Remove (addedfile);
624 AddTail (&newadded, addedfile);
627 ForeachNode (&cache->addedfiles, addedfile)
629 makefile = findmakefile (cache->topdir, addedfile->name);
630 if (makefile != NULL)
632 Remove (makefile);
633 freemakefile (makefile);
636 AssignList (&cache->addedfiles, &newadded);
638 regeneratemf (cache, &regeneratefiles);
640 debug(printf("MMAKE:cache.c->activatecache: Regenerated MFs\n"));
642 progress_reset (stdout);
643 printf ("Scanning makefiles...\n");
644 reread = updatetargetlist (cache, cache->topdir);
645 if (verbose)
646 printf ("Reread %d makefiles\n", reread);
647 if (debug)
649 printf ("Makefile and target tree for project %s\n", prj->node.name);
650 printdirnodemftarget (cache->topdir);
653 writecache (cache);
655 printf ("Collecting targets...\n");
656 buildtargetlist (cache, cache->topdir);
657 if (debug)
659 printf ("Targetlist of project %s\n", prj->node.name);
660 printtargetlist (&cache->publicpart.targets);
663 debug(printf("MMAKE:cache.c->activatecache: Finished\n"));
665 return (Cache *)cache;
668 void
669 closecache (Cache * gl_cache)
671 Cache_priv * cache = (Cache_priv *)gl_cache;
673 freetargetlist (cache);