mirror of
https://github.com/Sneed-Group/Poodletooth-iLand
synced 2024-12-26 05:02:31 -06:00
421 lines
13 KiB
C++
421 lines
13 KiB
C++
// 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);
|
|
}
|