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)
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. */
30 #ifdef HAVE_SYS_STAT_H
31 # include <sys/stat.h>
33 #ifdef HAVE_NETINET_IN_H
34 # include <netinet/in.h> /* for htonl/ntohl() */
52 #if defined(DEBUG_CACHE)
61 #define ID ((MAJOR << 24) | (MINOR << 16) | REVISION)
62 #define CHECK_ID(id) (((id) & 0xFFFF0000) == ((ID) & 0xFFFF0000))
66 struct Cache publicpart
;
67 struct Project
* project
;
68 struct DirNode
* topdir
;
69 struct List addedfiles
;
83 freetarget (struct Target
* target
)
85 xfree (target
->node
.name
);
87 freelist (&target
->makefiles
);
93 freetargetlist (struct Cache_priv
* cache
)
95 struct Node
* node
, * next
;
97 ForeachNodeSafe(&cache
->publicpart
.targets
,node
,next
)
100 freetarget ((struct Target
*)node
);
105 printtargetlist (struct List
* l
)
112 struct MakefileRef
* mfref
;
113 struct MakefileTarget
* mftarget
;
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
127 ForeachNode (&n
->makefiles
, mfref
)
129 mftarget
= FindNode (&mfref
->makefile
->targets
, n
->node
.name
);
130 ForeachNode (&mftarget
->deps
, node
)
131 addnodeonce (&deps
, node
->name
);
140 static int progcount
;
142 static char tokens
[]="|/-\\";
145 progress_reset (FILE * fh
)
149 fprintf (fh
, "\r|\r");
163 fprintf (fh
, "%c\r", tokens
[token
]);
170 readcache (struct Cache_priv
* cache
)
176 strcpy (path
, cache
->project
->buildtop
);
177 strcat (path
, "/mmake.cache");
178 assert (strlen(path
) < sizeof(path
));
180 fh
= fopen (path
, "rb");
184 if (!readuint32 (fh
, &id
) || !CHECK_ID(id
))
197 if (!readstring (fh
, &name
))
206 addnodeonce (&cache
->addedfiles
, name
);
209 while (name
!= NULL
);
211 if (!(cache
->topdir
= readcachedir (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;
234 printf ("readcache()\n");
235 printdirnode (cache
->topdir
, 1);
240 writecache (struct Cache_priv
* cache
)
246 struct Node
*addedfile
;
248 debug(printf("MMAKE:cache.c->writecache()\n"));
253 strcpy (path
, cache
->project
->buildtop
);
254 strcat (path
, "/mmake.cache");
255 assert (strlen(path
) < sizeof(path
));
257 fh
= fopen (path
, "wb");
265 ok
= writeuint32 (fh
, ID
);
269 ForeachNode (&cache
->addedfiles
, addedfile
)
271 ok
= writestring (fh
, addedfile
->name
);
274 error ("writecache/writestring():%d", __LINE__
);
279 ok
= writestring (fh
, NULL
);
282 error("writecache/fwrite():%d", __LINE__
);
286 ok
= writecachedir (fh
, cache
->topdir
);
296 printf ("[MMAKE] Warning: Creating the cache failed\n");
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 debug(printf("MMAKE/cache.c:stat(\"%s\", ...) failed\n", mfsrc
));
320 strcpy (mfdst
, mm_builddir
);
322 strcat (mfdst
, buildpath(makefile
->dir
));
324 strcat (mfdst
, makefile
->node
.name
);
326 if (stat (mfdst
, &dst
) == -1
327 || sst
.st_mtime
> dst
.st_mtime
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
));
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
);
346 debug(printf("MMAKE/cache.c:\"%s\" Not regenerated\n", makefile
->node
.name
));
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;
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");
369 if (chdir(node
->node
.name
) < 0)
371 error("Could not change to dir '%s'", node
->node
.name
);
377 if (scandirnode(node
, cache
->project
->defaultmakefilename
, &cache
->project
->ignoredirs
))
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
);
393 ASSERT(chdir(curdir
) == 0);
401 updatetargetlist (struct Project
* prj
, struct Cache_priv
* cache
, struct DirNode
* node
)
403 struct DirNode
* subdir
;
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
);
420 int mktempfile(char **name
)
422 char *temp
= getenv("TEMP");
423 size_t pathlen
= strlen(temp
) + 13;
424 char *path
= xmalloc(pathlen
);
427 strcat(path
, "\\genmfXXXXXX");
429 return mkstemps(path
, 0);
434 int mktempfile(char **name
)
436 static char tmpname
[20];
438 strcpy(tmpname
, "/tmp/genmfXXXXXX");
440 return mkstemp(tmpname
);
447 regeneratemf (struct Cache_priv
* cache
, struct List
* regeneratefiles
)
449 struct Regenerate
* reg
,* reg2
;
454 debug(printf("MMAKE:cache.c->regeneratemf()\n"));
456 if (GetHead (regeneratefiles
) == NULL
)
459 fd
= mktempfile(&tmpname
);
462 error ("Could not create temporary file %s", tmpname
);
467 f
= fdopen (fd
, "w");
470 error ("Could not open temporary file %s", tmpname
);
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)
484 strcat (mfsrc
, reg
->dir
);
487 strcat (mfsrc
, reg
->src
);
489 strcpy (mfdst
, cache
->project
->buildtop
);
490 if (strlen(reg
->dir
) > 0)
493 strcat (mfdst
, reg
->dir
);
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
);
513 setvar (&cache
->project
->vars
, "MMLIST", tmpname
);
514 if (!execute (cache
->project
, cache
->project
->genmakefilescript
,"-","-",""))
516 error ("Error regenerating makefile");
520 debug(printf("MMAKE:cache.c->regeneratemf: Finished\n"));
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
;
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
);
556 target
= FindNode (&cache
->publicpart
.targets
, mftarget
->node
.name
);
560 target
= newnodesize (mftarget
->node
.name
, sizeof(struct Target
));
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
);
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
;
587 debug(printf("MMAKE:cache.c->activatecache(Project @ %x)\n", prj
));
589 cache
= new (struct Cache_priv
);
592 NewList (®eneratefiles
);
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
);
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
, ®eneratefiles
);
609 debug(printf("MMAKE:cache.c->activatecache: Updated MF list.\n"));
612 printf ("[MMAKE] Reread %d dirs\n", reread
);
616 printf ("[MMAKE] Directory tree for project %s\n", prj
->node
.name
);
617 printdirnode (cache
->topdir
, 0);
620 /* Add the extra makefiles to the tree if needed */
621 ASSERT(chdir (cache
->project
->buildtop
) == 0);
623 ForeachNode (&cache
->project
->extramakefiles
, extrafile
)
625 addedfile
= FindNode (&cache
->addedfiles
, extrafile
->name
);
626 if (addedfile
== NULL
)
628 makefile
= addmakefile (cache
->topdir
, extrafile
->name
);
630 if (makefile
== NULL
)
632 error("Could not add makefile \"%s\"", extrafile
->name
);
636 addnodeonce (&newadded
, extrafile
->name
);
638 else /* addedfile != NULL => was already added before */
640 makefile
= findmakefile (cache
->topdir
, extrafile
->name
);
642 if (makefile
== NULL
)
644 error("Makefile \"%s\" has disappeared", extrafile
->name
);
649 AddTail (&newadded
, addedfile
);
652 ForeachNode (&cache
->addedfiles
, addedfile
)
654 makefile
= findmakefile (cache
->topdir
, addedfile
->name
);
655 if (makefile
!= NULL
)
658 freemakefile (makefile
);
661 AssignList (&cache
->addedfiles
, &newadded
);
663 regeneratemf (cache
, ®eneratefiles
);
665 debug(printf("MMAKE:cache.c->activatecache: Regenerated MFs\n"));
667 progress_reset (stdout
);
668 printf ("[MMAKE] Scanning makefiles...\n");
669 reread
= updatetargetlist (prj
, cache
, cache
->topdir
);
671 printf ("[MMAKE] Reread %d makefiles\n", reread
);
674 printf ("[MMAKE] Makefile and target tree for project %s\n", prj
->node
.name
);
675 printdirnodemftarget (cache
->topdir
);
680 printf ("[MMAKE] Collecting targets...\n");
681 buildtargetlist (cache
, cache
->topdir
);
684 printf ("[MMAKE] Targetlist of project %s\n", prj
->node
.name
);
685 printtargetlist (&cache
->publicpart
.targets
);
688 debug(printf("MMAKE:cache.c->activatecache: Finished\n"));
690 return (struct Cache
*)cache
;
694 closecache (struct Cache
* gl_cache
)
696 struct Cache_priv
* cache
= (struct Cache_priv
*)gl_cache
;
698 freetargetlist (cache
);