ppDependableFile.cxx 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. // Filename: ppDependableFile.cxx
  2. // Created by: drose (15Oct00)
  3. //
  4. ////////////////////////////////////////////////////////////////////
  5. #include "ppDependableFile.h"
  6. #include "ppDirectory.h"
  7. #include "ppDirectoryTree.h"
  8. #include "filename.h"
  9. #include "check_include.h"
  10. #ifdef HAVE_UNISTD_H
  11. #include <unistd.h>
  12. #endif
  13. #include <assert.h>
  14. #include <sys/stat.h>
  15. #include <algorithm>
  16. #include <iterator>
  17. class SortDependableFilesByName {
  18. public:
  19. bool operator () (PPDependableFile *a, PPDependableFile *b) const {
  20. return a->get_filename() < b->get_filename();
  21. }
  22. };
  23. ////////////////////////////////////////////////////////////////////
  24. // Function: PPDependableFile::Ordering Operator
  25. // Access: Public
  26. // Description: We provide this function so we can sort the
  27. // dependency list into a consistent ordering, so that
  28. // the makefiles won't get randomly regenerated between
  29. // different sessions.
  30. ////////////////////////////////////////////////////////////////////
  31. bool PPDependableFile::Dependency::
  32. operator < (const Dependency &other) const {
  33. return _file->get_filename() < other._file->get_filename();
  34. }
  35. ////////////////////////////////////////////////////////////////////
  36. // Function: PPDependableFile::Constructor
  37. // Access: Public
  38. // Description:
  39. ////////////////////////////////////////////////////////////////////
  40. PPDependableFile::
  41. PPDependableFile(PPDirectory *directory, const string &filename) :
  42. _directory(directory),
  43. _filename(filename)
  44. {
  45. _flags = 0;
  46. _mtime = 0;
  47. }
  48. ////////////////////////////////////////////////////////////////////
  49. // Function: PPDependableFile::update_from_cache
  50. // Access: Public
  51. // Description: Called as the dependency cache file is being read,
  52. // this asks the file to update its information from the
  53. // cache file if appropriate. This means comparing the
  54. // cached modification time against the file's actual
  55. // modification time, and storing the cached
  56. // dependencies if they match.
  57. //
  58. // The return value is true if the cache is valid, false
  59. // if something appears to be wrong.
  60. ////////////////////////////////////////////////////////////////////
  61. bool PPDependableFile::
  62. update_from_cache(const vector<string> &words) {
  63. // Shouldn't call this once the file has actually been read.
  64. assert((_flags & F_updated) == 0);
  65. assert((_flags & F_updating) == 0);
  66. assert((_flags & F_from_cache) == 0);
  67. assert(words.size() >= 2);
  68. if (!exists()) {
  69. // The file doesn't even exist; clearly the cache is bad.
  70. _flags |= F_bad_cache;
  71. } else {
  72. // The second parameter is the cached modification time.
  73. time_t mtime = strtol(words[1].c_str(), (char **)NULL, 10);
  74. if (mtime == get_mtime()) {
  75. // The modification matches; preserve the cache information.
  76. PPDirectoryTree *tree = _directory->get_tree();
  77. _dependencies.clear();
  78. vector<string>::const_iterator wi;
  79. for (wi = words.begin() + 2; wi != words.end(); ++wi) {
  80. string dirpath = (*wi);
  81. Dependency dep;
  82. dep._okcircular = false;
  83. if (dirpath.length() > 1 && dirpath[0] == '/') {
  84. // If the first character is '/', it means that the file has
  85. // been marked okcircular.
  86. dep._okcircular = true;
  87. dirpath = dirpath.substr(1);
  88. }
  89. if (dirpath.length() > 2 && dirpath.substr(0, 2) == "*/") {
  90. // This is an extra include file, not a file in this source
  91. // tree.
  92. _extra_includes.push_back(dirpath.substr(2));
  93. } else {
  94. dep._file =
  95. tree->get_dependable_file_by_dirpath(dirpath, false);
  96. if (dep._file != (PPDependableFile *)NULL) {
  97. _dependencies.push_back(dep);
  98. }
  99. }
  100. }
  101. _flags |= F_from_cache;
  102. sort(_dependencies.begin(), _dependencies.end());
  103. }
  104. }
  105. return ((_flags & F_bad_cache) == 0);
  106. }
  107. ////////////////////////////////////////////////////////////////////
  108. // Function: PPDependableFile::clear_cache
  109. // Access: Public
  110. // Description: Forgets the cache we just read.
  111. ////////////////////////////////////////////////////////////////////
  112. void PPDependableFile::
  113. clear_cache() {
  114. _dependencies.clear();
  115. _flags &= ~(F_bad_cache | F_from_cache);
  116. }
  117. ////////////////////////////////////////////////////////////////////
  118. // Function: PPDependableFile::write_cache
  119. // Access: Public
  120. // Description: Writes the dependency information out as a single
  121. // line to the indicated dependency cache file.
  122. ////////////////////////////////////////////////////////////////////
  123. void PPDependableFile::
  124. write_cache(ostream &out) {
  125. out << _filename << " " << get_mtime();
  126. Dependencies::const_iterator di;
  127. for (di = _dependencies.begin(); di != _dependencies.end(); ++di) {
  128. out << " ";
  129. if ((*di)._okcircular) {
  130. out << "/";
  131. }
  132. if ((*di)._file->get_directory()->get_tree() != get_directory()->get_tree()) {
  133. out << "+";
  134. }
  135. out << (*di)._file->get_dirpath();
  136. }
  137. // Also write out the extra includes--those #include directives
  138. // which do not reference a file within this source tree. We need
  139. // those just for comparison's sake later, so we can tell whether
  140. // the cache line is still current (without having to know which
  141. // files are part of the tree).
  142. ExtraIncludes::const_iterator ei;
  143. for (ei = _extra_includes.begin(); ei != _extra_includes.end(); ++ei) {
  144. out << " */" << (*ei);
  145. }
  146. out << "\n";
  147. }
  148. ////////////////////////////////////////////////////////////////////
  149. // Function: PPDependableFile::get_directory
  150. // Access: Public
  151. // Description: Returns the directory that this file can be found in.
  152. ////////////////////////////////////////////////////////////////////
  153. PPDirectory *PPDependableFile::
  154. get_directory() const {
  155. return _directory;
  156. }
  157. ////////////////////////////////////////////////////////////////////
  158. // Function: PPDependableFile::get_filename
  159. // Access: Public
  160. // Description: Returns the local filename of this particular file
  161. // within the directory.
  162. ////////////////////////////////////////////////////////////////////
  163. const string &PPDependableFile::
  164. get_filename() const {
  165. return _filename;
  166. }
  167. ////////////////////////////////////////////////////////////////////
  168. // Function: PPDependableFile::get_pathname
  169. // Access: Public
  170. // Description: Returns the relative pathname from the root of the
  171. // source tree to this particular filename.
  172. ////////////////////////////////////////////////////////////////////
  173. string PPDependableFile::
  174. get_pathname() const {
  175. return _directory->get_path() + "/" + _filename;
  176. }
  177. ////////////////////////////////////////////////////////////////////
  178. // Function: PPDependableFile::get_fullpath
  179. // Access: Public
  180. // Description: Returns the full pathname to this particular filename.
  181. ////////////////////////////////////////////////////////////////////
  182. string PPDependableFile::
  183. get_fullpath() const {
  184. return _directory->get_fullpath() + "/" + _filename;
  185. }
  186. ////////////////////////////////////////////////////////////////////
  187. // Function: PPDependableFile::get_dirpath
  188. // Access: Public
  189. // Description: Returns an abbreviated pathname to this file, in the
  190. // form dirname/filename.
  191. ////////////////////////////////////////////////////////////////////
  192. string PPDependableFile::
  193. get_dirpath() const {
  194. return _directory->get_dirname() + "/" + _filename;
  195. }
  196. ////////////////////////////////////////////////////////////////////
  197. // Function: PPDependableFile::exists
  198. // Access: Public
  199. // Description: Returns true if the file exists, false if it does
  200. // not.
  201. ////////////////////////////////////////////////////////////////////
  202. bool PPDependableFile::
  203. exists() {
  204. stat_file();
  205. return ((_flags & F_exists) != 0);
  206. }
  207. ////////////////////////////////////////////////////////////////////
  208. // Function: PPDependableFile::get_mtime
  209. // Access: Public
  210. // Description: Returns the last modification time of the file.
  211. ////////////////////////////////////////////////////////////////////
  212. time_t PPDependableFile::
  213. get_mtime() {
  214. stat_file();
  215. return _mtime;
  216. }
  217. ////////////////////////////////////////////////////////////////////
  218. // Function: PPDependableFile::get_num_dependencies
  219. // Access: Public
  220. // Description: Returns the number of files this file depends on.
  221. ////////////////////////////////////////////////////////////////////
  222. int PPDependableFile::
  223. get_num_dependencies() {
  224. update_dependencies();
  225. return _dependencies.size();
  226. }
  227. ////////////////////////////////////////////////////////////////////
  228. // Function: PPDependableFile::get_dependency
  229. // Access: Public
  230. // Description: Returns the nth file this file depends on.
  231. ////////////////////////////////////////////////////////////////////
  232. PPDependableFile *PPDependableFile::
  233. get_dependency(int n) {
  234. assert((_flags & F_updated) != 0);
  235. assert(n >= 0 && n < (int)_dependencies.size());
  236. return _dependencies[n]._file;
  237. }
  238. ////////////////////////////////////////////////////////////////////
  239. // Function: PPDependableFile::get_complete_dependencies
  240. // Access: Public
  241. // Description: This flavor of get_complete_dependencies() works like
  242. // the one below, except it returns the results in a
  243. // consistently-ordered vector. This allows us to keep
  244. // the dependencies in the same order between sessions
  245. // and prevent makefiles from being arbitrarily
  246. // regenerated.
  247. ////////////////////////////////////////////////////////////////////
  248. void PPDependableFile::
  249. get_complete_dependencies(vector<PPDependableFile *> &files) {
  250. set<PPDependableFile *> files_set;
  251. get_complete_dependencies(files_set);
  252. copy(files_set.begin(), files_set.end(), back_inserter(files));
  253. sort(files.begin(), files.end(), SortDependableFilesByName());
  254. }
  255. ////////////////////////////////////////////////////////////////////
  256. // Function: PPDependableFile::get_complete_dependencies
  257. // Access: Public
  258. // Description: Recursively determines the complete set of files this
  259. // file depends on. It is the user's responsibility to
  260. // empty the set before calling this function; the
  261. // results will simply be added to the existing set.
  262. ////////////////////////////////////////////////////////////////////
  263. void PPDependableFile::
  264. get_complete_dependencies(set<PPDependableFile *> &files) {
  265. update_dependencies();
  266. Dependencies::const_iterator di;
  267. for (di = _dependencies.begin(); di != _dependencies.end(); ++di) {
  268. PPDependableFile *file = (*di)._file;
  269. if (files.insert(file).second) {
  270. file->get_complete_dependencies(files);
  271. }
  272. }
  273. }
  274. ////////////////////////////////////////////////////////////////////
  275. // Function: PPDependableFile::is_circularity
  276. // Access: Public
  277. // Description: Returns true if a circular dependency exists between
  278. // this file and one or more other files.
  279. ////////////////////////////////////////////////////////////////////
  280. bool PPDependableFile::
  281. is_circularity() {
  282. update_dependencies();
  283. return (_flags & F_circularity) != 0;
  284. }
  285. ////////////////////////////////////////////////////////////////////
  286. // Function: PPDependableFile::get_circularity
  287. // Access: Public
  288. // Description: If is_circularity() returns true, returns a string
  289. // describing the circular dependency path for the user.
  290. ////////////////////////////////////////////////////////////////////
  291. string PPDependableFile::
  292. get_circularity() {
  293. update_dependencies();
  294. return _circularity;
  295. }
  296. ////////////////////////////////////////////////////////////////////
  297. // Function: PPDependableFile::was_examined
  298. // Access: Public
  299. // Description: Returns true if anyone ever asked this file for its
  300. // list of dependencies, or false otherwise.
  301. ////////////////////////////////////////////////////////////////////
  302. bool PPDependableFile::
  303. was_examined() const {
  304. return ((_flags & F_updated) != 0);
  305. }
  306. ////////////////////////////////////////////////////////////////////
  307. // Function: PPDependableFile::was_cached
  308. // Access: Public
  309. // Description: Returns true if this file was found in the cache,
  310. // false otherwise.
  311. ////////////////////////////////////////////////////////////////////
  312. bool PPDependableFile::
  313. was_cached() const {
  314. return ((_flags & F_from_cache) != 0);
  315. }
  316. ////////////////////////////////////////////////////////////////////
  317. // Function: PPDependableFile::update_dependencies
  318. // Access: Private
  319. // Description: Builds up the dependency list--the list of files this
  320. // file depends on--if it hasn't already been built. If
  321. // a circular dependency is detected during this
  322. // process, _circularity and _circularity_detected will
  323. // be updated accordingly.
  324. ////////////////////////////////////////////////////////////////////
  325. void PPDependableFile::
  326. update_dependencies() {
  327. if ((_flags & F_updated) != 0) {
  328. return;
  329. }
  330. assert((_flags & F_updating) == 0);
  331. string circularity;
  332. compute_dependencies(circularity);
  333. }
  334. ////////////////////////////////////////////////////////////////////
  335. // Function: PPDependableFile::compute_dependencies
  336. // Access: Private
  337. // Description: Builds up the dependency list--the list of files this
  338. // file depends on--if it hasn't already been built.
  339. //
  340. // If a circularity is detected, e.g. two files depend
  341. // on each other, a pointer to the offending file is
  342. // returned and the string is updated to indicate the
  343. // circularity. Otherwise, if there is no circularity,
  344. // NULL is returned.
  345. ////////////////////////////////////////////////////////////////////
  346. PPDependableFile *PPDependableFile::
  347. compute_dependencies(string &circularity) {
  348. if ((_flags & F_updated) != 0) {
  349. return (PPDependableFile *)NULL;
  350. } else if ((_flags & F_updating) != 0) {
  351. // Oh oh, a circular dependency!
  352. circularity = get_dirpath();
  353. return this;
  354. }
  355. _flags |= F_updating;
  356. if ((_flags & F_from_cache) == 0) {
  357. // Now open the file and scan it for #include statements.
  358. Filename filename(get_fullpath());
  359. filename.set_text();
  360. ifstream in;
  361. if (!filename.open_read(in)) {
  362. // Can't read the file, or the file doesn't exist. Interesting.
  363. if (exists()) {
  364. cerr << "Warning: dependent file " << filename
  365. << " exists but cannot be read.\n";
  366. } else {
  367. cerr << "Warning: dependent file " << filename
  368. << " does not exist.\n";
  369. _flags |= F_bad_cache;
  370. }
  371. } else {
  372. if (verbose) {
  373. cerr << "Reading (dep) \"" << filename << "\"\n";
  374. }
  375. PPDirectoryTree *tree = _directory->get_tree()->get_main_tree();
  376. bool okcircular = false;
  377. string line;
  378. getline(in, line);
  379. while (!in.fail() && !in.eof()) {
  380. if (line.substr(0, 16) == "/* okcircular */") {
  381. okcircular = true;
  382. } else {
  383. string filename = check_include(line);
  384. if (!filename.empty() && filename.find('/') == string::npos) {
  385. Dependency dep;
  386. dep._okcircular = okcircular;
  387. dep._file = tree->find_dependable_file(filename);
  388. if (dep._file != (PPDependableFile *)NULL) {
  389. // All right! Here's a file we depend on. Add it to the
  390. // list.
  391. _dependencies.push_back(dep);
  392. } else {
  393. // It's an include file from somewhere else, not from within
  394. // our source tree. We don't care about it, but we do need
  395. // to record it so we can easily check later if the cache
  396. // file has gone stale.
  397. _extra_includes.push_back(filename);
  398. }
  399. }
  400. okcircular = false;
  401. }
  402. getline(in, line);
  403. }
  404. }
  405. }
  406. // Now recursively expand all our dependent files, so we can check
  407. // for circularities.
  408. PPDependableFile *circ = (PPDependableFile *)NULL;
  409. Dependencies::iterator di;
  410. for (di = _dependencies.begin();
  411. di != _dependencies.end() && circ == (PPDependableFile *)NULL;
  412. ++di) {
  413. // Skip this file if the user specifically marked it
  414. // with an "okcircular" comment.
  415. if (!(*di)._okcircular) {
  416. circ = (*di)._file->compute_dependencies(circularity);
  417. if (((*di)._file->_flags & F_bad_cache) != 0) {
  418. // If our dependent file had a broken cache, our own cache is
  419. // suspect.
  420. _flags |= F_bad_cache;
  421. }
  422. if (circ != (PPDependableFile *)NULL) {
  423. // Oops, a circularity. Silly user.
  424. circularity = get_dirpath() + " => " + circularity;
  425. if (circ == this) {
  426. _flags |= F_circularity;
  427. _circularity = circularity;
  428. }
  429. }
  430. }
  431. }
  432. _flags = (_flags & ~F_updating) | F_updated;
  433. sort(_dependencies.begin(), _dependencies.end());
  434. if ((_flags & (F_bad_cache | F_from_cache)) == (F_bad_cache | F_from_cache)) {
  435. // Our cache is suspect. Re-read the file to flush the cache.
  436. if (verbose) {
  437. cerr << "Dependency cache for \"" << get_fullpath() << "\" is suspect.\n";
  438. }
  439. clear_cache();
  440. _flags &= ~F_updated;
  441. return compute_dependencies(circularity);
  442. }
  443. return circ;
  444. }
  445. ////////////////////////////////////////////////////////////////////
  446. // Function: PPDependableFile::stat_file
  447. // Access: Private
  448. // Description: Performs a stat() on the file, if it has not already
  449. // been performed, to check whether the file exists and
  450. // to get its last-modification time.
  451. ////////////////////////////////////////////////////////////////////
  452. void PPDependableFile::
  453. stat_file() {
  454. if ((_flags & F_statted) != 0) {
  455. // Already done.
  456. return;
  457. }
  458. _flags |= F_statted;
  459. struct stat st;
  460. Filename pathname(get_fullpath());
  461. string ospath = pathname.to_os_specific();
  462. if (stat(ospath.c_str(), &st) < 0) {
  463. // The file doesn't exist!
  464. return;
  465. }
  466. #ifdef S_ISREG
  467. if (!S_ISREG(st.st_mode)) {
  468. // The file exists, but it's not a regular file--we consider that
  469. // not existing.
  470. return;
  471. }
  472. #endif // S_ISREG
  473. _flags |= F_exists;
  474. _mtime = st.st_mtime;
  475. }