Poodletooth-iLand/build/nirai/panda3d/ppremake/ppMain.cxx

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);
}