1 /* MetaMake - A Make extension
2 Copyright © 1995-2012, 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 fgets (line
+strlen(line
), linelen
-strlen(line
), fh
);
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 fgets (line
+strlen(line
), linelen
-strlen(line
), fh
);
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 fgets (line
, linelen
, fh
);
231 while (*ptr
!= ':' && *ptr
)
236 targets
= getargs (line
, &count
, NULL
);
242 printf ("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 ("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 ("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
);
330 /* Call mmakefile with _MM_ target */
332 callmake_mm (struct Project
* prj
, struct Makefile
* makefile
)
334 static char buffer
[4096];
335 const char * path
= buildpath (makefile
->dir
);
336 const char * tname
= "_MM_";
339 debug(printf("MMAKE:project.c->callmake()\n"));
342 if (makefile
->generated
)
343 chdir (prj
->buildtop
);
349 setvar (&prj
->vars
, "CURDIR", path
);
350 setvar (&prj
->vars
, "TARGET", tname
);
354 for (t
=0; t
<mflagc
; t
++)
356 strcat (buffer
, mflags
[t
]);
357 strcat (buffer
, " ");
360 if (strcmp (makefile
->node
.name
, "Makefile")!=0 && strcmp (makefile
->node
.name
, "makefile")!=0);
362 strcat (buffer
, "--file=");
363 strcat (buffer
, makefile
->node
.name
);
364 strcat (buffer
, " ");
367 strcat (buffer
, tname
);
369 printf ("Making %s in %s\n", tname
, path
);
371 /* TODO: create filename for output */
372 /* execute returns 0 for error */
373 return execute (prj
, prj
->maketool
, "-", "-" /* "/home/mazze/mmtest" */, buffer
);
377 freemakefiletarget (struct MakefileTarget
* mftarget
)
379 freelist (&mftarget
->deps
);
385 freemakefiletargetlist (struct List
* targets
)
387 struct MakefileTarget
* mftarget
, * mftarget2
;
389 ForeachNodeSafe (targets
, mftarget
, mftarget2
)
390 freemakefiletarget (mftarget
);
396 printdirnode (struct DirNode
* node
, int level
)
398 struct DirNode
* subdir
;
401 for (t
=0; t
<level
; t
++)
404 printf ("%s\n", node
->node
.name
);
408 ForeachNode (&node
->subdirs
, subdir
)
409 printdirnode (subdir
, level
);
413 printdirnodemftarget (struct DirNode
* node
)
415 struct Makefile
* makefile
;
416 struct MakefileTarget
* mftarget
;
418 struct DirNode
* subdir
;
420 ForeachNode (&node
->makefiles
, makefile
)
422 printf ("%s/%s:\n", buildpath(node
), makefile
->node
.name
);
423 ForeachNode (&makefile
->targets
, mftarget
)
425 printf (" %s:", mftarget
->node
.name
);
426 ForeachNode (&mftarget
->deps
, dep
)
427 printf (" %s", dep
->name
);
432 ForeachNode (&node
->subdirs
, subdir
)
433 printdirnodemftarget (subdir
);
437 freedirnode (struct DirNode
* node
)
439 struct DirNode
* subnode
, * subnode2
;
441 ForeachNodeSafe (&node
->subdirs
, subnode
, subnode2
)
442 freedirnode (subnode
);
444 xfree (node
->node
.name
);
449 freemakefile (struct Makefile
* makefile
)
451 freemakefiletargetlist (&makefile
->targets
);
452 xfree (makefile
->node
.name
);
457 finddirnode (struct DirNode
* topnode
, const char * path
)
462 struct DirNode
* node
= topnode
, * subdir
;
473 for (len
=0; ptr
[len
] && ptr
[len
] != '/'; len
++);
475 strncpy (dirname
, ptr
, len
);
481 subdir
= FindNode (&node
->subdirs
, dirname
);
492 static int nodedepth (struct DirNode
* node
)
496 for (depth
= 0; node
->parent
; depth
++, node
= node
->parent
);
502 scandirnode (struct DirNode
* node
, const char * mfname
, struct List
* ignoredirs
)
506 struct dirent
* dirent
;
508 int mfnamelen
= strlen(mfname
), scanned
= 0;
511 * To avoid MetaMake going into infinite loop when circular
512 * linking is present, we limit the total depth.
514 if (nodedepth(node
) > MAX_NODEDEPTH
) {
515 error("scandirnode(): exceeded maximum directory depth of %d\n%s\n", MAX_NODEDEPTH
, buildpath(node
));
519 debug(printf("MMAKE:dirnode.c->scandirnode('%s')\n", node
->node
.name
));
521 if (stat(".", &st
) != 0)
523 error("scandirnode(): scanning %s\n",
524 strlen(node
->node
.name
) == 0
531 if (st
.st_mtime
> node
->time
)
533 struct List newdirs
, newmakefiles
;
534 struct DirNode
* subdir
= NULL
, * subdir2
;
535 struct Makefile
* makefile
;
537 debug(printf("MMAKE:dirnode.c->scandirnode dir->time changed .. scanning\n"));
540 printf("scandirnode(): scanning %s\n",
541 strlen(node
->node
.name
)==0 ? "topdir" : buildpath(node
)
545 NewList (&newmakefiles
);
547 node
->time
= st
.st_mtime
;
549 dirh
= opendir (".");
552 error("opendir: could not open current dir");
556 while ((dirent
= readdir (dirh
)))
558 /* Add makefile if it present or the file with .src is present */
559 if (strcmp(dirent
->d_name
, mfname
) == 0
560 || (strlen(dirent
->d_name
) == mfnamelen
+ 4
561 && strncmp(dirent
->d_name
, mfname
, mfnamelen
) == 0
562 && strcmp(dirent
->d_name
+ mfnamelen
, ".src") == 0
566 /* Don't add makefile twice */
567 debug(printf("MMAKE:dirnode.c->scandirnode: %s found ('%s')\n", mfname
, dirent
->d_name
));
569 makefile
= FindNode (&newmakefiles
, mfname
);
570 if (makefile
== NULL
)
572 debug(printf("MMAKE:dirnode.c->scandirnode: Creating New Makefile node\n"));
573 makefile
= FindNode (&node
->makefiles
, mfname
);
574 if (makefile
!= NULL
)
580 makefile
= newnodesize (mfname
, sizeof (struct Makefile
));
581 makefile
->dir
= node
;
582 debug(printf("MMAKE:dirnode.c->scandirnode: Makefile node dir '%s'\n", node
->node
.name
));
583 makefile
->time
= (time_t)0;
584 NewList (&makefile
->targets
);
586 AddTail (&newmakefiles
, makefile
);
588 if (strcmp(dirent
->d_name
+ mfnamelen
, ".src") == 0)
589 makefile
->generated
= 1;
593 /* If the file is already in the makefiles from the current dirnode
594 * and it is still present in the directory copy it to the new makefiles
597 if (strlen (dirent
->d_name
) > 4
598 && strcmp (dirent
->d_name
+ strlen(dirent
->d_name
) - 4, ".src") == 0
601 dirent
->d_name
[strlen(dirent
->d_name
) - 4] = 0;
602 makefile
= FindNode (&node
->makefiles
, dirent
->d_name
);
603 dirent
->d_name
[strlen(dirent
->d_name
)] = '.';
606 makefile
= FindNode (&node
->makefiles
, dirent
->d_name
);
608 if (makefile
!= NULL
)
611 AddTail (&newmakefiles
, makefile
);
615 /* Add file to newsubdirs if it is a directory and it has not to be ignored
617 st
.st_mode
= 0; /* This makes us to ignore the file if it can't be stat()'ed.
618 This lets us to succesfully skip Unicode-named files under Windows */
619 stat (dirent
->d_name
, &st
);
621 if (S_ISDIR (st
.st_mode
)
622 && strcmp (dirent
->d_name
, ".") != 0
623 && strcmp (dirent
->d_name
, "..") != 0
624 && !FindNode (ignoredirs
, dirent
->d_name
)
627 subdir
= FindNode (&node
->subdirs
, dirent
->d_name
);
635 subdir
= newnodesize (dirent
->d_name
, sizeof(struct DirNode
));
636 debug(printf("MMAKE:dirnode.c->scandirnode: New SubDir Node '%s' @ %p\n", dirent
->d_name
, subdir
));
637 subdir
->parent
= node
;
638 subdir
->time
= (time_t)0;
639 NewList (&subdir
->subdirs
);
640 NewList (&subdir
->makefiles
);
642 AddTail (&newdirs
, subdir
);
649 ForeachNodeSafe (&node
->subdirs
, subdir
, subdir2
)
650 freedirnode (subdir
);
651 AssignList (&node
->subdirs
, &newdirs
);
653 /* Clear the makefiles that have disappeared */
654 ForeachNode (&node
->makefiles
, makefile
)
656 struct MakefileTarget
* mftarget
;
658 ForeachNode (&makefile
->targets
, mftarget
)
659 freelist (&mftarget
->deps
);
661 freelist (&makefile
->targets
);
664 freelist (&node
->makefiles
);
666 AssignList (&node
->makefiles
, &newmakefiles
);
671 debug(printf("MMAKE:dirnode.c->scandirnode: Finished scanning dir '%s'\n", node
->node
.name
));
674 printf ("scandirnode()\n");
675 printdirnode (node
, 1);
683 scanmakefiles (struct Project
* prj
, struct DirNode
* node
, struct List
* vars
)
685 struct Makefile
* makefile
;
690 debug(printf("MMAKE:dirnode.c->scanmakefiles('%s')\n", node
->node
.name
));
694 ForeachNode (&node
->makefiles
, makefile
)
696 debug(printf("MMAKE:dirnode.c->scanmakefiles: %d '%s'\n", makefile
->generated
, makefile
->node
.name
));
698 if (makefile
->generated
== 0)
700 if (chdir(mm_srcdir
) < 0)
702 error("Could not change to dir '%s'", mm_srcdir
);
708 if (chdir(mm_builddir
) < 0)
710 error("Could not change to dir '%s'", mm_builddir
);
715 if ((strlen(makefile
->dir
->node
.name
) != 0) && (strcmp(makefile
->dir
->node
.name
, mm_srcdir
) != 0))
717 if (chdir(buildpath(makefile
->dir
)) < 0)
719 error("Could not change to dir '%s'", makefile
->dir
->node
.name
);
724 if (stat(makefile
->node
.name
, &st
) != 0)
726 error("Could not stat %s", makefile
->node
.name
);
730 if (st
.st_mtime
> makefile
->time
)
733 printf("scanmakefiles(): scanning makefile in %s/%s\n",
734 strlen(node
->node
.name
)==0 ? "topdir" : buildpath(node
),
739 printf ("Opening %s\n", makefile
->name
);
742 fh
= fopen (makefile
->node
.name
, "r");
745 error ("buildtargetlist:fopen(): Opening %s for reading",
750 /* Free old metatargets when the file is reread */
751 freemakefiletargetlist (&makefile
->targets
);
752 NewList (&makefile
->targets
);
754 readtargets(node
, makefile
, fh
);
757 makefile
->time
= st
.st_mtime
;
762 /* Call make for _MM_ target */
763 if (callmake_mm (prj
, makefile
))
766 /* TODO: parsing of the result */
771 } /* If the makefile needed to be scanned */
772 } /* For all makefiles in the project */
779 addmakefile (struct DirNode
* node
, const char * filename
)
781 static char curdir
[PATH_MAX
];
782 const char * ptr
= filename
;
785 struct DirNode
* subnode
;
786 struct Makefile
* makefile
= NULL
;
788 getcwd(curdir
, PATH_MAX
);
793 while (ptr
[len
] != '/' && ptr
[len
] != 0)
796 name
= xmalloc (len
+4+1); /* Make room for possibly adding .src at the end */
797 strncpy (name
, ptr
, len
);
802 subnode
= FindNode (&node
->subdirs
, name
);
815 if (len
>= 4 && strcmp (name
+len
-4, ".src") == 0)
818 makefile
= FindNode (&node
->makefiles
, name
);
820 if (makefile
== NULL
)
824 printf ("Trying to stat %s\n", name
);
826 if (stat(name
, &st
) != 0)
829 strcat (name
, ".src");
830 if (stat (name
, &st
) != 0)
839 makefile
= newnodesize (name
, sizeof (struct Makefile
));
840 makefile
->dir
= node
;
841 makefile
->time
= (time_t)0;
842 NewList (&makefile
->targets
);
843 AddTail (&node
->makefiles
, makefile
);
859 findmakefile (struct DirNode
* node
, const char *filename
)
861 const char * ptr
= filename
;
864 struct DirNode
* subnode
;
865 struct Makefile
* makefile
= NULL
;
870 while (ptr
[len
] != '/' && ptr
[len
] != 0)
873 name
= xstrndup (ptr
, len
);
878 subnode
= FindNode (&node
->subdirs
, name
);
890 if (len
>= 4 && strcmp (name
+len
-4, ".src") == 0)
893 makefile
= FindNode (&node
->makefiles
, name
);
906 struct DirNode
* dirnode
;
911 buildpath (struct DirNode
* node
)
913 static char path
[PATH_MAX
];
915 struct DirNodeRef
* ref
= NULL
;
921 if ((strlen (node
->node
.name
) > 0) && (strcmp(node
->node
.name
, mm_srcdir
) != 0))
923 ref
= newnodesize ("", sizeof (struct DirNodeRef
));
925 AddHead (&tree
, ref
);
928 } while (node
!= NULL
);
931 ForeachNode (&tree
, ref
)
935 strcat (path
, ref
->dirnode
->node
.name
);
944 readmakefile (FILE * fh
)
946 struct Makefile
* makefile
;
947 struct MakefileTarget
* mftarget
;
952 if (!readstring(fh
, &s
))
954 error ("readmakefile:readstring():%d", __LINE__
);
961 makefile
= newnodesize(s
, sizeof(struct Makefile
));
963 NewList(&makefile
->targets
);
965 if (!readuint32 (fh
, &intt
))
967 error ("readmakefile:fread():%d", __LINE__
);
970 makefile
->time
= intt
;
972 if (!readuint32 (fh
, &intt
))
974 error ("readmakefile:fread():%d", __LINE__
);
977 makefile
->generated
= intt
;
983 if (!readstring(fh
, &s
))
985 error ("readmakefile:readstring():%d", __LINE__
);
992 mftarget
= newnodesize(s
, sizeof(struct MakefileTarget
));
994 AddTail (&makefile
->targets
, mftarget
);
995 NewList (&mftarget
->deps
);
997 if (!readint32 (fh
, &in
))
999 error ("readmakefile:fread():%d", __LINE__
);
1002 mftarget
->virtualtarget
= in
;
1006 if (!readstring(fh
, &s
))
1008 error ("readmakefile:readstring():%d", __LINE__
);
1017 AddTail (&mftarget
->deps
, n
);
1026 writemakefile (FILE * fh
, struct Makefile
* makefile
)
1028 struct MakefileTarget
* mftarget
;
1031 if (makefile
== NULL
)
1033 if (!writestring (fh
, NULL
))
1035 error ("writemakefile/writestring():%d", __LINE__
);
1042 if (!writestring (fh
, makefile
->node
.name
))
1044 error ("writemakefile/writestring():%d", __LINE__
);
1048 if (!writeuint32 (fh
, makefile
->time
))
1050 error ("writemakefile/fwrite():%d", __LINE__
);
1054 if (!writeuint32 (fh
, makefile
->generated
))
1056 error ("writemakefile/fwrite():%d", __LINE__
);
1060 ForeachNode (&makefile
->targets
, mftarget
)
1062 if (!writestring (fh
, mftarget
->node
.name
))
1064 error ("writemakefile/writestring():%d", __LINE__
);
1068 if (!writeint32 (fh
, mftarget
->virtualtarget
))
1070 error ("writemakefile/fwrite():%d", __LINE__
);
1074 ForeachNode (&mftarget
->deps
, n
)
1076 if (!writestring (fh
, n
->name
))
1078 error ("writemakefile/writestring():%d", __LINE__
);
1083 if (!writestring (fh
, NULL
))
1085 error ("writemakefile/writestring():%d", __LINE__
);
1090 if (!writestring(fh
, NULL
))
1092 error ("writemakefile/writestring():%d", __LINE__
);
1101 readcachedir (FILE * fh
)
1103 struct DirNode
* node
, * subnode
;
1104 struct Makefile
* makefile
;
1108 if (!readstring(fh
, &s
))
1110 error ("readcachedir:readstring():%d", __LINE__
);
1117 node
= newnodesize(s
, sizeof(struct DirNode
));
1119 NewList(&node
->makefiles
);
1120 NewList(&node
->subdirs
);
1122 if (!readuint32 (fh
, &intt
))
1124 error ("readcachedir:fread():%d", __LINE__
);
1130 while ((makefile
= readmakefile (fh
)))
1132 makefile
->dir
= node
;
1133 AddTail (&node
->makefiles
, makefile
);
1136 while ((subnode
= readcachedir (fh
)))
1138 subnode
->parent
= node
;
1139 AddTail (&node
->subdirs
, subnode
);
1146 writecachedir (FILE * fh
, struct DirNode
* node
)
1149 struct DirNode
* subnode
;
1150 struct Makefile
* makefile
;
1154 if (!writestring(fh
, NULL
))
1156 error ("writecachedir/writestring():%d", __LINE__
);
1163 if (!writestring(fh
, node
->node
.name
))
1165 error ("writecachedir/writestring():%d", __LINE__
);
1169 if (!writeuint32 (fh
, node
->time
))
1171 error ("writecachedir/fwrite():%d", __LINE__
);
1175 ForeachNode (&node
->makefiles
, makefile
)
1176 writemakefile (fh
, makefile
);
1178 if (!writemakefile (fh
, NULL
))
1181 ForeachNode (&node
->subdirs
, subnode
)
1183 if (!writecachedir (fh
, subnode
))
1187 return writecachedir (fh
, NULL
);