ppDependableFile.cxx 18 KB

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