Port the SB128 code to AROS.
[AROS.git] / tools / MetaMake / cache.c
blobcaa882c9f9f67e0618f7fd22047eb43f6a5f76a1
1 /* MetaMake - A Make extension
2 Copyright © 1995-2009, 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"
50 #include "win32.h"
52 #if defined(DEBUG_CACHE)
53 #define debug(a) a
54 #else
55 #define debug(v)
56 #endif
58 #define MAJOR 0L
59 #define MINOR 9L
60 #define REVISION 0L
61 #define ID ((MAJOR << 24) | (MINOR << 16) | REVISION)
62 #define CHECK_ID(id) (((id) & 0xFFFF0000) == ((ID) & 0xFFFF0000))
64 struct Cache_priv
66 struct Cache publicpart;
67 struct Project * project;
68 struct DirNode * topdir;
69 struct List addedfiles;
72 struct Regenerate
74 struct Node node;
76 char *dir;
77 char *src;
78 char *dest;
82 static void
83 freetarget (struct Target * target)
85 xfree (target->node.name);
87 freelist (&target->makefiles);
89 xfree (target);
92 static void
93 freetargetlist (struct Cache_priv * cache)
95 struct Node * node, * next;
97 ForeachNodeSafe(&cache->publicpart.targets,node,next)
99 Remove (node);
100 freetarget ((struct Target *)node);
104 static void
105 printtargetlist (struct List * l)
107 struct Target * n;
109 ForeachNode (l,n)
111 struct List deps;
112 struct MakefileRef * mfref;
113 struct MakefileTarget * mftarget;
114 struct Node * node;
116 printf ("target %s:\n", n->node.name);
117 printf (" updated=%d\n", n->updated);
118 printf (" makefiles=\n");
119 ForeachNode (&n->makefiles, mfref)
120 printf(" \"%s/%s\"\n",
121 buildpath(mfref->makefile->dir),
122 mfref->makefile->node.name
125 printf (" deps=\n");
126 NewList (&deps);
127 ForeachNode (&n->makefiles, mfref)
129 mftarget = FindNode (&mfref->makefile->targets, n->node.name);
130 ForeachNode (&mftarget->deps, node)
131 addnodeonce (&deps, node->name);
134 printlist (&deps);
135 freelist (&deps);
140 static int progcount;
141 static int token;
142 static char tokens[]="|/-\\";
144 static void
145 progress_reset (FILE * fh)
147 progcount = 0;
148 token = 0;
149 fprintf (fh, "\r|\r");
150 fflush (fh);
153 static void
154 progress (FILE * fh)
156 progcount++;
157 if (progcount == 13)
159 progcount = 0;
160 token++;
161 if (token == 4)
162 token = 0;
163 fprintf (fh, "%c\r", tokens[token]);
164 fflush (fh);
169 void
170 readcache (struct Cache_priv * cache)
172 char path[256];
173 FILE * fh;
174 uint32_t id;
176 strcpy (path, cache->project->buildtop);
177 strcat (path, "/mmake.cache");
178 assert (strlen(path) < sizeof(path));
180 fh = fopen (path, "rb");
182 if (fh)
184 if (!readuint32 (fh, &id) || !CHECK_ID(id))
186 fclose (fh);
187 fh = NULL;
191 if (fh)
193 char * name;
197 if (!readstring (fh, &name))
199 fh = NULL;
200 break;
203 if (name == NULL)
204 continue;
206 addnodeonce (&cache->addedfiles, name);
207 xfree (name);
209 while (name != NULL);
211 if (!(cache->topdir = readcachedir (fh)))
213 fclose (fh);
214 fh = NULL;
218 if (!fh)
220 cache->topdir = newnodesize (cache->project->srctop, sizeof (struct DirNode));
221 cache->topdir->parent = NULL;
222 NewList(&cache->topdir->subdirs);
223 NewList(&cache->topdir->makefiles);
225 /* Force a check the first time */
226 cache->topdir->time = 0;
229 if (fh)
230 fclose (fh);
232 if (debug)
234 printf ("readcache()\n");
235 printdirnode (cache->topdir, 1);
239 void
240 writecache (struct Cache_priv * cache)
242 int ok = 1;
243 char path[256];
244 FILE * fh = NULL;
245 uint32_t id;
246 struct Node *addedfile;
248 debug(printf("MMAKE:cache.c->writecache()\n"));
250 if (!cache->topdir)
251 return;
253 strcpy (path, cache->project->buildtop);
254 strcat (path, "/mmake.cache");
255 assert (strlen(path) < sizeof(path));
257 fh = fopen (path, "wb");
259 if (!fh)
261 ok = 0;
262 goto writecacheend;
265 ok = writeuint32 (fh, ID);
266 if (!ok)
267 goto writecacheend;
269 ForeachNode (&cache->addedfiles, addedfile)
271 ok = writestring (fh, addedfile->name);
272 if (!ok)
274 error ("writecache/writestring():%d", __LINE__);
275 goto writecacheend;
279 ok = writestring (fh, NULL);
280 if (!ok)
282 error("writecache/fwrite():%d", __LINE__);
283 goto writecacheend;
286 ok = writecachedir (fh, cache->topdir);
288 writecacheend:
289 if (fh)
290 fclose (fh);
292 if (!ok)
294 unlink (path);
296 printf ("Warning: Creating the cache failed\n");
301 void
302 checknewsrc (struct Cache_priv * cache, struct Makefile * makefile, struct List * regeneratefiles)
304 char * mfsrc = xmalloc (strlen (makefile->node.name) + 5);
305 char * mfdst = xmalloc (strlen (mm_builddir) + 1 + strlen (buildpath(makefile->dir)) + 1 + strlen (makefile->node.name) + 1);
306 struct stat sst, dst;
308 debug(printf("MMAKE:cache.c->checknewsrc('%s')\n", makefile->node.name));
310 strcpy (mfsrc, makefile->node.name);
311 strcat (mfsrc, ".src");
313 if (stat (mfsrc, &sst) == -1)
315 xfree (mfsrc);
316 return;
319 strcpy (mfdst, mm_builddir);
320 strcat (mfdst, "/");
321 strcat (mfdst, buildpath(makefile->dir));
322 strcat (mfdst, "/");
323 strcat (mfdst, makefile->node.name);
325 if (stat (mfdst, &dst) == -1
326 || sst.st_mtime > dst.st_mtime
327 || checkdeps (&cache->project->genmakefiledeps, dst.st_mtime)
330 static char currdir[PATH_MAX];
331 struct Regenerate *reg = new (struct Regenerate);
333 getcwd(currdir, PATH_MAX);
334 reg->dir = xstrdup (buildpath(makefile->dir));
335 reg->src = mfsrc;
336 reg->dest = xstrdup (makefile->node.name);
338 AddTail (regeneratefiles, reg);
340 else
342 xfree (mfsrc);
348 updatemflist (struct Cache_priv * cache, struct DirNode * node, struct List * regeneratefiles)
350 struct DirNode * subdir;
351 struct Makefile * makefile;
352 int goup = 0, reread = 0;
353 char curdir[1024];
355 debug(printf("MMAKE:cache.c->updatemflist()\n"));
357 if (strlen(node->node.name) != 0)
359 if (getcwd(curdir, sizeof(curdir)) == NULL)
361 error("Could not get current directory");
362 exit (20);
364 if (chdir(node->node.name) < 0)
366 error("Could not change to dir '%s'", node->node.name);
367 exit (20);
369 goup = 1;
372 if (scandirnode(node, cache->project->defaultmakefilename, &cache->project->ignoredirs))
373 reread ++;
375 ForeachNode(&node->subdirs, subdir)
377 debug(printf("MMAKE:cache.c->updatemflist: checking subdir ..\n"));
378 reread += updatemflist(cache, subdir, regeneratefiles);
381 ForeachNode(&node->makefiles, makefile)
383 debug(printf("MMAKE:cache.c->updatemflist: checking makefile ..\n"));
384 checknewsrc(cache, makefile, regeneratefiles);
387 if (goup)
388 chdir(curdir);
390 progress (stdout);
392 return reread;
396 updatetargetlist (struct Project * prj, struct Cache_priv * cache, struct DirNode * node)
398 struct DirNode * subdir;
399 int reread = 0;
401 debug(printf("MMAKE:cache.c->updatetargetlist('%s')\n", node->node.name));
403 reread = scanmakefiles(prj, node, &cache->project->vars);
405 ForeachNode(&node->subdirs, subdir)
406 reread += updatetargetlist(prj, cache, subdir);
408 progress (stdout);
410 return reread;
413 #ifdef _WIN32
415 int mktempfile(char **name)
417 char *temp = getenv("TEMP");
418 size_t pathlen = strlen(temp) + 13;
419 char *path = xmalloc(pathlen);
421 strcpy(path, temp);
422 strcat(path, "\\genmfXXXXXX");
423 *name = path;
424 return mkstemps(path, 0);
427 #else
429 int mktempfile(char **name)
431 static char tmpname[20];
433 strcpy(tmpname, "/tmp/genmfXXXXXX");
434 *name = tmpname;
435 return mkstemp(tmpname);
438 #endif
441 void
442 regeneratemf (struct Cache_priv * cache, struct List * regeneratefiles)
444 struct Regenerate * reg,* reg2;
445 char *tmpname;
446 int fd;
447 FILE *f;
449 debug(printf("MMAKE:cache.c->regeneratemf()\n"));
451 if (GetHead (regeneratefiles) == NULL)
452 return;
454 fd = mktempfile(&tmpname);
455 if (fd < 0)
457 error ("Could not create temporary file %s", tmpname);
458 exit (10);
460 else
462 f = fdopen (fd, "w");
463 if (f == NULL)
465 error ("Could not open temporary file %s", tmpname);
466 exit (10);
470 ForeachNodeSafe (regeneratefiles, reg, reg2)
472 char * mfsrc = xmalloc (strlen(cache->project->srctop) + strlen(reg->dir) + strlen(reg->src) + 3);
473 char * mfdst = xmalloc (strlen(cache->project->buildtop) + strlen(reg->dir) + strlen(reg->dest) + 3);
475 strcpy (mfsrc, cache->project->srctop);
476 if (strlen(reg->dir) > 0)
478 strcat (mfsrc, "/");
479 strcat (mfsrc, reg->dir);
481 strcat (mfsrc, "/");
482 strcat (mfsrc, reg->src);
484 strcpy (mfdst, cache->project->buildtop);
485 if (strlen(reg->dir) > 0)
487 strcat (mfdst, "/");
488 strcat (mfdst, reg->dir);
490 strcat (mfdst, "/");
491 strcat (mfdst, reg->dest);
493 debug(printf("MMAKE:cache.c->regeneratemf: regenerate '%s' as '%s'\n", mfsrc, mfdst));
495 fprintf (f, "%s %s\n", mfsrc, mfdst);
496 Remove (reg);
497 xfree (mfsrc);
498 xfree (mfdst);
500 xfree (reg->dir);
501 xfree (reg->src);
502 xfree (reg->dest);
503 xfree (reg);
506 fclose (f);
508 setvar (&cache->project->vars, "MMLIST", tmpname);
509 if (!execute (cache->project, cache->project->genmakefilescript,"-","-",""))
511 error ("Error regenerating makefile");
512 exit (10);
515 debug(printf("MMAKE:cache.c->regeneratemf: Finished\n"));
517 unlink (tmpname);
520 void
521 buildtargetlist (struct Cache_priv * cache, struct DirNode * node)
523 struct Makefile * makefile;
524 struct MakefileRef * mfref;
525 struct MakefileTarget * mftarget;
526 struct DirNode * subdir;
527 struct Target * target;
528 struct Node * n;
530 debug(printf("MMAKE:cache.c->buildtargetlist()\n"));
532 ForeachNode (&node->makefiles, makefile)
534 ForeachNode (&makefile->targets, mftarget)
536 if (strchr (mftarget->node.name, '$') != NULL)
538 char * s = substvars(&cache->project->vars, mftarget->node.name);
539 SETSTR (mftarget->node.name, s);
542 ForeachNode (&mftarget->deps, n)
544 if (strchr (n->name, '$') != NULL)
546 char * s = substvars(&cache->project->vars, n->name);
547 SETSTR (n->name, s);
551 target = FindNode (&cache->publicpart.targets, mftarget->node.name);
553 if (target == NULL)
555 target = newnodesize (mftarget->node.name, sizeof(struct Target));
556 target->updated = 0;
557 NewList (&target->makefiles);
558 AddTail (&cache->publicpart.targets, target);
561 mfref = newnodesize ("", sizeof(struct MakefileRef));
562 mfref->virtualtarget = mftarget->virtualtarget;
563 mfref->makefile = makefile;
564 AddTail (&target->makefiles, mfref);
568 ForeachNode (&node->subdirs, subdir)
569 buildtargetlist (cache, subdir);
572 struct Cache *
573 activatecache (struct Project *prj)
575 struct Cache_priv * cache;
576 struct List regeneratefiles;
577 struct Node * addedfile, * extrafile;
578 struct Makefile * makefile;
579 struct List newadded;
580 int reread;
582 debug(printf("MMAKE:cache.c->activatecache(Project @ %x)\n", prj));
584 cache = new (struct Cache_priv);
585 if (!cache)
586 return NULL;
587 NewList (&regeneratefiles);
589 cache->project = prj;
591 debug(printf("MMAKE:cache.c->activatecache: Cache @ %x for Project @ %x\n", cache, prj));
593 NewList (&cache->addedfiles);
594 NewList (&cache->publicpart.targets);
596 readcache (cache);
598 debug(printf("MMAKE:cache.c->activatecache: Cache read.\n"));
600 progress_reset (stdout);
601 printf ("Scanning dirs...\n");
602 reread = updatemflist (cache, cache->topdir, &regeneratefiles);
604 debug(printf("MMAKE:cache.c->activatecache: Updated MF list.\n"));
606 if (verbose)
607 printf ("Reread %d dirs\n", reread);
609 if (debug)
611 printf ("Directory tree for project %s\n", prj->node.name);
612 printdirnode (cache->topdir, 0);
615 /* Add the extra makefiles to the tree if needed */
616 chdir (cache->project->buildtop);
617 NewList (&newadded);
618 ForeachNode (&cache->project->extramakefiles, extrafile)
620 addedfile = FindNode (&cache->addedfiles, extrafile->name);
621 if (addedfile == NULL)
623 makefile = addmakefile (cache->topdir, extrafile->name);
625 if (makefile == NULL)
627 error("Could not add makefile \"%s\"", extrafile->name);
628 exit (20);
631 addnodeonce (&newadded, extrafile->name);
633 else /* addedfile != NULL => was already added before */
635 makefile = findmakefile (cache->topdir, extrafile->name);
637 if (makefile == NULL)
639 error("Makefile \"%s\" has disappeared", extrafile->name);
640 exit (20);
643 Remove (addedfile);
644 AddTail (&newadded, addedfile);
647 ForeachNode (&cache->addedfiles, addedfile)
649 makefile = findmakefile (cache->topdir, addedfile->name);
650 if (makefile != NULL)
652 Remove (makefile);
653 freemakefile (makefile);
656 AssignList (&cache->addedfiles, &newadded);
658 regeneratemf (cache, &regeneratefiles);
660 debug(printf("MMAKE:cache.c->activatecache: Regenerated MFs\n"));
662 progress_reset (stdout);
663 printf ("Scanning makefiles...\n");
664 reread = updatetargetlist (prj, cache, cache->topdir);
665 if (verbose)
666 printf ("Reread %d makefiles\n", reread);
667 if (debug)
669 printf ("Makefile and target tree for project %s\n", prj->node.name);
670 printdirnodemftarget (cache->topdir);
673 writecache (cache);
675 printf ("Collecting targets...\n");
676 buildtargetlist (cache, cache->topdir);
677 if (debug)
679 printf ("Targetlist of project %s\n", prj->node.name);
680 printtargetlist (&cache->publicpart.targets);
683 debug(printf("MMAKE:cache.c->activatecache: Finished\n"));
685 return (struct Cache *)cache;
688 void
689 closecache (struct Cache * gl_cache)
691 struct Cache_priv * cache = (struct Cache_priv *)gl_cache;
693 freetargetlist (cache);