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 saveCmakeFile();
297 /**
298 *
299 */
300 bool saveRefFile(bool doXml);
302 /**
303 *
304 */
305 bool addIncludeFile(FileRec *frec, const String &fname);
307 /**
308 *
309 */
310 bool scanFile(const String &fname, FileRec *frec);
312 /**
313 *
314 */
315 bool processDependency(FileRec *ofile,
316 FileRec *include,
317 int depth);
319 /**
320 *
321 */
322 bool processReference(FileRec *ofile,
323 String &fname,
324 int depth);
326 /**
327 *
328 */
329 std::set<String> excludes;
331 /**
332 *
333 */
334 std::set<String> excludesUsed;
336 /**
337 *
338 */
339 std::set<String> excludesUnused;
341 /**
342 *
343 */
344 std::vector<String> directories;
346 /**
347 * A list of all files which will be processed for
348 * dependencies.
349 */
350 std::map<String, FileRec *> allFiles;
352 /**
353 * A list of .h files, with a list for each one
354 * of which other files include them.
355 */
356 std::map<String, FileRec *> refFiles;
358 /**
359 * The list of .o files, and the
360 * dependencies upon them.
361 */
362 std::map<String, FileRec *> depFiles;
364 char *fileBuf;
365 int fileSize;
367 static const int readBufLen = 8192;
368 char readBuf[8193];
371 };
374 //########################################################################
375 //# M A I N
376 //########################################################################
378 /**
379 * Constructor
380 */
381 DepTool::DepTool()
382 {
383 }
386 /**
387 * Destructor
388 */
389 DepTool::~DepTool()
390 {
391 reset();
392 }
394 /**
395 * Clean up after processing. Called by the destructor, but should
396 * also be called before the object is reused.
397 */
398 void DepTool::reset()
399 {
400 std::map<String, FileRec *>::iterator iter;
401 for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
402 {
403 FileRec *frec = iter->second;
404 delete frec;
405 }
406 allFiles.clear();
407 for (iter=refFiles.begin() ; iter!=refFiles.end() ; iter++)
408 {
409 FileRec *frec = iter->second;
410 delete frec;
411 }
412 refFiles.clear();
413 for (iter=depFiles.begin() ; iter!=depFiles.end() ; iter++)
414 {
415 FileRec *frec = iter->second;
416 delete frec;
417 }
418 depFiles.clear();
420 excludes.clear();
421 excludesUsed.clear();
422 excludesUnused.clear();
423 }
426 /**
427 * Format an error message in printf() style
428 */
429 void DepTool::error(char *fmt, ...)
430 {
431 va_list ap;
432 va_start(ap, fmt);
433 fprintf(stderr, "DepTool error: ");
434 vfprintf(stderr, fmt, ap);
435 fprintf(stderr, "\n");
436 va_end(ap);
437 }
440 /**
441 * Format an trace message in printf() style
442 */
443 void DepTool::trace(char *fmt, ...)
444 {
445 va_list ap;
446 va_start(ap, fmt);
447 fprintf(stdout, "DepTool: ");
448 vfprintf(stdout, fmt, ap);
449 fprintf(stdout, "\n");
450 va_end(ap);
451 }
455 //########################################################################
456 //# U T I L I T Y
457 //########################################################################
459 /**
460 * Removes whitespace from beginning and end of a string
461 */
462 String DepTool::trim(const String &s)
463 {
464 if (s.size() < 1)
465 return s;
467 //Find first non-ws char
468 unsigned int begin = 0;
469 for ( ; begin < s.size() ; begin++)
470 {
471 if (!isspace(s[begin]))
472 break;
473 }
475 //Find first non-ws char, going in reverse
476 unsigned int end = s.size() - 1;
477 for ( ; end > begin ; end--)
478 {
479 if (!isspace(s[end]))
480 break;
481 }
482 //trace("begin:%d end:%d", begin, end);
484 String res = s.substr(begin, end-begin+1);
485 return res;
486 }
489 /**
490 * Parse a full path name into path, base name, and suffix
491 */
492 void DepTool::parseName(const String &fullname,
493 String &path,
494 String &basename,
495 String &suffix)
496 {
497 if (fullname.size() < 2)
498 return;
500 String::size_type pos = fullname.find_last_of('/');
501 if (pos != fullname.npos && pos<fullname.size()-1)
502 {
503 path = fullname.substr(0, pos);
504 pos++;
505 basename = fullname.substr(pos, fullname.size()-pos);
506 }
507 else
508 {
509 path = "";
510 basename = fullname;
511 }
513 pos = basename.find_last_of('.');
514 if (pos != basename.npos && pos<basename.size()-1)
515 {
516 suffix = basename.substr(pos+1, basename.size()-pos-1);
517 basename = basename.substr(0, pos);
518 }
520 //trace("parsename:%s %s %s", path.c_str(),
521 // basename.c_str(), suffix.c_str());
522 }
525 /**
526 * Return the suffix, if any, of a file name
527 */
528 String DepTool::getSuffix(const String &fname)
529 {
530 if (fname.size() < 2)
531 return "";
532 String::size_type pos = fname.find_last_of('.');
533 if (pos == fname.npos)
534 return "";
535 pos++;
536 String res = fname.substr(pos, fname.size()-pos);
537 //trace("suffix:%s", res.c_str());
538 return res;
539 }
543 //########################################################################
544 //# P R O C E S S I N G
545 //########################################################################
547 /**
548 * Recursively list all files and directories under 'dirname', except
549 * those in the exclude list.
550 */
551 bool DepTool::listFilesInDirectory(const String &dirname, int depth)
552 {
553 //trace("### listFilesInDirectory(%s, %d)", dirname.c_str(), depth);
555 int cFiles = 0;
556 int hFiles = 0;
558 std::vector<String> subdirs;
559 DIR *dir = opendir(dirname.c_str());
560 while (true)
561 {
562 struct dirent *de = readdir(dir);
563 if (!de)
564 break;
565 String s = de->d_name;
566 struct stat finfo;
567 String fname;
568 if (s.size() == 0 || s[0] == '.')
569 continue;
571 if (dirname.size()>0 && dirname != ".")
572 {
573 fname.append(dirname);
574 fname.append("/");
575 }
576 fname.append(s);
577 if (stat(fname.c_str(), &finfo)<0)
578 {
579 error("cannot stat file:%s", s.c_str());
580 }
581 else if (excludes.find(fname) != excludes.end())
582 {
583 //trace("excluded file/dir: %s", fname.c_str());
584 excludesUsed.insert(fname);
585 }
586 else if (S_ISDIR(finfo.st_mode))
587 {
588 //trace("directory: %s", fname.c_str());
589 subdirs.push_back(fname);
590 }
591 else if (!S_ISREG(finfo.st_mode))
592 {
593 trace("not regular: %s", fname.c_str());
594 }
595 else
596 {
597 String path;
598 String basename;
599 String sfx;
600 parseName(fname, path, basename, sfx);
601 if (sfx == "cpp" || sfx == "c" || sfx == "cxx" || sfx == "cc")
602 {
603 cFiles++;
604 FileRec *fe = new FileRec(FileRec::CFILE);
605 fe->path = path;
606 fe->baseName = basename;
607 fe->suffix = sfx;
608 allFiles[fname] = fe;
609 }
610 else if (sfx == "h" || sfx == "hh" ||
611 sfx == "hpp" || sfx == "hxx")
612 {
613 hFiles++;
614 FileRec *fe = new FileRec(FileRec::HFILE);
615 fe->path = path;
616 fe->baseName = basename;
617 fe->suffix = sfx;
618 allFiles[fname] = fe;
619 }
620 }
621 }
622 closedir(dir);
624 if (hFiles > 0)
625 directories.push_back(dirname);
627 for (unsigned int i=0 ; i<subdirs.size() ; i++)
628 {
629 listFilesInDirectory(subdirs[i], depth+1);
630 }
632 return true;
633 }
637 /**
638 *
639 */
640 bool DepTool::createFileList()
641 {
642 excludes.insert("deptool.cpp");
643 FILE *f = fopen("make.exclude", "r");
644 if (!f)
645 {
646 trace("'make.exclude not found");
647 }
648 else
649 {
650 char readBuf[256];
651 while (!feof(f))
652 {
653 if (!fgets(readBuf, 255, f))
654 break;
655 String s = readBuf;
656 s = trim(s);
657 //trace("s: %d '%s' ", s.size(), s.c_str());
658 if (s.size() > 0 && s[0]!='#')
659 excludes.insert(s);
660 }
661 fclose(f);
662 }
664 listFilesInDirectory(".", 0);
666 // Note which files in the exclude list were not used.
667 std::set<String>::iterator iter;
668 for (iter=excludes.begin() ; iter!=excludes.end() ; iter++)
669 {
670 String fname = *iter;
671 std::set<String>::iterator citer = excludesUsed.find(fname);
672 if (citer == excludesUsed.end())
673 excludesUnused.insert(fname);
674 }
676 saveFileList();
678 return true;
679 }
682 /**
683 * Get a character from the buffer at pos. If out of range,
684 * return -1 for safety
685 */
686 int DepTool::get(int pos)
687 {
688 if (pos>fileSize)
689 return -1;
690 return fileBuf[pos];
691 }
695 /**
696 * Skip over all whitespace characters beginning at pos. Return
697 * the position of the first non-whitespace character.
698 */
699 int DepTool::skipwhite(int pos)
700 {
701 while (pos < fileSize)
702 {
703 int ch = get(pos);
704 if (ch < 0)
705 break;
706 if (!isspace(ch))
707 break;
708 pos++;
709 }
710 return pos;
711 }
714 /**
715 * Parse the buffer beginning at pos, for a word. Fill
716 * 'ret' with the result. Return the position after the
717 * word.
718 */
719 int DepTool::getword(int pos, String &ret)
720 {
721 while (pos < fileSize)
722 {
723 int ch = get(pos);
724 if (ch < 0)
725 break;
726 if (isspace(ch))
727 break;
728 ret.push_back((char)ch);
729 pos++;
730 }
731 return pos;
732 }
734 /**
735 * Return whether the sequence of characters in the buffer
736 * beginning at pos match the key, for the length of the key
737 */
738 bool DepTool::sequ(int pos, char *key)
739 {
740 while (*key)
741 {
742 if (*key != get(pos))
743 return false;
744 key++; pos++;
745 }
746 return true;
747 }
751 /**
752 * Add an include file name to a file record. If the name
753 * is not found in allFiles explicitly, try prepending include
754 * directory names to it and try again.
755 */
756 bool DepTool::addIncludeFile(FileRec *frec, const String &iname)
757 {
759 std::map<String, FileRec *>::iterator iter =
760 allFiles.find(iname);
761 if (iter != allFiles.end())
762 {
763 //h file in same dir
764 FileRec *other = iter->second;
765 //trace("local: '%s'", iname.c_str());
766 frec->files[iname] = other;
767 return true;
768 }
769 else
770 {
771 //look in other dirs
772 std::vector<String>::iterator diter;
773 for (diter=directories.begin() ;
774 diter!=directories.end() ; diter++)
775 {
776 String dfname = *diter;
777 dfname.append("/");
778 dfname.append(iname);
779 iter = allFiles.find(dfname);
780 if (iter != allFiles.end())
781 {
782 FileRec *other = iter->second;
783 //trace("other: '%s'", iname.c_str());
784 frec->files[dfname] = other;
785 return true;
786 }
787 }
788 }
789 return true;
790 }
794 /**
795 * Lightly parse a file to find the #include directives. Do
796 * a bit of state machine stuff to make sure that the directive
797 * is valid. (Like not in a comment).
798 */
799 bool DepTool::scanFile(const String &fname, FileRec *frec)
800 {
801 FILE *f = fopen(fname.c_str(), "r");
802 if (!f)
803 {
804 error("Could not open '%s' for reading", fname.c_str());
805 return false;
806 }
807 String buf;
808 while (!feof(f))
809 {
810 int len = fread(readBuf, 1, readBufLen, f);
811 readBuf[len] = '\0';
812 buf.append(readBuf);
813 }
814 fclose(f);
816 fileSize = buf.size();
817 fileBuf = (char *)buf.c_str();
818 int pos = 0;
821 while (pos < fileSize)
822 {
823 //trace("p:%c", get(pos));
825 //# Block comment
826 if (get(pos) == '/' && get(pos+1) == '*')
827 {
828 pos += 2;
829 while (pos < fileSize)
830 {
831 if (get(pos) == '*' && get(pos+1) == '/')
832 {
833 pos += 2;
834 break;
835 }
836 else
837 pos++;
838 }
839 }
840 //# Line comment
841 else if (get(pos) == '/' && get(pos+1) == '/')
842 {
843 pos += 2;
844 while (pos < fileSize)
845 {
846 if (get(pos) == '\n')
847 {
848 pos++;
849 break;
850 }
851 else
852 pos++;
853 }
854 }
855 //# #include! yaay
856 else if (sequ(pos, "#include"))
857 {
858 pos += 8;
859 pos = skipwhite(pos);
860 String iname;
861 pos = getword(pos, iname);
862 if (iname.size()>2)
863 {
864 iname = iname.substr(1, iname.size()-2);
865 addIncludeFile(frec, iname);
866 }
867 }
868 else
869 {
870 pos++;
871 }
872 }
874 return true;
875 }
879 /**
880 * Recursively check include lists to find all files in allFiles to which
881 * a given file is dependent.
882 */
883 bool DepTool::processDependency(FileRec *ofile,
884 FileRec *include,
885 int depth)
886 {
887 std::map<String, FileRec *>::iterator iter;
888 for (iter=include->files.begin() ; iter!=include->files.end() ; iter++)
889 {
890 String fname = iter->first;
891 if (ofile->files.find(fname) != ofile->files.end())
892 {
893 //trace("file '%s' already seen", fname.c_str());
894 continue;
895 }
896 FileRec *child = iter->second;
897 ofile->files[fname] = child;
899 processDependency(ofile, child, depth+1);
900 }
903 return true;
904 }
908 /**
909 * Recursively check include lists to find all files in allFiles which
910 * will eventually have a dependency on this file. This is basically
911 * the inverse of processDependency().
912 */
913 bool DepTool::processReference(FileRec *hfile,
914 String &fname,
915 int depth)
916 {
917 std::map<String, FileRec *>::iterator iter;
918 for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
919 {
920 FileRec *frec = iter->second;
921 std::map<String, FileRec *>::iterator fiter =
922 frec->files.find(fname);
923 if (fiter != frec->files.end())
924 {
925 String cfname = iter->first;
926 if (hfile->files.find(cfname) != hfile->files.end())
927 {
928 //trace("%d reffile '%s' already seen", depth, cfname.c_str());
929 continue;
930 }
931 FileRec *child = iter->second;
932 child->distance = depth;
933 hfile->files[cfname] = child;
934 processReference(hfile, cfname, depth+1);
935 }
936 }
938 return true;
939 }
943 /**
944 * Generate the file dependency and reference lists.
945 */
946 bool DepTool::generateDependencies()
947 {
948 std::map<String, FileRec *>::iterator iter;
949 //# First pass. Scan for all includes
950 for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
951 {
952 FileRec *frec = iter->second;
953 if (!scanFile(iter->first, frec))
954 {
955 //quit?
956 }
957 }
959 //# Second pass. Scan for all includes
960 for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
961 {
962 FileRec *include = iter->second;
963 if (include->type == FileRec::CFILE)
964 {
965 String cFileName = iter->first;
966 FileRec *ofile = new FileRec(FileRec::OFILE);
967 ofile->path = include->path;
968 ofile->baseName = include->baseName;
969 ofile->suffix = include->suffix;
970 String fname = include->path;
971 if (fname.size()>0)
972 fname.append("/");
973 fname.append(include->baseName);
974 fname.append(".o");
975 depFiles[fname] = ofile;
976 //add the .c file first, of course
977 ofile->files[cFileName] = include;
978 //trace("ofile:%s", fname.c_str());
980 processDependency(ofile, include, 0);
981 }
982 /*
983 else if (include->type == FileRec::HFILE)
984 {
985 String fname = iter->first;
986 FileRec *hfile = new FileRec(FileRec::HFILE);
987 hfile->path = include->path;
988 hfile->baseName = include->baseName;
989 hfile->suffix = include->suffix;
990 refFiles[fname] = hfile;
991 //trace("hfile:%s", fname.c_str());
993 processReference(hfile, fname, 0);
994 }
995 */
996 }
999 return true;
1000 }
1003 /**
1004 * High-level call to do what DepTool does.
1005 */
1006 bool DepTool::run()
1007 {
1008 reset();
1009 if (!createFileList())
1010 return false;
1011 if (!generateDependencies())
1012 return false;
1013 saveDepFile(false);
1014 saveCmakeFile();
1015 //saveRefFile(true);
1016 return true;
1017 }
1020 //########################################################################
1021 //# O U T P U T S
1022 //########################################################################
1026 /**
1027 * Save the allFiles list. This is basically all files in a directory
1028 * except those denied in the exclude list.
1029 */
1030 bool DepTool::saveFileList()
1031 {
1032 time_t tim;
1033 time(&tim);
1035 FILE *f = fopen("make.files", "w");
1036 if (!f)
1037 {
1038 trace("cannot open 'make.files' for writing");
1039 }
1040 fprintf(f, "########################################################\n");
1041 fprintf(f, "## File: make.files\n");
1042 fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1043 fprintf(f, "########################################################\n");
1045 fprintf(f, "\n\n\n");
1046 fprintf(f, "########################################################\n");
1047 fprintf(f, "## F I L E S\n");
1048 fprintf(f, "########################################################\n");
1050 std::map<String, FileRec *>::iterator iter;
1051 for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
1052 {
1053 fprintf(f, "%s\n", iter->first.c_str());
1054 }
1056 fprintf(f, "\n\n\n");
1057 fprintf(f, "########################################################\n");
1058 fprintf(f, "## E X C L U D E D\n");
1059 fprintf(f, "########################################################\n");
1061 std::set<String>::iterator uiter;
1062 for (uiter=excludesUsed.begin() ; uiter!=excludesUsed.end() ; uiter++)
1063 {
1064 String fname = *uiter;
1065 fprintf(f, "%s\n", fname.c_str());
1066 }
1068 fprintf(f, "\n\n\n");
1069 fprintf(f, "########################################################\n");
1070 fprintf(f, "## E X C L U D E entries unused\n");
1071 fprintf(f, "########################################################\n");
1073 for (uiter=excludesUnused.begin() ; uiter!=excludesUnused.end() ; uiter++)
1074 {
1075 String fname = *uiter;
1076 fprintf(f, "%s\n", fname.c_str());
1077 }
1079 fprintf(f, "\n\n\n");
1080 fprintf(f, "########################################################\n");
1081 fprintf(f, "## E N D\n");
1082 fprintf(f, "########################################################\n");
1084 fclose(f);
1086 return true;
1087 }
1090 /**
1091 * This is the main product. This file lists the Include directives,
1092 * the Object list, and the dependency list.
1093 */
1094 bool DepTool::saveDepFile(bool doXml)
1095 {
1096 time_t tim;
1097 time(&tim);
1099 FILE *f = fopen("make.dep", "w");
1100 if (!f)
1101 {
1102 trace("cannot open 'make.dep' for writing");
1103 }
1104 if (doXml)
1105 {
1106 fprintf(f, "<?xml version='1.0'?>\n");
1107 fprintf(f, "<deptool>\n");
1108 fprintf(f, "\n");
1109 fprintf(f, "<!--\n");
1110 fprintf(f, "########################################################\n");
1111 fprintf(f, "## File: make.dep\n");
1112 fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1113 fprintf(f, "########################################################\n");
1114 fprintf(f, "-->\n");
1116 fprintf(f, "\n\n");
1118 fprintf(f, "\n");
1119 fprintf(f, "<!--\n");
1120 fprintf(f, "########################################################\n");
1121 fprintf(f, "## I N C L U D E\n");
1122 fprintf(f, "########################################################\n");
1123 fprintf(f, "-->\n");
1124 fprintf(f, "<includes>\n");
1126 std::vector<String>::iterator inciter;
1127 for (inciter=directories.begin() ; inciter!=directories.end() ; inciter++)
1128 {
1129 String dirname = *inciter;
1130 fprintf(f, " <inc name='%s'/>\n", dirname.c_str());
1131 }
1133 fprintf(f, "</includes>\n");
1134 fprintf(f, "\n\n\n");
1135 fprintf(f, "<!--\n");
1136 fprintf(f, "########################################################\n");
1137 fprintf(f, "## O B J E C T S\n");
1138 fprintf(f, "########################################################\n");
1139 fprintf(f, "-->\n");
1140 fprintf(f, "<objects>\n");
1142 std::map<String, FileRec *>::iterator oiter;
1143 for (oiter=allFiles.begin() ; oiter!=allFiles.end() ; oiter++)
1144 {
1145 FileRec *frec = oiter->second;
1146 if (frec->type == FileRec::CFILE)
1147 {
1148 String fname = frec->path;
1149 if (fname.size()>0)
1150 fname.append("/");
1151 fname.append(frec->baseName);
1152 fname.append(".o");
1153 fprintf(f, " <obj name='%s'/>\n", fname.c_str());
1154 }
1155 }
1158 fprintf(f, "</objects>\n");
1159 fprintf(f, "\n\n\n");
1160 fprintf(f, "<!--\n");
1161 fprintf(f, "########################################################\n");
1162 fprintf(f, "## D E P E N D E N C I E S\n");
1163 fprintf(f, "########################################################\n");
1164 fprintf(f, "-->\n");
1165 fprintf(f, "<dependencies>\n\n");
1166 std::map<String, FileRec *>::iterator iter;
1167 for (iter=depFiles.begin() ; iter!=depFiles.end() ; iter++)
1168 {
1169 FileRec *frec = iter->second;
1170 if (frec->type == FileRec::OFILE)
1171 {
1172 String fname = iter->first;
1173 fprintf(f, "<file name='%s'>\n", fname.c_str());
1174 std::map<String, FileRec *>::iterator citer;
1175 for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
1176 {
1177 String cfname = citer->first;
1178 fprintf(f, " <dep name='%s'/>\n", cfname.c_str());
1179 }
1180 fprintf(f, "</file>\n\n");
1181 }
1182 }
1184 fprintf(f, "</dependencies>\n");
1185 fprintf(f, "\n\n\n");
1186 fprintf(f, "</deptool>\n");
1187 fprintf(f, "<!--\n");
1188 fprintf(f, "########################################################\n");
1189 fprintf(f, "## E N D\n");
1190 fprintf(f, "########################################################\n");
1191 fprintf(f, "-->\n");
1192 }
1193 else // ######### !XML
1194 {
1195 fprintf(f, "########################################################\n");
1196 fprintf(f, "## File: make.dep\n");
1197 fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1198 fprintf(f, "########################################################\n");
1200 fprintf(f, "\n\n");
1202 fprintf(f, "########################################################\n");
1203 fprintf(f, "## I N C L U D E\n");
1204 fprintf(f, "########################################################\n");
1205 fprintf(f, "DEPTOOL_INCLUDE =");
1207 std::vector<String>::iterator inciter;
1208 for (inciter=directories.begin() ; inciter!=directories.end() ; inciter++)
1209 {
1210 fprintf(f, " \\\n");
1211 String dirname = *inciter;
1212 fprintf(f, "-I%s", dirname.c_str());
1213 }
1215 fprintf(f, "\n\n\n");
1216 fprintf(f, "########################################################\n");
1217 fprintf(f, "## O B J E C T S\n");
1218 fprintf(f, "########################################################\n");
1219 fprintf(f, "DEPTOOL_OBJECTS =");
1221 std::map<String, FileRec *>::iterator oiter;
1222 for (oiter=allFiles.begin() ; oiter!=allFiles.end() ; oiter++)
1223 {
1224 FileRec *frec = oiter->second;
1225 if (frec->type == FileRec::CFILE)
1226 {
1227 fprintf(f, " \\\n");
1228 String fname = frec->path;
1229 if (fname.size()>0)
1230 fname.append("/");
1231 fname.append(frec->baseName);
1232 fname.append(".o");
1233 fprintf(f, "%s", fname.c_str());
1234 }
1235 }
1238 fprintf(f, "\n\n\n");
1239 fprintf(f, "########################################################\n");
1240 fprintf(f, "## D E P E N D E N C I E S\n");
1241 fprintf(f, "########################################################\n");
1242 std::map<String, FileRec *>::iterator iter;
1243 for (iter=depFiles.begin() ; iter!=depFiles.end() ; iter++)
1244 {
1245 FileRec *frec = iter->second;
1246 if (frec->type == FileRec::OFILE)
1247 {
1248 String fname = iter->first;
1249 fprintf(f, "%s:", fname.c_str());
1250 std::map<String, FileRec *>::iterator citer;
1251 for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
1252 {
1253 String cfname = citer->first;
1254 fprintf(f, " \\\n");
1255 fprintf(f, "\t%s", cfname.c_str());
1256 }
1257 fprintf(f, "\n\n\n");
1258 }
1259 }
1261 fprintf(f, "\n\n\n");
1262 fprintf(f, "########################################################\n");
1263 fprintf(f, "## E N D\n");
1264 fprintf(f, "########################################################\n");
1265 }
1267 fclose(f);
1269 return true;
1270 }
1273 /**
1274 * Save the "reference" file, which lists each include file, and any files
1275 * that are judged to be dependent upon it.
1276 */
1277 bool DepTool::saveRefFile(bool doXml)
1278 {
1279 time_t tim;
1280 time(&tim);
1282 FILE *f = fopen("make.ref", "w");
1283 if (!f)
1284 {
1285 trace("cannot open 'make.ref' for writing");
1286 }
1287 if (doXml)
1288 {
1289 fprintf(f, "<?xml version='1.0'?>\n");
1290 fprintf(f, "<deptool>\n\n");
1291 fprintf(f, "<!--\n");
1292 fprintf(f, "########################################################\n");
1293 fprintf(f, "## File: make.ref\n");
1294 fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1295 fprintf(f, "## Note: The metric is the 'distance' of inclusion from\n");
1296 fprintf(f, "## the given file.\n");
1297 fprintf(f, "########################################################\n");
1298 fprintf(f, "-->\n");
1299 fprintf(f, "\n\n");
1302 std::map<String, FileRec *>::iterator iter;
1303 for (iter=refFiles.begin() ; iter!=refFiles.end() ; iter++)
1304 {
1305 FileRec *frec = iter->second;
1306 if (frec->type == FileRec::HFILE)
1307 {
1308 String fname = iter->first;
1309 fprintf(f, "<file name='%s'>\n", fname.c_str());
1310 std::map<String, FileRec *>::iterator citer;
1311 for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
1312 {
1313 String cfname = citer->first;
1314 fprintf(f, " <ref d='%d' name='%s'/>\n",
1315 citer->second->distance, cfname.c_str());
1316 }
1317 fprintf(f, "</file>\n\n");
1318 }
1319 }
1320 fprintf(f, "\n\n\n");
1321 fprintf(f, "</deptool>\n");
1322 fprintf(f, "<!--\n");
1323 fprintf(f, "########################################################\n");
1324 fprintf(f, "## E N D\n");
1325 fprintf(f, "########################################################\n");
1326 fprintf(f, "-->\n");
1327 }
1329 else //######### not xml
1330 {
1331 fprintf(f, "########################################################\n");
1332 fprintf(f, "## File: make.ref\n");
1333 fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1334 fprintf(f, "## Note: The metric is the 'distance' of inclusion from\n");
1335 fprintf(f, "## the given file.\n");
1336 fprintf(f, "########################################################\n");
1337 fprintf(f, "\n\n");
1340 std::map<String, FileRec *>::iterator iter;
1341 for (iter=refFiles.begin() ; iter!=refFiles.end() ; iter++)
1342 {
1343 FileRec *frec = iter->second;
1344 if (frec->type == FileRec::HFILE)
1345 {
1346 String fname = iter->first;
1347 fprintf(f, "### %s\n", fname.c_str());
1348 std::map<String, FileRec *>::iterator citer;
1349 for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
1350 {
1351 String cfname = citer->first;
1352 fprintf(f, "%3d %s\n", citer->second->distance,
1353 cfname.c_str());
1354 }
1355 fprintf(f, "\n");
1356 }
1357 }
1359 fprintf(f, "\n\n\n");
1360 fprintf(f, "########################################################\n");
1361 fprintf(f, "## E N D\n");
1362 fprintf(f, "########################################################\n");
1363 }
1365 fclose(f);
1367 return true;
1368 }
1371 /**
1372 * This is a new thing. It creates a cmake file that should be able to
1373 * build the entire thing.
1374 */
1375 bool DepTool::saveCmakeFile()
1376 {
1377 time_t tim;
1378 time(&tim);
1380 FILE *f = fopen("CMakeLists.txt", "w");
1381 if (!f)
1382 {
1383 trace("cannot open 'CMakeLists.txt' for writing");
1384 }
1385 fprintf(f, "########################################################\n");
1386 fprintf(f, "## File: CMakeLists.txt\n");
1387 fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1388 fprintf(f, "########################################################\n");
1390 fprintf(f, "\n\n");
1392 fprintf(f, "\n\n\n");
1393 fprintf(f, "########################################################\n");
1394 fprintf(f, "## P R O J E C T\n");
1395 fprintf(f, "########################################################\n");
1396 fprintf(f, "project (INKSCAPE)\n");
1397 fprintf(f, "\n\n\n");
1398 fprintf(f, "########################################################\n");
1399 fprintf(f, "## O B J E C T S\n");
1400 fprintf(f, "########################################################\n");
1401 fprintf(f, "set (INKSCAPE_SRCS\n");
1403 std::map<String, FileRec *>::iterator oiter;
1404 for (oiter=allFiles.begin() ; oiter!=allFiles.end() ; oiter++)
1405 {
1406 FileRec *frec = oiter->second;
1407 if (frec->type == FileRec::CFILE)
1408 {
1409 //fprintf(f, " \\\n");
1410 String fname = frec->path;
1411 if (fname.size()>0)
1412 fname.append("/");
1413 fname.append(frec->baseName);
1414 fname.append(".");
1415 fname.append(frec->suffix);
1416 fprintf(f, "%s\n", fname.c_str());
1417 }
1418 }
1419 fprintf(f, ")\n\n");
1421 fprintf(f, "add_executable (inkscape ${INKSCAPE_SRCS})\n");
1423 fprintf(f, "\n\n\n");
1424 fprintf(f, "########################################################\n");
1425 fprintf(f, "## E N D\n");
1426 fprintf(f, "########################################################\n");
1428 fclose(f);
1430 return true;
1431 }
1438 //########################################################################
1439 //# M A I N
1440 //########################################################################
1443 /**
1444 * Run the DepTool's main functions
1445 */
1446 static bool runTool()
1447 {
1448 DepTool depTool;
1450 if (!depTool.run())
1451 return false;
1453 return true;
1454 }
1457 /**
1458 * Console main()
1459 */
1460 int main(int argc, char **argv)
1461 {
1462 if (!runTool())
1463 return 1;
1465 return 0;
1466 }
1469 //########################################################################
1470 //# E N D O F F I L E
1471 //########################################################################