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 ("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)
319 strcpy (mfdst
, mm_builddir
);
321 strcat (mfdst
, buildpath(makefile
->dir
));
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
));
336 reg
->dest
= xstrdup (makefile
->node
.name
);
338 AddTail (regeneratefiles
, reg
);
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;
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");
364 if (chdir(node
->node
.name
) < 0)
366 error("Could not change to dir '%s'", node
->node
.name
);
372 if (scandirnode(node
, cache
->project
->defaultmakefilename
, &cache
->project
->ignoredirs
))
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
);
396 updatetargetlist (struct Project
* prj
, struct Cache_priv
* cache
, struct DirNode
* node
)
398 struct DirNode
* subdir
;
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
);
415 int mktempfile(char **name
)
417 char *temp
= getenv("TEMP");
418 size_t pathlen
= strlen(temp
) + 13;
419 char *path
= xmalloc(pathlen
);
422 strcat(path
, "\\genmfXXXXXX");
424 return mkstemps(path
, 0);
429 int mktempfile(char **name
)
431 static char tmpname
[20];
433 strcpy(tmpname
, "/tmp/genmfXXXXXX");
435 return mkstemp(tmpname
);
442 regeneratemf (struct Cache_priv
* cache
, struct List
* regeneratefiles
)
444 struct Regenerate
* reg
,* reg2
;
449 debug(printf("MMAKE:cache.c->regeneratemf()\n"));
451 if (GetHead (regeneratefiles
) == NULL
)
454 fd
= mktempfile(&tmpname
);
457 error ("Could not create temporary file %s", tmpname
);
462 f
= fdopen (fd
, "w");
465 error ("Could not open temporary file %s", tmpname
);
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)
479 strcat (mfsrc
, reg
->dir
);
482 strcat (mfsrc
, reg
->src
);
484 strcpy (mfdst
, cache
->project
->buildtop
);
485 if (strlen(reg
->dir
) > 0)
488 strcat (mfdst
, reg
->dir
);
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
);
508 setvar (&cache
->project
->vars
, "MMLIST", tmpname
);
509 if (!execute (cache
->project
, cache
->project
->genmakefilescript
,"-","-",""))
511 error ("Error regenerating makefile");
515 debug(printf("MMAKE:cache.c->regeneratemf: Finished\n"));
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
;
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
);
551 target
= FindNode (&cache
->publicpart
.targets
, mftarget
->node
.name
);
555 target
= newnodesize (mftarget
->node
.name
, sizeof(struct Target
));
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
);
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
;
582 debug(printf("MMAKE:cache.c->activatecache(Project @ %x)\n", prj
));
584 cache
= new (struct Cache_priv
);
587 NewList (®eneratefiles
);
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
);
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
, ®eneratefiles
);
604 debug(printf("MMAKE:cache.c->activatecache: Updated MF list.\n"));
607 printf ("Reread %d dirs\n", reread
);
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
);
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
);
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
);
644 AddTail (&newadded
, addedfile
);
647 ForeachNode (&cache
->addedfiles
, addedfile
)
649 makefile
= findmakefile (cache
->topdir
, addedfile
->name
);
650 if (makefile
!= NULL
)
653 freemakefile (makefile
);
656 AssignList (&cache
->addedfiles
, &newadded
);
658 regeneratemf (cache
, ®eneratefiles
);
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
);
666 printf ("Reread %d makefiles\n", reread
);
669 printf ("Makefile and target tree for project %s\n", prj
->node
.name
);
670 printdirnodemftarget (cache
->topdir
);
675 printf ("Collecting targets...\n");
676 buildtargetlist (cache
, cache
->topdir
);
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
;
689 closecache (struct Cache
* gl_cache
)
691 struct Cache_priv
* cache
= (struct Cache_priv
*)gl_cache
;
693 freetargetlist (cache
);