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. */
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 FLAG_VIRTUAL 0x0001
61 /* Return true if last non whitespace character is a '\' */
63 check_continue(const char *str
)
65 int pos
= strlen(str
) - 1;
66 while (pos
>= 0 && isspace(str
[pos
]))
70 if (pos
>= 0 && str
[pos
] == '\\')
77 static struct MakefileTarget
*
78 newmakefiletarget (char *name
, int virtualtarget
)
80 struct MakefileTarget
* mftarget
;
82 mftarget
= newnodesize (name
, sizeof(struct MakefileTarget
));
83 mftarget
->virtualtarget
= virtualtarget
;
84 NewList (&mftarget
->deps
);
89 /* Read the metatargets from a file handle */
91 readtargets(struct DirNode
* node
, struct Makefile
* makefile
, FILE * fh
)
95 struct MakefileTarget
* mftarget
= NULL
;
96 static char * line
= NULL
;
97 static int linelen
= 512;
100 line
= xmalloc(linelen
);
102 while (fgets (line
, linelen
, fh
))
106 while (line
[strlen(line
)-1] != '\n' && !feof(fh
))
111 ptr
= xmalloc (linelen
);
115 fgets (line
+strlen(line
), linelen
-strlen(line
), fh
);
118 if (line
[strlen(line
)-1] == '\n')
120 line
[strlen(line
)-1] = 0;
123 if (strncmp (line
, "#MM", 3) == 0)
126 int count
, count2
, t
;
129 printf ("found #MM in %s\n", makefile
->name
);
132 /* Read in next lines if there is continuation */
133 while (check_continue(line
))
135 ptr
= line
+ strlen(line
) - 1;
137 if (!fgets (ptr
, linelen
-strlen(line
)+1, fh
))
139 error("%s/%s:unexpected end of makefile",
148 while (line
[strlen(line
)-1] != '\n' && !feof(fh
))
150 int pos
= ptr
- line
;
152 ptr
= xmalloc (linelen
);
156 fgets (line
+strlen(line
), linelen
-strlen(line
), fh
);
160 if (line
[strlen(line
)-1] == '\n')
162 line
[strlen(line
)-1] = 0;
165 if (strncmp (ptr
, "##MM", 3) == 0)
167 *ptr
= line
[strlen(line
)-1];
172 if (strncmp (ptr
, "#MM", 3) != 0)
175 error("%s/%s:%d:continuation line has to start with #MM",
183 memmove (ptr
, ptr
+4, strlen(ptr
)-4+1);
190 flags
|= FLAG_VIRTUAL
;
194 flags
&= ~FLAG_VIRTUAL
;
196 while (isspace (*ptr
))
201 /* Line with only #MM, metatarget is on next line */
203 fgets (line
, linelen
, fh
);
207 while (*ptr
!= ':' && *ptr
)
212 targets
= getargs (line
, &count
, NULL
);
218 printf ("Warning: Multiple metatargets, only the 1st will be added in %s:%d (%s)\n",
219 makefile
->node
.name
, lineno
, buildpath(node
)
221 /* FIXME: should we better add all metatargets? */
223 mftarget
= FindNode (&makefile
->targets
, targets
[0]);
225 if (mftarget
== NULL
)
227 mftarget
= newmakefiletarget (targets
[0], 0);
228 AddTail (&makefile
->targets
, mftarget
);
231 mftarget
->virtualtarget
= 0;
234 printf ("Warning: Can't find metatarget in %s:%d (%s)\n", makefile
->node
.name
, lineno
, buildpath(node
));
238 struct List newtargets
;
239 char * ptr2
= ptr
, ** tptr
;
240 struct MakefileTarget
* mftarget2
, * mftarget3
;
242 NewList (&newtargets
);
244 while (*ptr2
!= ':' && *ptr2
)
250 tptr
= getargs (ptr
, &count
, NULL
);
252 for (t
= 0; t
< count
; t
++)
254 mftarget
= newmakefiletarget (tptr
[t
], (flags
& FLAG_VIRTUAL
) != 0);
255 AddTail (&newtargets
, mftarget
);
258 tptr
= getargs (ptr2
, &count2
, NULL
);
260 if (count
> 1 && count2
== 0)
262 /* could mean a missing colon */
263 printf ("Warning: multiple metatargets but no prerequisites %s:%d (%s)\n",
264 makefile
->node
.name
, lineno
, buildpath(node
)
268 for (t
= 0; t
< count2
; t
++)
270 ForeachNode (&newtargets
, mftarget
)
271 addnodeonce (&mftarget
->deps
, tptr
[t
]);
274 ForeachNodeSafe (&newtargets
, mftarget
, mftarget2
)
276 mftarget3
= FindNode (&makefile
->targets
, mftarget
->node
.name
);
278 /* mftarget doesn't exists yet add it to targets */
279 if (mftarget3
== NULL
)
282 AddTail (&makefile
->targets
, mftarget
);
286 /* Merge data in mftarget into mftarget3 */
289 mftarget3
->virtualtarget
= mftarget3
->virtualtarget
&& mftarget
->virtualtarget
;
291 ForeachNode (&mftarget
->deps
, node
)
292 addnodeonce (&mftarget3
->deps
, node
->name
);
294 /* Free the targets from which the data was merged in other targets */
295 freemakefiletargetlist (&newtargets
);
298 } /* If this is a MetaMake line in the makefile */
299 } /* For all lines in a makefile */
302 printf ("Read %d lines\n", lineno
);
306 /* Call mmakefile with _MM_ target */
308 callmake_mm (struct Project
* prj
, struct Makefile
* makefile
)
310 static char buffer
[4096];
311 const char * path
= buildpath (makefile
->dir
);
312 const char * tname
= "_MM_";
315 debug(printf("MMAKE:project.c->callmake()\n"));
318 if (makefile
->generated
)
319 chdir (prj
->buildtop
);
325 setvar (&prj
->vars
, "CURDIR", path
);
326 setvar (&prj
->vars
, "TARGET", tname
);
330 for (t
=0; t
<mflagc
; t
++)
332 strcat (buffer
, mflags
[t
]);
333 strcat (buffer
, " ");
336 if (strcmp (makefile
->node
.name
, "Makefile")!=0 && strcmp (makefile
->node
.name
, "makefile")!=0);
338 strcat (buffer
, "--file=");
339 strcat (buffer
, makefile
->node
.name
);
340 strcat (buffer
, " ");
343 strcat (buffer
, tname
);
345 printf ("Making %s in %s\n", tname
, path
);
347 /* TODO: create filename for output */
348 /* execute returns 0 for error */
349 return execute (prj
, prj
->maketool
, "-", "-" /* "/home/mazze/mmtest" */, buffer
);
353 freemakefiletarget (struct MakefileTarget
* mftarget
)
355 freelist (&mftarget
->deps
);
360 freemakefiletargetlist (struct List
* targets
)
362 struct MakefileTarget
* mftarget
, * mftarget2
;
364 ForeachNodeSafe (targets
, mftarget
, mftarget2
)
365 freemakefiletarget (mftarget
);
371 printdirnode (struct DirNode
* node
, int level
)
373 struct DirNode
* subdir
;
376 for (t
=0; t
<level
; t
++)
379 printf ("%s\n", node
->node
.name
);
383 ForeachNode (&node
->subdirs
, subdir
)
384 printdirnode (subdir
, level
);
388 printdirnodemftarget (struct DirNode
* node
)
390 struct Makefile
* makefile
;
391 struct MakefileTarget
* mftarget
;
393 struct DirNode
* subdir
;
395 ForeachNode (&node
->makefiles
, makefile
)
397 printf ("%s/%s:\n", buildpath(node
), makefile
->node
.name
);
398 ForeachNode (&makefile
->targets
, mftarget
)
400 printf (" %s:", mftarget
->node
.name
);
401 ForeachNode (&mftarget
->deps
, dep
)
402 printf (" %s", dep
->name
);
407 ForeachNode (&node
->subdirs
, subdir
)
408 printdirnodemftarget (subdir
);
412 freedirnode (struct DirNode
* node
)
414 struct DirNode
* subnode
, * subnode2
;
416 ForeachNodeSafe (&node
->subdirs
, subnode
, subnode2
)
417 freedirnode (subnode
);
419 xfree (node
->node
.name
);
424 freemakefile (struct Makefile
* makefile
)
426 freemakefiletargetlist (&makefile
->targets
);
427 xfree (makefile
->node
.name
);
432 finddirnode (struct DirNode
* topnode
, const char * path
)
437 struct DirNode
* node
= topnode
, * subdir
;
448 for (len
=0; ptr
[len
] && ptr
[len
] != '/'; len
++);
450 strncpy (dirname
, ptr
, len
);
456 subdir
= FindNode (&node
->subdirs
, dirname
);
469 scandirnode (struct DirNode
* node
, const char * mfname
, struct List
* ignoredirs
)
473 struct dirent
* dirent
;
475 int mfnamelen
= strlen(mfname
), scanned
= 0;
477 debug(printf("MMAKE:dirnode.c->scandirnode('%s')\n", node
->node
.name
));
479 if (stat(".", &st
) != 0)
481 error("scandirnode(): scanning %s\n",
482 strlen(node
->node
.name
) == 0
489 if (st
.st_mtime
> node
->time
)
491 struct List newdirs
, newmakefiles
;
492 struct DirNode
* subdir
= NULL
, * subdir2
;
493 struct Makefile
* makefile
;
495 debug(printf("MMAKE:dirnode.c->scandirnode dir->time changed .. scanning\n"));
498 printf("scandirnode(): scanning %s\n",
499 strlen(node
->node
.name
)==0 ? "topdir" : buildpath(node
)
503 NewList (&newmakefiles
);
505 node
->time
= st
.st_mtime
;
507 dirh
= opendir (".");
510 error("opendir: could not open current dir");
514 while ((dirent
= readdir (dirh
)))
516 /* Add makefile if it present or the file with .src is present */
517 if (strcmp(dirent
->d_name
, mfname
) == 0
518 || (strlen(dirent
->d_name
) == mfnamelen
+ 4
519 && strncmp(dirent
->d_name
, mfname
, mfnamelen
) == 0
520 && strcmp(dirent
->d_name
+ mfnamelen
, ".src") == 0
524 /* Don't add makefile twice */
525 debug(printf("MMAKE:dirnode.c->scandirnode: %s found ('%s')\n", mfname
, dirent
->d_name
));
527 makefile
= FindNode (&newmakefiles
, mfname
);
528 if (makefile
== NULL
)
530 debug(printf("MMAKE:dirnode.c->scandirnode: Creating New Makefile node\n"));
531 makefile
= FindNode (&node
->makefiles
, mfname
);
532 if (makefile
!= NULL
)
538 makefile
= newnodesize (mfname
, sizeof (struct Makefile
));
539 makefile
->dir
= node
;
540 debug(printf("MMAKE:dirnode.c->scandirnode: Makefile node dir '%s'\n", node
->node
.name
));
541 makefile
->time
= (time_t)0;
542 NewList (&makefile
->targets
);
544 AddTail (&newmakefiles
, makefile
);
546 if (strcmp(dirent
->d_name
+ mfnamelen
, ".src") == 0)
547 makefile
->generated
= 1;
551 /* If the file is already in the makefiles from the current dirnode
552 * and it is still present in the directory copy it to the new makefiles
555 if (strlen (dirent
->d_name
) > 4
556 && strcmp (dirent
->d_name
+ strlen(dirent
->d_name
) - 4, ".src") == 0
559 dirent
->d_name
[strlen(dirent
->d_name
) - 4] = 0;
560 makefile
= FindNode (&node
->makefiles
, dirent
->d_name
);
561 dirent
->d_name
[strlen(dirent
->d_name
)] = '.';
564 makefile
= FindNode (&node
->makefiles
, dirent
->d_name
);
566 if (makefile
!= NULL
)
569 AddTail (&newmakefiles
, makefile
);
573 /* Add file to newsubdirs if it is a directory and it has not to be ignored
575 st
.st_mode
= 0; /* This makes us to ignore the file if it can't be stat()'ed.
576 This lets us to succesfully skip Unicode-named files under Windows */
577 lstat (dirent
->d_name
, &st
);
579 /* TODO: Add support to MetaMake for going through links
580 * If this feature is to be supported one also has to implement
581 * checks to avoid MetaMake going into infinite loop when circular
584 if (S_ISDIR (st
.st_mode
)
585 && strcmp (dirent
->d_name
, ".") != 0
586 && strcmp (dirent
->d_name
, "..") != 0
587 && !S_ISLNK (st
.st_mode
)
588 && !FindNode (ignoredirs
, dirent
->d_name
)
591 subdir
= FindNode (&node
->subdirs
, dirent
->d_name
);
599 subdir
= newnodesize (dirent
->d_name
, sizeof(struct DirNode
));
600 debug(printf("MMAKE:dirnode.c->scandirnode: New SubDir Node '%s' @ %p\n", dirent
->d_name
, subdir
));
601 subdir
->parent
= node
;
602 subdir
->time
= (time_t)0;
603 NewList (&subdir
->subdirs
);
604 NewList (&subdir
->makefiles
);
606 AddTail (&newdirs
, subdir
);
613 ForeachNodeSafe (&node
->subdirs
, subdir
, subdir2
)
614 freedirnode (subdir
);
615 AssignList (&node
->subdirs
, &newdirs
);
617 /* Clear the makefiles that have disappeared */
618 ForeachNode (&node
->makefiles
, makefile
)
620 struct MakefileTarget
* mftarget
;
622 ForeachNode (&makefile
->targets
, mftarget
)
623 freelist (&mftarget
->deps
);
625 freelist (&makefile
->targets
);
628 freelist (&node
->makefiles
);
630 AssignList (&node
->makefiles
, &newmakefiles
);
635 debug(printf("MMAKE:dirnode.c->scandirnode: Finished scanning dir '%s'\n", node
->node
.name
));
638 printf ("scandirnode()\n");
639 printdirnode (node
, 1);
647 scanmakefiles (struct Project
* prj
, struct DirNode
* node
, struct List
* vars
)
649 struct Makefile
* makefile
;
654 debug(printf("MMAKE:dirnode.c->scanmakefiles('%s')\n", node
->node
.name
));
658 ForeachNode (&node
->makefiles
, makefile
)
660 debug(printf("MMAKE:dirnode.c->scanmakefiles: %d '%s'\n", makefile
->generated
, makefile
->node
.name
));
662 if (makefile
->generated
== 0)
664 if (chdir(mm_srcdir
) < 0)
666 error("Could not change to dir '%s'", mm_srcdir
);
672 if (chdir(mm_builddir
) < 0)
674 error("Could not change to dir '%s'", mm_builddir
);
679 if ((strlen(makefile
->dir
->node
.name
) != 0) && (strcmp(makefile
->dir
->node
.name
, mm_srcdir
) != 0))
681 if (chdir(buildpath(makefile
->dir
)) < 0)
683 error("Could not change to dir '%s'", makefile
->dir
->node
.name
);
688 if (stat(makefile
->node
.name
, &st
) != 0)
690 error("Could not stat %s", makefile
->node
.name
);
694 if (st
.st_mtime
> makefile
->time
)
697 printf("scanmakefiles(): scanning makefile in %s/%s\n",
698 strlen(node
->node
.name
)==0 ? "topdir" : buildpath(node
),
703 printf ("Opening %s\n", makefile
->name
);
706 fh
= fopen (makefile
->node
.name
, "r");
709 error ("buildtargetlist:fopen(): Opening %s for reading",
714 /* Free old metatargets when the file is reread */
715 freemakefiletargetlist (&makefile
->targets
);
716 NewList (&makefile
->targets
);
718 readtargets(node
, makefile
, fh
);
721 makefile
->time
= st
.st_mtime
;
726 /* Call make for _MM_ target */
727 if (callmake_mm (prj
, makefile
))
730 /* TODO: parsing of the result */
735 } /* If the makefile needed to be scanned */
736 } /* For all makefiles in the project */
743 addmakefile (struct DirNode
* node
, const char * filename
)
745 static char curdir
[PATH_MAX
];
746 const char * ptr
= filename
;
749 struct DirNode
* subnode
;
750 struct Makefile
* makefile
= NULL
;
752 getcwd(curdir
, PATH_MAX
);
757 while (ptr
[len
] != '/' && ptr
[len
] != 0)
760 name
= xmalloc (len
+4+1); /* Make room for possibly adding .src at the end */
761 strncpy (name
, ptr
, len
);
766 subnode
= FindNode (&node
->subdirs
, name
);
779 if (len
>= 4 && strcmp (name
+len
-4, ".src") == 0)
782 makefile
= FindNode (&node
->makefiles
, name
);
784 if (makefile
== NULL
)
788 printf ("Trying to stat %s\n", name
);
790 if (stat(name
, &st
) != 0)
793 strcat (name
, ".src");
794 if (stat (name
, &st
) != 0)
803 makefile
= newnodesize (name
, sizeof (struct Makefile
));
804 makefile
->dir
= node
;
805 makefile
->time
= (time_t)0;
806 NewList (&makefile
->targets
);
807 AddTail (&node
->makefiles
, makefile
);
823 findmakefile (struct DirNode
* node
, const char *filename
)
825 const char * ptr
= filename
;
828 struct DirNode
* subnode
;
829 struct Makefile
* makefile
= NULL
;
834 while (ptr
[len
] != '/' && ptr
[len
] != 0)
837 name
= xstrndup (ptr
, len
);
842 subnode
= FindNode (&node
->subdirs
, name
);
854 if (len
>= 4 && strcmp (name
+len
-4, ".src") == 0)
857 makefile
= FindNode (&node
->makefiles
, name
);
870 struct DirNode
* dirnode
;
875 buildpath (struct DirNode
* node
)
877 static char path
[PATH_MAX
];
879 struct DirNodeRef
* ref
= NULL
;
885 if ((strlen (node
->node
.name
) > 0) && (strcmp(node
->node
.name
, mm_srcdir
) != 0))
887 ref
= newnodesize ("", sizeof (struct DirNodeRef
));
889 AddHead (&tree
, ref
);
892 } while (node
!= NULL
);
895 ForeachNode (&tree
, ref
)
899 strcat (path
, ref
->dirnode
->node
.name
);
908 readmakefile (FILE * fh
)
910 struct Makefile
* makefile
;
911 struct MakefileTarget
* mftarget
;
916 if (!readstring(fh
, &s
))
918 error ("readmakefile:readstring():%d", __LINE__
);
925 makefile
= newnodesize(s
, sizeof(struct Makefile
));
927 NewList(&makefile
->targets
);
929 if (!readuint32 (fh
, &intt
))
931 error ("readmakefile:fread():%d", __LINE__
);
934 makefile
->time
= intt
;
936 if (!readuint32 (fh
, &intt
))
938 error ("readmakefile:fread():%d", __LINE__
);
941 makefile
->generated
= intt
;
947 if (!readstring(fh
, &s
))
949 error ("readmakefile:readstring():%d", __LINE__
);
956 mftarget
= newnodesize(s
, sizeof(struct MakefileTarget
));
958 AddTail (&makefile
->targets
, mftarget
);
959 NewList (&mftarget
->deps
);
961 if (!readint32 (fh
, &in
))
963 error ("readmakefile:fread():%d", __LINE__
);
966 mftarget
->virtualtarget
= in
;
970 if (!readstring(fh
, &s
))
972 error ("readmakefile:readstring():%d", __LINE__
);
981 AddTail (&mftarget
->deps
, n
);
990 writemakefile (FILE * fh
, struct Makefile
* makefile
)
992 struct MakefileTarget
* mftarget
;
995 if (makefile
== NULL
)
997 if (!writestring (fh
, NULL
))
999 error ("writemakefile/writestring():%d", __LINE__
);
1006 if (!writestring (fh
, makefile
->node
.name
))
1008 error ("writemakefile/writestring():%d", __LINE__
);
1012 if (!writeuint32 (fh
, makefile
->time
))
1014 error ("writemakefile/fwrite():%d", __LINE__
);
1018 if (!writeuint32 (fh
, makefile
->generated
))
1020 error ("writemakefile/fwrite():%d", __LINE__
);
1024 ForeachNode (&makefile
->targets
, mftarget
)
1026 if (!writestring (fh
, mftarget
->node
.name
))
1028 error ("writemakefile/writestring():%d", __LINE__
);
1032 if (!writeint32 (fh
, mftarget
->virtualtarget
))
1034 error ("writemakefile/fwrite():%d", __LINE__
);
1038 ForeachNode (&mftarget
->deps
, n
)
1040 if (!writestring (fh
, n
->name
))
1042 error ("writemakefile/writestring():%d", __LINE__
);
1047 if (!writestring (fh
, NULL
))
1049 error ("writemakefile/writestring():%d", __LINE__
);
1054 if (!writestring(fh
, NULL
))
1056 error ("writemakefile/writestring():%d", __LINE__
);
1065 readcachedir (FILE * fh
)
1067 struct DirNode
* node
, * subnode
;
1068 struct Makefile
* makefile
;
1072 if (!readstring(fh
, &s
))
1074 error ("readcachedir:readstring():%d", __LINE__
);
1081 node
= newnodesize(s
, sizeof(struct DirNode
));
1083 NewList(&node
->makefiles
);
1084 NewList(&node
->subdirs
);
1086 if (!readuint32 (fh
, &intt
))
1088 error ("readcachedir:fread():%d", __LINE__
);
1094 while ((makefile
= readmakefile (fh
)))
1096 makefile
->dir
= node
;
1097 AddTail (&node
->makefiles
, makefile
);
1100 while ((subnode
= readcachedir (fh
)))
1102 subnode
->parent
= node
;
1103 AddTail (&node
->subdirs
, subnode
);
1110 writecachedir (FILE * fh
, struct DirNode
* node
)
1113 struct DirNode
* subnode
;
1114 struct Makefile
* makefile
;
1118 if (!writestring(fh
, NULL
))
1120 error ("writecachedir/writestring():%d", __LINE__
);
1127 if (!writestring(fh
, node
->node
.name
))
1129 error ("writecachedir/writestring():%d", __LINE__
);
1133 if (!writeuint32 (fh
, node
->time
))
1135 error ("writecachedir/fwrite():%d", __LINE__
);
1139 ForeachNode (&node
->makefiles
, makefile
)
1140 writemakefile (fh
, makefile
);
1142 if (!writemakefile (fh
, NULL
))
1145 ForeachNode (&node
->subdirs
, subnode
)
1147 if (!writecachedir (fh
, subnode
))
1151 return writecachedir (fh
, NULL
);