1 /* MetaMake - A Make extension
2 Copyright © 1995-2004, 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. */
32 #ifdef HAVE_SYS_STAT_H
33 # include <sys/stat.h>
35 #ifdef HAVE_SYS_TYPES_H
36 # include <sys/types.h>
48 #define FLAG_VIRTUAL 0x0001
50 static MakefileTarget
*
51 newmakefiletarget (char *name
, int virtualtarget
)
53 MakefileTarget
* mftarget
;
55 mftarget
= newnodesize (name
, sizeof(MakefileTarget
));
56 mftarget
->virtualtarget
= virtualtarget
;
57 NewList (&mftarget
->deps
);
63 freemakefiletarget (MakefileTarget
* mftarget
)
65 freelist (&mftarget
->deps
);
70 freemakefiletargetlist (List
* targets
)
72 MakefileTarget
* mftarget
, * mftarget2
;
74 ForeachNodeSafe (targets
, mftarget
, mftarget2
)
75 freemakefiletarget (mftarget
);
81 printdirnode (DirNode
* node
, int level
)
86 for (t
=0; t
<level
; t
++)
89 printf ("%s\n", node
->node
.name
);
93 ForeachNode (&node
->subdirs
, subdir
)
94 printdirnode (subdir
, level
);
98 printdirnodemftarget (DirNode
* node
)
101 MakefileTarget
* mftarget
;
105 ForeachNode (&node
->makefiles
, makefile
)
107 printf ("%s/%s:\n", buildpath(node
), makefile
->node
.name
);
108 ForeachNode (&makefile
->targets
, mftarget
)
110 printf (" %s:", mftarget
->node
.name
);
111 ForeachNode (&mftarget
->deps
, dep
)
112 printf (" %s", dep
->name
);
117 ForeachNode (&node
->subdirs
, subdir
)
118 printdirnodemftarget (subdir
);
122 freedirnode (DirNode
* node
)
124 DirNode
* subnode
, * subnode2
;
126 ForeachNodeSafe (&node
->subdirs
, subnode
, subnode2
)
127 freedirnode (subnode
);
129 xfree (node
->node
.name
);
134 freemakefile (Makefile
* makefile
)
136 freemakefiletargetlist (&makefile
->targets
);
137 xfree (makefile
->node
.name
);
142 finddirnode (DirNode
* topnode
, const char * path
)
147 DirNode
* node
= topnode
, * subdir
;
158 for (len
=0; ptr
[len
] && ptr
[len
] != '/'; len
++);
160 strncpy (dirname
, ptr
, len
);
166 subdir
= FindNode (&node
->subdirs
, dirname
);
179 scandirnode (DirNode
* node
, const char * mfname
, List
* ignoredirs
)
183 struct dirent
* dirent
;
185 int mfnamelen
= strlen(mfname
), scanned
= 0;
187 if (stat(".", &st
) != 0)
189 error("scandirnode(): scanning %s\n",
190 strlen(node
->node
.name
) == 0
197 if (st
.st_mtime
> node
->time
)
199 List newdirs
, newmakefiles
;
200 DirNode
* subdir
= NULL
, * subdir2
;
204 printf("scandirnode(): scanning %s\n",
205 strlen(node
->node
.name
)==0 ? "topdir" : buildpath(node
)
209 NewList (&newmakefiles
);
211 node
->time
= st
.st_mtime
;
213 dirh
= opendir (".");
216 error("opendir: could not open current dir");
220 while ((dirent
= readdir (dirh
)))
222 /* Add makefile if it present or the file with .src is present */
223 if (strcmp(dirent
->d_name
, mfname
) == 0
224 || (strlen(dirent
->d_name
) == mfnamelen
+ 4
225 && strncmp(dirent
->d_name
, mfname
, mfnamelen
) == 0
226 && strcmp(dirent
->d_name
+ mfnamelen
, ".src") == 0
230 /* Don't add makefile twice */
231 makefile
= FindNode (&newmakefiles
, mfname
);
232 if (makefile
== NULL
)
234 makefile
= FindNode (&node
->makefiles
, mfname
);
235 if (makefile
!= NULL
)
241 makefile
= newnodesize (mfname
, sizeof (Makefile
));
242 makefile
->dir
= node
;
243 makefile
->time
= (time_t)0;
244 NewList (&makefile
->targets
);
246 AddTail (&newmakefiles
, makefile
);
251 /* If the file is already in the makefiles from the current dirnode
252 * and it is still present in the directory copy it to the new makefiles
255 if (strlen (dirent
->d_name
) > 4
256 && strcmp (dirent
->d_name
+ strlen(dirent
->d_name
) - 4, ".src") == 0
259 dirent
->d_name
[strlen(dirent
->d_name
) - 4] = 0;
260 makefile
= FindNode (&node
->makefiles
, dirent
->d_name
);
261 dirent
->d_name
[strlen(dirent
->d_name
)] = '.';
264 makefile
= FindNode (&node
->makefiles
, dirent
->d_name
);
266 if (makefile
!= NULL
)
269 AddTail (&newmakefiles
, makefile
);
273 /* Add file to newsubdirs if it is a directory and it has not to be ignored
275 if (lstat (dirent
->d_name
, &st
) == -1)
277 error ("scandirnode: stat(%s)", dirent
->d_name
);
281 if (S_ISDIR (st
.st_mode
)
282 && strcmp (dirent
->d_name
, ".") != 0
283 && strcmp (dirent
->d_name
, "..") != 0
284 && !S_ISLNK (st
.st_mode
)
285 && !FindNode (ignoredirs
, dirent
->d_name
)
288 subdir
= FindNode (&node
->subdirs
, dirent
->d_name
);
296 subdir
= newnodesize (dirent
->d_name
, sizeof(DirNode
));
297 subdir
->parent
= node
;
298 subdir
->time
= (time_t)0;
299 NewList (&subdir
->subdirs
);
300 NewList (&subdir
->makefiles
);
302 AddTail (&newdirs
, subdir
);
309 ForeachNodeSafe (&node
->subdirs
, subdir
, subdir2
)
310 freedirnode (subdir
);
311 AssignList (&node
->subdirs
, &newdirs
);
313 /* Clear the makefiles that have disappeared */
314 ForeachNode (&node
->makefiles
, makefile
)
316 MakefileTarget
* mftarget
;
318 ForeachNode (&makefile
->targets
, mftarget
)
319 freelist (&mftarget
->deps
);
321 freelist (&makefile
->targets
);
324 freelist (&node
->makefiles
);
326 AssignList (&node
->makefiles
, &newmakefiles
);
332 printf ("scandirnode()\n");
341 scanmakefiles (DirNode
* node
, List
* vars
)
345 static char * line
= NULL
;
346 static int linelen
= 512;
353 line
= xmalloc(linelen
);
355 ForeachNode (&node
->makefiles
, makefile
)
357 if (stat(makefile
->node
.name
, &st
) != 0)
359 error("Could not stat %s", makefile
->node
.name
);
363 if (st
.st_mtime
> makefile
->time
)
367 MakefileTarget
* mftarget
= NULL
;
370 printf("scanmakefiles(): scanning makefile in %s/%s\n",
371 strlen(node
->node
.name
)==0 ? "topdir" : buildpath(node
),
376 printf ("Opening %s\n", makefile
->name
);
379 fh
= fopen (makefile
->node
.name
, "r");
382 error ("buildtargetlist:fopen(): Opening %s for reading",
387 /* Free old metatargets when the file is reread */
388 freemakefiletargetlist (&makefile
->targets
);
389 NewList (&makefile
->targets
);
391 while (fgets (line
, linelen
, fh
))
395 while (line
[strlen(line
)-1] != '\n' && !feof(fh
))
400 ptr
= xmalloc (linelen
);
404 fgets (line
+strlen(line
), linelen
-strlen(line
), fh
);
407 if (line
[strlen(line
)-1] == '\n')
409 line
[strlen(line
)-1] = 0;
412 if (strncmp (line
, "#MM", 3) == 0)
418 printf ("found #MM in %s\n", makefile
->name
);
421 /* Read in next lines if there is continuation */
422 while (line
[strlen(line
)-1] == '\\')
424 ptr
= line
+ strlen(line
) - 1;
426 if (!fgets (ptr
, linelen
-strlen(line
)+1, fh
))
428 error("%s/%s:unexpected end of makefile",
437 while (line
[strlen(line
)-1] != '\n' && !feof(fh
))
439 int pos
= ptr
- line
;
441 ptr
= xmalloc (linelen
);
445 fgets (line
+strlen(line
), linelen
-strlen(line
), fh
);
449 if (line
[strlen(line
)-1] == '\n')
451 line
[strlen(line
)-1] = 0;
454 if (strncmp (ptr
, "##MM", 3) == 0)
456 *ptr
= line
[strlen(line
)-1];
461 if (strncmp (ptr
, "#MM", 3) != 0)
464 error("%s/%s:%d:continuation line has to start with #MM",
472 memmove (ptr
, ptr
+4, strlen(ptr
)-4+1);
479 flags
|= FLAG_VIRTUAL
;
483 flags
&= ~FLAG_VIRTUAL
;
485 while (isspace (*ptr
))
490 /* Line with only #MM, metatarget is on next line */
492 fgets (line
, linelen
, fh
);
496 while (*ptr
!= ':' && *ptr
)
501 targets
= getargs (line
, &count
, NULL
);
505 mftarget
= FindNode (&makefile
->targets
, targets
[0]);
507 if (mftarget
== NULL
)
509 mftarget
= newmakefiletarget (targets
[0], 0);
510 AddTail (&makefile
->targets
, mftarget
);
513 mftarget
->virtualtarget
= 0;
516 printf ("Warning: Can't find metatarget in %s:%d (%s)\n", makefile
->node
.name
, lineno
, buildpath(node
));
521 char * ptr2
= ptr
, ** tptr
;
522 MakefileTarget
* mftarget2
, * mftarget3
;
524 NewList (&newtargets
);
526 while (*ptr2
!= ':' && *ptr2
)
531 tptr
= getargs (ptr
, &count
, NULL
);
533 for (t
= 0; t
< count
; t
++)
535 mftarget
= newmakefiletarget (tptr
[t
], (flags
& FLAG_VIRTUAL
) != 0);
536 AddTail (&newtargets
, mftarget
);
539 tptr
= getargs (ptr2
, &count
, NULL
);
540 for (t
= 0; t
< count
; t
++)
542 ForeachNode (&newtargets
, mftarget
)
543 addnodeonce (&mftarget
->deps
, tptr
[t
]);
546 ForeachNodeSafe (&newtargets
, mftarget
, mftarget2
)
548 mftarget3
= FindNode (&makefile
->targets
, mftarget
->node
.name
);
550 /* mftarget doesn't exists yet add it to targets */
551 if (mftarget3
== NULL
)
554 AddTail (&makefile
->targets
, mftarget
);
558 /* Merge data in mftarget into mftarget3 */
561 mftarget3
->virtualtarget
= mftarget3
->virtualtarget
&& mftarget
->virtualtarget
;
563 ForeachNode (&mftarget
->deps
, node
)
564 addnodeonce (&mftarget3
->deps
, node
->name
);
566 /* Free the targets from which the data was merged in other targets */
567 freemakefiletargetlist (&newtargets
);
570 } /* If this is a MetaMake line in the makefile */
571 } /* For all lines in a makefile */
574 makefile
->time
= st
.st_mtime
;
576 printf ("Read %d lines\n", lineno
);
580 } /* If the makefile needed to be scanned */
581 } /* For all makefiles in the project */
588 addmakefile (DirNode
* node
, const char * filename
)
590 static char curdir
[PATH_MAX
];
591 const char * ptr
= filename
;
595 Makefile
* makefile
= NULL
;
597 getcwd(curdir
, PATH_MAX
);
602 while (ptr
[len
] != '/' && ptr
[len
] != 0)
605 name
= xmalloc (len
+4+1); /* Make room for possibly adding .src at the end */
606 strncpy (name
, ptr
, len
);
611 subnode
= FindNode (&node
->subdirs
, name
);
624 if (len
>= 4 && strcmp (name
+len
-4, ".src") == 0)
627 makefile
= FindNode (&node
->makefiles
, name
);
629 if (makefile
== NULL
)
633 printf ("Trying to stat %s\n", name
);
635 if (stat(name
, &st
) != 0)
638 strcat (name
, ".src");
639 if (stat (name
, &st
) != 0)
648 makefile
= newnodesize (name
, sizeof (Makefile
));
649 makefile
->dir
= node
;
650 makefile
->time
= (time_t)0;
651 NewList (&makefile
->targets
);
652 AddTail (&node
->makefiles
, makefile
);
668 findmakefile (DirNode
* node
, const char *filename
)
670 const char * ptr
= filename
;
674 Makefile
* makefile
= NULL
;
679 while (ptr
[len
] != '/' && ptr
[len
] != 0)
682 name
= xstrndup (ptr
, len
);
687 subnode
= FindNode (&node
->subdirs
, name
);
699 if (len
>= 4 && strcmp (name
+len
-4, ".src") == 0)
702 makefile
= FindNode (&node
->makefiles
, name
);
720 buildpath (DirNode
* node
)
722 static char path
[PATH_MAX
];
724 DirNodeRef
* ref
= NULL
;
730 if (strlen (node
->node
.name
) > 0)
732 ref
= newnodesize ("", sizeof (DirNodeRef
));
734 AddHead (&tree
, ref
);
737 } while (node
!= NULL
);
740 ForeachNode (&tree
, ref
)
744 strcat (path
, ref
->dirnode
->node
.name
);
753 readmakefile (FILE * fh
)
756 MakefileTarget
* mftarget
;
761 if (!readstring(fh
, &s
))
763 error ("readmakefile:readstring():%d", __LINE__
);
770 makefile
= newnodesize(s
, sizeof(Makefile
));
772 NewList(&makefile
->targets
);
774 if (!readuint32 (fh
, &intt
))
776 error ("readmakefile:fread():%d", __LINE__
);
779 makefile
->time
= intt
;
785 if (!readstring(fh
, &s
))
787 error ("readmakefile:readstring():%d", __LINE__
);
794 mftarget
= newnodesize(s
, sizeof(MakefileTarget
));
796 AddTail (&makefile
->targets
, mftarget
);
797 NewList (&mftarget
->deps
);
799 if (!readint32 (fh
, &in
))
801 error ("readmakefile:fread():%d", __LINE__
);
804 mftarget
->virtualtarget
= in
;
808 if (!readstring(fh
, &s
))
810 error ("readmakefile:readstring():%d", __LINE__
);
819 AddTail (&mftarget
->deps
, n
);
828 writemakefile (FILE * fh
, Makefile
* makefile
)
830 MakefileTarget
* mftarget
;
833 if (makefile
== NULL
)
835 if (!writestring (fh
, NULL
))
837 error ("writemakefile/writestring():%d", __LINE__
);
844 if (!writestring (fh
, makefile
->node
.name
))
846 error ("writemakefile/writestring():%d", __LINE__
);
850 if (!writeuint32 (fh
, makefile
->time
))
852 error ("writemakefile/fwrite():%d", __LINE__
);
856 ForeachNode (&makefile
->targets
, mftarget
)
858 if (!writestring (fh
, mftarget
->node
.name
))
860 error ("writemakefile/writestring():%d", __LINE__
);
864 if (!writeint32 (fh
, mftarget
->virtualtarget
))
866 error ("writemakefile/fwrite():%d", __LINE__
);
870 ForeachNode (&mftarget
->deps
, n
)
872 if (!writestring (fh
, n
->name
))
874 error ("writemakefile/writestring():%d", __LINE__
);
879 if (!writestring (fh
, NULL
))
881 error ("writemakefile/writestring():%d", __LINE__
);
886 if (!writestring(fh
, NULL
))
888 error ("writemakefile/writestring():%d", __LINE__
);
897 readcachedir (FILE * fh
)
899 DirNode
* node
, * subnode
;
904 if (!readstring(fh
, &s
))
906 error ("readcachedir:readstring():%d", __LINE__
);
913 node
= newnodesize(s
, sizeof(DirNode
));
915 NewList(&node
->makefiles
);
916 NewList(&node
->subdirs
);
918 if (!readuint32 (fh
, &intt
))
920 error ("readcachedir:fread():%d", __LINE__
);
926 while ((makefile
= readmakefile (fh
)))
928 makefile
->dir
= node
;
929 AddTail (&node
->makefiles
, makefile
);
932 while ((subnode
= readcachedir (fh
)))
934 subnode
->parent
= node
;
935 AddTail (&node
->subdirs
, subnode
);
942 writecachedir (FILE * fh
, DirNode
* node
)
950 if (!writestring(fh
, NULL
))
952 error ("writecachedir/writestring():%d", __LINE__
);
959 if (!writestring(fh
, node
->node
.name
))
961 error ("writecachedir/writestring():%d", __LINE__
);
965 if (!writeuint32 (fh
, node
->time
))
967 error ("writecachedir/fwrite():%d", __LINE__
);
971 ForeachNode (&node
->makefiles
, makefile
)
972 writemakefile (fh
, makefile
);
974 if (!writemakefile (fh
, NULL
))
977 ForeachNode (&node
->subdirs
, subnode
)
979 if (!writecachedir (fh
, subnode
))
983 return writecachedir (fh
, NULL
);