1 /* MetaMake - A Make extension
2 Copyright © 1995-2016, 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. */
21 //#define DEBUG_DIRNODE
34 #ifdef HAVE_SYS_STAT_H
35 # include <sys/stat.h>
37 #ifdef HAVE_SYS_TYPES_H
38 # include <sys/types.h>
53 #if defined(DEBUG_DIRNODE)
59 #define MAX_NODEDEPTH 128
61 #define FLAG_VIRTUAL 0x0001
63 /* Return true if last non whitespace character is a '\' */
65 check_continue(const char *str
)
67 int pos
= strlen(str
) - 1;
68 while (pos
>= 0 && isspace(str
[pos
]))
72 if (pos
>= 0 && str
[pos
] == '\\')
79 static struct MakefileTarget
*
80 newmakefiletarget (char *name
, int virtualtarget
)
82 struct MakefileTarget
* mftarget
;
84 mftarget
= newnodesize (name
, sizeof(struct MakefileTarget
));
85 mftarget
->virtualtarget
= virtualtarget
;
86 NewList (&mftarget
->deps
);
91 /* Read the metatargets from a file handle */
93 readtargets(struct DirNode
* node
, struct Makefile
* makefile
, FILE * fh
)
97 struct MakefileTarget
* mftarget
= NULL
;
98 static char * line
= NULL
;
99 static int linelen
= 512;
102 line
= xmalloc(linelen
);
104 while (fgets (line
, linelen
, fh
))
108 while (line
[strlen(line
)-1] != '\n' && !feof(fh
))
113 ptr
= xmalloc (linelen
);
117 ASSERT(fgets (line
+strlen(line
), linelen
-strlen(line
), fh
) != NULL
);
120 if (line
[strlen(line
)-1] == '\n')
122 line
[strlen(line
)-1] = 0;
125 if (strncmp (line
, "#MM", 3) == 0)
128 int count
, count2
, t
;
131 printf ("found #MM in %s\n", makefile
->node
.name
);
134 /* Read in next lines if there is continuation */
135 while (check_continue(line
))
137 ptr
= line
+ strlen(line
) - 1;
139 if (!fgets (ptr
, linelen
-strlen(line
)+1, fh
))
141 error("%s/%s:unexpected end of makefile",
150 while (line
[strlen(line
)-1] != '\n' && !feof(fh
))
152 int pos
= ptr
- line
;
154 ptr
= xmalloc (linelen
);
158 ASSERT(fgets (line
+strlen(line
), linelen
-strlen(line
), fh
) != NULL
);
162 if (line
[strlen(line
)-1] == '\n')
164 line
[strlen(line
)-1] = 0;
167 if (strncmp (ptr
, "##MM", 3) == 0)
169 *ptr
= line
[strlen(line
)-1];
174 if (strncmp (ptr
, "#MM", 3) != 0)
177 error("%s/%s:%d:continuation line has to start with #MM",
185 memmove (ptr
, ptr
+4, strlen(ptr
)-4+1);
192 flags
|= FLAG_VIRTUAL
;
196 flags
&= ~FLAG_VIRTUAL
;
198 while (isspace (*ptr
))
204 if (flags
& FLAG_VIRTUAL
)
206 error("%s/%s:%d:malformed virtual target, only one '-' allowed",
214 error("%s/%s:%d:malformed virtual target, '-' must follow directly after '#MM'",
225 /* Line with only #MM, metatarget is on next line */
227 ASSERT(fgets (line
, linelen
, fh
) != NULL
);
231 while (*ptr
!= ':' && *ptr
)
236 targets
= getargs (line
, &count
, NULL
);
242 printf ("[MMAKE] Warning: Multiple metatargets, only the 1st will be added in %s:%d (%s)\n",
243 makefile
->node
.name
, lineno
, buildpath(node
)
245 /* FIXME: should we better add all metatargets? */
247 mftarget
= FindNode (&makefile
->targets
, targets
[0]);
249 if (mftarget
== NULL
)
251 mftarget
= newmakefiletarget (targets
[0], 0);
252 AddTail (&makefile
->targets
, mftarget
);
255 mftarget
->virtualtarget
= 0;
258 printf ("[MMAKE] Warning: Can't find metatarget in %s:%d (%s)\n", makefile
->node
.name
, lineno
, buildpath(node
));
262 struct List newtargets
;
263 char * ptr2
= ptr
, ** tptr
;
264 struct MakefileTarget
* mftarget2
, * mftarget3
;
266 NewList (&newtargets
);
268 while (*ptr2
!= ':' && *ptr2
)
274 tptr
= getargs (ptr
, &count
, NULL
);
276 for (t
= 0; t
< count
; t
++)
278 mftarget
= newmakefiletarget (tptr
[t
], (flags
& FLAG_VIRTUAL
) != 0);
279 AddTail (&newtargets
, mftarget
);
282 tptr
= getargs (ptr2
, &count2
, NULL
);
284 if (count
> 1 && count2
== 0)
286 /* could mean a missing colon */
287 printf ("[MMAKE] Warning: multiple metatargets but no prerequisites %s:%d (%s)\n",
288 makefile
->node
.name
, lineno
, buildpath(node
)
292 for (t
= 0; t
< count2
; t
++)
294 ForeachNode (&newtargets
, mftarget
)
295 addnodeonce (&mftarget
->deps
, tptr
[t
]);
298 ForeachNodeSafe (&newtargets
, mftarget
, mftarget2
)
300 mftarget3
= FindNode (&makefile
->targets
, mftarget
->node
.name
);
302 /* mftarget doesn't exists yet add it to targets */
303 if (mftarget3
== NULL
)
306 AddTail (&makefile
->targets
, mftarget
);
310 /* Merge data in mftarget into mftarget3 */
313 mftarget3
->virtualtarget
= mftarget3
->virtualtarget
&& mftarget
->virtualtarget
;
315 ForeachNode (&mftarget
->deps
, node
)
316 addnodeonce (&mftarget3
->deps
, node
->name
);
318 /* Free the targets from which the data was merged in other targets */
319 freemakefiletargetlist (&newtargets
);
322 } /* If this is a MetaMake line in the makefile */
323 } /* For all lines in a makefile */
326 printf ("Read %d lines\n", lineno
);
331 freemakefiletarget (struct MakefileTarget
* mftarget
)
333 freelist (&mftarget
->deps
);
339 freemakefiletargetlist (struct List
* targets
)
341 struct MakefileTarget
* mftarget
, * mftarget2
;
343 ForeachNodeSafe (targets
, mftarget
, mftarget2
)
344 freemakefiletarget (mftarget
);
350 printdirnode (struct DirNode
* node
, int level
)
352 struct DirNode
* subdir
;
355 for (t
=0; t
<level
; t
++)
358 printf ("%s\n", node
->node
.name
);
362 ForeachNode (&node
->subdirs
, subdir
)
363 printdirnode (subdir
, level
);
367 printdirnodemftarget (struct DirNode
* node
)
369 struct Makefile
* makefile
;
370 struct MakefileTarget
* mftarget
;
372 struct DirNode
* subdir
;
374 ForeachNode (&node
->makefiles
, makefile
)
376 printf ("%s/%s:\n", buildpath(node
), makefile
->node
.name
);
377 ForeachNode (&makefile
->targets
, mftarget
)
379 printf (" %s:", mftarget
->node
.name
);
380 ForeachNode (&mftarget
->deps
, dep
)
381 printf (" %s", dep
->name
);
386 ForeachNode (&node
->subdirs
, subdir
)
387 printdirnodemftarget (subdir
);
391 freedirnode (struct DirNode
* node
)
393 struct DirNode
* subnode
, * subnode2
;
395 ForeachNodeSafe (&node
->subdirs
, subnode
, subnode2
)
396 freedirnode (subnode
);
398 xfree (node
->node
.name
);
403 freemakefile (struct Makefile
* makefile
)
405 freemakefiletargetlist (&makefile
->targets
);
406 xfree (makefile
->node
.name
);
411 finddirnode (struct DirNode
* topnode
, const char * path
)
416 struct DirNode
* node
= topnode
, * subdir
;
427 for (len
=0; ptr
[len
] && ptr
[len
] != '/'; len
++);
429 strncpy (dirname
, ptr
, len
);
435 subdir
= FindNode (&node
->subdirs
, dirname
);
446 static int nodedepth (struct DirNode
* node
)
450 for (depth
= 0; node
->parent
; depth
++, node
= node
->parent
);
456 scandirnode (struct DirNode
* node
, const char * mfname
, struct List
* ignoredirs
)
460 struct dirent
* dirent
;
462 int mfnamelen
= strlen(mfname
), scanned
= 0;
465 * To avoid MetaMake going into infinite loop when circular
466 * linking is present, we limit the total depth.
468 if (nodedepth(node
) > MAX_NODEDEPTH
) {
469 error("scandirnode(): exceeded maximum directory depth of %d\n%s\n", MAX_NODEDEPTH
, buildpath(node
));
473 debug(printf("MMAKE:dirnode.c->scandirnode('%s')\n", node
->node
.name
));
475 if (stat(".", &st
) != 0)
477 error("scandirnode(): scanning %s\n",
478 strlen(node
->node
.name
) == 0
485 if (st
.st_mtime
> node
->time
)
487 struct List newdirs
, newmakefiles
;
488 struct DirNode
* subdir
= NULL
, * subdir2
;
489 struct Makefile
* makefile
;
491 debug(printf("MMAKE:dirnode.c->scandirnode dir->time changed .. scanning\n"));
494 printf("[MMAKE] scandirnode(): scanning %s\n",
495 strlen(node
->node
.name
)==0 ? "topdir" : buildpath(node
)
499 NewList (&newmakefiles
);
501 node
->time
= st
.st_mtime
;
503 dirh
= opendir (".");
506 error("opendir: could not open current dir");
510 while ((dirent
= readdir (dirh
)))
512 /* Add makefile if it present or the file with .src is present */
513 if (strcmp(dirent
->d_name
, mfname
) == 0
514 || (strlen(dirent
->d_name
) == mfnamelen
+ 4
515 && strncmp(dirent
->d_name
, mfname
, mfnamelen
) == 0
516 && strcmp(dirent
->d_name
+ mfnamelen
, ".src") == 0
520 /* Don't add makefile twice */
521 debug(printf("MMAKE:dirnode.c->scandirnode: %s found ('%s')\n", mfname
, dirent
->d_name
));
523 makefile
= FindNode (&newmakefiles
, mfname
);
524 if (makefile
== NULL
)
526 debug(printf("MMAKE:dirnode.c->scandirnode: Creating New Makefile node\n"));
527 makefile
= FindNode (&node
->makefiles
, mfname
);
528 if (makefile
!= NULL
)
534 makefile
= newnodesize (mfname
, sizeof (struct Makefile
));
535 makefile
->dir
= node
;
536 debug(printf("MMAKE:dirnode.c->scandirnode: Makefile node dir '%s'\n", node
->node
.name
));
537 makefile
->time
= (time_t)0;
538 NewList (&makefile
->targets
);
540 AddTail (&newmakefiles
, makefile
);
542 if (strcmp(dirent
->d_name
+ mfnamelen
, ".src") == 0)
543 makefile
->generated
= 1;
547 /* If the file is already in the makefiles from the current dirnode
548 * and it is still present in the directory copy it to the new makefiles
551 if (strlen (dirent
->d_name
) > 4
552 && strcmp (dirent
->d_name
+ strlen(dirent
->d_name
) - 4, ".src") == 0
555 dirent
->d_name
[strlen(dirent
->d_name
) - 4] = 0;
556 makefile
= FindNode (&node
->makefiles
, dirent
->d_name
);
557 dirent
->d_name
[strlen(dirent
->d_name
)] = '.';
560 makefile
= FindNode (&node
->makefiles
, dirent
->d_name
);
562 if (makefile
!= NULL
)
565 AddTail (&newmakefiles
, makefile
);
569 /* Add file to newsubdirs if it is a directory and it has not to be ignored
571 st
.st_mode
= 0; /* This makes us ignore the file if it can't be stat()'ed.
572 This lets us successfully skip Unicode-named files under Windows */
573 stat (dirent
->d_name
, &st
);
575 if (S_ISDIR (st
.st_mode
)
576 && strcmp (dirent
->d_name
, ".") != 0
577 && strcmp (dirent
->d_name
, "..") != 0
578 && !FindNode (ignoredirs
, dirent
->d_name
)
581 subdir
= FindNode (&node
->subdirs
, dirent
->d_name
);
589 subdir
= newnodesize (dirent
->d_name
, sizeof(struct DirNode
));
590 debug(printf("MMAKE:dirnode.c->scandirnode: New SubDir Node '%s' @ %p\n", dirent
->d_name
, subdir
));
591 subdir
->parent
= node
;
592 subdir
->time
= (time_t)0;
593 NewList (&subdir
->subdirs
);
594 NewList (&subdir
->makefiles
);
596 AddTail (&newdirs
, subdir
);
603 ForeachNodeSafe (&node
->subdirs
, subdir
, subdir2
)
604 freedirnode (subdir
);
605 AssignList (&node
->subdirs
, &newdirs
);
607 /* Clear the makefiles that have disappeared */
608 ForeachNode (&node
->makefiles
, makefile
)
610 struct MakefileTarget
* mftarget
;
612 ForeachNode (&makefile
->targets
, mftarget
)
613 freelist (&mftarget
->deps
);
615 freelist (&makefile
->targets
);
618 freelist (&node
->makefiles
);
620 AssignList (&node
->makefiles
, &newmakefiles
);
625 debug(printf("MMAKE:dirnode.c->scandirnode: Finished scanning dir '%s'\n", node
->node
.name
));
628 printf ("[MMAKE] scandirnode()\n");
629 printdirnode (node
, 1);
637 scanmakefiles (struct Project
* prj
, struct DirNode
* node
, struct List
* vars
)
639 struct Makefile
* makefile
;
644 debug(printf("MMAKE:dirnode.c->scanmakefiles('%s')\n", node
->node
.name
));
648 ForeachNode (&node
->makefiles
, makefile
)
650 debug(printf("MMAKE:dirnode.c->scanmakefiles: %d '%s'\n", makefile
->generated
, makefile
->node
.name
));
652 if (makefile
->generated
== 0)
654 if (chdir(mm_srcdir
) < 0)
656 error("Could not change to dir '%s'", mm_srcdir
);
662 if (chdir(mm_builddir
) < 0)
664 error("Could not change to dir '%s'", mm_builddir
);
669 if ((strlen(makefile
->dir
->node
.name
) != 0) && (strcmp(makefile
->dir
->node
.name
, mm_srcdir
) != 0))
671 if (chdir(buildpath(makefile
->dir
)) < 0)
673 error("Could not change to dir '%s'", makefile
->dir
->node
.name
);
678 if (stat(makefile
->node
.name
, &st
) != 0)
680 error("Could not stat %s", makefile
->node
.name
);
684 if (st
.st_mtime
> makefile
->time
)
687 printf("[MMAKE] scanmakefiles(): scanning makefile in %s/%s\n",
688 strlen(node
->node
.name
)==0 ? "topdir" : buildpath(node
),
693 printf ("Opening %s\n", makefile
->name
);
696 fh
= fopen (makefile
->node
.name
, "r");
699 error ("buildtargetlist:fopen(): Opening %s for reading",
704 /* Free old metatargets when the file is reread */
705 freemakefiletargetlist (&makefile
->targets
);
706 NewList (&makefile
->targets
);
708 readtargets(node
, makefile
, fh
);
711 makefile
->time
= st
.st_mtime
;
715 } /* If the makefile needed to be scanned */
716 } /* For all makefiles in the project */
723 addmakefile (struct DirNode
* node
, const char * filename
)
725 static char curdir
[PATH_MAX
];
726 const char * ptr
= filename
;
729 struct DirNode
* subnode
;
730 struct Makefile
* makefile
= NULL
;
732 ASSERT(getcwd(curdir
, PATH_MAX
) != NULL
);
737 while (ptr
[len
] != '/' && ptr
[len
] != 0)
740 name
= xmalloc (len
+4+1); /* Make room for possibly adding .src at the end */
741 strncpy (name
, ptr
, len
);
746 subnode
= FindNode (&node
->subdirs
, name
);
750 ASSERT(chdir (curdir
) == 0);
753 ASSERT(chdir (name
) == 0);
759 if (len
>= 4 && strcmp (name
+len
-4, ".src") == 0)
762 makefile
= FindNode (&node
->makefiles
, name
);
764 if (makefile
== NULL
)
768 printf ("[MMAKE] Trying to stat %s\n", name
);
770 if (stat(name
, &st
) != 0)
773 strcat (name
, ".src");
774 if (stat (name
, &st
) != 0)
777 ASSERT(chdir (curdir
) == 0);
783 makefile
= newnodesize (name
, sizeof (struct Makefile
));
784 makefile
->dir
= node
;
785 makefile
->time
= (time_t)0;
786 NewList (&makefile
->targets
);
787 AddTail (&node
->makefiles
, makefile
);
796 ASSERT(chdir (curdir
) == 0);
803 findmakefile (struct DirNode
* node
, const char *filename
)
805 const char * ptr
= filename
;
808 struct DirNode
* subnode
;
809 struct Makefile
* makefile
= NULL
;
814 while (ptr
[len
] != '/' && ptr
[len
] != 0)
817 name
= xstrndup (ptr
, len
);
822 subnode
= FindNode (&node
->subdirs
, name
);
834 if (len
>= 4 && strcmp (name
+len
-4, ".src") == 0)
837 makefile
= FindNode (&node
->makefiles
, name
);
850 struct DirNode
* dirnode
;
855 buildpath (struct DirNode
* node
)
857 static char path
[PATH_MAX
];
859 struct DirNodeRef
* ref
= NULL
;
865 if ((strlen (node
->node
.name
) > 0) && (strcmp(node
->node
.name
, mm_srcdir
) != 0))
867 ref
= newnodesize ("", sizeof (struct DirNodeRef
));
869 AddHead (&tree
, ref
);
872 } while (node
!= NULL
);
875 ForeachNode (&tree
, ref
)
879 strcat (path
, ref
->dirnode
->node
.name
);
888 readmakefile (FILE * fh
)
890 struct Makefile
* makefile
;
891 struct MakefileTarget
* mftarget
;
896 if (!readstring(fh
, &s
))
898 error ("readmakefile:readstring():%d", __LINE__
);
905 makefile
= newnodesize(s
, sizeof(struct Makefile
));
907 NewList(&makefile
->targets
);
909 if (!readuint32 (fh
, &intt
))
911 error ("readmakefile:fread():%d", __LINE__
);
914 makefile
->time
= intt
;
916 if (!readuint32 (fh
, &intt
))
918 error ("readmakefile:fread():%d", __LINE__
);
921 makefile
->generated
= intt
;
927 if (!readstring(fh
, &s
))
929 error ("readmakefile:readstring():%d", __LINE__
);
936 mftarget
= newnodesize(s
, sizeof(struct MakefileTarget
));
938 AddTail (&makefile
->targets
, mftarget
);
939 NewList (&mftarget
->deps
);
941 if (!readint32 (fh
, &in
))
943 error ("readmakefile:fread():%d", __LINE__
);
946 mftarget
->virtualtarget
= in
;
950 if (!readstring(fh
, &s
))
952 error ("readmakefile:readstring():%d", __LINE__
);
961 AddTail (&mftarget
->deps
, n
);
970 writemakefile (FILE * fh
, struct Makefile
* makefile
)
972 struct MakefileTarget
* mftarget
;
975 if (makefile
== NULL
)
977 if (!writestring (fh
, NULL
))
979 error ("writemakefile/writestring():%d", __LINE__
);
986 if (!writestring (fh
, makefile
->node
.name
))
988 error ("writemakefile/writestring():%d", __LINE__
);
992 if (!writeuint32 (fh
, makefile
->time
))
994 error ("writemakefile/fwrite():%d", __LINE__
);
998 if (!writeuint32 (fh
, makefile
->generated
))
1000 error ("writemakefile/fwrite():%d", __LINE__
);
1004 ForeachNode (&makefile
->targets
, mftarget
)
1006 if (!writestring (fh
, mftarget
->node
.name
))
1008 error ("writemakefile/writestring():%d", __LINE__
);
1012 if (!writeint32 (fh
, mftarget
->virtualtarget
))
1014 error ("writemakefile/fwrite():%d", __LINE__
);
1018 ForeachNode (&mftarget
->deps
, n
)
1020 if (!writestring (fh
, n
->name
))
1022 error ("writemakefile/writestring():%d", __LINE__
);
1027 if (!writestring (fh
, NULL
))
1029 error ("writemakefile/writestring():%d", __LINE__
);
1034 if (!writestring(fh
, NULL
))
1036 error ("writemakefile/writestring():%d", __LINE__
);
1045 readcachedir (FILE * fh
)
1047 struct DirNode
* node
, * subnode
;
1048 struct Makefile
* makefile
;
1052 if (!readstring(fh
, &s
))
1054 error ("readcachedir:readstring():%d", __LINE__
);
1061 node
= newnodesize(s
, sizeof(struct DirNode
));
1063 NewList(&node
->makefiles
);
1064 NewList(&node
->subdirs
);
1066 if (!readuint32 (fh
, &intt
))
1068 error ("readcachedir:fread():%d", __LINE__
);
1074 while ((makefile
= readmakefile (fh
)))
1076 makefile
->dir
= node
;
1077 AddTail (&node
->makefiles
, makefile
);
1080 while ((subnode
= readcachedir (fh
)))
1082 subnode
->parent
= node
;
1083 AddTail (&node
->subdirs
, subnode
);
1090 writecachedir (FILE * fh
, struct DirNode
* node
)
1093 struct DirNode
* subnode
;
1094 struct Makefile
* makefile
;
1098 if (!writestring(fh
, NULL
))
1100 error ("writecachedir/writestring():%d", __LINE__
);
1107 if (!writestring(fh
, node
->node
.name
))
1109 error ("writecachedir/writestring():%d", __LINE__
);
1113 if (!writeuint32 (fh
, node
->time
))
1115 error ("writecachedir/fwrite():%d", __LINE__
);
1119 ForeachNode (&node
->makefiles
, makefile
)
1120 writemakefile (fh
, makefile
);
1122 if (!writemakefile (fh
, NULL
))
1125 ForeachNode (&node
->subdirs
, subnode
)
1127 if (!writecachedir (fh
, subnode
))
1131 return writecachedir (fh
, NULL
);