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 private:
164 void init()
165 {
166 }
168 void assign(const FileRec &other)
169 {
170 type = other.type;
171 distance = other.distance;
172 baseName = other.baseName;
173 suffix = other.suffix;
174 files = other.files;
175 }
177 };
181 /**
182 * Main class which does the work.
183 */
184 class DepTool
185 {
186 public:
188 /**
189 * Constructor
190 */
191 DepTool();
193 /**
194 * Destructor
195 */
196 virtual ~DepTool();
198 /**
199 * Creates the list of all file names which will be
200 * candidates for further processing. Reads make.exclude
201 * to see which files for directories to leave out.
202 */
203 virtual bool createFileList();
206 /**
207 * Generates the forward and reverse dependency lists
208 */
209 virtual bool generateDependencies();
211 /**
212 * Calls the other two methods, then generates the files.
213 */
214 virtual bool run();
217 private:
219 /**
220 *
221 */
222 void reset();
224 /**
225 *
226 */
227 void error(char *fmt, ...);
229 /**
230 *
231 */
232 void trace(char *fmt, ...);
234 /**
235 * Removes whitespace from beginning and end of a string
236 */
237 String trim(const String &val);
239 /**
240 *
241 */
242 String getSuffix(const String &fname);
244 /**
245 *
246 */
247 void parseName(const String &fullname,
248 String &path,
249 String &basename,
250 String &suffix);
252 /**
253 *
254 */
255 int get(int pos);
257 /**
258 *
259 */
260 int skipwhite(int pos);
262 /**
263 *
264 */
265 int getword(int pos, String &ret);
267 /**
268 *
269 */
270 bool sequ(int pos, char *key);
272 /**
273 *
274 */
275 bool listFilesInDirectory(const String &dirname, int depth);
277 /**
278 *
279 */
280 bool saveFileList();
282 /**
283 *
284 */
285 bool saveDepFile(bool doXml);
287 /**
288 *
289 */
290 bool saveRefFile(bool doXml);
292 /**
293 *
294 */
295 bool addIncludeFile(FileRec *frec, const String &fname);
297 /**
298 *
299 */
300 bool scanFile(const String &fname, FileRec *frec);
302 /**
303 *
304 */
305 bool processDependency(FileRec *ofile,
306 FileRec *include,
307 int depth);
309 /**
310 *
311 */
312 bool processReference(FileRec *ofile,
313 String &fname,
314 int depth);
316 /**
317 *
318 */
319 std::set<String> excludes;
321 /**
322 *
323 */
324 std::set<String> excludesUsed;
326 /**
327 *
328 */
329 std::set<String> excludesUnused;
331 /**
332 *
333 */
334 std::vector<String> directories;
336 /**
337 * A list of all files which will be processed for
338 * dependencies.
339 */
340 std::map<String, FileRec *> allFiles;
342 /**
343 * A list of .h files, with a list for each one
344 * of which other files include them.
345 */
346 std::map<String, FileRec *> refFiles;
348 /**
349 * The list of .o files, and the
350 * dependencies upon them.
351 */
352 std::map<String, FileRec *> depFiles;
354 char *fileBuf;
355 int fileSize;
358 };
361 //########################################################################
362 //# M A I N
363 //########################################################################
365 /**
366 * Constructor
367 */
368 DepTool::DepTool()
369 {
370 }
373 /**
374 * Destructor
375 */
376 DepTool::~DepTool()
377 {
378 reset();
379 }
381 /**
382 * Clean up after processing. Called by the destructor, but should
383 * also be called before the object is reused.
384 */
385 void DepTool::reset()
386 {
387 std::map<String, FileRec *>::iterator iter;
388 for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
389 {
390 FileRec *frec = iter->second;
391 delete frec;
392 }
393 allFiles.clear();
394 for (iter=refFiles.begin() ; iter!=refFiles.end() ; iter++)
395 {
396 FileRec *frec = iter->second;
397 delete frec;
398 }
399 refFiles.clear();
400 for (iter=depFiles.begin() ; iter!=depFiles.end() ; iter++)
401 {
402 FileRec *frec = iter->second;
403 delete frec;
404 }
405 depFiles.clear();
407 excludes.clear();
408 excludesUsed.clear();
409 excludesUnused.clear();
410 }
413 /**
414 * Format an error message in printf() style
415 */
416 void DepTool::error(char *fmt, ...)
417 {
418 va_list ap;
419 va_start(ap, fmt);
420 fprintf(stderr, "DepTool error: ");
421 vfprintf(stderr, fmt, ap);
422 fprintf(stderr, "\n");
423 va_end(ap);
424 }
427 /**
428 * Format an trace message in printf() style
429 */
430 void DepTool::trace(char *fmt, ...)
431 {
432 va_list ap;
433 va_start(ap, fmt);
434 fprintf(stdout, "DepTool: ");
435 vfprintf(stdout, fmt, ap);
436 fprintf(stdout, "\n");
437 va_end(ap);
438 }
442 //########################################################################
443 //# U T I L I T Y
444 //########################################################################
446 /**
447 * Removes whitespace from beginning and end of a string
448 */
449 String DepTool::trim(const String &s)
450 {
451 if (s.size() < 1)
452 return s;
454 //Find first non-ws char
455 unsigned int begin = 0;
456 for ( ; begin < s.size() ; begin++)
457 {
458 if (!isspace(s[begin]))
459 break;
460 }
462 //Find first non-ws char, going in reverse
463 unsigned int end = s.size() - 1;
464 for ( ; end > begin ; end--)
465 {
466 if (!isspace(s[end]))
467 break;
468 }
469 //trace("begin:%d end:%d", begin, end);
471 String res = s.substr(begin, end-begin+1);
472 return res;
473 }
476 /**
477 * Parse a full path name into path, base name, and suffix
478 */
479 void DepTool::parseName(const String &fullname,
480 String &path,
481 String &basename,
482 String &suffix)
483 {
484 if (fullname.size() < 2)
485 return;
487 unsigned int pos = fullname.find_last_of('/');
488 if (pos != fullname.npos && pos<fullname.size()-1)
489 {
490 path = fullname.substr(0, pos);
491 pos++;
492 basename = fullname.substr(pos, fullname.size()-pos);
493 }
494 else
495 {
496 path = "";
497 basename = fullname;
498 }
500 pos = basename.find_last_of('.');
501 if (pos != basename.npos && pos<basename.size()-1)
502 {
503 suffix = basename.substr(pos+1, basename.size()-pos-1);
504 basename = basename.substr(0, pos);
505 }
507 //trace("parsename:%s %s %s", path.c_str(),
508 // basename.c_str(), suffix.c_str());
509 }
512 /**
513 * Return the suffix, if any, of a file name
514 */
515 String DepTool::getSuffix(const String &fname)
516 {
517 if (fname.size() < 2)
518 return "";
519 unsigned int pos = fname.find_last_of('.');
520 if (pos == fname.npos)
521 return "";
522 pos++;
523 String res = fname.substr(pos, fname.size()-pos);
524 //trace("suffix:%s", res.c_str());
525 return res;
526 }
530 //########################################################################
531 //# P R O C E S S I N G
532 //########################################################################
534 /**
535 * Recursively list all files and directories under 'dirname', except
536 * those in the exclude list.
537 */
538 bool DepTool::listFilesInDirectory(const String &dirname, int depth)
539 {
540 //trace("### listFilesInDirectory(%s, %d)", dirname.c_str(), depth);
542 int cFiles = 0;
543 int hFiles = 0;
545 std::vector<String> subdirs;
546 DIR *dir = opendir(dirname.c_str());
547 while (true)
548 {
549 struct dirent *de = readdir(dir);
550 if (!de)
551 break;
552 String s = de->d_name;
553 struct stat finfo;
554 String fname;
555 if (s.size() == 0 || s[0] == '.')
556 continue;
558 if (dirname.size()>0 && dirname != ".")
559 {
560 fname.append(dirname);
561 fname.append("/");
562 }
563 fname.append(s);
564 if (stat(fname.c_str(), &finfo)<0)
565 {
566 error("cannot stat file:%s", s.c_str());
567 }
568 else if (excludes.find(fname) != excludes.end())
569 {
570 //trace("excluded file/dir: %s", fname.c_str());
571 excludesUsed.insert(fname);
572 }
573 else if (S_ISDIR(finfo.st_mode))
574 {
575 //trace("directory: %s", fname.c_str());
576 subdirs.push_back(fname);
577 }
578 else if (!S_ISREG(finfo.st_mode))
579 {
580 trace("not regular: %s", fname.c_str());
581 }
582 else
583 {
584 String path;
585 String basename;
586 String sfx;
587 parseName(fname, path, basename, sfx);
588 if (sfx == "cpp" || sfx == "c" || sfx == "cxx" || sfx == "cc")
589 {
590 cFiles++;
591 FileRec *fe = new FileRec(FileRec::CFILE);
592 fe->path = path;
593 fe->baseName = basename;
594 fe->suffix = sfx;
595 allFiles[fname] = fe;
596 }
597 else if (sfx == "h" || sfx == "hh" ||
598 sfx == "hpp" || sfx == "hxx")
599 {
600 hFiles++;
601 FileRec *fe = new FileRec(FileRec::HFILE);
602 fe->path = path;
603 fe->baseName = basename;
604 fe->suffix = sfx;
605 allFiles[fname] = fe;
606 }
607 }
608 }
609 closedir(dir);
611 if (hFiles > 0)
612 directories.push_back(dirname);
614 for (unsigned int i=0 ; i<subdirs.size() ; i++)
615 {
616 listFilesInDirectory(subdirs[i], depth+1);
617 }
619 return true;
620 }
624 /**
625 *
626 */
627 bool DepTool::createFileList()
628 {
629 excludes.insert("deptool.cpp");
630 FILE *f = fopen("make.exclude", "r");
631 if (!f)
632 {
633 trace("'make.exclude not found");
634 }
635 else
636 {
637 char readBuf[256];
638 while (!feof(f))
639 {
640 if (!fgets(readBuf, 255, f))
641 break;
642 String s = readBuf;
643 s = trim(s);
644 //trace("s: %d '%s' ", s.size(), s.c_str());
645 if (s.size() > 0 && s[0]!='#')
646 excludes.insert(s);
647 }
648 fclose(f);
649 }
651 listFilesInDirectory(".", 0);
653 // Note which files in the exclude list were not used.
654 std::set<String>::iterator iter;
655 for (iter=excludes.begin() ; iter!=excludes.end() ; iter++)
656 {
657 String fname = *iter;
658 std::set<String>::iterator citer = excludesUsed.find(fname);
659 if (citer == excludesUsed.end())
660 excludesUnused.insert(fname);
661 }
663 saveFileList();
665 return true;
666 }
669 /**
670 * Get a character from the buffer at pos. If out of range,
671 * return -1 for safety
672 */
673 int DepTool::get(int pos)
674 {
675 if (pos>fileSize)
676 return -1;
677 return fileBuf[pos];
678 }
682 /**
683 * Skip over all whitespace characters beginning at pos. Return
684 * the position of the first non-whitespace character.
685 */
686 int DepTool::skipwhite(int pos)
687 {
688 while (pos < fileSize)
689 {
690 int ch = get(pos);
691 if (ch < 0)
692 break;
693 if (!isspace(ch))
694 break;
695 pos++;
696 }
697 return pos;
698 }
701 /**
702 * Parse the buffer beginning at pos, for a word. Fill
703 * 'ret' with the result. Return the position after the
704 * word.
705 */
706 int DepTool::getword(int pos, String &ret)
707 {
708 while (pos < fileSize)
709 {
710 int ch = get(pos);
711 if (ch < 0)
712 break;
713 if (isspace(ch))
714 break;
715 ret.push_back((char)ch);
716 pos++;
717 }
718 return pos;
719 }
721 /**
722 * Return whether the sequence of characters in the buffer
723 * beginning at pos match the key, for the length of the key
724 */
725 bool DepTool::sequ(int pos, char *key)
726 {
727 while (*key)
728 {
729 if (*key != get(pos))
730 return false;
731 key++; pos++;
732 }
733 return true;
734 }
738 /**
739 * Add an include file name to a file record. If the name
740 * is not found in allFiles explicitly, try prepending include
741 * directory names to it and try again.
742 */
743 bool DepTool::addIncludeFile(FileRec *frec, const String &iname)
744 {
746 std::map<String, FileRec *>::iterator iter =
747 allFiles.find(iname);
748 if (iter != allFiles.end())
749 {
750 //h file in same dir
751 FileRec *other = iter->second;
752 //trace("local: '%s'", iname.c_str());
753 frec->files[iname] = other;
754 return true;
755 }
756 else
757 {
758 //look in other dirs
759 std::vector<String>::iterator diter;
760 for (diter=directories.begin() ;
761 diter!=directories.end() ; diter++)
762 {
763 String dfname = *diter;
764 dfname.append("/");
765 dfname.append(iname);
766 iter = allFiles.find(dfname);
767 if (iter != allFiles.end())
768 {
769 FileRec *other = iter->second;
770 //trace("other: '%s'", iname.c_str());
771 frec->files[dfname] = other;
772 return true;
773 }
774 }
775 }
776 return true;
777 }
781 /**
782 * Lightly parse a file to find the #include directives. Do
783 * a bit of state machine stuff to make sure that the directive
784 * is valid. (Like not in a comment).
785 */
786 bool DepTool::scanFile(const String &fname, FileRec *frec)
787 {
788 FILE *f = fopen(fname.c_str(), "r");
789 if (!f)
790 {
791 error("Could not open '%s' for reading", fname.c_str());
792 return false;
793 }
794 String buf;
795 while (true)
796 {
797 int ch = fgetc(f);
798 if (ch < 0)
799 break;
800 buf.push_back((char)ch);
801 }
802 fclose(f);
804 fileSize = buf.size();
805 fileBuf = (char *)buf.c_str();
806 int pos = 0;
809 while (pos < fileSize)
810 {
811 //trace("p:%c", get(pos));
813 //# Block comment
814 if (get(pos) == '/' && get(pos+1) == '*')
815 {
816 pos += 2;
817 while (pos < fileSize)
818 {
819 if (get(pos) == '*' && get(pos+1) == '/')
820 {
821 pos += 2;
822 break;
823 }
824 else
825 pos++;
826 }
827 }
828 //# Line comment
829 else if (get(pos) == '/' && get(pos+1) == '/')
830 {
831 pos += 2;
832 while (pos < fileSize)
833 {
834 if (get(pos) == '\n')
835 {
836 pos++;
837 break;
838 }
839 else
840 pos++;
841 }
842 }
843 //# #include! yaay
844 else if (sequ(pos, "#include"))
845 {
846 pos += 8;
847 pos = skipwhite(pos);
848 String iname;
849 pos = getword(pos, iname);
850 if (iname.size()>2)
851 {
852 iname = iname.substr(1, iname.size()-2);
853 addIncludeFile(frec, iname);
854 }
855 }
856 else
857 {
858 pos++;
859 }
860 }
862 return true;
863 }
867 /**
868 * Recursively check include lists to find all files in allFiles to which
869 * a given file is dependent.
870 */
871 bool DepTool::processDependency(FileRec *ofile,
872 FileRec *include,
873 int depth)
874 {
875 std::map<String, FileRec *>::iterator iter;
876 for (iter=include->files.begin() ; iter!=include->files.end() ; iter++)
877 {
878 String fname = iter->first;
879 if (ofile->files.find(fname) != ofile->files.end())
880 {
881 //trace("file '%s' already seen", fname.c_str());
882 continue;
883 }
884 FileRec *child = iter->second;
885 ofile->files[fname] = child;
887 processDependency(ofile, child, depth+1);
888 }
891 return true;
892 }
896 /**
897 * Recursively check include lists to find all files in allFiles which
898 * will eventually have a dependency on this file. This is basically
899 * the inverse of processDependency().
900 */
901 bool DepTool::processReference(FileRec *hfile,
902 String &fname,
903 int depth)
904 {
905 std::map<String, FileRec *>::iterator iter;
906 for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
907 {
908 FileRec *frec = iter->second;
909 std::map<String, FileRec *>::iterator fiter =
910 frec->files.find(fname);
911 if (fiter != frec->files.end())
912 {
913 String cfname = iter->first;
914 if (hfile->files.find(cfname) != hfile->files.end())
915 {
916 //trace("%d reffile '%s' already seen", depth, cfname.c_str());
917 continue;
918 }
919 FileRec *child = iter->second;
920 child->distance = depth;
921 hfile->files[cfname] = child;
922 processReference(hfile, cfname, depth+1);
923 }
924 }
926 return true;
927 }
931 /**
932 * Generate the file dependency and reference lists.
933 */
934 bool DepTool::generateDependencies()
935 {
936 std::map<String, FileRec *>::iterator iter;
937 //# First pass. Scan for all includes
938 for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
939 {
940 FileRec *frec = iter->second;
941 if (!scanFile(iter->first, frec))
942 {
943 //quit?
944 }
945 }
947 //# Second pass. Scan for all includes
948 for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
949 {
950 FileRec *include = iter->second;
951 if (include->type == FileRec::CFILE)
952 {
953 String cFileName = iter->first;
954 FileRec *ofile = new FileRec(FileRec::OFILE);
955 ofile->path = include->path;
956 ofile->baseName = include->baseName;
957 ofile->suffix = include->suffix;
958 String fname = include->path;
959 if (fname.size()>0)
960 fname.append("/");
961 fname.append(include->baseName);
962 fname.append(".o");
963 depFiles[fname] = ofile;
964 //add the .c file first, of course
965 ofile->files[cFileName] = include;
966 //trace("ofile:%s", fname.c_str());
968 processDependency(ofile, include, 0);
969 }
970 /*
971 else if (include->type == FileRec::HFILE)
972 {
973 String fname = iter->first;
974 FileRec *hfile = new FileRec(FileRec::HFILE);
975 hfile->path = include->path;
976 hfile->baseName = include->baseName;
977 hfile->suffix = include->suffix;
978 refFiles[fname] = hfile;
979 //trace("hfile:%s", fname.c_str());
981 processReference(hfile, fname, 0);
982 }
983 */
984 }
987 return true;
988 }
991 /**
992 * High-level call to do what DepTool does.
993 */
994 bool DepTool::run()
995 {
996 reset();
997 if (!createFileList())
998 return false;
999 if (!generateDependencies())
1000 return false;
1001 saveDepFile(false);
1002 //saveRefFile(true);
1003 return true;
1004 }
1007 //########################################################################
1008 //# O U T P U T S
1009 //########################################################################
1013 /**
1014 * Save the allFiles list. This is basically all files in a directory
1015 * except those denied in the exclude list.
1016 */
1017 bool DepTool::saveFileList()
1018 {
1019 time_t tim;
1020 time(&tim);
1022 FILE *f = fopen("make.files", "w");
1023 if (!f)
1024 {
1025 trace("cannot open 'make.files' for writing");
1026 }
1027 fprintf(f, "########################################################\n");
1028 fprintf(f, "## File: make.files\n");
1029 fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1030 fprintf(f, "########################################################\n");
1032 fprintf(f, "\n\n\n");
1033 fprintf(f, "########################################################\n");
1034 fprintf(f, "## F I L E S\n");
1035 fprintf(f, "########################################################\n");
1037 std::map<String, FileRec *>::iterator iter;
1038 for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
1039 {
1040 fprintf(f, "%s\n", iter->first.c_str());
1041 }
1043 fprintf(f, "\n\n\n");
1044 fprintf(f, "########################################################\n");
1045 fprintf(f, "## E X C L U D E D\n");
1046 fprintf(f, "########################################################\n");
1048 std::set<String>::iterator uiter;
1049 for (uiter=excludesUsed.begin() ; uiter!=excludesUsed.end() ; uiter++)
1050 {
1051 String fname = *uiter;
1052 fprintf(f, "%s\n", fname.c_str());
1053 }
1055 fprintf(f, "\n\n\n");
1056 fprintf(f, "########################################################\n");
1057 fprintf(f, "## E X C L U D E entries unused\n");
1058 fprintf(f, "########################################################\n");
1060 for (uiter=excludesUnused.begin() ; uiter!=excludesUnused.end() ; uiter++)
1061 {
1062 String fname = *uiter;
1063 fprintf(f, "%s\n", fname.c_str());
1064 }
1066 fprintf(f, "\n\n\n");
1067 fprintf(f, "########################################################\n");
1068 fprintf(f, "## E N D\n");
1069 fprintf(f, "########################################################\n");
1071 fclose(f);
1073 return true;
1074 }
1077 /**
1078 * This is the main product. This file lists the Include directives,
1079 * the Object list, and the dependency list.
1080 */
1081 bool DepTool::saveDepFile(bool doXml)
1082 {
1083 time_t tim;
1084 time(&tim);
1086 FILE *f = fopen("make.dep", "w");
1087 if (!f)
1088 {
1089 trace("cannot open 'make.dep' for writing");
1090 }
1091 if (doXml)
1092 {
1093 fprintf(f, "<?xml version='1.0'?>\n");
1094 fprintf(f, "<deptool>\n");
1095 fprintf(f, "\n");
1096 fprintf(f, "<!--\n");
1097 fprintf(f, "########################################################\n");
1098 fprintf(f, "## File: make.dep\n");
1099 fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1100 fprintf(f, "########################################################\n");
1101 fprintf(f, "-->\n");
1103 fprintf(f, "\n\n");
1105 fprintf(f, "\n");
1106 fprintf(f, "<!--\n");
1107 fprintf(f, "########################################################\n");
1108 fprintf(f, "## I N C L U D E\n");
1109 fprintf(f, "########################################################\n");
1110 fprintf(f, "-->\n");
1111 fprintf(f, "<includes>\n");
1113 std::vector<String>::iterator inciter;
1114 for (inciter=directories.begin() ; inciter!=directories.end() ; inciter++)
1115 {
1116 String dirname = *inciter;
1117 fprintf(f, " <inc name='%s'/>\n", dirname.c_str());
1118 }
1120 fprintf(f, "</includes>\n");
1121 fprintf(f, "\n\n\n");
1122 fprintf(f, "<!--\n");
1123 fprintf(f, "########################################################\n");
1124 fprintf(f, "## O B J E C T S\n");
1125 fprintf(f, "########################################################\n");
1126 fprintf(f, "-->\n");
1127 fprintf(f, "<objects>\n");
1129 std::map<String, FileRec *>::iterator oiter;
1130 for (oiter=allFiles.begin() ; oiter!=allFiles.end() ; oiter++)
1131 {
1132 FileRec *frec = oiter->second;
1133 if (frec->type == FileRec::CFILE)
1134 {
1135 String fname = frec->path;
1136 if (fname.size()>0)
1137 fname.append("/");
1138 fname.append(frec->baseName);
1139 fname.append(".o");
1140 fprintf(f, " <obj name='%s'/>\n", fname.c_str());
1141 }
1142 }
1145 fprintf(f, "</objects>\n");
1146 fprintf(f, "\n\n\n");
1147 fprintf(f, "<!--\n");
1148 fprintf(f, "########################################################\n");
1149 fprintf(f, "## D E P E N D E N C I E S\n");
1150 fprintf(f, "########################################################\n");
1151 fprintf(f, "-->\n");
1152 fprintf(f, "<dependencies>\n\n");
1153 std::map<String, FileRec *>::iterator iter;
1154 for (iter=depFiles.begin() ; iter!=depFiles.end() ; iter++)
1155 {
1156 FileRec *frec = iter->second;
1157 if (frec->type == FileRec::OFILE)
1158 {
1159 String fname = iter->first;
1160 fprintf(f, "<file name='%s'>\n", fname.c_str());
1161 std::map<String, FileRec *>::iterator citer;
1162 for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
1163 {
1164 String cfname = citer->first;
1165 fprintf(f, " <dep name='%s'/>\n", cfname.c_str());
1166 }
1167 fprintf(f, "</file>\n\n");
1168 }
1169 }
1171 fprintf(f, "</dependencies>\n");
1172 fprintf(f, "\n\n\n");
1173 fprintf(f, "</deptool>\n");
1174 fprintf(f, "<!--\n");
1175 fprintf(f, "########################################################\n");
1176 fprintf(f, "## E N D\n");
1177 fprintf(f, "########################################################\n");
1178 fprintf(f, "-->\n");
1179 }
1180 else // ######### !XML
1181 {
1182 fprintf(f, "########################################################\n");
1183 fprintf(f, "## File: make.dep\n");
1184 fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1185 fprintf(f, "########################################################\n");
1187 fprintf(f, "\n\n");
1189 fprintf(f, "########################################################\n");
1190 fprintf(f, "## I N C L U D E\n");
1191 fprintf(f, "########################################################\n");
1192 fprintf(f, "DEPTOOL_INCLUDE =");
1194 std::vector<String>::iterator inciter;
1195 for (inciter=directories.begin() ; inciter!=directories.end() ; inciter++)
1196 {
1197 fprintf(f, " \\\n");
1198 String dirname = *inciter;
1199 fprintf(f, "-I%s", dirname.c_str());
1200 }
1202 fprintf(f, "\n\n\n");
1203 fprintf(f, "########################################################\n");
1204 fprintf(f, "## O B J E C T S\n");
1205 fprintf(f, "########################################################\n");
1206 fprintf(f, "DEPTOOL_OBJECTS =");
1208 std::map<String, FileRec *>::iterator oiter;
1209 for (oiter=allFiles.begin() ; oiter!=allFiles.end() ; oiter++)
1210 {
1211 FileRec *frec = oiter->second;
1212 if (frec->type == FileRec::CFILE)
1213 {
1214 fprintf(f, " \\\n");
1215 String fname = frec->path;
1216 if (fname.size()>0)
1217 fname.append("/");
1218 fname.append(frec->baseName);
1219 fname.append(".o");
1220 fprintf(f, "%s", fname.c_str());
1221 }
1222 }
1225 fprintf(f, "\n\n\n");
1226 fprintf(f, "########################################################\n");
1227 fprintf(f, "## D E P E N D E N C I E S\n");
1228 fprintf(f, "########################################################\n");
1229 std::map<String, FileRec *>::iterator iter;
1230 for (iter=depFiles.begin() ; iter!=depFiles.end() ; iter++)
1231 {
1232 FileRec *frec = iter->second;
1233 if (frec->type == FileRec::OFILE)
1234 {
1235 String fname = iter->first;
1236 fprintf(f, "%s:", fname.c_str());
1237 std::map<String, FileRec *>::iterator citer;
1238 for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
1239 {
1240 String cfname = citer->first;
1241 fprintf(f, " \\\n");
1242 fprintf(f, "\t%s", cfname.c_str());
1243 }
1244 fprintf(f, "\n\n\n");
1245 }
1246 }
1248 fprintf(f, "\n\n\n");
1249 fprintf(f, "########################################################\n");
1250 fprintf(f, "## E N D\n");
1251 fprintf(f, "########################################################\n");
1252 }
1254 fclose(f);
1256 return true;
1257 }
1260 /**
1261 * Save the "reference" file, which lists each include file, and any files
1262 * that are judged to be dependent upon it.
1263 */
1264 bool DepTool::saveRefFile(bool doXml)
1265 {
1266 time_t tim;
1267 time(&tim);
1269 FILE *f = fopen("make.ref", "w");
1270 if (!f)
1271 {
1272 trace("cannot open 'make.ref' for writing");
1273 }
1274 if (doXml)
1275 {
1276 fprintf(f, "<?xml version='1.0'?>\n");
1277 fprintf(f, "<deptool>\n\n");
1278 fprintf(f, "<!--\n");
1279 fprintf(f, "########################################################\n");
1280 fprintf(f, "## File: make.ref\n");
1281 fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1282 fprintf(f, "## Note: The metric is the 'distance' of inclusion from\n");
1283 fprintf(f, "## the given file.\n");
1284 fprintf(f, "########################################################\n");
1285 fprintf(f, "-->\n");
1286 fprintf(f, "\n\n");
1289 std::map<String, FileRec *>::iterator iter;
1290 for (iter=refFiles.begin() ; iter!=refFiles.end() ; iter++)
1291 {
1292 FileRec *frec = iter->second;
1293 if (frec->type == FileRec::HFILE)
1294 {
1295 String fname = iter->first;
1296 fprintf(f, "<file name='%s'>\n", fname.c_str());
1297 std::map<String, FileRec *>::iterator citer;
1298 for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
1299 {
1300 String cfname = citer->first;
1301 fprintf(f, " <ref d='%d' name='%s'/>\n",
1302 citer->second->distance, cfname.c_str());
1303 }
1304 fprintf(f, "</file>\n\n");
1305 }
1306 }
1307 fprintf(f, "\n\n\n");
1308 fprintf(f, "</deptool>\n");
1309 fprintf(f, "<!--\n");
1310 fprintf(f, "########################################################\n");
1311 fprintf(f, "## E N D\n");
1312 fprintf(f, "########################################################\n");
1313 fprintf(f, "-->\n");
1314 }
1316 else //######### not xml
1317 {
1318 fprintf(f, "########################################################\n");
1319 fprintf(f, "## File: make.ref\n");
1320 fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1321 fprintf(f, "## Note: The metric is the 'distance' of inclusion from\n");
1322 fprintf(f, "## the given file.\n");
1323 fprintf(f, "########################################################\n");
1324 fprintf(f, "\n\n");
1327 std::map<String, FileRec *>::iterator iter;
1328 for (iter=refFiles.begin() ; iter!=refFiles.end() ; iter++)
1329 {
1330 FileRec *frec = iter->second;
1331 if (frec->type == FileRec::HFILE)
1332 {
1333 String fname = iter->first;
1334 fprintf(f, "### %s\n", fname.c_str());
1335 std::map<String, FileRec *>::iterator citer;
1336 for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
1337 {
1338 String cfname = citer->first;
1339 fprintf(f, "%3d %s\n", citer->second->distance,
1340 cfname.c_str());
1341 }
1342 fprintf(f, "\n");
1343 }
1344 }
1346 fprintf(f, "\n\n\n");
1347 fprintf(f, "########################################################\n");
1348 fprintf(f, "## E N D\n");
1349 fprintf(f, "########################################################\n");
1350 }
1352 fclose(f);
1354 return true;
1355 }
1362 //########################################################################
1363 //# M A I N
1364 //########################################################################
1367 /**
1368 * Run the DepTool's main functions
1369 */
1370 static bool runTool()
1371 {
1372 DepTool depTool;
1374 if (!depTool.run())
1375 return false;
1377 return true;
1378 }
1381 /**
1382 * Console main()
1383 */
1384 int main(int argc, char **argv)
1385 {
1386 if (!runTool())
1387 return 1;
1389 return 0;
1390 }
1393 //########################################################################
1394 //# E N D O F F I L E
1395 //########################################################################