re-order some parts of the code so that the msg and rect are only allocated once.
[AROS.git] / tools / MetaMake / cache.c
blob0b5559494c54a35f372f325052c8a4f4e6c03bcf
1 /* MetaMake - A Make extension
2 Copyright © 1995-2019, 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;
142 static void
143 progress_reset (FILE * fh)
145 progcount = 0;
146 fprintf(fh, "\n");
149 static void
150 progress (FILE * fh)
152 progcount++;
153 if (progcount == 20)
155 progcount = 0;
156 fprintf(fh, ".");
157 fflush (fh);
162 void
163 readcache (struct Cache_priv * cache)
165 char path[256];
166 FILE * fh;
167 uint32_t id;
169 strcpy (path, cache->project->buildtop);
170 strcat (path, "/mmake.cache");
171 assert (strlen(path) < sizeof(path));
173 fh = fopen (path, "rb");
175 if (fh)
177 if (!readuint32 (fh, &id) || !CHECK_ID(id))
179 fclose (fh);
180 fh = NULL;
184 if (fh)
186 char * name;
190 if (!readstring (fh, &name))
192 fh = NULL;
193 break;
196 if (name == NULL)
197 continue;
199 addnodeonce (&cache->addedfiles, name);
200 xfree (name);
202 while (name != NULL);
204 if (!(cache->topdir = readcachedir (fh)))
206 fclose (fh);
207 fh = NULL;
211 if (!fh)
213 cache->topdir = newnodesize (cache->project->srctop, sizeof (struct DirNode));
214 cache->topdir->parent = NULL;
215 NewList(&cache->topdir->subdirs);
216 NewList(&cache->topdir->makefiles);
218 /* Force a check the first time */
219 cache->topdir->time = 0;
222 if (fh)
223 fclose (fh);
225 if (debug)
227 printf ("readcache()\n");
228 printdirnode (cache->topdir, 1);
232 void
233 writecache (struct Cache_priv * cache)
235 int ok = 1;
236 char path[256];
237 FILE * fh = NULL;
238 uint32_t id;
239 struct Node *addedfile;
241 debug(printf("MMAKE:cache.c->writecache()\n"));
243 if (!cache->topdir)
244 return;
246 strcpy (path, cache->project->buildtop);
247 strcat (path, "/mmake.cache");
248 assert (strlen(path) < sizeof(path));
250 fh = fopen (path, "wb");
252 if (!fh)
254 ok = 0;
255 goto writecacheend;
258 ok = writeuint32 (fh, ID);
259 if (!ok)
260 goto writecacheend;
262 ForeachNode (&cache->addedfiles, addedfile)
264 ok = writestring (fh, addedfile->name);
265 if (!ok)
267 error ("writecache/writestring():%d", __LINE__);
268 goto writecacheend;
272 ok = writestring (fh, NULL);
273 if (!ok)
275 error("writecache/fwrite():%d", __LINE__);
276 goto writecacheend;
279 ok = writecachedir (fh, cache->topdir);
281 writecacheend:
282 if (fh)
283 fclose (fh);
285 if (!ok)
287 unlink (path);
289 printf ("[MMAKE] %s: Warning! - Creating the cache failed\n", __func__);
294 void
295 checknewsrc (struct Cache_priv * cache, struct Makefile * makefile, struct List * regeneratefiles)
297 char * mfsrc = xmalloc (strlen (makefile->node.name) + 5);
298 char * mfdst = xmalloc (strlen (mm_builddir) + 1 + strlen (buildpath(makefile->dir)) + 1 + strlen (makefile->node.name) + 1);
299 struct stat sst, dst;
300 double diff_t = 0.0;
301 int res;
303 debug(printf("[MMAKE] %s('%s')\n", __func__, makefile->node.name));
305 strcpy (mfsrc, makefile->node.name);
306 strcat (mfsrc, ".src");
308 if ((res = stat (mfsrc, &sst)) == -1)
310 debug(printf("[MMAKE] %s: stat('%s') failed\n", __func__, mfsrc));
311 xfree (mfsrc);
312 return;
315 strcpy (mfdst, mm_builddir);
316 strcat (mfdst, "/");
317 strcat (mfdst, buildpath(makefile->dir));
318 strcat (mfdst, "/");
319 strcat (mfdst, makefile->node.name);
321 if ((res = stat (mfdst, &dst)) != -1)
323 diff_t = difftime(dst.st_mtime, sst.st_mtime);
326 if (res == -1
327 || (diff_t < 0.0)
328 || checkdeps (&cache->project->genmakefiledeps, dst.st_mtime)
331 static char currdir[PATH_MAX];
332 struct Regenerate *reg = new (struct Regenerate);
334 ASSERT(getcwd(currdir, PATH_MAX) != NULL);
335 reg->dir = xstrdup (buildpath(makefile->dir));
336 reg->src = mfsrc;
337 reg->dest = xstrdup (makefile->node.name);
339 debug(printf("MMAKE/cache.c:Added \"%s\" to be regenerated from \"%s\" in \"%s\"\n",
340 reg->dest, reg->src, reg->dir
342 AddTail (regeneratefiles, reg);
344 else
346 debug(printf("MMAKE/cache.c:\"%s\" Not regenerated\n", makefile->node.name));
347 xfree (mfsrc);
353 updatemflist (struct Cache_priv * cache, struct DirNode * node, struct List * regeneratefiles)
355 struct DirNode * subdir;
356 struct Makefile * makefile;
357 int goup = 0, reread = 0;
358 char curdir[1024];
360 debug(printf("MMAKE:cache.c->updatemflist(\"%s\")\n", node->node.name));
362 if (strlen(node->node.name) != 0)
364 if (getcwd(curdir, sizeof(curdir)) == NULL)
366 error("Could not get current directory");
367 exit (20);
369 if (chdir(node->node.name) < 0)
371 error("Could not change to dir '%s'", node->node.name);
372 exit (20);
374 goup = 1;
377 if (scandirnode(node, cache->project->defaultmakefilename, &cache->project->ignoredirs))
378 reread ++;
380 ForeachNode(&node->subdirs, subdir)
382 debug(printf("MMAKE:cache.c->updatemflist: checking subdir ..\n"));
383 reread += updatemflist(cache, subdir, regeneratefiles);
386 ForeachNode(&node->makefiles, makefile)
388 debug(printf("MMAKE:cache.c->updatemflist: checking makefile ..\n"));
389 checknewsrc(cache, makefile, regeneratefiles);
392 if (goup)
393 ASSERT(chdir(curdir) == 0);
395 progress (stdout);
397 return reread;
401 updatetargetlist (struct Project * prj, struct Cache_priv * cache, struct DirNode * node)
403 struct DirNode * subdir;
404 int reread = 0;
406 debug(printf("MMAKE:cache.c->updatetargetlist('%s')\n", node->node.name));
408 reread = scanmakefiles(prj, node, &cache->project->vars);
410 ForeachNode(&node->subdirs, subdir)
411 reread += updatetargetlist(prj, cache, subdir);
413 progress (stdout);
415 return reread;
418 #ifdef _WIN32
420 int mktempfile(char **name)
422 char *temp = getenv("TEMP");
423 size_t pathlen = strlen(temp) + 13;
424 char *path = xmalloc(pathlen);
426 strcpy(path, temp);
427 strcat(path, "\\genmfXXXXXX");
428 *name = path;
429 return mkstemps(path, 0);
432 #else
434 int mktempfile(char **name)
436 static char tmpname[20];
438 strcpy(tmpname, "/tmp/genmfXXXXXX");
439 *name = tmpname;
440 return mkstemp(tmpname);
443 #endif
446 void
447 regeneratemf (struct Cache_priv * cache, struct List * regeneratefiles)
449 struct Regenerate * reg,* reg2;
450 char *tmpname;
451 int fd;
452 FILE *f;
454 debug(printf("MMAKE:cache.c->regeneratemf()\n"));
456 if (GetHead (regeneratefiles) == NULL)
457 return;
459 fd = mktempfile(&tmpname);
460 if (fd < 0)
462 error ("Could not create temporary file %s", tmpname);
463 exit (10);
465 else
467 f = fdopen (fd, "w");
468 if (f == NULL)
470 error ("Could not open temporary file %s", tmpname);
471 exit (10);
475 ForeachNodeSafe (regeneratefiles, reg, reg2)
477 char * mfsrc = xmalloc (strlen(cache->project->srctop) + strlen(reg->dir) + strlen(reg->src) + 3);
478 char * mfdst = xmalloc (strlen(cache->project->buildtop) + strlen(reg->dir) + strlen(reg->dest) + 3);
480 strcpy (mfsrc, cache->project->srctop);
481 if (strlen(reg->dir) > 0)
483 strcat (mfsrc, "/");
484 strcat (mfsrc, reg->dir);
486 strcat (mfsrc, "/");
487 strcat (mfsrc, reg->src);
489 strcpy (mfdst, cache->project->buildtop);
490 if (strlen(reg->dir) > 0)
492 strcat (mfdst, "/");
493 strcat (mfdst, reg->dir);
495 strcat (mfdst, "/");
496 strcat (mfdst, reg->dest);
498 debug(printf("MMAKE:cache.c->regeneratemf: regenerate '%s' as '%s'\n", mfsrc, mfdst));
500 fprintf (f, "%s %s\n", mfsrc, mfdst);
501 Remove (reg);
502 xfree (mfsrc);
503 xfree (mfdst);
505 xfree (reg->dir);
506 xfree (reg->src);
507 xfree (reg->dest);
508 xfree (reg);
511 fclose (f);
513 setvar (&cache->project->vars, "MMLIST", tmpname);
514 if (!execute (cache->project, cache->project->genmakefilescript,"-","-",""))
516 error ("Error regenerating makefile");
517 exit (10);
520 debug(printf("MMAKE:cache.c->regeneratemf: Finished\n"));
522 unlink (tmpname);
525 void
526 buildtargetlist (struct Cache_priv * cache, struct DirNode * node)
528 struct Makefile * makefile;
529 struct MakefileRef * mfref;
530 struct MakefileTarget * mftarget;
531 struct DirNode * subdir;
532 struct Target * target;
533 struct Node * n;
535 debug(printf("MMAKE:cache.c->buildtargetlist()\n"));
537 ForeachNode (&node->makefiles, makefile)
539 ForeachNode (&makefile->targets, mftarget)
541 if (strchr (mftarget->node.name, '$') != NULL)
543 char * s = substvars(&cache->project->vars, mftarget->node.name);
544 SETSTR (mftarget->node.name, s);
547 ForeachNode (&mftarget->deps, n)
549 if (strchr (n->name, '$') != NULL)
551 char * s = substvars(&cache->project->vars, n->name);
552 SETSTR (n->name, s);
556 target = FindNode (&cache->publicpart.targets, mftarget->node.name);
558 if (target == NULL)
560 target = newnodesize (mftarget->node.name, sizeof(struct Target));
561 target->updated = 0;
562 NewList (&target->makefiles);
563 AddTail (&cache->publicpart.targets, target);
566 mfref = newnodesize ("", sizeof(struct MakefileRef));
567 mfref->virtualtarget = mftarget->virtualtarget;
568 mfref->makefile = makefile;
569 AddTail (&target->makefiles, mfref);
573 ForeachNode (&node->subdirs, subdir)
574 buildtargetlist (cache, subdir);
577 struct Cache *
578 activatecache (struct Project *prj)
580 struct Cache_priv * cache;
581 struct List regeneratefiles;
582 struct Node * addedfile, * extrafile;
583 struct Makefile * makefile;
584 struct List newadded;
585 int reread;
587 debug(printf("MMAKE:cache.c->activatecache(Project @ %x)\n", prj));
589 cache = new (struct Cache_priv);
590 if (!cache)
591 return NULL;
592 NewList (&regeneratefiles);
594 cache->project = prj;
596 debug(printf("MMAKE:cache.c->activatecache: Cache @ %x for Project @ %x\n", cache, prj));
598 NewList (&cache->addedfiles);
599 NewList (&cache->publicpart.targets);
601 readcache (cache);
603 debug(printf("MMAKE:cache.c->activatecache: Cache read.\n"));
605 progress_reset (stdout);
606 printf ("[MMAKE] Scanning dirs...\n");
607 reread = updatemflist (cache, cache->topdir, &regeneratefiles);
608 progress_reset (stdout);
610 debug(printf("MMAKE:cache.c->activatecache: Updated MF list.\n"));
612 if (verbose)
613 printf ("[MMAKE] Reread %d dirs\n", reread);
615 if (debug)
617 printf ("[MMAKE] Directory tree for project %s\n", prj->node.name);
618 printdirnode (cache->topdir, 0);
621 /* Add the extra makefiles to the tree if needed */
622 ASSERT(chdir (cache->project->buildtop) == 0);
623 NewList (&newadded);
624 ForeachNode (&cache->project->extramakefiles, extrafile)
626 addedfile = FindNode (&cache->addedfiles, extrafile->name);
627 if (addedfile == NULL)
629 makefile = addmakefile (cache->topdir, extrafile->name);
631 if (makefile == NULL)
633 error("Could not add makefile \"%s\"", extrafile->name);
634 exit (20);
637 addnodeonce (&newadded, extrafile->name);
639 else /* addedfile != NULL => was already added before */
641 makefile = findmakefile (cache->topdir, extrafile->name);
643 if (makefile == NULL)
645 error("Makefile \"%s\" has disappeared", extrafile->name);
646 exit (20);
649 Remove (addedfile);
650 AddTail (&newadded, addedfile);
653 ForeachNode (&cache->addedfiles, addedfile)
655 makefile = findmakefile (cache->topdir, addedfile->name);
656 if (makefile != NULL)
658 Remove (makefile);
659 freemakefile (makefile);
662 AssignList (&cache->addedfiles, &newadded);
664 regeneratemf (cache, &regeneratefiles);
666 debug(printf("MMAKE:cache.c->activatecache: Regenerated MFs\n"));
668 progress_reset (stdout);
669 printf ("[MMAKE] Scanning makefiles...\n");
670 reread = updatetargetlist (prj, cache, cache->topdir);
671 if (verbose)
672 printf ("[MMAKE] Reread %d makefiles\n", reread);
673 if (debug)
675 printf ("[MMAKE] Makefile and target tree for project %s\n", prj->node.name);
676 printdirnodemftarget (cache->topdir);
679 writecache (cache);
681 progress_reset (stdout);
682 printf ("[MMAKE] Collecting targets...\n");
683 buildtargetlist (cache, cache->topdir);
684 if (debug)
686 printf ("[MMAKE] Targetlist of project %s\n", prj->node.name);
687 printtargetlist (&cache->publicpart.targets);
690 debug(printf("MMAKE:cache.c->activatecache: Finished\n"));
692 return (struct Cache *)cache;
695 void
696 closecache (struct Cache * gl_cache)
698 struct Cache_priv * cache = (struct Cache_priv *)gl_cache;
700 freetargetlist (cache);