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 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
->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
))
203 /* Line with only #MM, metatarget is on next line */
205 fgets (line
, linelen
, fh
);
209 while (*ptr
!= ':' && *ptr
)
214 targets
= getargs (line
, &count
, NULL
);
220 printf ("Warning: Multiple metatargets, only the 1st will be added in %s:%d (%s)\n",
221 makefile
->node
.name
, lineno
, buildpath(node
)
223 /* FIXME: should we better add all metatargets? */
225 mftarget
= FindNode (&makefile
->targets
, targets
[0]);
227 if (mftarget
== NULL
)
229 mftarget
= newmakefiletarget (targets
[0], 0);
230 AddTail (&makefile
->targets
, mftarget
);
233 mftarget
->virtualtarget
= 0;
236 printf ("Warning: Can't find metatarget in %s:%d (%s)\n", makefile
->node
.name
, lineno
, buildpath(node
));
240 struct List newtargets
;
241 char * ptr2
= ptr
, ** tptr
;
242 struct MakefileTarget
* mftarget2
, * mftarget3
;
244 NewList (&newtargets
);
246 while (*ptr2
!= ':' && *ptr2
)
252 tptr
= getargs (ptr
, &count
, NULL
);
254 for (t
= 0; t
< count
; t
++)
256 mftarget
= newmakefiletarget (tptr
[t
], (flags
& FLAG_VIRTUAL
) != 0);
257 AddTail (&newtargets
, mftarget
);
260 tptr
= getargs (ptr2
, &count2
, NULL
);
262 if (count
> 1 && count2
== 0)
264 /* could mean a missing colon */
265 printf ("Warning: multiple metatargets but no prerequisites %s:%d (%s)\n",
266 makefile
->node
.name
, lineno
, buildpath(node
)
270 for (t
= 0; t
< count2
; t
++)
272 ForeachNode (&newtargets
, mftarget
)
273 addnodeonce (&mftarget
->deps
, tptr
[t
]);
276 ForeachNodeSafe (&newtargets
, mftarget
, mftarget2
)
278 mftarget3
= FindNode (&makefile
->targets
, mftarget
->node
.name
);
280 /* mftarget doesn't exists yet add it to targets */
281 if (mftarget3
== NULL
)
284 AddTail (&makefile
->targets
, mftarget
);
288 /* Merge data in mftarget into mftarget3 */
291 mftarget3
->virtualtarget
= mftarget3
->virtualtarget
&& mftarget
->virtualtarget
;
293 ForeachNode (&mftarget
->deps
, node
)
294 addnodeonce (&mftarget3
->deps
, node
->name
);
296 /* Free the targets from which the data was merged in other targets */
297 freemakefiletargetlist (&newtargets
);
300 } /* If this is a MetaMake line in the makefile */
301 } /* For all lines in a makefile */
304 printf ("Read %d lines\n", lineno
);
308 /* Call mmakefile with _MM_ target */
310 callmake_mm (struct Project
* prj
, struct Makefile
* makefile
)
312 static char buffer
[4096];
313 const char * path
= buildpath (makefile
->dir
);
314 const char * tname
= "_MM_";
317 debug(printf("MMAKE:project.c->callmake()\n"));
320 if (makefile
->generated
)
321 chdir (prj
->buildtop
);
327 setvar (&prj
->vars
, "CURDIR", path
);
328 setvar (&prj
->vars
, "TARGET", tname
);
332 for (t
=0; t
<mflagc
; t
++)
334 strcat (buffer
, mflags
[t
]);
335 strcat (buffer
, " ");
338 if (strcmp (makefile
->node
.name
, "Makefile")!=0 && strcmp (makefile
->node
.name
, "makefile")!=0);
340 strcat (buffer
, "--file=");
341 strcat (buffer
, makefile
->node
.name
);
342 strcat (buffer
, " ");
345 strcat (buffer
, tname
);
347 printf ("Making %s in %s\n", tname
, path
);
349 /* TODO: create filename for output */
350 /* execute returns 0 for error */
351 return execute (prj
, prj
->maketool
, "-", "-" /* "/home/mazze/mmtest" */, buffer
);
355 freemakefiletarget (struct MakefileTarget
* mftarget
)
357 freelist (&mftarget
->deps
);
363 freemakefiletargetlist (struct List
* targets
)
365 struct MakefileTarget
* mftarget
, * mftarget2
;
367 ForeachNodeSafe (targets
, mftarget
, mftarget2
)
368 freemakefiletarget (mftarget
);
374 printdirnode (struct DirNode
* node
, int level
)
376 struct DirNode
* subdir
;
379 for (t
=0; t
<level
; t
++)
382 printf ("%s\n", node
->node
.name
);
386 ForeachNode (&node
->subdirs
, subdir
)
387 printdirnode (subdir
, level
);
391 printdirnodemftarget (struct DirNode
* node
)
393 struct Makefile
* makefile
;
394 struct MakefileTarget
* mftarget
;
396 struct DirNode
* subdir
;
398 ForeachNode (&node
->makefiles
, makefile
)
400 printf ("%s/%s:\n", buildpath(node
), makefile
->node
.name
);
401 ForeachNode (&makefile
->targets
, mftarget
)
403 printf (" %s:", mftarget
->node
.name
);
404 ForeachNode (&mftarget
->deps
, dep
)
405 printf (" %s", dep
->name
);
410 ForeachNode (&node
->subdirs
, subdir
)
411 printdirnodemftarget (subdir
);
415 freedirnode (struct DirNode
* node
)
417 struct DirNode
* subnode
, * subnode2
;
419 ForeachNodeSafe (&node
->subdirs
, subnode
, subnode2
)
420 freedirnode (subnode
);
422 xfree (node
->node
.name
);
427 freemakefile (struct Makefile
* makefile
)
429 freemakefiletargetlist (&makefile
->targets
);
430 xfree (makefile
->node
.name
);
435 finddirnode (struct DirNode
* topnode
, const char * path
)
440 struct DirNode
* node
= topnode
, * subdir
;
451 for (len
=0; ptr
[len
] && ptr
[len
] != '/'; len
++);
453 strncpy (dirname
, ptr
, len
);
459 subdir
= FindNode (&node
->subdirs
, dirname
);
470 static int nodedepth (struct DirNode
* node
)
474 for (depth
= 0; node
->parent
; depth
++, node
= node
->parent
);
480 scandirnode (struct DirNode
* node
, const char * mfname
, struct List
* ignoredirs
)
484 struct dirent
* dirent
;
486 int mfnamelen
= strlen(mfname
), scanned
= 0;
489 * To avoid MetaMake going into infinite loop when circular
490 * linking is present, we limit the total depth.
492 if (nodedepth(node
) > MAX_NODEDEPTH
) {
493 error("scandirnode(): exceeded maximum directory depth of %d\n%s\n", MAX_NODEDEPTH
, buildpath(node
));
497 debug(printf("MMAKE:dirnode.c->scandirnode('%s')\n", node
->node
.name
));
499 if (stat(".", &st
) != 0)
501 error("scandirnode(): scanning %s\n",
502 strlen(node
->node
.name
) == 0
509 if (st
.st_mtime
> node
->time
)
511 struct List newdirs
, newmakefiles
;
512 struct DirNode
* subdir
= NULL
, * subdir2
;
513 struct Makefile
* makefile
;
515 debug(printf("MMAKE:dirnode.c->scandirnode dir->time changed .. scanning\n"));
518 printf("scandirnode(): scanning %s\n",
519 strlen(node
->node
.name
)==0 ? "topdir" : buildpath(node
)
523 NewList (&newmakefiles
);
525 node
->time
= st
.st_mtime
;
527 dirh
= opendir (".");
530 error("opendir: could not open current dir");
534 while ((dirent
= readdir (dirh
)))
536 /* Add makefile if it present or the file with .src is present */
537 if (strcmp(dirent
->d_name
, mfname
) == 0
538 || (strlen(dirent
->d_name
) == mfnamelen
+ 4
539 && strncmp(dirent
->d_name
, mfname
, mfnamelen
) == 0
540 && strcmp(dirent
->d_name
+ mfnamelen
, ".src") == 0
544 /* Don't add makefile twice */
545 debug(printf("MMAKE:dirnode.c->scandirnode: %s found ('%s')\n", mfname
, dirent
->d_name
));
547 makefile
= FindNode (&newmakefiles
, mfname
);
548 if (makefile
== NULL
)
550 debug(printf("MMAKE:dirnode.c->scandirnode: Creating New Makefile node\n"));
551 makefile
= FindNode (&node
->makefiles
, mfname
);
552 if (makefile
!= NULL
)
558 makefile
= newnodesize (mfname
, sizeof (struct Makefile
));
559 makefile
->dir
= node
;
560 debug(printf("MMAKE:dirnode.c->scandirnode: Makefile node dir '%s'\n", node
->node
.name
));
561 makefile
->time
= (time_t)0;
562 NewList (&makefile
->targets
);
564 AddTail (&newmakefiles
, makefile
);
566 if (strcmp(dirent
->d_name
+ mfnamelen
, ".src") == 0)
567 makefile
->generated
= 1;
571 /* If the file is already in the makefiles from the current dirnode
572 * and it is still present in the directory copy it to the new makefiles
575 if (strlen (dirent
->d_name
) > 4
576 && strcmp (dirent
->d_name
+ strlen(dirent
->d_name
) - 4, ".src") == 0
579 dirent
->d_name
[strlen(dirent
->d_name
) - 4] = 0;
580 makefile
= FindNode (&node
->makefiles
, dirent
->d_name
);
581 dirent
->d_name
[strlen(dirent
->d_name
)] = '.';
584 makefile
= FindNode (&node
->makefiles
, dirent
->d_name
);
586 if (makefile
!= NULL
)
589 AddTail (&newmakefiles
, makefile
);
593 /* Add file to newsubdirs if it is a directory and it has not to be ignored
595 st
.st_mode
= 0; /* This makes us to ignore the file if it can't be stat()'ed.
596 This lets us to succesfully skip Unicode-named files under Windows */
597 stat (dirent
->d_name
, &st
);
599 if (S_ISDIR (st
.st_mode
)
600 && strcmp (dirent
->d_name
, ".") != 0
601 && strcmp (dirent
->d_name
, "..") != 0
602 && !FindNode (ignoredirs
, dirent
->d_name
)
605 subdir
= FindNode (&node
->subdirs
, dirent
->d_name
);
613 subdir
= newnodesize (dirent
->d_name
, sizeof(struct DirNode
));
614 debug(printf("MMAKE:dirnode.c->scandirnode: New SubDir Node '%s' @ %p\n", dirent
->d_name
, subdir
));
615 subdir
->parent
= node
;
616 subdir
->time
= (time_t)0;
617 NewList (&subdir
->subdirs
);
618 NewList (&subdir
->makefiles
);
620 AddTail (&newdirs
, subdir
);
627 ForeachNodeSafe (&node
->subdirs
, subdir
, subdir2
)
628 freedirnode (subdir
);
629 AssignList (&node
->subdirs
, &newdirs
);
631 /* Clear the makefiles that have disappeared */
632 ForeachNode (&node
->makefiles
, makefile
)
634 struct MakefileTarget
* mftarget
;
636 ForeachNode (&makefile
->targets
, mftarget
)
637 freelist (&mftarget
->deps
);
639 freelist (&makefile
->targets
);
642 freelist (&node
->makefiles
);
644 AssignList (&node
->makefiles
, &newmakefiles
);
649 debug(printf("MMAKE:dirnode.c->scandirnode: Finished scanning dir '%s'\n", node
->node
.name
));
652 printf ("scandirnode()\n");
653 printdirnode (node
, 1);
661 scanmakefiles (struct Project
* prj
, struct DirNode
* node
, struct List
* vars
)
663 struct Makefile
* makefile
;
668 debug(printf("MMAKE:dirnode.c->scanmakefiles('%s')\n", node
->node
.name
));
672 ForeachNode (&node
->makefiles
, makefile
)
674 debug(printf("MMAKE:dirnode.c->scanmakefiles: %d '%s'\n", makefile
->generated
, makefile
->node
.name
));
676 if (makefile
->generated
== 0)
678 if (chdir(mm_srcdir
) < 0)
680 error("Could not change to dir '%s'", mm_srcdir
);
686 if (chdir(mm_builddir
) < 0)
688 error("Could not change to dir '%s'", mm_builddir
);
693 if ((strlen(makefile
->dir
->node
.name
) != 0) && (strcmp(makefile
->dir
->node
.name
, mm_srcdir
) != 0))
695 if (chdir(buildpath(makefile
->dir
)) < 0)
697 error("Could not change to dir '%s'", makefile
->dir
->node
.name
);
702 if (stat(makefile
->node
.name
, &st
) != 0)
704 error("Could not stat %s", makefile
->node
.name
);
708 if (st
.st_mtime
> makefile
->time
)
711 printf("scanmakefiles(): scanning makefile in %s/%s\n",
712 strlen(node
->node
.name
)==0 ? "topdir" : buildpath(node
),
717 printf ("Opening %s\n", makefile
->name
);
720 fh
= fopen (makefile
->node
.name
, "r");
723 error ("buildtargetlist:fopen(): Opening %s for reading",
728 /* Free old metatargets when the file is reread */
729 freemakefiletargetlist (&makefile
->targets
);
730 NewList (&makefile
->targets
);
732 readtargets(node
, makefile
, fh
);
735 makefile
->time
= st
.st_mtime
;
740 /* Call make for _MM_ target */
741 if (callmake_mm (prj
, makefile
))
744 /* TODO: parsing of the result */
749 } /* If the makefile needed to be scanned */
750 } /* For all makefiles in the project */
757 addmakefile (struct DirNode
* node
, const char * filename
)
759 static char curdir
[PATH_MAX
];
760 const char * ptr
= filename
;
763 struct DirNode
* subnode
;
764 struct Makefile
* makefile
= NULL
;
766 getcwd(curdir
, PATH_MAX
);
771 while (ptr
[len
] != '/' && ptr
[len
] != 0)
774 name
= xmalloc (len
+4+1); /* Make room for possibly adding .src at the end */
775 strncpy (name
, ptr
, len
);
780 subnode
= FindNode (&node
->subdirs
, name
);
793 if (len
>= 4 && strcmp (name
+len
-4, ".src") == 0)
796 makefile
= FindNode (&node
->makefiles
, name
);
798 if (makefile
== NULL
)
802 printf ("Trying to stat %s\n", name
);
804 if (stat(name
, &st
) != 0)
807 strcat (name
, ".src");
808 if (stat (name
, &st
) != 0)
817 makefile
= newnodesize (name
, sizeof (struct Makefile
));
818 makefile
->dir
= node
;
819 makefile
->time
= (time_t)0;
820 NewList (&makefile
->targets
);
821 AddTail (&node
->makefiles
, makefile
);
837 findmakefile (struct DirNode
* node
, const char *filename
)
839 const char * ptr
= filename
;
842 struct DirNode
* subnode
;
843 struct Makefile
* makefile
= NULL
;
848 while (ptr
[len
] != '/' && ptr
[len
] != 0)
851 name
= xstrndup (ptr
, len
);
856 subnode
= FindNode (&node
->subdirs
, name
);
868 if (len
>= 4 && strcmp (name
+len
-4, ".src") == 0)
871 makefile
= FindNode (&node
->makefiles
, name
);
884 struct DirNode
* dirnode
;
889 buildpath (struct DirNode
* node
)
891 static char path
[PATH_MAX
];
893 struct DirNodeRef
* ref
= NULL
;
899 if ((strlen (node
->node
.name
) > 0) && (strcmp(node
->node
.name
, mm_srcdir
) != 0))
901 ref
= newnodesize ("", sizeof (struct DirNodeRef
));
903 AddHead (&tree
, ref
);
906 } while (node
!= NULL
);
909 ForeachNode (&tree
, ref
)
913 strcat (path
, ref
->dirnode
->node
.name
);
922 readmakefile (FILE * fh
)
924 struct Makefile
* makefile
;
925 struct MakefileTarget
* mftarget
;
930 if (!readstring(fh
, &s
))
932 error ("readmakefile:readstring():%d", __LINE__
);
939 makefile
= newnodesize(s
, sizeof(struct Makefile
));
941 NewList(&makefile
->targets
);
943 if (!readuint32 (fh
, &intt
))
945 error ("readmakefile:fread():%d", __LINE__
);
948 makefile
->time
= intt
;
950 if (!readuint32 (fh
, &intt
))
952 error ("readmakefile:fread():%d", __LINE__
);
955 makefile
->generated
= intt
;
961 if (!readstring(fh
, &s
))
963 error ("readmakefile:readstring():%d", __LINE__
);
970 mftarget
= newnodesize(s
, sizeof(struct MakefileTarget
));
972 AddTail (&makefile
->targets
, mftarget
);
973 NewList (&mftarget
->deps
);
975 if (!readint32 (fh
, &in
))
977 error ("readmakefile:fread():%d", __LINE__
);
980 mftarget
->virtualtarget
= in
;
984 if (!readstring(fh
, &s
))
986 error ("readmakefile:readstring():%d", __LINE__
);
995 AddTail (&mftarget
->deps
, n
);
1004 writemakefile (FILE * fh
, struct Makefile
* makefile
)
1006 struct MakefileTarget
* mftarget
;
1009 if (makefile
== NULL
)
1011 if (!writestring (fh
, NULL
))
1013 error ("writemakefile/writestring():%d", __LINE__
);
1020 if (!writestring (fh
, makefile
->node
.name
))
1022 error ("writemakefile/writestring():%d", __LINE__
);
1026 if (!writeuint32 (fh
, makefile
->time
))
1028 error ("writemakefile/fwrite():%d", __LINE__
);
1032 if (!writeuint32 (fh
, makefile
->generated
))
1034 error ("writemakefile/fwrite():%d", __LINE__
);
1038 ForeachNode (&makefile
->targets
, mftarget
)
1040 if (!writestring (fh
, mftarget
->node
.name
))
1042 error ("writemakefile/writestring():%d", __LINE__
);
1046 if (!writeint32 (fh
, mftarget
->virtualtarget
))
1048 error ("writemakefile/fwrite():%d", __LINE__
);
1052 ForeachNode (&mftarget
->deps
, n
)
1054 if (!writestring (fh
, n
->name
))
1056 error ("writemakefile/writestring():%d", __LINE__
);
1061 if (!writestring (fh
, NULL
))
1063 error ("writemakefile/writestring():%d", __LINE__
);
1068 if (!writestring(fh
, NULL
))
1070 error ("writemakefile/writestring():%d", __LINE__
);
1079 readcachedir (FILE * fh
)
1081 struct DirNode
* node
, * subnode
;
1082 struct Makefile
* makefile
;
1086 if (!readstring(fh
, &s
))
1088 error ("readcachedir:readstring():%d", __LINE__
);
1095 node
= newnodesize(s
, sizeof(struct DirNode
));
1097 NewList(&node
->makefiles
);
1098 NewList(&node
->subdirs
);
1100 if (!readuint32 (fh
, &intt
))
1102 error ("readcachedir:fread():%d", __LINE__
);
1108 while ((makefile
= readmakefile (fh
)))
1110 makefile
->dir
= node
;
1111 AddTail (&node
->makefiles
, makefile
);
1114 while ((subnode
= readcachedir (fh
)))
1116 subnode
->parent
= node
;
1117 AddTail (&node
->subdirs
, subnode
);
1124 writecachedir (FILE * fh
, struct DirNode
* node
)
1127 struct DirNode
* subnode
;
1128 struct Makefile
* makefile
;
1132 if (!writestring(fh
, NULL
))
1134 error ("writecachedir/writestring():%d", __LINE__
);
1141 if (!writestring(fh
, node
->node
.name
))
1143 error ("writecachedir/writestring():%d", __LINE__
);
1147 if (!writeuint32 (fh
, node
->time
))
1149 error ("writecachedir/fwrite():%d", __LINE__
);
1153 ForeachNode (&node
->makefiles
, makefile
)
1154 writemakefile (fh
, makefile
);
1156 if (!writemakefile (fh
, NULL
))
1159 ForeachNode (&node
->subdirs
, subnode
)
1161 if (!writecachedir (fh
, subnode
))
1165 return writecachedir (fh
, NULL
);