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();
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 else if (include->type == FileRec::HFILE)
971 {
972 String fname = iter->first;
973 FileRec *hfile = new FileRec(FileRec::HFILE);
974 hfile->path = include->path;
975 hfile->baseName = include->baseName;
976 hfile->suffix = include->suffix;
977 refFiles[fname] = hfile;
978 //trace("hfile:%s", fname.c_str());
980 processReference(hfile, fname, 0);
981 }
982 }
985 return true;
986 }
989 /**
990 * High-level call to do what DepTool does.
991 */
992 bool DepTool::run()
993 {
994 reset();
995 if (!createFileList())
996 return false;
997 if (!generateDependencies())
998 return false;
999 saveDepFile();
1000 saveRefFile(true);
1001 return true;
1002 }
1005 //########################################################################
1006 //# O U T P U T S
1007 //########################################################################
1011 /**
1012 * Save the allFiles list. This is basically all files in a directory
1013 * except those denied in the exclude list.
1014 */
1015 bool DepTool::saveFileList()
1016 {
1017 time_t tim;
1018 time(&tim);
1020 FILE *f = fopen("make.files", "w");
1021 if (!f)
1022 {
1023 trace("cannot open 'make.files' for writing");
1024 }
1025 fprintf(f, "########################################################\n");
1026 fprintf(f, "## File: make.files\n");
1027 fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1028 fprintf(f, "########################################################\n");
1030 fprintf(f, "\n\n\n");
1031 fprintf(f, "########################################################\n");
1032 fprintf(f, "## F I L E S\n");
1033 fprintf(f, "########################################################\n");
1035 std::map<String, FileRec *>::iterator iter;
1036 for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
1037 {
1038 fprintf(f, "%s\n", iter->first.c_str());
1039 }
1041 fprintf(f, "\n\n\n");
1042 fprintf(f, "########################################################\n");
1043 fprintf(f, "## E X C L U D E D\n");
1044 fprintf(f, "########################################################\n");
1046 std::set<String>::iterator uiter;
1047 for (uiter=excludesUsed.begin() ; uiter!=excludesUsed.end() ; uiter++)
1048 {
1049 String fname = *uiter;
1050 fprintf(f, "%s\n", fname.c_str());
1051 }
1053 fprintf(f, "\n\n\n");
1054 fprintf(f, "########################################################\n");
1055 fprintf(f, "## E X C L U D E entries unused\n");
1056 fprintf(f, "########################################################\n");
1058 for (uiter=excludesUnused.begin() ; uiter!=excludesUnused.end() ; uiter++)
1059 {
1060 String fname = *uiter;
1061 fprintf(f, "%s\n", fname.c_str());
1062 }
1064 fprintf(f, "\n\n\n");
1065 fprintf(f, "########################################################\n");
1066 fprintf(f, "## E N D\n");
1067 fprintf(f, "########################################################\n");
1069 fclose(f);
1071 return true;
1072 }
1075 /**
1076 * This is the main product. This file lists the Include directives,
1077 * the Object list, and the dependency list.
1078 */
1079 bool DepTool::saveDepFile()
1080 {
1081 time_t tim;
1082 time(&tim);
1084 FILE *f = fopen("make.dep", "w");
1085 if (!f)
1086 {
1087 trace("cannot open 'make.dep' for writing");
1088 }
1089 fprintf(f, "########################################################\n");
1090 fprintf(f, "## File: make.dep\n");
1091 fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1092 fprintf(f, "########################################################\n");
1094 fprintf(f, "\n\n");
1096 fprintf(f, "########################################################\n");
1097 fprintf(f, "## I N C L U D E\n");
1098 fprintf(f, "########################################################\n");
1099 fprintf(f, "DEPTOOL_INCLUDE =");
1101 std::vector<String>::iterator inciter;
1102 for (inciter=directories.begin() ; inciter!=directories.end() ; inciter++)
1103 {
1104 fprintf(f, " \\\n");
1105 String dirname = *inciter;
1106 fprintf(f, "-I%s", dirname.c_str());
1107 }
1109 fprintf(f, "\n\n\n");
1110 fprintf(f, "########################################################\n");
1111 fprintf(f, "## O B J E C T S\n");
1112 fprintf(f, "########################################################\n");
1113 fprintf(f, "DEPTOOL_OBJECTS =");
1115 std::map<String, FileRec *>::iterator oiter;
1116 for (oiter=allFiles.begin() ; oiter!=allFiles.end() ; oiter++)
1117 {
1118 FileRec *frec = oiter->second;
1119 if (frec->type == FileRec::CFILE)
1120 {
1121 fprintf(f, " \\\n");
1122 String fname = frec->path;
1123 if (fname.size()>0)
1124 fname.append("/");
1125 fname.append(frec->baseName);
1126 fname.append(".o");
1127 fprintf(f, "%s", fname.c_str());
1128 }
1129 }
1132 fprintf(f, "\n\n\n");
1133 fprintf(f, "########################################################\n");
1134 fprintf(f, "## D E P E N D E N C I E S\n");
1135 fprintf(f, "########################################################\n");
1136 std::map<String, FileRec *>::iterator iter;
1137 for (iter=depFiles.begin() ; iter!=depFiles.end() ; iter++)
1138 {
1139 FileRec *frec = iter->second;
1140 if (frec->type == FileRec::OFILE)
1141 {
1142 String fname = iter->first;
1143 fprintf(f, "%s:", fname.c_str());
1144 std::map<String, FileRec *>::iterator citer;
1145 for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
1146 {
1147 String cfname = citer->first;
1148 fprintf(f, " \\\n");
1149 fprintf(f, "\t%s", cfname.c_str());
1150 }
1151 fprintf(f, "\n\n\n");
1152 }
1153 }
1155 fprintf(f, "\n\n\n");
1156 fprintf(f, "########################################################\n");
1157 fprintf(f, "## E N D\n");
1158 fprintf(f, "########################################################\n");
1160 fclose(f);
1162 return true;
1163 }
1166 /**
1167 * Save the "reference" file, which lists each include file, and any files
1168 * that are judged to be dependent upon it.
1169 */
1170 bool DepTool::saveRefFile(bool doXml)
1171 {
1172 time_t tim;
1173 time(&tim);
1175 FILE *f = fopen("make.ref", "w");
1176 if (!f)
1177 {
1178 trace("cannot open 'make.ref' for writing");
1179 }
1180 if (doXml)
1181 {
1182 fprintf(f, "<?xml version='1.0'?>\n");
1183 fprintf(f, "<deptool>\n\n");
1184 fprintf(f, "<!--\n");
1185 fprintf(f, "########################################################\n");
1186 fprintf(f, "## File: make.ref\n");
1187 fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1188 fprintf(f, "## Note: The metric is the 'distance' of inclusion from\n");
1189 fprintf(f, "## the given file.\n");
1190 fprintf(f, "########################################################\n");
1191 fprintf(f, "--!>\n");
1192 fprintf(f, "\n\n");
1195 std::map<String, FileRec *>::iterator iter;
1196 for (iter=refFiles.begin() ; iter!=refFiles.end() ; iter++)
1197 {
1198 FileRec *frec = iter->second;
1199 if (frec->type == FileRec::HFILE)
1200 {
1201 String fname = iter->first;
1202 fprintf(f, "<file name='%s'>\n", fname.c_str());
1203 std::map<String, FileRec *>::iterator citer;
1204 for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
1205 {
1206 String cfname = citer->first;
1207 fprintf(f, " <ref d='%d' name='%s'/>\n",
1208 citer->second->distance, cfname.c_str());
1209 }
1210 fprintf(f, "</file>\n\n");
1211 }
1212 }
1213 fprintf(f, "\n\n\n");
1214 fprintf(f, "</deptool>\n");
1215 fprintf(f, "<!--\n");
1216 fprintf(f, "########################################################\n");
1217 fprintf(f, "## E N D\n");
1218 fprintf(f, "########################################################\n");
1219 fprintf(f, "--!>\n");
1220 }
1222 else //######### not xml
1223 {
1224 fprintf(f, "########################################################\n");
1225 fprintf(f, "## File: make.ref\n");
1226 fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1227 fprintf(f, "## Note: The metric is the 'distance' of inclusion from\n");
1228 fprintf(f, "## the given file.\n");
1229 fprintf(f, "########################################################\n");
1230 fprintf(f, "\n\n");
1233 std::map<String, FileRec *>::iterator iter;
1234 for (iter=refFiles.begin() ; iter!=refFiles.end() ; iter++)
1235 {
1236 FileRec *frec = iter->second;
1237 if (frec->type == FileRec::HFILE)
1238 {
1239 String fname = iter->first;
1240 fprintf(f, "### %s\n", fname.c_str());
1241 std::map<String, FileRec *>::iterator citer;
1242 for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
1243 {
1244 String cfname = citer->first;
1245 fprintf(f, "%3d %s\n", citer->second->distance,
1246 cfname.c_str());
1247 }
1248 fprintf(f, "\n");
1249 }
1250 }
1252 fprintf(f, "\n\n\n");
1253 fprintf(f, "########################################################\n");
1254 fprintf(f, "## E N D\n");
1255 fprintf(f, "########################################################\n");
1256 }
1258 fclose(f);
1260 return true;
1261 }
1268 //########################################################################
1269 //# M A I N
1270 //########################################################################
1273 /**
1274 * Run the DepTool's main functions
1275 */
1276 static bool runTool()
1277 {
1278 DepTool depTool;
1280 if (!depTool.run())
1281 return false;
1283 return true;
1284 }
1287 /**
1288 * Console main()
1289 */
1290 int main(int argc, char **argv)
1291 {
1292 if (!runTool())
1293 return 1;
1295 return 0;
1296 }
1299 //########################################################################
1300 //# E N D O F F I L E
1301 //########################################################################