1 /* MetaMake - A Make extension
2 Copyright © 1995-2008, 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>
50 #if defined(DEBUG_DIRNODE)
56 #define FLAG_VIRTUAL 0x0001
58 extern char *mm_srcdir
;
59 extern char *mm_builddir
;
61 static MakefileTarget
*
62 newmakefiletarget (char *name
, int virtualtarget
)
64 MakefileTarget
* mftarget
;
66 mftarget
= newnodesize (name
, sizeof(MakefileTarget
));
67 mftarget
->virtualtarget
= virtualtarget
;
68 NewList (&mftarget
->deps
);
74 freemakefiletarget (MakefileTarget
* mftarget
)
76 freelist (&mftarget
->deps
);
81 freemakefiletargetlist (List
* targets
)
83 MakefileTarget
* mftarget
, * mftarget2
;
85 ForeachNodeSafe (targets
, mftarget
, mftarget2
)
86 freemakefiletarget (mftarget
);
92 printdirnode (DirNode
* node
, int level
)
97 for (t
=0; t
<level
; t
++)
100 printf ("%s\n", node
->node
.name
);
104 ForeachNode (&node
->subdirs
, subdir
)
105 printdirnode (subdir
, level
);
109 printdirnodemftarget (DirNode
* node
)
112 MakefileTarget
* mftarget
;
116 ForeachNode (&node
->makefiles
, makefile
)
118 printf ("%s/%s:\n", buildpath(node
), makefile
->node
.name
);
119 ForeachNode (&makefile
->targets
, mftarget
)
121 printf (" %s:", mftarget
->node
.name
);
122 ForeachNode (&mftarget
->deps
, dep
)
123 printf (" %s", dep
->name
);
128 ForeachNode (&node
->subdirs
, subdir
)
129 printdirnodemftarget (subdir
);
133 freedirnode (DirNode
* node
)
135 DirNode
* subnode
, * subnode2
;
137 ForeachNodeSafe (&node
->subdirs
, subnode
, subnode2
)
138 freedirnode (subnode
);
140 xfree (node
->node
.name
);
145 freemakefile (Makefile
* makefile
)
147 freemakefiletargetlist (&makefile
->targets
);
148 xfree (makefile
->node
.name
);
153 finddirnode (DirNode
* topnode
, const char * path
)
158 DirNode
* node
= topnode
, * subdir
;
169 for (len
=0; ptr
[len
] && ptr
[len
] != '/'; len
++);
171 strncpy (dirname
, ptr
, len
);
177 subdir
= FindNode (&node
->subdirs
, dirname
);
190 scandirnode (DirNode
* node
, const char * mfname
, List
* ignoredirs
)
194 struct dirent
* dirent
;
196 int mfnamelen
= strlen(mfname
), scanned
= 0;
198 debug(printf("MMAKE:dirnode.c->scandirnode('%s')\n", node
->node
.name
));
200 if (stat(".", &st
) != 0)
202 error("scandirnode(): scanning %s\n",
203 strlen(node
->node
.name
) == 0
210 if (st
.st_mtime
> node
->time
)
212 List newdirs
, newmakefiles
;
213 DirNode
* subdir
= NULL
, * subdir2
;
216 debug(printf("MMAKE:dirnode.c->scandirnode dir->time changed .. scanning\n"));
219 printf("scandirnode(): scanning %s\n",
220 strlen(node
->node
.name
)==0 ? "topdir" : buildpath(node
)
224 NewList (&newmakefiles
);
226 node
->time
= st
.st_mtime
;
228 dirh
= opendir (".");
231 error("opendir: could not open current dir");
235 while ((dirent
= readdir (dirh
)))
237 /* Add makefile if it present or the file with .src is present */
238 if (strcmp(dirent
->d_name
, mfname
) == 0
239 || (strlen(dirent
->d_name
) == mfnamelen
+ 4
240 && strncmp(dirent
->d_name
, mfname
, mfnamelen
) == 0
241 && strcmp(dirent
->d_name
+ mfnamelen
, ".src") == 0
245 /* Don't add makefile twice */
246 debug(printf("MMAKE:dirnode.c->scandirnode: %s found ('%s')\n", mfname
, dirent
->d_name
));
248 makefile
= FindNode (&newmakefiles
, mfname
);
249 if (makefile
== NULL
)
251 debug(printf("MMAKE:dirnode.c->scandirnode: Creating New Makefile node\n"));
252 makefile
= FindNode (&node
->makefiles
, mfname
);
253 if (makefile
!= NULL
)
259 makefile
= newnodesize (mfname
, sizeof (Makefile
));
260 makefile
->dir
= node
;
261 debug(printf("MMAKE:dirnode.c->scandirnode: Makefile node dir '%s'\n", node
->node
.name
));
262 makefile
->time
= (time_t)0;
263 NewList (&makefile
->targets
);
265 AddTail (&newmakefiles
, makefile
);
267 if (strcmp(dirent
->d_name
+ mfnamelen
, ".src") == 0)
268 makefile
->generated
= 1;
272 /* If the file is already in the makefiles from the current dirnode
273 * and it is still present in the directory copy it to the new makefiles
276 if (strlen (dirent
->d_name
) > 4
277 && strcmp (dirent
->d_name
+ strlen(dirent
->d_name
) - 4, ".src") == 0
280 dirent
->d_name
[strlen(dirent
->d_name
) - 4] = 0;
281 makefile
= FindNode (&node
->makefiles
, dirent
->d_name
);
282 dirent
->d_name
[strlen(dirent
->d_name
)] = '.';
285 makefile
= FindNode (&node
->makefiles
, dirent
->d_name
);
287 if (makefile
!= NULL
)
290 AddTail (&newmakefiles
, makefile
);
294 /* Add file to newsubdirs if it is a directory and it has not to be ignored
296 if (lstat (dirent
->d_name
, &st
) == -1)
298 error ("scandirnode: stat(%s)", dirent
->d_name
);
302 /* TODO: Add support to MetaMake for going through links
303 * If this feature is to be supported one also has to implement
304 * checks to avoid MetaMake going into infinite loop when circular
307 if (S_ISDIR (st
.st_mode
)
308 && strcmp (dirent
->d_name
, ".") != 0
309 && strcmp (dirent
->d_name
, "..") != 0
310 && !S_ISLNK (st
.st_mode
)
311 && !FindNode (ignoredirs
, dirent
->d_name
)
314 subdir
= FindNode (&node
->subdirs
, dirent
->d_name
);
322 subdir
= newnodesize (dirent
->d_name
, sizeof(DirNode
));
323 debug(printf("MMAKE:dirnode.c->scandirnode: New SubDir Node '%s' @ %p\n", dirent
->d_name
, subdir
));
324 subdir
->parent
= node
;
325 subdir
->time
= (time_t)0;
326 NewList (&subdir
->subdirs
);
327 NewList (&subdir
->makefiles
);
329 AddTail (&newdirs
, subdir
);
336 ForeachNodeSafe (&node
->subdirs
, subdir
, subdir2
)
337 freedirnode (subdir
);
338 AssignList (&node
->subdirs
, &newdirs
);
340 /* Clear the makefiles that have disappeared */
341 ForeachNode (&node
->makefiles
, makefile
)
343 MakefileTarget
* mftarget
;
345 ForeachNode (&makefile
->targets
, mftarget
)
346 freelist (&mftarget
->deps
);
348 freelist (&makefile
->targets
);
351 freelist (&node
->makefiles
);
353 AssignList (&node
->makefiles
, &newmakefiles
);
358 debug(printf("MMAKE:dirnode.c->scandirnode: Finished scanning dir '%s'\n", node
->node
.name
));
361 printf ("scandirnode()\n");
362 printdirnode (node
, 1);
370 scanmakefiles (DirNode
* node
, List
* vars
)
374 static char * line
= NULL
;
375 static int linelen
= 512;
379 debug(printf("MMAKE:dirnode.c->scanmakefiles('%s')\n", node
->node
.name
));
384 line
= xmalloc(linelen
);
386 ForeachNode (&node
->makefiles
, makefile
)
388 debug(printf("MMAKE:dirnode.c->scanmakefiles: %d '%s'\n", makefile
->generated
, makefile
->node
.name
));
390 if (makefile
->generated
== 0)
392 if (chdir(mm_srcdir
) < 0)
394 error("Could not change to dir '%s'", mm_srcdir
);
400 if (chdir(mm_builddir
) < 0)
402 error("Could not change to dir '%s'", mm_builddir
);
407 if ((strlen(makefile
->dir
->node
.name
) != 0) && (strcmp(makefile
->dir
->node
.name
, mm_srcdir
) != 0))
409 if (chdir(buildpath(makefile
->dir
)) < 0)
411 error("Could not change to dir '%s'", makefile
->dir
->node
.name
);
416 if (stat(makefile
->node
.name
, &st
) != 0)
418 error("Could not stat %s", makefile
->node
.name
);
422 if (st
.st_mtime
> makefile
->time
)
426 MakefileTarget
* mftarget
= NULL
;
429 printf("scanmakefiles(): scanning makefile in %s/%s\n",
430 strlen(node
->node
.name
)==0 ? "topdir" : buildpath(node
),
435 printf ("Opening %s\n", makefile
->name
);
438 fh
= fopen (makefile
->node
.name
, "r");
441 error ("buildtargetlist:fopen(): Opening %s for reading",
446 /* Free old metatargets when the file is reread */
447 freemakefiletargetlist (&makefile
->targets
);
448 NewList (&makefile
->targets
);
450 while (fgets (line
, linelen
, fh
))
454 while (line
[strlen(line
)-1] != '\n' && !feof(fh
))
459 ptr
= xmalloc (linelen
);
463 fgets (line
+strlen(line
), linelen
-strlen(line
), fh
);
466 if (line
[strlen(line
)-1] == '\n')
468 line
[strlen(line
)-1] = 0;
471 if (strncmp (line
, "#MM", 3) == 0)
477 printf ("found #MM in %s\n", makefile
->name
);
480 /* Read in next lines if there is continuation */
481 while (line
[strlen(line
)-1] == '\\')
483 ptr
= line
+ strlen(line
) - 1;
485 if (!fgets (ptr
, linelen
-strlen(line
)+1, fh
))
487 error("%s/%s:unexpected end of makefile",
496 while (line
[strlen(line
)-1] != '\n' && !feof(fh
))
498 int pos
= ptr
- line
;
500 ptr
= xmalloc (linelen
);
504 fgets (line
+strlen(line
), linelen
-strlen(line
), fh
);
508 if (line
[strlen(line
)-1] == '\n')
510 line
[strlen(line
)-1] = 0;
513 if (strncmp (ptr
, "##MM", 3) == 0)
515 *ptr
= line
[strlen(line
)-1];
520 if (strncmp (ptr
, "#MM", 3) != 0)
523 error("%s/%s:%d:continuation line has to start with #MM",
531 memmove (ptr
, ptr
+4, strlen(ptr
)-4+1);
538 flags
|= FLAG_VIRTUAL
;
542 flags
&= ~FLAG_VIRTUAL
;
544 while (isspace (*ptr
))
549 /* Line with only #MM, metatarget is on next line */
551 fgets (line
, linelen
, fh
);
555 while (*ptr
!= ':' && *ptr
)
560 targets
= getargs (line
, &count
, NULL
);
564 mftarget
= FindNode (&makefile
->targets
, targets
[0]);
566 if (mftarget
== NULL
)
568 mftarget
= newmakefiletarget (targets
[0], 0);
569 AddTail (&makefile
->targets
, mftarget
);
572 mftarget
->virtualtarget
= 0;
575 printf ("Warning: Can't find metatarget in %s:%d (%s)\n", makefile
->node
.name
, lineno
, buildpath(node
));
580 char * ptr2
= ptr
, ** tptr
;
581 MakefileTarget
* mftarget2
, * mftarget3
;
583 NewList (&newtargets
);
585 while (*ptr2
!= ':' && *ptr2
)
590 tptr
= getargs (ptr
, &count
, NULL
);
592 for (t
= 0; t
< count
; t
++)
594 mftarget
= newmakefiletarget (tptr
[t
], (flags
& FLAG_VIRTUAL
) != 0);
595 AddTail (&newtargets
, mftarget
);
598 tptr
= getargs (ptr2
, &count
, NULL
);
599 for (t
= 0; t
< count
; t
++)
601 ForeachNode (&newtargets
, mftarget
)
602 addnodeonce (&mftarget
->deps
, tptr
[t
]);
605 ForeachNodeSafe (&newtargets
, mftarget
, mftarget2
)
607 mftarget3
= FindNode (&makefile
->targets
, mftarget
->node
.name
);
609 /* mftarget doesn't exists yet add it to targets */
610 if (mftarget3
== NULL
)
613 AddTail (&makefile
->targets
, mftarget
);
617 /* Merge data in mftarget into mftarget3 */
620 mftarget3
->virtualtarget
= mftarget3
->virtualtarget
&& mftarget
->virtualtarget
;
622 ForeachNode (&mftarget
->deps
, node
)
623 addnodeonce (&mftarget3
->deps
, node
->name
);
625 /* Free the targets from which the data was merged in other targets */
626 freemakefiletargetlist (&newtargets
);
629 } /* If this is a MetaMake line in the makefile */
630 } /* For all lines in a makefile */
633 makefile
->time
= st
.st_mtime
;
635 printf ("Read %d lines\n", lineno
);
639 } /* If the makefile needed to be scanned */
640 } /* For all makefiles in the project */
647 addmakefile (DirNode
* node
, const char * filename
)
649 static char curdir
[PATH_MAX
];
650 const char * ptr
= filename
;
654 Makefile
* makefile
= NULL
;
656 getcwd(curdir
, PATH_MAX
);
661 while (ptr
[len
] != '/' && ptr
[len
] != 0)
664 name
= xmalloc (len
+4+1); /* Make room for possibly adding .src at the end */
665 strncpy (name
, ptr
, len
);
670 subnode
= FindNode (&node
->subdirs
, name
);
683 if (len
>= 4 && strcmp (name
+len
-4, ".src") == 0)
686 makefile
= FindNode (&node
->makefiles
, name
);
688 if (makefile
== NULL
)
692 printf ("Trying to stat %s\n", name
);
694 if (stat(name
, &st
) != 0)
697 strcat (name
, ".src");
698 if (stat (name
, &st
) != 0)
707 makefile
= newnodesize (name
, sizeof (Makefile
));
708 makefile
->dir
= node
;
709 makefile
->time
= (time_t)0;
710 NewList (&makefile
->targets
);
711 AddTail (&node
->makefiles
, makefile
);
727 findmakefile (DirNode
* node
, const char *filename
)
729 const char * ptr
= filename
;
733 Makefile
* makefile
= NULL
;
738 while (ptr
[len
] != '/' && ptr
[len
] != 0)
741 name
= xstrndup (ptr
, len
);
746 subnode
= FindNode (&node
->subdirs
, name
);
758 if (len
>= 4 && strcmp (name
+len
-4, ".src") == 0)
761 makefile
= FindNode (&node
->makefiles
, name
);
779 buildpath (DirNode
* node
)
781 static char path
[PATH_MAX
];
783 DirNodeRef
* ref
= NULL
;
789 if ((strlen (node
->node
.name
) > 0) && (strcmp(node
->node
.name
, mm_srcdir
) != 0))
791 ref
= newnodesize ("", sizeof (DirNodeRef
));
793 AddHead (&tree
, ref
);
796 } while (node
!= NULL
);
799 ForeachNode (&tree
, ref
)
803 strcat (path
, ref
->dirnode
->node
.name
);
812 readmakefile (FILE * fh
)
815 MakefileTarget
* mftarget
;
820 if (!readstring(fh
, &s
))
822 error ("readmakefile:readstring():%d", __LINE__
);
829 makefile
= newnodesize(s
, sizeof(Makefile
));
831 NewList(&makefile
->targets
);
833 if (!readuint32 (fh
, &intt
))
835 error ("readmakefile:fread():%d", __LINE__
);
838 makefile
->time
= intt
;
844 if (!readstring(fh
, &s
))
846 error ("readmakefile:readstring():%d", __LINE__
);
853 mftarget
= newnodesize(s
, sizeof(MakefileTarget
));
855 AddTail (&makefile
->targets
, mftarget
);
856 NewList (&mftarget
->deps
);
858 if (!readint32 (fh
, &in
))
860 error ("readmakefile:fread():%d", __LINE__
);
863 mftarget
->virtualtarget
= in
;
867 if (!readstring(fh
, &s
))
869 error ("readmakefile:readstring():%d", __LINE__
);
878 AddTail (&mftarget
->deps
, n
);
887 writemakefile (FILE * fh
, Makefile
* makefile
)
889 MakefileTarget
* mftarget
;
892 if (makefile
== NULL
)
894 if (!writestring (fh
, NULL
))
896 error ("writemakefile/writestring():%d", __LINE__
);
903 if (!writestring (fh
, makefile
->node
.name
))
905 error ("writemakefile/writestring():%d", __LINE__
);
909 if (!writeuint32 (fh
, makefile
->time
))
911 error ("writemakefile/fwrite():%d", __LINE__
);
915 ForeachNode (&makefile
->targets
, mftarget
)
917 if (!writestring (fh
, mftarget
->node
.name
))
919 error ("writemakefile/writestring():%d", __LINE__
);
923 if (!writeint32 (fh
, mftarget
->virtualtarget
))
925 error ("writemakefile/fwrite():%d", __LINE__
);
929 ForeachNode (&mftarget
->deps
, n
)
931 if (!writestring (fh
, n
->name
))
933 error ("writemakefile/writestring():%d", __LINE__
);
938 if (!writestring (fh
, NULL
))
940 error ("writemakefile/writestring():%d", __LINE__
);
945 if (!writestring(fh
, NULL
))
947 error ("writemakefile/writestring():%d", __LINE__
);
956 readcachedir (FILE * fh
)
958 DirNode
* node
, * subnode
;
963 if (!readstring(fh
, &s
))
965 error ("readcachedir:readstring():%d", __LINE__
);
972 node
= newnodesize(s
, sizeof(DirNode
));
974 NewList(&node
->makefiles
);
975 NewList(&node
->subdirs
);
977 if (!readuint32 (fh
, &intt
))
979 error ("readcachedir:fread():%d", __LINE__
);
985 while ((makefile
= readmakefile (fh
)))
987 makefile
->dir
= node
;
988 AddTail (&node
->makefiles
, makefile
);
991 while ((subnode
= readcachedir (fh
)))
993 subnode
->parent
= node
;
994 AddTail (&node
->subdirs
, subnode
);
1001 writecachedir (FILE * fh
, DirNode
* node
)
1005 Makefile
* makefile
;
1009 if (!writestring(fh
, NULL
))
1011 error ("writecachedir/writestring():%d", __LINE__
);
1018 if (!writestring(fh
, node
->node
.name
))
1020 error ("writecachedir/writestring():%d", __LINE__
);
1024 if (!writeuint32 (fh
, node
->time
))
1026 error ("writecachedir/fwrite():%d", __LINE__
);
1030 ForeachNode (&node
->makefiles
, makefile
)
1031 writemakefile (fh
, makefile
);
1033 if (!writemakefile (fh
, NULL
))
1036 ForeachNode (&node
->subdirs
, subnode
)
1038 if (!writecachedir (fh
, subnode
))
1042 return writecachedir (fh
, NULL
);