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