|
Pol
Revision:e09f183
|
00001 /* 00002 History 00003 ======= 00004 00005 Notes 00006 ======= 00007 00008 */ 00009 00010 #include "../clib/xmain.h" 00011 #include "../clib/Program/ProgramConfig.h" 00012 #include "../clib/clib.h" 00013 #include "../clib/dirlist.h" 00014 #include "../clib/fileutil.h" 00015 #include "../clib/logfacility.h" 00016 #include "../clib/mdump.h" 00017 #include "../clib/timer.h" 00018 00019 #include "../plib/pkg.h" 00020 #include "../plib/systemstate.h" 00021 00022 #include "../bscript/compilercfg.h" 00023 #include "../bscript/filefmt.h" 00024 #include "../bscript/userfunc.h" 00025 #include "../bscript/compiler.h" 00026 #include "../bscript/escriptv.h" 00027 #include "../bscript/executor.h" 00028 #include "../bscript/userfunc.h" 00029 00030 #include <cstring> 00031 #include <cstdio> 00032 #include <memory> 00033 #include <string> 00034 00035 #include <stdexcept> 00036 00037 #ifdef _MSC_VER 00038 #pragma warning(disable:4996) // deprecated POSIX getenv, strcpy warning 00039 #endif 00040 00041 namespace Pol { 00042 namespace Bscript { 00043 ExecInstrFunc Executor::GetInstrFunc( const Token& /*token*/ ) 00044 { 00045 return NULL; 00046 } 00047 } 00048 } 00049 00050 namespace Pol { 00051 namespace Ecompile { 00052 using namespace Bscript; 00053 #if REFPTR_DEBUG 00054 unsigned int ref_counted::_ctor_calls; 00055 #endif 00056 00057 int debug = 0; 00058 bool quiet = false; 00059 bool opt_generate_wordlist = false; 00060 bool keep_building = false; 00061 bool verbose = false; 00062 bool force_update = false; 00063 bool show_timing_details = false; 00064 bool timing_quiet_override = false; 00065 bool expect_compile_failure = false; 00066 bool dont_optimize_object_members = false; 00067 std::string EmPathEnv; // "ECOMPILE_PATH_EM=xxx" 00068 std::string IncPathEnv; // ECOMPILE_PATH_INC=yyy" 00069 std::string CfgPathEnv; // ECOMPILE_CFG_PATH=zzz" 00070 00071 struct Summary 00072 { 00073 unsigned UpToDateScripts; 00074 unsigned CompiledScripts; 00075 unsigned ScriptsWithCompileErrors; 00076 } summary; 00077 00078 void usage( void ) 00079 { 00080 ERROR_PRINT << " Usage:\n" 00081 << " " << "ECOMPILE [options] filespec [filespec ...]\n" 00082 << " Output is : filespec.ecl\n" 00083 << " Options: \n" 00084 << " -a compile *.asp pages also\n" 00085 << " -A automatically compile scripts in main and enabled packages\n" 00086 << " -Au (as '-A' but only compile updated files)\n" 00087 << " -b keep building other scripts after errors\n" 00088 << " -C cfgpath path to configuration (replaces ecompile.cfg)\n" 00089 << " -d display confusing compiler parse information\n" 00090 << " -D write dependency information\n" 00091 << " -e report error on successful compilation (used for testing)\n" 00092 #ifdef WIN32 00093 << " -Ecfgpath set or change the ECOMPILE_CFG_PATH Evironment Variable\n" 00094 #endif 00095 << " -i include intrusive debug info in .ecl file\n" 00096 << " -l generate listfile\n" 00097 << " -m don't optimize object members\n" 00098 #ifdef WIN32 00099 << " -Pdir set or change the EM and INC files Environment Variables\n" 00100 #endif 00101 << " -q quiet mode (suppress normal output)\n" 00102 << " -r [dir] recurse folder [from 'dir'] (defaults to current folder)\n" 00103 << " -ri [dir] (as '-r' but only compile .inc files)\n" 00104 << " -t[v] show timing/profiling information [override quiet mode]\n" 00105 << " -u compile only updated scripts (.src newer than .ecl)\n" 00106 << " -f force compile even if up-to-date\n" 00107 << " -s display summary if -q is not set\n" 00108 << " -T use threaded compilation\n" 00109 << " -vN verbosity level\n" 00110 << " -w display warnings\n" 00111 << " -W generate wordfile\n" 00112 << " -y treat warnings as errors\n" 00113 << " -x write external .dbg file\n" 00114 << " -xt write external .dbg.txt info file\n" 00115 << "\n" 00116 << " NOTE:\n" 00117 << " If <filespec> are required after an empty -r[i] option, you MUST specify\n" 00118 << " a literal [dir] of '.' (no quotes) or options will not parse correctly.\n"; 00119 if ( Clib::Logging::global_logger ) 00120 Clib::Logging::global_logger->wait_for_empty_queue(); 00121 } 00122 00123 void generate_wordlist() 00124 { 00125 INFO_PRINT << "Writing word list to wordlist.txt\n"; 00126 std::ofstream ofs("wordlist.txt", std::ios::out | std::ios::trunc); 00127 Parser::write_words( ofs ); 00128 } 00129 00130 void compile_inc( const char* path ) 00131 { 00132 if ( !quiet ) 00133 INFO_PRINT << "Compiling: " << path << "\n"; 00134 00135 Compiler C; 00136 00137 C.setQuiet( !debug ); 00138 C.setIncludeCompileMode(); 00139 int res = C.compileFile( path ); 00140 00141 if ( res ) 00142 throw std::runtime_error("Error compiling file"); 00143 } 00144 00145 bool compile_file( const char *path ) 00146 { 00147 std::string fname(path); 00148 std::string filename_src = fname, ext(""); 00149 00150 std::string::size_type pos = fname.rfind("."); 00151 if (pos != std::string::npos) 00152 ext = fname.substr( pos ); 00153 00154 if ( !ext.compare( ".inc" ) ) 00155 { 00156 compile_inc( path ); 00157 return true; 00158 } 00159 00160 if ( ext.compare( ".src" ) != 0 && 00161 ext.compare( ".hsr" ) != 0 && 00162 ext.compare( ".asp" ) != 0 ) 00163 { 00164 INFO_PRINT << "Didn't find '.src', '.hsr', or '.asp' extension on source filename '" 00165 << path << "'!\n"; 00166 throw std::runtime_error("Error in source filename"); 00167 } 00168 std::string filename_ecl = fname.replace(pos, 4, ".ecl"); 00169 std::string filename_lst = fname.replace(pos, 4, ".lst"); 00170 std::string filename_dep = fname.replace(pos, 4, ".dep"); 00171 std::string filename_dbg = fname.replace(pos, 4, ".dbg"); 00172 00173 if ( compilercfg.OnlyCompileUpdatedScripts && !force_update ) 00174 { 00175 bool all_old = true; 00176 unsigned int ecl_timestamp = Clib::GetFileTimestamp( filename_ecl.c_str() ); 00177 if ( Clib::GetFileTimestamp( filename_src.c_str( ) ) >= ecl_timestamp ) 00178 { 00179 if ( verbose ) 00180 INFO_PRINT << filename_src << " is newer than " << filename_ecl << "\n"; 00181 all_old = false; 00182 } 00183 00184 if ( all_old ) 00185 { 00186 std::ifstream ifs(filename_dep.c_str()); 00187 // if the file doesn't exist, gotta build. 00188 if ( ifs.is_open() ) 00189 { 00190 std::string depname; 00191 while ( getline( ifs, depname ) ) 00192 { 00193 if ( Clib::GetFileTimestamp( depname.c_str( ) ) >= ecl_timestamp ) 00194 { 00195 if ( verbose ) 00196 INFO_PRINT << depname << " is newer than " << filename_ecl << "\n"; 00197 all_old = false; 00198 break; 00199 } 00200 } 00201 } 00202 else 00203 { 00204 if ( verbose ) 00205 INFO_PRINT << filename_dep << " does not exist." << "\n"; 00206 all_old = false; 00207 } 00208 } 00209 if ( all_old ) 00210 { 00211 if ( !quiet && compilercfg.DisplayUpToDateScripts ) 00212 INFO_PRINT << filename_ecl << " is up-to-date." << "\n"; 00213 return false; 00214 } 00215 00216 } 00217 00218 { 00219 if ( !quiet ) 00220 INFO_PRINT << "Compiling: " << path << "\n"; 00221 00222 Compiler C; 00223 00224 C.setQuiet( !debug ); 00225 int res = C.compileFile( path ); 00226 00227 if ( expect_compile_failure ) 00228 { 00229 if ( res ) // good, it failed 00230 { 00231 if ( !quiet ) 00232 INFO_PRINT << "Compilation failed as expected." << "\n"; 00233 return true; 00234 } 00235 else 00236 { 00237 throw std::runtime_error("Compilation succeeded (-e indicates failure was expected)"); 00238 } 00239 } 00240 00241 if ( res ) 00242 throw std::runtime_error("Error compiling file"); 00243 00244 00245 00246 if ( !quiet ) 00247 INFO_PRINT << "Writing: " << filename_ecl << "\n"; 00248 00249 if ( C.write( filename_ecl.c_str() ) ) 00250 { 00251 throw std::runtime_error("Error writing output file"); 00252 } 00253 00254 if ( compilercfg.GenerateListing ) 00255 { 00256 if ( !quiet ) 00257 INFO_PRINT << "Writing: " << filename_lst << "\n"; 00258 std::ofstream ofs(filename_lst.c_str()); 00259 C.dump( ofs ); 00260 } 00261 else if ( Clib::FileExists( filename_lst.c_str( ) ) ) 00262 { 00263 if ( !quiet ) INFO_PRINT << "Deleting: " << filename_lst << "\n"; 00264 Clib::RemoveFile( filename_lst ); 00265 } 00266 00267 if ( compilercfg.GenerateDebugInfo ) 00268 { 00269 if ( !quiet ) 00270 { 00271 INFO_PRINT << "Writing: " << filename_dbg << "\n"; 00272 if ( compilercfg.GenerateDebugTextInfo ) 00273 INFO_PRINT << "Writing: " << filename_dbg << ".txt" << "\n"; 00274 } 00275 C.write_dbg( filename_dbg.c_str(), compilercfg.GenerateDebugTextInfo ); 00276 } 00277 else if ( Clib::FileExists( filename_dbg.c_str( ) ) ) 00278 { 00279 if ( !quiet ) INFO_PRINT << "Deleting: " << filename_dbg << "\n"; 00280 Clib::RemoveFile( filename_dbg ); 00281 } 00282 00283 if ( compilercfg.GenerateDependencyInfo ) 00284 { 00285 if ( !quiet ) 00286 INFO_PRINT << "Writing: " << filename_dep << "\n"; 00287 C.writeIncludedFilenames( filename_dep.c_str() ); 00288 } 00289 else if ( Clib::FileExists( filename_dep.c_str( ) ) ) 00290 { 00291 if ( !quiet ) INFO_PRINT << "Deleting: " << filename_dep << "\n"; 00292 Clib::RemoveFile( filename_dep ); 00293 } 00294 00295 } 00296 return true; 00297 } 00298 00299 void compile_file_wrapper( const char* path ) 00300 { 00301 try 00302 { 00303 if ( compile_file( path ) ) 00304 ++summary.CompiledScripts; 00305 else 00306 ++summary.UpToDateScripts; 00307 } 00308 catch ( std::exception& ) 00309 { 00310 ++summary.CompiledScripts; 00311 ++summary.ScriptsWithCompileErrors; 00312 if ( !keep_building ) 00313 throw; 00314 } 00315 } 00316 00317 bool setting_value( const char* arg ) 00318 { 00319 // format of arg is -C or -C- 00320 if ( arg[2] == '\0' ) 00321 return true; 00322 else if ( arg[2] == '-' ) 00323 return false; 00324 else if ( arg[2] == '+' ) 00325 return true; 00326 else 00327 return true; 00328 } 00329 00330 00331 int readargs( int argc, char **argv ) 00332 { 00333 bool unknown_opt = false; 00334 00335 for ( int i = 1; i < argc; i++ ) 00336 { 00337 const char* arg = argv[i]; 00338 #ifdef __linux__ 00339 if ( arg[0] == '-' ) 00340 #else 00341 if ( arg[0] == '/' || arg[0] == '-' ) 00342 #endif 00343 { 00344 switch ( arg[1] ) 00345 { 00346 case 'A': // skip it at this point. 00347 break; 00348 00349 case 'C': // skip it at this point. 00350 ++i; // and skip its parameter. 00351 break; 00352 00353 case 'd': 00354 debug = 1; 00355 break; 00356 00357 case 'D': 00358 compilercfg.GenerateDependencyInfo = setting_value( arg ); 00359 break; 00360 00361 case 'e': 00362 expect_compile_failure = true; 00363 break; 00364 00365 #ifdef WIN32 00366 case 'E': 00367 { 00368 std::string path = &argv[i][2]; 00369 CfgPathEnv = "ECOMPILE_CFG_PATH=" + path; 00370 _putenv( CfgPathEnv.c_str() ); 00371 } 00372 break; 00373 #endif 00374 00375 case 'q': 00376 quiet = true; 00377 break; 00378 00379 case 'w': 00380 compilercfg.DisplayWarnings = setting_value( arg ); 00381 if ( argv[i][2] == 'P' ) 00382 compilercfg.ParanoiaWarnings = true; 00383 break; 00384 case 'y': 00385 compilercfg.ErrorOnWarning = setting_value( arg ); 00386 break; 00387 00388 case 'l': 00389 compilercfg.GenerateListing = setting_value( arg ); 00390 break; 00391 00392 case 'i': 00393 include_debug = 1; 00394 break; 00395 00396 case 'r': // -r[i] [dir] is okay 00397 // Only suboption allowed is '-ri' (.inc recurse) 00398 if ( argv[i][2] && argv[i][2] != 'i' ) 00399 { 00400 // BZZZZT! *error* 00401 unknown_opt = true; 00402 break; 00403 } 00404 00405 // Only skip next parameter if it's not an option!! 00406 #ifdef __linux__ 00407 if ( i+1<argc && argv[i+1][0] != '-' ) 00408 #else 00409 if ( i + 1 < argc && argv[i + 1][0] != '/' && argv[i + 1][0] != '-' ) 00410 #endif 00411 ++i; 00412 break; 00413 00414 case 't': 00415 show_timing_details = true; 00416 if ( argv[i][2] == 'v' ) 00417 timing_quiet_override = true; 00418 break; 00419 00420 case 's': 00421 // show_source = true; 00422 compilercfg.DisplaySummary = true; 00423 break; 00424 00425 case 'W': 00426 opt_generate_wordlist = true; 00427 break; 00428 00429 case 'a': 00430 compilercfg.CompileAspPages = setting_value( arg ); 00431 break; 00432 00433 case 'm': 00434 compilercfg.OptimizeObjectMembers = false; 00435 break; 00436 00437 case 'b': 00438 keep_building = true; 00439 break; 00440 00441 case 'u': 00442 compilercfg.OnlyCompileUpdatedScripts = setting_value( arg ); 00443 if ( compilercfg.OnlyCompileUpdatedScripts ) 00444 compilercfg.GenerateDependencyInfo = true; 00445 break; 00446 00447 case 'f': 00448 force_update = true; 00449 break; 00450 00451 case 'v': 00452 verbose = true; 00453 int vlev; 00454 vlev = atoi( &argv[i][2] ); 00455 if ( !vlev ) 00456 vlev = 1; 00457 Compiler::setVerbosityLevel( vlev ); 00458 break; 00459 00460 case 'x': 00461 compilercfg.GenerateDebugInfo = setting_value( arg ); 00462 compilercfg.GenerateDebugTextInfo = ( argv[i][2] == 't' ); 00463 break; 00464 00465 #ifdef WIN32 00466 case 'P': 00467 { 00468 std::string path = &argv[i][2]; 00469 EmPathEnv = "ECOMPILE_PATH_EM=" + path; 00470 IncPathEnv = "ECOMPILE_PATH_INC=" + path; 00471 _putenv( EmPathEnv.c_str() ); 00472 _putenv( IncPathEnv.c_str() ); 00473 } 00474 break; 00475 #endif 00476 case 'T': 00477 compilercfg.ThreadedCompilation = true; 00478 break; 00479 00480 default: 00481 unknown_opt = true; 00482 break; 00483 } 00484 } 00485 00486 if ( unknown_opt ) 00487 { 00488 ERROR_PRINT << "Unknown option: " << argv[i] << "\n"; 00489 usage(); 00490 return 1; 00491 } 00492 } 00493 return 0; 00494 } 00495 00496 void recurse_compile(const std::string& basedir, std::vector<std::string>* files) 00497 { 00498 int s_compiled, s_uptodate, s_errors; 00499 clock_t start, finish; 00500 00501 if ( !Clib::IsDirectory( basedir.c_str( ) ) ) 00502 return; 00503 00504 s_compiled = s_uptodate = s_errors = 0; 00505 start = clock(); 00506 for ( Clib::DirList dl( basedir.c_str( ) ); !dl.at_end( ); dl.next( ) ) 00507 { 00508 std::string name = dl.name(), ext; 00509 if ( name[0] == '.' ) continue; 00510 00511 std::string::size_type pos = name.rfind("."); 00512 if (pos != std::string::npos) 00513 ext = name.substr( pos ); 00514 00515 try 00516 { 00517 if (pos != std::string::npos && 00518 ( !ext.compare( ".src" ) || 00519 !ext.compare( ".hsr" ) || 00520 ( compilercfg.CompileAspPages && !ext.compare( ".asp" ) ) ) ) 00521 { 00522 s_compiled++; 00523 if ( files == NULL ) 00524 { 00525 if ( compile_file( ( basedir + name ).c_str() ) ) 00526 { 00527 ++summary.CompiledScripts; 00528 } 00529 else 00530 { 00531 ++s_uptodate; 00532 ++summary.UpToDateScripts; 00533 } 00534 } 00535 else 00536 files->push_back( ( basedir + name ) ); 00537 } 00538 else 00539 { 00540 recurse_compile( basedir + name + "/", files ); 00541 } 00542 } 00543 catch ( std::exception& ) 00544 { 00545 ++summary.CompiledScripts; 00546 ++summary.ScriptsWithCompileErrors; 00547 if ( !keep_building ) 00548 throw; 00549 s_errors++; 00550 } 00551 } 00552 if ( files == NULL ) 00553 return; 00554 finish = clock(); 00555 00556 if ( ( !quiet || timing_quiet_override ) && show_timing_details && s_compiled > 0 && files == NULL ) 00557 { 00558 INFO_PRINT << "Compiled " << s_compiled << " script" << ( s_compiled == 1 ? "" : "s" ) 00559 << " in " << basedir 00560 << " in " << (int)( ( finish - start ) / CLOCKS_PER_SEC ) << " second(s)\n"; 00561 if ( s_uptodate > 0 ) 00562 INFO_PRINT << " " << s_uptodate << " script" << ( s_uptodate == 1 ? " was" : "s were" ) 00563 << " already up-to-date.\n"; 00564 if ( s_errors > 0 ) 00565 INFO_PRINT << " " << s_errors << " script" << ( s_errors == 1 ? "" : "s" ) 00566 << " had errors.\n"; 00567 } 00568 } 00569 void recurse_compile_inc(const std::string& basedir, std::vector<std::string>* files) 00570 { 00571 for ( Clib::DirList dl( basedir.c_str( ) ); !dl.at_end( ); dl.next( ) ) 00572 { 00573 std::string name = dl.name(), ext; 00574 if ( name[0] == '.' ) continue; 00575 00576 std::string::size_type pos = name.rfind("."); 00577 if (pos != std::string::npos) 00578 ext = name.substr( pos ); 00579 00580 if (pos != std::string::npos && !ext.compare(".inc")) 00581 { 00582 if ( files == NULL ) 00583 compile_file( ( basedir + name ).c_str() ); 00584 else 00585 files->push_back( ( basedir + name ) ); 00586 } 00587 else 00588 { 00589 recurse_compile( basedir + name + "/", files ); 00590 } 00591 } 00592 } 00593 00594 void parallel_compile(const std::vector<std::string> &files) 00595 { 00596 unsigned compiled_scripts = 0; 00597 unsigned uptodate_scripts = 0; 00598 unsigned error_scripts = 0; 00599 bool omp_keep_building = true; 00600 #pragma omp parallel for reduction(+ : compiled_scripts, uptodate_scripts, error_scripts) shared(omp_keep_building) 00601 for ( int i = 0; i < (int)files.size(); ++i ) 00602 { 00603 #pragma omp flush(omp_keep_building) 00604 if ( omp_keep_building ) 00605 { 00606 try 00607 { 00608 if ( compile_file( files[i].c_str() ) ) 00609 ++compiled_scripts; 00610 else 00611 ++uptodate_scripts; 00612 } 00613 catch ( std::exception& e ) 00614 { 00615 ++compiled_scripts; 00616 ++error_scripts; 00617 ERROR_PRINT << "failed to compile " << e.what() << "\n"; 00618 if ( !keep_building ) 00619 { 00620 #pragma omp critical(building_break) 00621 omp_keep_building = false; 00622 //Clib::force_backtrace(); 00623 } 00624 } 00625 catch ( ... ) 00626 { 00627 #pragma omp critical(building_break) 00628 omp_keep_building = false; 00629 Clib::force_backtrace( ); 00630 } 00631 00632 } 00633 } 00634 summary.CompiledScripts = compiled_scripts; 00635 summary.UpToDateScripts = uptodate_scripts; 00636 summary.ScriptsWithCompileErrors = error_scripts; 00637 } 00638 00639 void AutoCompile() 00640 { 00641 bool save = compilercfg.OnlyCompileUpdatedScripts; 00642 compilercfg.OnlyCompileUpdatedScripts = compilercfg.UpdateOnlyOnAutoCompile; 00643 if ( compilercfg.ThreadedCompilation ) 00644 { 00645 std::vector<std::string> files; 00646 recurse_compile( Clib::normalized_dir_form( compilercfg.PolScriptRoot ), &files ); 00647 for ( const auto &pkg : Plib::systemstate.packages ) 00648 { 00649 recurse_compile( Clib::normalized_dir_form( pkg->dir( ) ), &files ); 00650 } 00651 parallel_compile( files ); 00652 } 00653 else 00654 { 00655 recurse_compile( Clib::normalized_dir_form( compilercfg.PolScriptRoot ), NULL ); 00656 for ( const auto &pkg : Plib::systemstate.packages ) 00657 { 00658 recurse_compile( Clib::normalized_dir_form( pkg->dir() ), NULL ); 00659 } 00660 } 00661 compilercfg.OnlyCompileUpdatedScripts = save; 00662 } 00663 00664 bool run( int argc, char **argv ) 00665 { 00666 for ( const auto &elem : compilercfg.PackageRoot ) 00667 { 00668 Plib::load_packages( elem, true /* quiet */ ); 00669 } 00670 Plib::replace_packages(); 00671 Plib::check_package_deps(); 00672 00673 Tools::Timer<> timer; 00674 bool any = false; 00675 00676 for ( int i = 1; i < argc; i++ ) 00677 { 00678 #ifdef __linux__ 00679 if (argv[i][0] == '-') 00680 #else 00681 if ( argv[i][0] == '/' || argv[i][0] == '-' ) 00682 #endif 00683 { 00684 // -r[i] [<dir>] 00685 if ( argv[i][1] == 'A' ) 00686 { 00687 compilercfg.UpdateOnlyOnAutoCompile = ( argv[i][2] == 'u' ); 00688 any = true; 00689 00690 AutoCompile(); 00691 } 00692 else if ( argv[i][1] == 'r' ) 00693 { 00694 any = true; 00695 std::string dir("."); 00696 bool compile_inc = ( argv[i][2] == 'i' ); // compile .inc files 00697 00698 ++i; 00699 if ( i < argc && argv[i] && argv[i][0] != '-' ) 00700 dir.assign( argv[i] ); 00701 00702 if ( compilercfg.ThreadedCompilation ) 00703 { 00704 std::vector<std::string> files; 00705 if ( compile_inc ) 00706 recurse_compile_inc( Clib::normalized_dir_form( dir ), &files ); 00707 else 00708 recurse_compile( Clib::normalized_dir_form( dir ), &files ); 00709 parallel_compile( files ); 00710 } 00711 else 00712 { 00713 if ( compile_inc ) 00714 recurse_compile_inc( Clib::normalized_dir_form( dir ), NULL ); 00715 else 00716 recurse_compile( Clib::normalized_dir_form( dir ), NULL ); 00717 } 00718 } 00719 else if ( argv[i][1] == 'C' ) 00720 { 00721 ++i; // skip the config file pathname 00722 } 00723 // and skip any other option. 00724 } 00725 else 00726 { 00727 any = true; 00728 #ifdef _WIN32 00729 Clib::forspec( argv[i], compile_file_wrapper ); 00730 #else 00731 compile_file_wrapper( argv[i] ); 00732 #endif 00733 } 00734 } 00735 00736 if ( !any && compilercfg.AutoCompileByDefault ) 00737 { 00738 any = true; 00739 AutoCompile(); 00740 } 00741 00742 timer.stop(); 00743 00744 Plib::systemstate.deinitialize(); 00745 00746 if ( any && compilercfg.DisplaySummary && !quiet ) 00747 { 00748 fmt::Writer tmp; 00749 tmp << "Compilation Summary:\n"; 00750 if ( summary.CompiledScripts ) 00751 tmp << " Compiled " << summary.CompiledScripts << " script" << ( summary.CompiledScripts == 1 ? "" : "s" ) 00752 << " in " << timer.ellapsed() << " ms.\n"; 00753 00754 if ( summary.ScriptsWithCompileErrors ) 00755 tmp << " " << summary.ScriptsWithCompileErrors << " of those script" << ( summary.ScriptsWithCompileErrors == 1 ? "" : "s" ) 00756 << " had errors.\n"; 00757 00758 if ( summary.UpToDateScripts ) 00759 tmp << " " << summary.UpToDateScripts << " script" << ( summary.UpToDateScripts == 1 ? " was" : "s were" ) 00760 << " already up-to-date.\n"; 00761 INFO_PRINT << tmp.str(); 00762 } 00763 00764 return any; 00765 } 00766 00767 void read_config_file( int argc, char* argv[] ) 00768 { 00769 for ( int i = 1; i < argc; i++ ) 00770 { 00771 if ( argv[i][0] == '/' || argv[i][0] == '-' ) 00772 { 00773 // -C cfgpath 00774 if ( argv[i][1] == 'C' ) 00775 { 00776 ++i; 00777 if ( i == argc ) 00778 throw std::runtime_error("-C specified without pathname"); 00779 00780 compilercfg.Read(std::string(argv[i])); 00781 return; 00782 } 00783 } 00784 } 00785 00786 // check ECOMPILE_CFG_PATH environment variable 00787 const char* env_ecompile_cfg_path = getenv( "ECOMPILE_CFG_PATH" ); 00788 if ( env_ecompile_cfg_path != NULL ) 00789 { 00790 compilercfg.Read(std::string(env_ecompile_cfg_path)); 00791 return; 00792 } 00793 00794 // no -C arg, so use binary path (hope it's right..sigh.) 00795 std::string cfgpath = PROG_CONFIG::programDir() + "ecompile.cfg"; 00796 if ( Clib::FileExists( "ecompile.cfg" ) ) 00797 { 00798 compilercfg.Read( "ecompile.cfg" ); 00799 } 00800 else if ( Clib::FileExists( cfgpath ) ) 00801 { 00802 compilercfg.Read( cfgpath ); 00803 } 00804 else 00805 { 00806 ERROR_PRINT << "Could not find " << cfgpath << "; using defaults.\n"; 00807 compilercfg.SetDefaults(); 00808 } 00809 } 00810 } 00811 00812 00813 00814 int xmain( int argc, char *argv[] ) 00815 { 00816 int progver = 1; //TODO: use a better solution here 00817 00818 #ifdef _WIN32 00819 Clib::MiniDumper::Initialize(); 00820 #endif 00821 00822 Ecompile::read_config_file( argc, argv ); 00823 00824 int res = Ecompile::readargs( argc, argv ); 00825 if ( res ) 00826 return res; 00827 00828 if ( !Ecompile::quiet ) 00829 { 00830 // vX.YY 00831 double vernum = (double)progver + (double)( ESCRIPT_FILE_VER_CURRENT / 100.0f ); 00832 ERROR_PRINT << "EScript Compiler v" << vernum << "\n" 00833 << "Copyright (C) 1993-2015 Eric N. Swanson\n\n"; 00834 } 00835 00836 if ( Ecompile::opt_generate_wordlist ) 00837 { 00838 Ecompile::generate_wordlist( ); 00839 return 0; 00840 } 00841 00842 bool didanything = Ecompile::run( argc, argv ); 00843 00844 if ( !didanything ) 00845 { 00846 Ecompile::usage( ); 00847 return 1; 00848 } 00849 else 00850 { 00851 return 0; 00852 } 00853 } 00854 }