ppMain.cxx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. // Filename: ppMain.cxx
  2. // Created by: drose (28Sep00)
  3. //
  4. ////////////////////////////////////////////////////////////////////
  5. #include "ppMain.h"
  6. #include "ppScope.h"
  7. #include "ppCommandFile.h"
  8. #include "ppDirectory.h"
  9. #include "tokenize.h"
  10. #ifdef HAVE_UNISTD_H
  11. #include <unistd.h>
  12. #endif
  13. #include <assert.h>
  14. #include <errno.h>
  15. #include <stdio.h> // for perror
  16. #ifdef WIN32_VC
  17. #include <direct.h> // Windows requires this for getcwd()
  18. #define getcwd _getcwd
  19. #endif // WIN32_VC
  20. Filename PPMain::_root;
  21. ////////////////////////////////////////////////////////////////////
  22. // Function: PPMain::Constructor
  23. // Access: Public
  24. // Description:
  25. ////////////////////////////////////////////////////////////////////
  26. PPMain::
  27. PPMain(PPScope *global_scope) {
  28. _global_scope = global_scope;
  29. PPScope::push_scope(_global_scope);
  30. _def_scope = (PPScope *)NULL;
  31. _defs = (PPCommandFile *)NULL;
  32. // save current working directory name, so that "ppremake ." can map
  33. // to the current directory.
  34. Filename dirpath = get_cwd();
  35. _original_working_dir = dirpath.get_basename();
  36. }
  37. ////////////////////////////////////////////////////////////////////
  38. // Function: PPMain::Destructor
  39. // Access: Public
  40. // Description:
  41. ////////////////////////////////////////////////////////////////////
  42. PPMain::
  43. ~PPMain() {
  44. if (_def_scope != (PPScope *)NULL) {
  45. delete _def_scope;
  46. }
  47. if (_defs != (PPCommandFile *)NULL) {
  48. delete _defs;
  49. }
  50. }
  51. ////////////////////////////////////////////////////////////////////
  52. // Function: PPMain::read_source
  53. // Access: Public
  54. // Description: Reads the directory hierarchy of Sources.pp files, at
  55. // the indicated directory and below.
  56. ////////////////////////////////////////////////////////////////////
  57. bool PPMain::
  58. read_source(const string &root) {
  59. // First, find the top of the source tree, as indicated by the
  60. // presence of a Package.pp file.
  61. Filename trydir = root;
  62. Filename package_file(trydir, PACKAGE_FILENAME);
  63. bool any_source_files_found = false;
  64. while (!package_file.exists()) {
  65. // We continue to walk up directories as long as we see a source
  66. // file in each directory. When we stop seeing source files, we
  67. // stop walking upstairs.
  68. Filename source_file(trydir, SOURCE_FILENAME);
  69. if (!source_file.exists()) {
  70. if (!any_source_files_found) {
  71. // If we never saw a single Sources.pp file, complain about that.
  72. cerr << "Could not find ppremake source file " << SOURCE_FILENAME
  73. << ".\n\n"
  74. << "This file should be present at each level of the source directory tree;\n"
  75. << "it defines how each directory should be processed by ppremake.\n\n";
  76. } else {
  77. // If we found at least one Sources.pp file, but didn't find
  78. // the Package.pp file at the top of the tree, complain about
  79. // *that*.
  80. cerr << "Could not find ppremake package file " << PACKAGE_FILENAME
  81. << ".\n\n"
  82. << "This file should be present in the top of the source directory tree;\n"
  83. << "it defines implementation-specific variables to control the output\n"
  84. << "of ppremake, as well as pointing out the installed location of\n"
  85. << "important ppremake config files.\n\n";
  86. }
  87. return false;
  88. }
  89. any_source_files_found = true;
  90. trydir = Filename(trydir, "..");
  91. package_file = Filename(trydir, PACKAGE_FILENAME);
  92. }
  93. // Now cd to the source root and get the actual path.
  94. string osdir;
  95. #ifdef HAVE_CYGWIN
  96. osdir = trydir;
  97. #else
  98. osdir = trydir.to_os_specific();
  99. #endif
  100. if (chdir(osdir.c_str()) < 0) {
  101. perror("chdir");
  102. return false;
  103. }
  104. _root = get_cwd();
  105. _tree.set_fullpath(_root);
  106. cerr << "Root is " << _root << "\n";
  107. _def_scope = new PPScope(&_named_scopes);
  108. _def_scope->define_variable("PACKAGEFILE", package_file);
  109. _def_scope->define_variable("TOPDIR", _root);
  110. _def_scope->define_variable("DEPENDABLE_HEADER_DIRS", "");
  111. _defs = new PPCommandFile(_def_scope);
  112. if (!_defs->read_file(PACKAGE_FILENAME)) {
  113. return false;
  114. }
  115. // Now check the *_PLATFORM variables that System.pp was supposed to
  116. // set.
  117. if (!trim_blanks(_def_scope->expand_string("$[UNIX_PLATFORM]")).empty()) {
  118. unix_platform = true;
  119. }
  120. if (!trim_blanks(_def_scope->expand_string("$[WINDOWS_PLATFORM]")).empty()) {
  121. windows_platform = true;
  122. }
  123. PPScope::push_scope(_def_scope);
  124. if (!_tree.scan_source(&_named_scopes)) {
  125. return false;
  126. }
  127. _def_scope->define_variable("TREE", _tree.get_complete_tree());
  128. if (_tree.count_source_files() == 0) {
  129. cerr << "Could not find any source definition files named " << SOURCE_FILENAME
  130. << ".\n\n"
  131. << "A file by this name should be present in each directory of the source\n"
  132. << "hierarchy; it defines the source files and targets that should be\n"
  133. << "built in each directory, as well as the relationships between the\n"
  134. << "directories.\n\n";
  135. return false;
  136. }
  137. cerr << "Read " << _tree.count_source_files() << " " << SOURCE_FILENAME
  138. << " files.\n";
  139. if (!read_global_file()) {
  140. return false;
  141. }
  142. if (!_tree.scan_depends(&_named_scopes)) {
  143. return false;
  144. }
  145. string dependable_header_dirs =
  146. _def_scope->expand_variable("DEPENDABLE_HEADER_DIRS");
  147. string cache_filename =
  148. _def_scope->expand_variable("DEPENDENCY_CACHE_FILENAME");
  149. if (!_tree.scan_extra_depends(dependable_header_dirs, cache_filename)) {
  150. return false;
  151. }
  152. return true;
  153. }
  154. ////////////////////////////////////////////////////////////////////
  155. // Function: PPMain::process_all
  156. // Access: Public
  157. // Description: Does all the processing on all known directories.
  158. // See process().
  159. ////////////////////////////////////////////////////////////////////
  160. bool PPMain::
  161. process_all() {
  162. string cache_filename = _def_scope->expand_variable("DEPENDENCY_CACHE_FILENAME");
  163. if (cache_filename.empty()) {
  164. cerr << "Warning: no definition given for $[DEPENDENCY_CACHE_FILENAME].\n";
  165. } else {
  166. _tree.read_file_dependencies(cache_filename);
  167. }
  168. if (!r_process_all(_tree.get_root())) {
  169. return false;
  170. }
  171. if (!cache_filename.empty()) {
  172. _tree.update_file_dependencies(cache_filename);
  173. }
  174. return true;
  175. }
  176. ////////////////////////////////////////////////////////////////////
  177. // Function: PPMain::process
  178. // Access: Public
  179. // Description: Does the processing associated with the source file
  180. // in the indicated subdirectory name. This involves
  181. // reading in the template file and generating whatever
  182. // output the template file indicates.
  183. ////////////////////////////////////////////////////////////////////
  184. bool PPMain::
  185. process(string dirname) {
  186. string cache_filename = _def_scope->expand_variable("DEPENDENCY_CACHE_FILENAME");
  187. if (cache_filename.empty()) {
  188. cerr << "Warning: no definition given for $[DEPENDENCY_CACHE_FILENAME].\n";
  189. } else {
  190. _tree.read_file_dependencies(cache_filename);
  191. }
  192. if (dirname == ".") {
  193. dirname = _original_working_dir;
  194. }
  195. PPDirectory *dir = _tree.find_dirname(dirname);
  196. if (dir == (PPDirectory *)NULL) {
  197. cerr << "Unknown directory: " << dirname << "\n";
  198. return false;
  199. }
  200. if (dir->get_source() == (PPCommandFile *)NULL) {
  201. cerr << "No source file in " << dirname << "\n";
  202. return false;
  203. }
  204. if (!p_process(dir)) {
  205. return false;
  206. }
  207. if (!cache_filename.empty()) {
  208. _tree.update_file_dependencies(cache_filename);
  209. }
  210. return true;
  211. }
  212. ////////////////////////////////////////////////////////////////////
  213. // Function: PPMain::report_depends
  214. // Access: Public
  215. // Description: Reports all the directories that the named directory
  216. // depends on.
  217. ////////////////////////////////////////////////////////////////////
  218. void PPMain::
  219. report_depends(const string &dirname) const {
  220. PPDirectory *dir = _tree.find_dirname(dirname);
  221. if (dir == (PPDirectory *)NULL) {
  222. cerr << "Unknown directory: " << dirname << "\n";
  223. return;
  224. }
  225. dir->report_depends();
  226. }
  227. ////////////////////////////////////////////////////////////////////
  228. // Function: PPMain::report_reverse_depends
  229. // Access: Public
  230. // Description: Reports all the directories that depend on (need) the
  231. // named directory.
  232. ////////////////////////////////////////////////////////////////////
  233. void PPMain::
  234. report_reverse_depends(const string &dirname) const {
  235. PPDirectory *dir = _tree.find_dirname(dirname);
  236. if (dir == (PPDirectory *)NULL) {
  237. cerr << "Unknown directory: " << dirname << "\n";
  238. return;
  239. }
  240. dir->report_reverse_depends();
  241. }
  242. ////////////////////////////////////////////////////////////////////
  243. // Function: PPMain::get_root
  244. // Access: Public, Static
  245. // Description: Returns the full path to the root directory of the
  246. // source hierarchy; this is the directory in which the
  247. // runs most of the time.
  248. ////////////////////////////////////////////////////////////////////
  249. string PPMain::
  250. get_root() {
  251. return _root.get_fullpath();
  252. }
  253. ////////////////////////////////////////////////////////////////////
  254. // Function: PPMain::chdir_root
  255. // Access: Public, Static
  256. // Description: Changes the current directory to the root directory
  257. // of the source hierarchy. This should be executed
  258. // after a temporary change to another directory, to
  259. // restore the current directory to a known state.
  260. ////////////////////////////////////////////////////////////////////
  261. void PPMain::
  262. chdir_root() {
  263. if (chdir(_root.c_str()) < 0) {
  264. perror("chdir");
  265. // This is a real error! We can't get back to our starting
  266. // directory!
  267. cerr << "Error! Source directory is invalid!\n";
  268. exit(1);
  269. }
  270. }
  271. ////////////////////////////////////////////////////////////////////
  272. // Function: PPMain::r_process_all
  273. // Access: Private
  274. // Description: The recursive implementation of process_all().
  275. ////////////////////////////////////////////////////////////////////
  276. bool PPMain::
  277. r_process_all(PPDirectory *dir) {
  278. if (dir->get_source() != (PPCommandFile *)NULL) {
  279. if (!p_process(dir)) {
  280. return false;
  281. }
  282. }
  283. int num_children = dir->get_num_children();
  284. for (int i = 0; i < num_children; i++) {
  285. if (!r_process_all(dir->get_child(i))) {
  286. return false;
  287. }
  288. }
  289. return true;
  290. }
  291. ////////////////////////////////////////////////////////////////////
  292. // Function: PPMain::p_process
  293. // Access: Private
  294. // Description: The private implementation of process().
  295. ////////////////////////////////////////////////////////////////////
  296. bool PPMain::
  297. p_process(PPDirectory *dir) {
  298. current_output_directory = dir;
  299. _named_scopes.set_current(dir->get_dirname());
  300. PPCommandFile *source = dir->get_source();
  301. assert(source != (PPCommandFile *)NULL);
  302. PPScope *scope = source->get_scope();
  303. string template_filename = scope->expand_variable("TEMPLATE_FILE");
  304. if (template_filename.empty()) {
  305. cerr << "No definition given for $[TEMPLATE_FILE], cannot process.\n";
  306. return false;
  307. }
  308. PPCommandFile template_file(scope);
  309. if (!template_file.read_file(template_filename)) {
  310. cerr << "Error reading template file " << template_filename << ".\n";
  311. return false;
  312. }
  313. return true;
  314. }
  315. ////////////////////////////////////////////////////////////////////
  316. // Function: PPMain::read_global_file
  317. // Access: Private
  318. // Description: Reads in the Global.pp file after all sources files
  319. // have been read and sorted into dependency order.
  320. ////////////////////////////////////////////////////////////////////
  321. bool PPMain::
  322. read_global_file() {
  323. assert(_def_scope != (PPScope *)NULL);
  324. string global_filename = _def_scope->expand_variable("GLOBAL_FILE");
  325. if (global_filename.empty()) {
  326. cerr << "No definition given for $[GLOBAL_FILE], cannot process.\n";
  327. return false;
  328. }
  329. PPCommandFile global(_def_scope);
  330. if (!global.read_file(global_filename)) {
  331. cerr << "Error reading global definition file "
  332. << global_filename << ".\n";
  333. return false;
  334. }
  335. return true;
  336. }
  337. ////////////////////////////////////////////////////////////////////
  338. // Function: PPMain::get_cwd
  339. // Access: Private, Static
  340. // Description: Calls the system getcwd(), automatically allocating a
  341. // large enough string.
  342. ////////////////////////////////////////////////////////////////////
  343. Filename PPMain::
  344. get_cwd() {
  345. static size_t bufsize = 1024;
  346. static char *buffer = NULL;
  347. if (buffer == (char *)NULL) {
  348. buffer = new char[bufsize];
  349. }
  350. while (getcwd(buffer, bufsize) == (char *)NULL) {
  351. if (errno != ERANGE) {
  352. perror("getcwd");
  353. return string();
  354. }
  355. delete[] buffer;
  356. bufsize = bufsize * 2;
  357. buffer = new char[bufsize];
  358. assert(buffer != (char *)NULL);
  359. }
  360. return Filename::from_os_specific(buffer);
  361. }