name = $name; $this->outputName = $output_name; $this->guid = $guid; $this->type = $type; $this->game_dir = $game_dir; $this->dir_list = array(); $this->defines = array(); $this->includes = array(); $this->libs = array(); $this->libsDebug = array(); $this->libsIgnore = array(); $this->lib_dirs = array(); $this->lib_includes = array(); $this->fileCopyPaths = array(); $this->outputs = array(); $this->dependencies = array(); $this->disabledWarnings = array(); $this->references = array(); } public function isApp() { return $this->type == self::$TYPE_APP; } public function isSharedApp() { return $this->type == self::$TYPE_SHARED_APP; } public function isLib() { return $this->type == self::$TYPE_LIB; } public function isSharedLib() { return $this->type == self::$TYPE_SHARED_LIB; } public function isCSProject() { return $this->type == self::$TYPE_CSPROJECT; } public function isActiveX() { return $this->type == self::$TYPE_ACTIVEX; } public function isSafari() { return $this->type == self::$TYPE_SAFARI; } public function setUniformOutputFile() { return $this->uniformOutputFile = 1; } public function setSubSystem( $subSystem ) { $this->projSubSystem = $subSystem; } public function validate() { // Sort the path list sort( $this->dir_list ); // Make sure we don't have any duplicate paths $this->dir_list = array_unique( $this->dir_list ); } public function addReference($refName, $version = "") { $this->references[$refName] = $version; } public function addIncludes( $includes ) { $this->includes = array_merge( $includes, $this->includes ); } public function validateDependencies() { $pguids = array(); foreach( $this->dependencies as $pname ) { $p = T3D_Generator::lookupProjectByName( $pname ); if( $p ) array_push( $pguids, $p->guid ); else trigger_error( "Project dependency not found: " .$pname, E_USER_ERROR ); } // todo: change to dependencyGuids $this->dependencies = $pguids; } private function generateXUID() { return sprintf( "%023X", Project::$xUID++ ); } private function createFileEntry( $output, $curPath, $curFile ) { // See if we need to reject it based on our rules.. if( $output->ruleReject( $curFile ) ) return null; // Get the extension - is it one of our allowed values? if( !$output->allowedFileExt( $curFile ) ) return null; // Cool - note in the list! $newEntry = new stdClass(); $newEntry->name = $curFile; $newEntry->path = FileUtil::collapsePath( $curPath . "/" . $curFile ); if ( !FileUtil::isAbsolutePath( $newEntry->path ) ) { // This could be consolidated into a single OR statement but it is easier to // read as two separate if's if ( !T3D_Generator::$absPath ) $newEntry->path = $output->project_rel_path . $newEntry->path; if ( T3D_Generator::$absPath && !stristr($newEntry->path, T3D_Generator::$absPath) ) $newEntry->path = $output->project_rel_path . $newEntry->path; } // Store a project-unique ID here for Xcode projects // It will be appended by a single char in the templates. $newEntry->hash = Project::generateXUID(); return $newEntry; } function generateFileList( &$projectFiles, $outputName, &$output ) { $projName = $this->name; $projectFiles[ $projName ] = array(); foreach( $this->dir_list as $dir ) { $dir = FileUtil::normalizeSlashes( $dir ); // Build the path. if ( FileUtil::isAbsolutePath( $dir ) ) $curPath = $dir; else $curPath = FileUtil::collapsePath( $output->base_dir . $dir ); $pathWalk = &$projectFiles[ $projName ]; if ( T3D_Generator::$absPath ) { if ( stristr($curPath, getEngineSrcDir()) || stristr($curPath, getLibSrcDir()) ) $curPath = T3D_Generator::$absPath . "/". str_replace("../", "", $curPath); } // Check if its a file or a directory. // If its a file just add it directly and build a containng filter/folder structure, // for it else if a dir add all files in it. if( is_file( $curPath ) ) { // Get the file name $curFile = basename( $curPath ); $curPath = dirname( $curPath ); //echo( "FILE: " . $curFile . " PATH: " . $curPath . "\n" ); } if( is_dir( $curPath ) ) { //echo( "DIR: " . $curPath . "\n" ); // Get the array we'll be adding things to... $pathParts = explode( '/', FileUtil::collapsePath( $dir ) ); foreach( $pathParts as $part ) { // Skip parts that are relative paths - only want meaningful directories. if( $part == '..' ) continue; if( !is_array( $pathWalk[ $part ] ) ) $pathWalk[ $part ] = array(); $pathWalk = &$pathWalk[ $part ]; } // Open directory. //echo( "SCANNING: " . $curPath . "\n"); $dirHdl = opendir( $curPath ); if( !$dirHdl ) { echo( "Path " . $curPath . " not found, giving up.\n" ); return false; } // Iterate over all the files in the path if not a single file spec. if( !$curFile ) { while( $curFile = readdir( $dirHdl ) ) { // Skip out if it's an uninteresting dir... if( $curFile == '.' || $curFile == '..' || $curFile == '.svn' || $curFile == 'CVS' ) continue; $newEntry = $this->createFileEntry( $output, $curPath, $curFile ); if( $newEntry ) $pathWalk[] = $newEntry; } } else { $newEntry = $this->createFileEntry( $output, $curPath, $curFile ); if( $newEntry ) $pathWalk = $newEntry; $curFile = ''; } // Clean up after ourselves! closedir( $dirHdl ); } } FileUtil::trimFileList( $projectFiles ); // Uncomment me to see the structure the file lister is returning. //print_r($projectFiles); return true; } private function setTemplateParams( $tpl, $output, &$projectFiles ) { // Set the template delimiters $tpl->left_delimiter = $output->ldelim ? $output->ldelim : '{'; $tpl->right_delimiter = $output->rdelim ? $output->rdelim : '}'; $gameProjectName = getGameProjectName(); // Evaluate template into a file. $tpl->assign_by_ref( 'projSettings', $this ); $tpl->assign_by_ref( 'projOutput', $output ); $tpl->assign_by_ref( 'fileArray', $projectFiles ); $tpl->assign_by_ref( 'projName', $this->name ); $tpl->assign_by_ref( 'projOutName', $this->outputName ); $tpl->assign_by_ref( 'gameFolder', $this->game_dir ); $tpl->assign_by_ref( 'GUID', $this->guid ); $tpl->assign_by_ref( 'projDefines', $this->defines ); $tpl->assign_by_ref( 'projDisabledWarnings', $this->disabledWarnings ); $tpl->assign_by_ref( 'projIncludes', $this->includes ); $tpl->assign_by_ref( 'projLibs', $this->libs ); $tpl->assign_by_ref( 'projLibsDebug',$this->libsDebug); $tpl->assign_by_ref( 'projLibsIgnore',$this->libsIgnore); $tpl->assign_by_ref( 'projLibDirs', $this->lib_dirs ); $tpl->assign_by_ref( 'projDepend', $this->dependencies ); $tpl->assign_by_ref( 'gameProjectName', $gameProjectName ); $tpl->assign_by_ref( 'projModuleDefinitionFile', $this->moduleDefinitionFile ); $tpl->assign_by_ref( 'projSubSystem', $this->projSubSystem ); if (T3D_Generator::$useDLLRuntime) { // /MD and /MDd $tpl->assign( 'projRuntimeRelease', 2 ); $tpl->assign( 'projRuntimeDebug', 3 ); } else { // /MT and /MTd $tpl->assign( 'projRuntimeRelease', 0 ); $tpl->assign( 'projRuntimeDebug', 1 ); } if (!$this->commandDebug && ( $this->isSharedLib() || $this->isSharedApp() )) { $command = "$(TargetDir)\\".$this->outputName; $tpl->assign( 'commandDebug' , $command."_DEBUG.exe"); $tpl->assign( 'commandRelease' , $command.".exe"); $tpl->assign( 'commandOptimized' , $command."_OPTIMIZEDDEBUG.exe"); } else { $tpl->assign_by_ref( 'commandDebug' , $this->commandDebug); $tpl->assign_by_ref( 'commandRelease' , $this->commandRelease); $tpl->assign_by_ref( 'commandOptimized' , $this->commandOptimized); } $tpl->assign_by_ref( 'argsDebug' , $this->argsDebug); $tpl->assign_by_ref( 'argsRelease' , $this->argsRelease); $tpl->assign_by_ref( 'argsOptimized' , $this->argsOptimized); $ptypes = array(); $projectDepends = array(); foreach ($this->dependencies as $pname) { $p = T3D_Generator::lookupProjectByName( $pname ); $projectDepends[$pname] = $p; if ( $p ) $ptypes[$pname] = $p->isSharedLib() || $p->isSafari(); } $tpl->assign_by_ref( 'projTypes', $ptypes ); $tpl->assign_by_ref( 'projectDepends', $projectDepends ); // Assign some handy paths for the template to reference $tpl->assign( 'projectOffset', $output->project_rel_path ); if ( T3D_Generator::$absPath ) $tpl->assign( 'srcDir', T3D_Generator::$absPath . "/". str_replace("../", "", getAppEngineSrcDir()) ); else $tpl->assign( 'srcDir', $output->project_rel_path . getAppEngineSrcDir() ); if ( T3D_Generator::$absPath ) $tpl->assign( 'libDir', T3D_Generator::$absPath . "/". str_replace("../", "", getAppLibSrcDir()) ); else $tpl->assign( 'libDir', $output->project_rel_path . getAppLibSrcDir() ); if ( T3D_Generator::$absPath ) $tpl->assign( 'binDir', T3D_Generator::$absPath . "/". str_replace("../", "", getAppEngineBinDir()) ); else $tpl->assign( 'binDir', $output->project_rel_path . getAppEngineBinDir() ); $tpl->assign( 'uniformOutputFile', $this->uniformOutputFile); } private function conditionDirectories( $output, &$projectFiles ) { foreach ($this->includes as &$include) { if ( !FileUtil::isAbsolutePath( $include ) ) $include = $output->project_rel_path . $include; } foreach ($this->lib_dirs as &$libDirs) { if ( !FileUtil::isAbsolutePath( $libDirs ) ) $libDirs = $output->project_rel_path . $libDirs; } if ( T3D_Generator::$absPath ) { foreach ($this->includes as &$include) { if ( stristr($include, getEngineSrcDir()) || stristr($include, getLibSrcDir()) ) $include = T3D_Generator::$absPath . "/". str_replace("../", "", $include); } foreach ($this->lib_dirs as &$libDirs) { if ( stristr($libDirs, getEngineSrcDir()) || stristr($libDirs, getLibSrcDir()) ) $libDirs = T3D_Generator::$absPath . "/". str_replace("../", "", $libDirs); } } } public function generate( $tpl, $platform, $base_dir ) { // Alright, for each project scan and generate the file list. $projectFiles = array (); $rootPhpBuildDir = getcwd(); // Iterate over this project's outputs. foreach( $this->outputs as $outputName => $output ) { $saved_includes = $this->includes; $saved_lib_dirs = $this->lib_dirs; //print_r( $output ); // Supported platform? if( !$output->supportsPlatform( $platform ) ) { //echo( " # Skipping output: '$outputName'.\n" ); continue; } // Get to the right working directory (first go back to root, then to relative) chdir( $base_dir ); //echo( " - Changing CWD to " . $output->output_dir . "\n" ); // echo(" (From: " . getcwd() . ")\n"); if( !FileUtil::prepareOutputDir( $output->output_dir ) ) continue; //echo( " - Scanning directory for output '.$outputName.'...\n" ); if( !$this->generateFileList( $projectFiles, $outputName, $output ) ) { echo( "File list generation failed. Giving up on this project.\n" ); continue; } // Do any special work on the include/lib directories that we need $this->conditionDirectories( $output, $projectFiles[ $this->name ] ); $this->projectFileExt = $output->output_ext; if ( $this->isCSProject() ) $this->projectFileExt = ".csproj"; // always csproj C# project under VS/MonoDevelop $outfile = $output->project_dir . $this->name . $this->projectFileExt; echo( " o Writing project file " . $outfile . "\n" ); $this->setTemplateParams( $tpl, $output, $projectFiles[ $this->name ] ); // To put a bandaid on the tools/player output dir problem // CodeReview: This should be in the template. -- BJG, 3/13/2007 // Moved into templates -- neo // Write file $outdir = dirname( $outfile ); if( !file_exists( $outdir ) ) mkdir_r( $outdir, 0777 ); if( $hdl = fopen( $outfile, 'w' ) ) { if ($this->isApp()) $template = $output->template_app; else if ($this->isLib()) $template = $output->template_lib; else if ($this->isSharedLib()) $template = $output->template_shared_lib; else if ($this->isSharedApp()) $template = $output->template_shared_app; else if ($this->isActiveX()) $template = $output->template_activex; else if ($this->isSafari()) $template = $output->template_activex; //rename template? else if ($this->isCSProject()) $template = $output->template_csproj; fputs( $hdl, $tpl->fetch( $template ) ); fclose( $hdl ); } else trigger_error( "Could not write output file: " . $output->outputFile, E_USER_ERROR ); if ($output->template_user) { $outfile = $output->project_dir . $this->name . $this->projectFileExt .'.'.getenv("COMPUTERNAME").'.'.getenv("USERNAME").'.user'; if( !file_exists( $outfile ) ) { if( $hdl = fopen( $outfile, 'w' ) ) { $template = $output->template_user; fputs( $hdl, $tpl->fetch( $template ) ); fclose( $hdl ); } else trigger_error( "Could not write output file: " . $outfile, E_USER_ERROR ); } } // Build the .filters file used by VS2010. if ( $output->template_filter ) { $filterData = new FilterData(); array_walk( $projectFiles[ $this->name ], array($filterData, 'callback'), '' ); $tpl->assign_by_ref('Folders', $filterData->folders); $tpl->assign_by_ref('SrcFiles', $filterData->srcFiles); $tpl->assign_by_ref('IncFiles', $filterData->incFiles); $tpl->assign_by_ref('OtherFiles', $filterData->otherFiles); $tpl->register_function( 'gen_uuid', 'gen_uuid' ); $outfile = $output->project_dir . $this->name . $this->projectFileExt . '.filters'; if ( $hdl = fopen( $outfile, 'w' ) ) { fputs( $hdl, $tpl->fetch( $output->template_filter ) ); fclose( $hdl ); } } $this->includes = $saved_includes; $this->lib_dirs = $saved_lib_dirs; } // Copy any files into the project foreach( $this->fileCopyPaths as $paths ) { $source = $paths[0]; $dest = $paths[1]; // We need forward slashes for paths. $source = str_replace( "\\", "/", $source); $dest = str_replace( "\\", "/", $dest); // Remove trailing slashes. $source = rtrim($source, " /"); $dest = rtrim($dest, " /"); // Remove any beginning slash from the destination $dest = ltrim($dest, " /"); // Build full destination path $fullDest = $base_dir . "/" . $dest; echo( " o Copying file " . $source . " to " . $fullDest . "\n" ); if(!copy($source, $fullDest)) { trigger_error( "\n*******************************************************************". "\n". "\n Unable to copy required file for project!". "\n". "Source file: " . $source . "\n" . "Destination file: " . $fullDest . "\n" . "\n". "\n*******************************************************************". "\n", E_USER_ERROR ); } } } } class FilterData { public $folders = array(); public $srcFiles = array(); public $incFiles = array(); public $otherFiles = array(); public function callback( $value, $key, $dir ) { if ( is_array( $value ) ) { if ( $dir != '' ) $dirpath = $dir . '\\' . $key; else $dirpath = $key; array_push( $this->folders, $dirpath ); array_walk( $value, array($this, 'callback'), $dirpath ); return; } $path = str_replace( '/', '\\', $value->path ); $ext = strrchr( $path, '.' ); if ( $ext == FALSE ) return; if ( strcasecmp( $ext, '.c' ) == 0 || strcasecmp( $ext, '.cpp' ) == 0 || strcasecmp( $ext, '.cc' ) == 0 ) $this->srcFiles[$path] = $dir; else if ( strcasecmp( $ext, '.h' ) == 0 || strcasecmp( $ext, '.hpp' ) == 0 || strcasecmp( $ext, '.inl' ) == 0 ) $this->incFiles[$path] = $dir; else $this->otherFiles[$path] = $dir; } } // class FilterData ?>