1 /**
2 * DepTool dependency tool
3 *
4 * This is a simple dependency generator coded in C++
5 *
6 * Authors:
7 * Bob Jamison
8 *
9 * Copyright (C) 2006 Bob Jamison
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 */
26 /*
27 INSTRUCTIONS
29 1. First you optionally create a file named 'make.exclude.' This
30 lists the file names relative to the current directory. Lines starting
31 with a '#' are ignored. Here is an example:
33 ========= SNIP ========
34 ######################################################################
35 # File: make.exclude
36 #
37 # This is a list of files to exclude from building, using DepTool
38 #
39 ######################################################################
42 ast
43 bonobo
45 dialogs/filedialog-win32.cpp
46 display/testnr.cpp
47 display/bezier-utils-test.cpp
48 dom/work
49 #next line is ignored
50 #dom/odf/SvgOdg.cpp
51 extension/api.cpp
52 ========= SNIP ========
54 2. Run deptool. This will take a few seconds to scan all of your files
55 and make its dependency lists. Three files are created:
56 make.files: lists all of the files that were considered
57 make.dep: contains the output INCLUDE and OBJECT declarations
58 for you to include and use in your makefile. It also contains
59 the dependency listings.
60 make.ref: contains a reverse-dependency listing. This takes each file
61 and recursively determines which other files include it, and how
62 far the nesting is.
64 3. Include deptool.mk in your makefile.
66 */
69 #include <stdio.h>
70 #include <stdarg.h>
71 #include <time.h>
72 #include <sys/time.h>
74 #include <dirent.h>
75 #include <sys/stat.h>
77 #include <string>
78 #include <set>
79 #include <map>
80 #include <vector>
83 //# This will allow us to redefine the string in the future
84 typedef std::string String;
86 /**
87 * Class which holds information for each file.
88 */
89 class FileRec
90 {
91 public:
93 typedef enum
94 {
95 UNKNOWN,
96 CFILE,
97 HFILE,
98 OFILE
99 } FileType;
101 /**
102 * Constructor
103 */
104 FileRec()
105 {type = UNKNOWN;}
107 /**
108 * Copy constructor
109 */
110 FileRec(const FileRec &other)
111 {assign(other);}
112 /**
113 * Constructor
114 */
115 FileRec(int typeVal)
116 {init(); type = typeVal;}
117 /**
118 * Assignment operator
119 */
120 FileRec &operator=(const FileRec &other)
121 {assign(other); return *this;}
124 /**
125 * Destructor
126 */
127 ~FileRec()
128 {}
130 /**
131 * Directory part of the file name
132 */
133 String path;
135 /**
136 * Base name, sans directory and suffix
137 */
138 String baseName;
140 /**
141 * File extension, such as cpp or h
142 */
143 String suffix;
145 /**
146 * Type of file: CFILE, HFILE, OFILE
147 */
148 int type;
150 /**
151 * 'Distance' of inclusion from a file that depends on this one.
152 */
153 int distance;
155 /**
156 * Used to list files ref'd by this one, in the case of allFiles,
157 * or other files which reference this one, such as refFiles;
158 */
159 std::map<String, FileRec *> files;
162 bool checked;
164 private:
166 void init()
167 {
168 type = UNKNOWN;
169 checked = false;
170 }
172 void assign(const FileRec &other)
173 {
174 type = other.type;
175 distance = other.distance;
176 baseName = other.baseName;
177 suffix = other.suffix;
178 files = other.files;
179 checked = other.checked;
180 }
182 };
186 /**
187 * Main class which does the work.
188 */
189 class DepTool
190 {
191 public:
193 /**
194 * Constructor
195 */
196 DepTool();
198 /**
199 * Destructor
200 */
201 virtual ~DepTool();
203 /**
204 * Creates the list of all file names which will be
205 * candidates for further processing. Reads make.exclude
206 * to see which files for directories to leave out.
207 */
208 virtual bool createFileList();
211 /**
212 * Generates the forward and reverse dependency lists
213 */
214 virtual bool generateDependencies();
216 /**
217 * Calls the other two methods, then generates the files.
218 */
219 virtual bool run();
222 private:
224 /**
225 *
226 */
227 void reset();
229 /**
230 *
231 */
232 void error(char *fmt, ...);
234 /**
235 *
236 */
237 void trace(char *fmt, ...);
239 /**
240 * Removes whitespace from beginning and end of a string
241 */
242 String trim(const String &val);
244 /**
245 *
246 */
247 String getSuffix(const String &fname);
249 /**
250 *
251 */
252 void parseName(const String &fullname,
253 String &path,
254 String &basename,
255 String &suffix);
257 /**
258 *
259 */
260 int get(int pos);
262 /**
263 *
264 */
265 int skipwhite(int pos);
267 /**
268 *
269 */
270 int getword(int pos, String &ret);
272 /**
273 *
274 */
275 bool sequ(int pos, char *key);
277 /**
278 *
279 */
280 bool listFilesInDirectory(const String &dirname, int depth);
282 /**
283 *
284 */
285 bool saveFileList();
287 /**
288 *
289 */
290 bool saveDepFile(bool doXml);
292 /**
293 *
294 */
295 bool saveRefFile(bool doXml);
297 /**
298 *
299 */
300 bool addIncludeFile(FileRec *frec, const String &fname);
302 /**
303 *
304 */
305 bool scanFile(const String &fname, FileRec *frec);
307 /**
308 *
309 */
310 bool processDependency(FileRec *ofile,
311 FileRec *include,
312 int depth);
314 /**
315 *
316 */
317 bool processReference(FileRec *ofile,
318 String &fname,
319 int depth);
321 /**
322 *
323 */
324 std::set<String> excludes;
326 /**
327 *
328 */
329 std::set<String> excludesUsed;
331 /**
332 *
333 */
334 std::set<String> excludesUnused;
336 /**
337 *
338 */
339 std::vector<String> directories;
341 /**
342 * A list of all files which will be processed for
343 * dependencies.
344 */
345 std::map<String, FileRec *> allFiles;
347 /**
348 * A list of .h files, with a list for each one
349 * of which other files include them.
350 */
351 std::map<String, FileRec *> refFiles;
353 /**
354 * The list of .o files, and the
355 * dependencies upon them.
356 */
357 std::map<String, FileRec *> depFiles;
359 char *fileBuf;
360 int fileSize;
362 static const int readBufLen = 8192;
363 char readBuf[8193];
366 };
369 //########################################################################
370 //# M A I N
371 //########################################################################
373 /**
374 * Constructor
375 */
376 DepTool::DepTool()
377 {
378 }
381 /**
382 * Destructor
383 */
384 DepTool::~DepTool()
385 {
386 reset();
387 }
389 /**
390 * Clean up after processing. Called by the destructor, but should
391 * also be called before the object is reused.
392 */
393 void DepTool::reset()
394 {
395 std::map<String, FileRec *>::iterator iter;
396 for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
397 {
398 FileRec *frec = iter->second;
399 delete frec;
400 }
401 allFiles.clear();
402 for (iter=refFiles.begin() ; iter!=refFiles.end() ; iter++)
403 {
404 FileRec *frec = iter->second;
405 delete frec;
406 }
407 refFiles.clear();
408 for (iter=depFiles.begin() ; iter!=depFiles.end() ; iter++)
409 {
410 FileRec *frec = iter->second;
411 delete frec;
412 }
413 depFiles.clear();
415 excludes.clear();
416 excludesUsed.clear();
417 excludesUnused.clear();
418 }
421 /**
422 * Format an error message in printf() style
423 */
424 void DepTool::error(char *fmt, ...)
425 {
426 va_list ap;
427 va_start(ap, fmt);
428 fprintf(stderr, "DepTool error: ");
429 vfprintf(stderr, fmt, ap);
430 fprintf(stderr, "\n");
431 va_end(ap);
432 }
435 /**
436 * Format an trace message in printf() style
437 */
438 void DepTool::trace(char *fmt, ...)
439 {
440 va_list ap;
441 va_start(ap, fmt);
442 fprintf(stdout, "DepTool: ");
443 vfprintf(stdout, fmt, ap);
444 fprintf(stdout, "\n");
445 va_end(ap);
446 }
450 //########################################################################
451 //# U T I L I T Y
452 //########################################################################
454 /**
455 * Removes whitespace from beginning and end of a string
456 */
457 String DepTool::trim(const String &s)
458 {
459 if (s.size() < 1)
460 return s;
462 //Find first non-ws char
463 unsigned int begin = 0;
464 for ( ; begin < s.size() ; begin++)
465 {
466 if (!isspace(s[begin]))
467 break;
468 }
470 //Find first non-ws char, going in reverse
471 unsigned int end = s.size() - 1;
472 for ( ; end > begin ; end--)
473 {
474 if (!isspace(s[end]))
475 break;
476 }
477 //trace("begin:%d end:%d", begin, end);
479 String res = s.substr(begin, end-begin+1);
480 return res;
481 }
484 /**
485 * Parse a full path name into path, base name, and suffix
486 */
487 void DepTool::parseName(const String &fullname,
488 String &path,
489 String &basename,
490 String &suffix)
491 {
492 if (fullname.size() < 2)
493 return;
495 unsigned int pos = fullname.find_last_of('/');
496 if (pos != fullname.npos && pos<fullname.size()-1)
497 {
498 path = fullname.substr(0, pos);
499 pos++;
500 basename = fullname.substr(pos, fullname.size()-pos);
501 }
502 else
503 {
504 path = "";
505 basename = fullname;
506 }
508 pos = basename.find_last_of('.');
509 if (pos != basename.npos && pos<basename.size()-1)
510 {
511 suffix = basename.substr(pos+1, basename.size()-pos-1);
512 basename = basename.substr(0, pos);
513 }
515 //trace("parsename:%s %s %s", path.c_str(),
516 // basename.c_str(), suffix.c_str());
517 }
520 /**
521 * Return the suffix, if any, of a file name
522 */
523 String DepTool::getSuffix(const String &fname)
524 {
525 if (fname.size() < 2)
526 return "";
527 unsigned int pos = fname.find_last_of('.');
528 if (pos == fname.npos)
529 return "";
530 pos++;
531 String res = fname.substr(pos, fname.size()-pos);
532 //trace("suffix:%s", res.c_str());
533 return res;
534 }
538 //########################################################################
539 //# P R O C E S S I N G
540 //########################################################################
542 /**
543 * Recursively list all files and directories under 'dirname', except
544 * those in the exclude list.
545 */
546 bool DepTool::listFilesInDirectory(const String &dirname, int depth)
547 {
548 //trace("### listFilesInDirectory(%s, %d)", dirname.c_str(), depth);
550 int cFiles = 0;
551 int hFiles = 0;
553 std::vector<String> subdirs;
554 DIR *dir = opendir(dirname.c_str());
555 while (true)
556 {
557 struct dirent *de = readdir(dir);
558 if (!de)
559 break;
560 String s = de->d_name;
561 struct stat finfo;
562 String fname;
563 if (s.size() == 0 || s[0] == '.')
564 continue;
566 if (dirname.size()>0 && dirname != ".")
567 {
568 fname.append(dirname);
569 fname.append("/");
570 }
571 fname.append(s);
572 if (stat(fname.c_str(), &finfo)<0)
573 {
574 error("cannot stat file:%s", s.c_str());
575 }
576 else if (excludes.find(fname) != excludes.end())
577 {
578 //trace("excluded file/dir: %s", fname.c_str());
579 excludesUsed.insert(fname);
580 }
581 else if (S_ISDIR(finfo.st_mode))
582 {
583 //trace("directory: %s", fname.c_str());
584 subdirs.push_back(fname);
585 }
586 else if (!S_ISREG(finfo.st_mode))
587 {
588 trace("not regular: %s", fname.c_str());
589 }
590 else
591 {
592 String path;
593 String basename;
594 String sfx;
595 parseName(fname, path, basename, sfx);
596 if (sfx == "cpp" || sfx == "c" || sfx == "cxx" || sfx == "cc")
597 {
598 cFiles++;
599 FileRec *fe = new FileRec(FileRec::CFILE);
600 fe->path = path;
601 fe->baseName = basename;
602 fe->suffix = sfx;
603 allFiles[fname] = fe;
604 }
605 else if (sfx == "h" || sfx == "hh" ||
606 sfx == "hpp" || sfx == "hxx")
607 {
608 hFiles++;
609 FileRec *fe = new FileRec(FileRec::HFILE);
610 fe->path = path;
611 fe->baseName = basename;
612 fe->suffix = sfx;
613 allFiles[fname] = fe;
614 }
615 }
616 }
617 closedir(dir);
619 if (hFiles > 0)
620 directories.push_back(dirname);
622 for (unsigned int i=0 ; i<subdirs.size() ; i++)
623 {
624 listFilesInDirectory(subdirs[i], depth+1);
625 }
627 return true;
628 }
632 /**
633 *
634 */
635 bool DepTool::createFileList()
636 {
637 excludes.insert("deptool.cpp");
638 FILE *f = fopen("make.exclude", "r");
639 if (!f)
640 {
641 trace("'make.exclude not found");
642 }
643 else
644 {
645 char readBuf[256];
646 while (!feof(f))
647 {
648 if (!fgets(readBuf, 255, f))
649 break;
650 String s = readBuf;
651 s = trim(s);
652 //trace("s: %d '%s' ", s.size(), s.c_str());
653 if (s.size() > 0 && s[0]!='#')
654 excludes.insert(s);
655 }
656 fclose(f);
657 }
659 listFilesInDirectory(".", 0);
661 // Note which files in the exclude list were not used.
662 std::set<String>::iterator iter;
663 for (iter=excludes.begin() ; iter!=excludes.end() ; iter++)
664 {
665 String fname = *iter;
666 std::set<String>::iterator citer = excludesUsed.find(fname);
667 if (citer == excludesUsed.end())
668 excludesUnused.insert(fname);
669 }
671 saveFileList();
673 return true;
674 }
677 /**
678 * Get a character from the buffer at pos. If out of range,
679 * return -1 for safety
680 */
681 int DepTool::get(int pos)
682 {
683 if (pos>fileSize)
684 return -1;
685 return fileBuf[pos];
686 }
690 /**
691 * Skip over all whitespace characters beginning at pos. Return
692 * the position of the first non-whitespace character.
693 */
694 int DepTool::skipwhite(int pos)
695 {
696 while (pos < fileSize)
697 {
698 int ch = get(pos);
699 if (ch < 0)
700 break;
701 if (!isspace(ch))
702 break;
703 pos++;
704 }
705 return pos;
706 }
709 /**
710 * Parse the buffer beginning at pos, for a word. Fill
711 * 'ret' with the result. Return the position after the
712 * word.
713 */
714 int DepTool::getword(int pos, String &ret)
715 {
716 while (pos < fileSize)
717 {
718 int ch = get(pos);
719 if (ch < 0)
720 break;
721 if (isspace(ch))
722 break;
723 ret.push_back((char)ch);
724 pos++;
725 }
726 return pos;
727 }
729 /**
730 * Return whether the sequence of characters in the buffer
731 * beginning at pos match the key, for the length of the key
732 */
733 bool DepTool::sequ(int pos, char *key)
734 {
735 while (*key)
736 {
737 if (*key != get(pos))
738 return false;
739 key++; pos++;
740 }
741 return true;
742 }
746 /**
747 * Add an include file name to a file record. If the name
748 * is not found in allFiles explicitly, try prepending include
749 * directory names to it and try again.
750 */
751 bool DepTool::addIncludeFile(FileRec *frec, const String &iname)
752 {
754 std::map<String, FileRec *>::iterator iter =
755 allFiles.find(iname);
756 if (iter != allFiles.end())
757 {
758 //h file in same dir
759 FileRec *other = iter->second;
760 //trace("local: '%s'", iname.c_str());
761 frec->files[iname] = other;
762 return true;
763 }
764 else
765 {
766 //look in other dirs
767 std::vector<String>::iterator diter;
768 for (diter=directories.begin() ;
769 diter!=directories.end() ; diter++)
770 {
771 String dfname = *diter;
772 dfname.append("/");
773 dfname.append(iname);
774 iter = allFiles.find(dfname);
775 if (iter != allFiles.end())
776 {
777 FileRec *other = iter->second;
778 //trace("other: '%s'", iname.c_str());
779 frec->files[dfname] = other;
780 return true;
781 }
782 }
783 }
784 return true;
785 }
789 /**
790 * Lightly parse a file to find the #include directives. Do
791 * a bit of state machine stuff to make sure that the directive
792 * is valid. (Like not in a comment).
793 */
794 bool DepTool::scanFile(const String &fname, FileRec *frec)
795 {
796 FILE *f = fopen(fname.c_str(), "r");
797 if (!f)
798 {
799 error("Could not open '%s' for reading", fname.c_str());
800 return false;
801 }
802 String buf;
803 while (!feof(f))
804 {
805 int len = fread(readBuf, 1, readBufLen, f);
806 readBuf[len] = '\0';
807 buf.append(readBuf);
808 }
809 fclose(f);
811 fileSize = buf.size();
812 fileBuf = (char *)buf.c_str();
813 int pos = 0;
816 while (pos < fileSize)
817 {
818 //trace("p:%c", get(pos));
820 //# Block comment
821 if (get(pos) == '/' && get(pos+1) == '*')
822 {
823 pos += 2;
824 while (pos < fileSize)
825 {
826 if (get(pos) == '*' && get(pos+1) == '/')
827 {
828 pos += 2;
829 break;
830 }
831 else
832 pos++;
833 }
834 }
835 //# Line comment
836 else if (get(pos) == '/' && get(pos+1) == '/')
837 {
838 pos += 2;
839 while (pos < fileSize)
840 {
841 if (get(pos) == '\n')
842 {
843 pos++;
844 break;
845 }
846 else
847 pos++;
848 }
849 }
850 //# #include! yaay
851 else if (sequ(pos, "#include"))
852 {
853 pos += 8;
854 pos = skipwhite(pos);
855 String iname;
856 pos = getword(pos, iname);
857 if (iname.size()>2)
858 {
859 iname = iname.substr(1, iname.size()-2);
860 addIncludeFile(frec, iname);
861 }
862 }
863 else
864 {
865 pos++;
866 }
867 }
869 return true;
870 }
874 /**
875 * Recursively check include lists to find all files in allFiles to which
876 * a given file is dependent.
877 */
878 bool DepTool::processDependency(FileRec *ofile,
879 FileRec *include,
880 int depth)
881 {
882 std::map<String, FileRec *>::iterator iter;
883 for (iter=include->files.begin() ; iter!=include->files.end() ; iter++)
884 {
885 String fname = iter->first;
886 if (ofile->files.find(fname) != ofile->files.end())
887 {
888 //trace("file '%s' already seen", fname.c_str());
889 continue;
890 }
891 FileRec *child = iter->second;
892 ofile->files[fname] = child;
894 processDependency(ofile, child, depth+1);
895 }
898 return true;
899 }
903 /**
904 * Recursively check include lists to find all files in allFiles which
905 * will eventually have a dependency on this file. This is basically
906 * the inverse of processDependency().
907 */
908 bool DepTool::processReference(FileRec *hfile,
909 String &fname,
910 int depth)
911 {
912 std::map<String, FileRec *>::iterator iter;
913 for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
914 {
915 FileRec *frec = iter->second;
916 std::map<String, FileRec *>::iterator fiter =
917 frec->files.find(fname);
918 if (fiter != frec->files.end())
919 {
920 String cfname = iter->first;
921 if (hfile->files.find(cfname) != hfile->files.end())
922 {
923 //trace("%d reffile '%s' already seen", depth, cfname.c_str());
924 continue;
925 }
926 FileRec *child = iter->second;
927 child->distance = depth;
928 hfile->files[cfname] = child;
929 processReference(hfile, cfname, depth+1);
930 }
931 }
933 return true;
934 }
938 /**
939 * Generate the file dependency and reference lists.
940 */
941 bool DepTool::generateDependencies()
942 {
943 std::map<String, FileRec *>::iterator iter;
944 //# First pass. Scan for all includes
945 for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
946 {
947 FileRec *frec = iter->second;
948 if (!scanFile(iter->first, frec))
949 {
950 //quit?
951 }
952 }
954 //# Second pass. Scan for all includes
955 for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
956 {
957 FileRec *include = iter->second;
958 if (include->type == FileRec::CFILE)
959 {
960 String cFileName = iter->first;
961 FileRec *ofile = new FileRec(FileRec::OFILE);
962 ofile->path = include->path;
963 ofile->baseName = include->baseName;
964 ofile->suffix = include->suffix;
965 String fname = include->path;
966 if (fname.size()>0)
967 fname.append("/");
968 fname.append(include->baseName);
969 fname.append(".o");
970 depFiles[fname] = ofile;
971 //add the .c file first, of course
972 ofile->files[cFileName] = include;
973 //trace("ofile:%s", fname.c_str());
975 processDependency(ofile, include, 0);
976 }
977 /*
978 else if (include->type == FileRec::HFILE)
979 {
980 String fname = iter->first;
981 FileRec *hfile = new FileRec(FileRec::HFILE);
982 hfile->path = include->path;
983 hfile->baseName = include->baseName;
984 hfile->suffix = include->suffix;
985 refFiles[fname] = hfile;
986 //trace("hfile:%s", fname.c_str());
988 processReference(hfile, fname, 0);
989 }
990 */
991 }
994 return true;
995 }
998 /**
999 * High-level call to do what DepTool does.
1000 */
1001 bool DepTool::run()
1002 {
1003 reset();
1004 if (!createFileList())
1005 return false;
1006 if (!generateDependencies())
1007 return false;
1008 saveDepFile(false);
1009 //saveRefFile(true);
1010 return true;
1011 }
1014 //########################################################################
1015 //# O U T P U T S
1016 //########################################################################
1020 /**
1021 * Save the allFiles list. This is basically all files in a directory
1022 * except those denied in the exclude list.
1023 */
1024 bool DepTool::saveFileList()
1025 {
1026 time_t tim;
1027 time(&tim);
1029 FILE *f = fopen("make.files", "w");
1030 if (!f)
1031 {
1032 trace("cannot open 'make.files' for writing");
1033 }
1034 fprintf(f, "########################################################\n");
1035 fprintf(f, "## File: make.files\n");
1036 fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1037 fprintf(f, "########################################################\n");
1039 fprintf(f, "\n\n\n");
1040 fprintf(f, "########################################################\n");
1041 fprintf(f, "## F I L E S\n");
1042 fprintf(f, "########################################################\n");
1044 std::map<String, FileRec *>::iterator iter;
1045 for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
1046 {
1047 fprintf(f, "%s\n", iter->first.c_str());
1048 }
1050 fprintf(f, "\n\n\n");
1051 fprintf(f, "########################################################\n");
1052 fprintf(f, "## E X C L U D E D\n");
1053 fprintf(f, "########################################################\n");
1055 std::set<String>::iterator uiter;
1056 for (uiter=excludesUsed.begin() ; uiter!=excludesUsed.end() ; uiter++)
1057 {
1058 String fname = *uiter;
1059 fprintf(f, "%s\n", fname.c_str());
1060 }
1062 fprintf(f, "\n\n\n");
1063 fprintf(f, "########################################################\n");
1064 fprintf(f, "## E X C L U D E entries unused\n");
1065 fprintf(f, "########################################################\n");
1067 for (uiter=excludesUnused.begin() ; uiter!=excludesUnused.end() ; uiter++)
1068 {
1069 String fname = *uiter;
1070 fprintf(f, "%s\n", fname.c_str());
1071 }
1073 fprintf(f, "\n\n\n");
1074 fprintf(f, "########################################################\n");
1075 fprintf(f, "## E N D\n");
1076 fprintf(f, "########################################################\n");
1078 fclose(f);
1080 return true;
1081 }
1084 /**
1085 * This is the main product. This file lists the Include directives,
1086 * the Object list, and the dependency list.
1087 */
1088 bool DepTool::saveDepFile(bool doXml)
1089 {
1090 time_t tim;
1091 time(&tim);
1093 FILE *f = fopen("make.dep", "w");
1094 if (!f)
1095 {
1096 trace("cannot open 'make.dep' for writing");
1097 }
1098 if (doXml)
1099 {
1100 fprintf(f, "<?xml version='1.0'?>\n");
1101 fprintf(f, "<deptool>\n");
1102 fprintf(f, "\n");
1103 fprintf(f, "<!--\n");
1104 fprintf(f, "########################################################\n");
1105 fprintf(f, "## File: make.dep\n");
1106 fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1107 fprintf(f, "########################################################\n");
1108 fprintf(f, "-->\n");
1110 fprintf(f, "\n\n");
1112 fprintf(f, "\n");
1113 fprintf(f, "<!--\n");
1114 fprintf(f, "########################################################\n");
1115 fprintf(f, "## I N C L U D E\n");
1116 fprintf(f, "########################################################\n");
1117 fprintf(f, "-->\n");
1118 fprintf(f, "<includes>\n");
1120 std::vector<String>::iterator inciter;
1121 for (inciter=directories.begin() ; inciter!=directories.end() ; inciter++)
1122 {
1123 String dirname = *inciter;
1124 fprintf(f, " <inc name='%s'/>\n", dirname.c_str());
1125 }
1127 fprintf(f, "</includes>\n");
1128 fprintf(f, "\n\n\n");
1129 fprintf(f, "<!--\n");
1130 fprintf(f, "########################################################\n");
1131 fprintf(f, "## O B J E C T S\n");
1132 fprintf(f, "########################################################\n");
1133 fprintf(f, "-->\n");
1134 fprintf(f, "<objects>\n");
1136 std::map<String, FileRec *>::iterator oiter;
1137 for (oiter=allFiles.begin() ; oiter!=allFiles.end() ; oiter++)
1138 {
1139 FileRec *frec = oiter->second;
1140 if (frec->type == FileRec::CFILE)
1141 {
1142 String fname = frec->path;
1143 if (fname.size()>0)
1144 fname.append("/");
1145 fname.append(frec->baseName);
1146 fname.append(".o");
1147 fprintf(f, " <obj name='%s'/>\n", fname.c_str());
1148 }
1149 }
1152 fprintf(f, "</objects>\n");
1153 fprintf(f, "\n\n\n");
1154 fprintf(f, "<!--\n");
1155 fprintf(f, "########################################################\n");
1156 fprintf(f, "## D E P E N D E N C I E S\n");
1157 fprintf(f, "########################################################\n");
1158 fprintf(f, "-->\n");
1159 fprintf(f, "<dependencies>\n\n");
1160 std::map<String, FileRec *>::iterator iter;
1161 for (iter=depFiles.begin() ; iter!=depFiles.end() ; iter++)
1162 {
1163 FileRec *frec = iter->second;
1164 if (frec->type == FileRec::OFILE)
1165 {
1166 String fname = iter->first;
1167 fprintf(f, "<file name='%s'>\n", fname.c_str());
1168 std::map<String, FileRec *>::iterator citer;
1169 for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
1170 {
1171 String cfname = citer->first;
1172 fprintf(f, " <dep name='%s'/>\n", cfname.c_str());
1173 }
1174 fprintf(f, "</file>\n\n");
1175 }
1176 }
1178 fprintf(f, "</dependencies>\n");
1179 fprintf(f, "\n\n\n");
1180 fprintf(f, "</deptool>\n");
1181 fprintf(f, "<!--\n");
1182 fprintf(f, "########################################################\n");
1183 fprintf(f, "## E N D\n");
1184 fprintf(f, "########################################################\n");
1185 fprintf(f, "-->\n");
1186 }
1187 else // ######### !XML
1188 {
1189 fprintf(f, "########################################################\n");
1190 fprintf(f, "## File: make.dep\n");
1191 fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1192 fprintf(f, "########################################################\n");
1194 fprintf(f, "\n\n");
1196 fprintf(f, "########################################################\n");
1197 fprintf(f, "## I N C L U D E\n");
1198 fprintf(f, "########################################################\n");
1199 fprintf(f, "DEPTOOL_INCLUDE =");
1201 std::vector<String>::iterator inciter;
1202 for (inciter=directories.begin() ; inciter!=directories.end() ; inciter++)
1203 {
1204 fprintf(f, " \\\n");
1205 String dirname = *inciter;
1206 fprintf(f, "-I%s", dirname.c_str());
1207 }
1209 fprintf(f, "\n\n\n");
1210 fprintf(f, "########################################################\n");
1211 fprintf(f, "## O B J E C T S\n");
1212 fprintf(f, "########################################################\n");
1213 fprintf(f, "DEPTOOL_OBJECTS =");
1215 std::map<String, FileRec *>::iterator oiter;
1216 for (oiter=allFiles.begin() ; oiter!=allFiles.end() ; oiter++)
1217 {
1218 FileRec *frec = oiter->second;
1219 if (frec->type == FileRec::CFILE)
1220 {
1221 fprintf(f, " \\\n");
1222 String fname = frec->path;
1223 if (fname.size()>0)
1224 fname.append("/");
1225 fname.append(frec->baseName);
1226 fname.append(".o");
1227 fprintf(f, "%s", fname.c_str());
1228 }
1229 }
1232 fprintf(f, "\n\n\n");
1233 fprintf(f, "########################################################\n");
1234 fprintf(f, "## D E P E N D E N C I E S\n");
1235 fprintf(f, "########################################################\n");
1236 std::map<String, FileRec *>::iterator iter;
1237 for (iter=depFiles.begin() ; iter!=depFiles.end() ; iter++)
1238 {
1239 FileRec *frec = iter->second;
1240 if (frec->type == FileRec::OFILE)
1241 {
1242 String fname = iter->first;
1243 fprintf(f, "%s:", fname.c_str());
1244 std::map<String, FileRec *>::iterator citer;
1245 for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
1246 {
1247 String cfname = citer->first;
1248 fprintf(f, " \\\n");
1249 fprintf(f, "\t%s", cfname.c_str());
1250 }
1251 fprintf(f, "\n\n\n");
1252 }
1253 }
1255 fprintf(f, "\n\n\n");
1256 fprintf(f, "########################################################\n");
1257 fprintf(f, "## E N D\n");
1258 fprintf(f, "########################################################\n");
1259 }
1261 fclose(f);
1263 return true;
1264 }
1267 /**
1268 * Save the "reference" file, which lists each include file, and any files
1269 * that are judged to be dependent upon it.
1270 */
1271 bool DepTool::saveRefFile(bool doXml)
1272 {
1273 time_t tim;
1274 time(&tim);
1276 FILE *f = fopen("make.ref", "w");
1277 if (!f)
1278 {
1279 trace("cannot open 'make.ref' for writing");
1280 }
1281 if (doXml)
1282 {
1283 fprintf(f, "<?xml version='1.0'?>\n");
1284 fprintf(f, "<deptool>\n\n");
1285 fprintf(f, "<!--\n");
1286 fprintf(f, "########################################################\n");
1287 fprintf(f, "## File: make.ref\n");
1288 fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1289 fprintf(f, "## Note: The metric is the 'distance' of inclusion from\n");
1290 fprintf(f, "## the given file.\n");
1291 fprintf(f, "########################################################\n");
1292 fprintf(f, "-->\n");
1293 fprintf(f, "\n\n");
1296 std::map<String, FileRec *>::iterator iter;
1297 for (iter=refFiles.begin() ; iter!=refFiles.end() ; iter++)
1298 {
1299 FileRec *frec = iter->second;
1300 if (frec->type == FileRec::HFILE)
1301 {
1302 String fname = iter->first;
1303 fprintf(f, "<file name='%s'>\n", fname.c_str());
1304 std::map<String, FileRec *>::iterator citer;
1305 for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
1306 {
1307 String cfname = citer->first;
1308 fprintf(f, " <ref d='%d' name='%s'/>\n",
1309 citer->second->distance, cfname.c_str());
1310 }
1311 fprintf(f, "</file>\n\n");
1312 }
1313 }
1314 fprintf(f, "\n\n\n");
1315 fprintf(f, "</deptool>\n");
1316 fprintf(f, "<!--\n");
1317 fprintf(f, "########################################################\n");
1318 fprintf(f, "## E N D\n");
1319 fprintf(f, "########################################################\n");
1320 fprintf(f, "-->\n");
1321 }
1323 else //######### not xml
1324 {
1325 fprintf(f, "########################################################\n");
1326 fprintf(f, "## File: make.ref\n");
1327 fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1328 fprintf(f, "## Note: The metric is the 'distance' of inclusion from\n");
1329 fprintf(f, "## the given file.\n");
1330 fprintf(f, "########################################################\n");
1331 fprintf(f, "\n\n");
1334 std::map<String, FileRec *>::iterator iter;
1335 for (iter=refFiles.begin() ; iter!=refFiles.end() ; iter++)
1336 {
1337 FileRec *frec = iter->second;
1338 if (frec->type == FileRec::HFILE)
1339 {
1340 String fname = iter->first;
1341 fprintf(f, "### %s\n", fname.c_str());
1342 std::map<String, FileRec *>::iterator citer;
1343 for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
1344 {
1345 String cfname = citer->first;
1346 fprintf(f, "%3d %s\n", citer->second->distance,
1347 cfname.c_str());
1348 }
1349 fprintf(f, "\n");
1350 }
1351 }
1353 fprintf(f, "\n\n\n");
1354 fprintf(f, "########################################################\n");
1355 fprintf(f, "## E N D\n");
1356 fprintf(f, "########################################################\n");
1357 }
1359 fclose(f);
1361 return true;
1362 }
1369 //########################################################################
1370 //# M A I N
1371 //########################################################################
1374 /**
1375 * Run the DepTool's main functions
1376 */
1377 static bool runTool()
1378 {
1379 DepTool depTool;
1381 if (!depTool.run())
1382 return false;
1384 return true;
1385 }
1388 /**
1389 * Console main()
1390 */
1391 int main(int argc, char **argv)
1392 {
1393 if (!runTool())
1394 return 1;
1396 return 0;
1397 }
1400 //########################################################################
1401 //# E N D O F F I L E
1402 //########################################################################