2015-11-14 11:40:25 +01:00
|
|
|
#include "ECompileMain.h"
|
|
|
|
|
|
2018-01-29 21:55:48 +01:00
|
|
|
#include <cstdio>
|
|
|
|
|
#include <exception>
|
2021-12-30 07:21:20 +01:00
|
|
|
#include <filesystem>
|
2018-01-29 21:55:48 +01:00
|
|
|
#include <iosfwd>
|
2020-08-05 20:28:07 +02:00
|
|
|
#include <memory>
|
2018-01-29 21:55:48 +01:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string>
|
2021-12-30 07:21:20 +01:00
|
|
|
#include <system_error>
|
2018-01-29 21:55:48 +01:00
|
|
|
#include <time.h>
|
|
|
|
|
|
2024-03-16 00:08:06 +01:00
|
|
|
#include "EfswFileWatchListener.h"
|
2015-11-14 11:40:25 +01:00
|
|
|
|
2021-12-30 07:21:20 +01:00
|
|
|
#include "bscript/compctx.h"
|
|
|
|
|
#include "bscript/compiler/Compiler.h"
|
|
|
|
|
#include "bscript/compiler/Profile.h"
|
|
|
|
|
#include "bscript/compiler/file/SourceFileCache.h"
|
|
|
|
|
#include "bscript/compilercfg.h"
|
|
|
|
|
#include "bscript/escriptv.h"
|
|
|
|
|
#include "bscript/executor.h"
|
|
|
|
|
#include "bscript/executortype.h"
|
|
|
|
|
#include "bscript/filefmt.h"
|
|
|
|
|
#include "clib/Program/ProgramConfig.h"
|
|
|
|
|
#include "clib/Program/ProgramMain.h"
|
|
|
|
|
#include "clib/esignal.h"
|
|
|
|
|
#include "clib/fileutil.h"
|
|
|
|
|
#include "clib/logfacility.h"
|
|
|
|
|
#include "clib/mdump.h"
|
|
|
|
|
#include "clib/passert.h"
|
|
|
|
|
#include "clib/threadhelp.h"
|
|
|
|
|
#include "clib/timer.h"
|
|
|
|
|
#include "plib/pkg.h"
|
|
|
|
|
#include "plib/systemstate.h"
|
|
|
|
|
|
2024-03-16 00:08:06 +01:00
|
|
|
#define VERBOSE_PRINTLN \
|
|
|
|
|
if ( compilercfg.VerbosityLevel > 0 ) \
|
|
|
|
|
INFO_PRINTLN
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
namespace Pol
|
|
|
|
|
{
|
|
|
|
|
namespace ECompile
|
|
|
|
|
{
|
2021-12-30 07:21:20 +01:00
|
|
|
namespace fs = std::filesystem;
|
2015-11-14 11:40:25 +01:00
|
|
|
using namespace Pol::Core;
|
|
|
|
|
using namespace Pol::Plib;
|
|
|
|
|
using namespace Pol::Bscript;
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2018-01-29 21:55:48 +01:00
|
|
|
ECompileMain::ECompileMain() : Pol::Clib::ProgramMain() {}
|
|
|
|
|
ECompileMain::~ECompileMain() {}
|
2015-11-14 11:40:25 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void ECompileMain::showHelp()
|
|
|
|
|
{
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN(
|
|
|
|
|
"Usage:\n"
|
|
|
|
|
" \n"
|
|
|
|
|
" ECOMPILE [options] filespec [filespec ...]\n"
|
|
|
|
|
" \n"
|
|
|
|
|
" Output is : filespec.ecl\n"
|
|
|
|
|
" Options:\n"
|
|
|
|
|
" Options: \n"
|
2024-02-26 21:21:44 +01:00
|
|
|
" -F format filespec (print result)\n"
|
|
|
|
|
" -Fi format filespec (inplace)\n"
|
2024-01-10 18:29:10 +01:00
|
|
|
" -a compile *.asp pages also\n"
|
|
|
|
|
" -A automatically compile scripts in main and enabled packages\n"
|
|
|
|
|
" -Au (as '-A' but only compile updated files)\n"
|
|
|
|
|
" -b keep building other scripts after errors\n"
|
|
|
|
|
" -c treat wrong capitalization in include directives as error\n"
|
|
|
|
|
" -C cfgpath path to configuration (replaces ecompile.cfg)\n"
|
|
|
|
|
" -d display confusing compiler parse information\n"
|
|
|
|
|
" -D write dependency information\n"
|
|
|
|
|
" -e report error on successful compilation (used for testing)\n"
|
2016-02-19 19:26:35 +01:00
|
|
|
#ifdef WIN32
|
2024-01-10 18:29:10 +01:00
|
|
|
" -Ecfgpath set or change the ECOMPILE_CFG_PATH evironment variable\n"
|
2016-02-19 19:26:35 +01:00
|
|
|
#endif
|
2020-08-04 22:42:46 -07:00
|
|
|
|
2024-01-10 18:29:10 +01:00
|
|
|
" -i include intrusive debug info in .ecl file\n"
|
|
|
|
|
" -l generate listfile\n"
|
|
|
|
|
" -m don't optimize object members\n"
|
2016-02-19 19:26:35 +01:00
|
|
|
#ifdef WIN32
|
2024-01-10 18:29:10 +01:00
|
|
|
" -Pdir set or change the EM and INC files Environment Variables\n"
|
2016-02-19 19:26:35 +01:00
|
|
|
#endif
|
2024-01-10 18:29:10 +01:00
|
|
|
" -q quiet mode (suppress normal output)\n"
|
|
|
|
|
" -r [dir] recurse folder [from 'dir'] (defaults to current folder)\n"
|
|
|
|
|
" -ri [dir] (as '-r' but only compile .inc files)\n"
|
|
|
|
|
" -t[v] show timing/profiling information [override quiet mode]\n"
|
|
|
|
|
" -u compile only updated scripts (.src newer than .ecl)\n"
|
|
|
|
|
" -f force compile even if up-to-date\n"
|
|
|
|
|
" -s display summary if -q is not set\n"
|
|
|
|
|
" -T[N] use threaded compilation, force N threads to run\n"
|
|
|
|
|
" -vN verbosity level\n"
|
|
|
|
|
" -w display warnings\n"
|
2024-03-16 00:08:06 +01:00
|
|
|
" -W watch mode\n"
|
2024-01-10 18:29:10 +01:00
|
|
|
" -y treat warnings as errors\n"
|
|
|
|
|
" -x write external .dbg file\n"
|
|
|
|
|
" -xt write external .dbg.txt info file\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" NOTE:\n"
|
|
|
|
|
" If <filespec> are required after an empty -r[i] option, you MUST specify\n"
|
|
|
|
|
" a literal [dir] of '.' (no quotes) or options will not parse correctly." );
|
2015-11-14 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
static int s_argc;
|
2016-02-19 19:26:35 +01:00
|
|
|
static char** s_argv;
|
2015-11-14 11:40:25 +01:00
|
|
|
|
|
|
|
|
int debug = 0;
|
|
|
|
|
bool quiet = false;
|
|
|
|
|
bool keep_building = false;
|
|
|
|
|
bool force_update = false;
|
2024-02-26 21:21:44 +01:00
|
|
|
bool format_source = false;
|
|
|
|
|
bool format_source_inplace = false;
|
2015-11-14 11:40:25 +01:00
|
|
|
bool show_timing_details = false;
|
|
|
|
|
bool timing_quiet_override = false;
|
|
|
|
|
bool expect_compile_failure = false;
|
|
|
|
|
bool dont_optimize_object_members = false;
|
2024-03-16 00:08:06 +01:00
|
|
|
bool watch_source = false;
|
2016-02-19 19:26:35 +01:00
|
|
|
std::string EmPathEnv; // "ECOMPILE_PATH_EM=xxx"
|
|
|
|
|
std::string IncPathEnv; // ECOMPILE_PATH_INC=yyy"
|
|
|
|
|
std::string CfgPathEnv; // ECOMPILE_CFG_PATH=zzz"
|
2015-11-14 11:40:25 +01:00
|
|
|
|
|
|
|
|
struct Summary
|
|
|
|
|
{
|
2018-04-29 14:44:50 +02:00
|
|
|
unsigned UpToDateScripts = 0;
|
|
|
|
|
unsigned CompiledScripts = 0;
|
|
|
|
|
unsigned ScriptsWithCompileErrors = 0;
|
|
|
|
|
size_t ThreadCount = 0;
|
2020-08-08 07:31:55 -07:00
|
|
|
Compiler::Profile profile;
|
2015-11-14 11:40:25 +01:00
|
|
|
} summary;
|
|
|
|
|
|
2020-08-05 00:01:07 -07:00
|
|
|
struct Comparison
|
|
|
|
|
{
|
2021-02-24 09:50:51 +01:00
|
|
|
std::atomic<long long> CompileTimeV1Micros{};
|
|
|
|
|
std::atomic<long long> CompileTimeV2Micros{};
|
|
|
|
|
std::atomic<long> MatchingResult{};
|
|
|
|
|
std::atomic<long> NonMatchingResult{};
|
|
|
|
|
std::atomic<long> MatchingOutput{};
|
|
|
|
|
std::atomic<long> NonMatchingOutput{};
|
2020-08-05 00:01:07 -07:00
|
|
|
} comparison;
|
|
|
|
|
|
2020-08-16 17:22:16 -07:00
|
|
|
Compiler::SourceFileCache em_parse_tree_cache( summary.profile );
|
|
|
|
|
Compiler::SourceFileCache inc_parse_tree_cache( summary.profile );
|
|
|
|
|
|
2024-03-16 00:08:06 +01:00
|
|
|
using DependencyInfo = std::map<fs::path, std::set<fs::path>>;
|
|
|
|
|
// Map owner (sources) -> dependencies
|
|
|
|
|
DependencyInfo owner_dependencies;
|
|
|
|
|
// Map dependency -> owners (sources)
|
|
|
|
|
DependencyInfo dependency_owners;
|
|
|
|
|
|
|
|
|
|
std::set<fs::path> compiled_dirs;
|
|
|
|
|
|
2021-03-04 17:39:14 +01:00
|
|
|
std::unique_ptr<Compiler::Compiler> create_compiler()
|
2020-09-13 00:41:45 -07:00
|
|
|
{
|
2021-03-04 17:39:14 +01:00
|
|
|
auto compiler = std::make_unique<Compiler::Compiler>( em_parse_tree_cache, inc_parse_tree_cache,
|
|
|
|
|
summary.profile );
|
2020-09-13 00:41:45 -07:00
|
|
|
return compiler;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-14 11:40:25 +01:00
|
|
|
void compile_inc( const char* path )
|
|
|
|
|
{
|
|
|
|
|
if ( !quiet )
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "Compiling: {}", path );
|
2015-11-14 11:40:25 +01:00
|
|
|
|
2021-03-04 17:39:14 +01:00
|
|
|
std::unique_ptr<Compiler::Compiler> compiler = create_compiler();
|
2015-11-14 11:40:25 +01:00
|
|
|
|
2020-09-13 00:41:45 -07:00
|
|
|
compiler->set_include_compile_mode();
|
|
|
|
|
bool res = compiler->compile_file( path );
|
2015-11-14 11:40:25 +01:00
|
|
|
|
2020-09-13 00:41:45 -07:00
|
|
|
if ( !res )
|
2016-02-19 19:26:35 +01:00
|
|
|
throw std::runtime_error( "Error compiling file" );
|
2015-11-14 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
2020-09-12 14:26:58 -07:00
|
|
|
std::vector<unsigned char> file_contents( const std::string& pathname, std::ios::openmode openmode )
|
|
|
|
|
{
|
|
|
|
|
std::ifstream ifs( pathname, openmode );
|
2021-02-24 09:50:51 +01:00
|
|
|
return std::vector<unsigned char>( std::istreambuf_iterator<char>( ifs ), {} );
|
2020-09-12 14:26:58 -07:00
|
|
|
}
|
|
|
|
|
|
2020-08-05 00:01:07 -07:00
|
|
|
std::vector<unsigned char> binary_contents( const std::string& pathname )
|
|
|
|
|
{
|
|
|
|
|
std::ifstream input1( pathname, std::ios::binary );
|
|
|
|
|
std::vector<unsigned char> buffer( std::istreambuf_iterator<char>( input1 ), {} );
|
|
|
|
|
return buffer;
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-24 09:50:51 +01:00
|
|
|
std::vector<std::string> instruction_filenames( const std::vector<unsigned>& ins_filenums,
|
|
|
|
|
const std::vector<std::string>& filenames )
|
2020-09-12 14:26:58 -07:00
|
|
|
{
|
|
|
|
|
std::vector<std::string> result;
|
|
|
|
|
result.reserve( ins_filenums.size() );
|
|
|
|
|
|
2021-02-24 09:50:51 +01:00
|
|
|
for ( auto& ins_filenum : ins_filenums )
|
2020-09-12 14:26:58 -07:00
|
|
|
{
|
2021-02-24 09:50:51 +01:00
|
|
|
result.push_back( filenames.at( ins_filenum ) );
|
2020-09-12 14:26:58 -07:00
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-26 21:21:44 +01:00
|
|
|
bool format_file( const char* path )
|
|
|
|
|
{
|
|
|
|
|
std::string fname( path );
|
|
|
|
|
std::string filename_src = fname, ext( "" );
|
|
|
|
|
|
|
|
|
|
std::string::size_type pos = fname.rfind( '.' );
|
|
|
|
|
if ( pos != std::string::npos )
|
|
|
|
|
ext = fname.substr( pos );
|
|
|
|
|
|
|
|
|
|
if ( ext.compare( ".src" ) != 0 && ext.compare( ".inc" ) != 0 && ext.compare( ".em" ) != 0 )
|
|
|
|
|
{
|
|
|
|
|
compiler_error( "Didn't find '.src', '.inc', or '.em' extension on source filename '{}'!",
|
|
|
|
|
path );
|
|
|
|
|
throw std::runtime_error( "Error in source filename" );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( !quiet )
|
|
|
|
|
INFO_PRINTLN( "Formatting: {}", path );
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<Compiler::Compiler> compiler = create_compiler();
|
|
|
|
|
|
|
|
|
|
bool success = compiler->format_file( path, ext.compare( ".em" ) == 0, format_source_inplace );
|
|
|
|
|
|
|
|
|
|
if ( expect_compile_failure )
|
|
|
|
|
{
|
|
|
|
|
if ( !success ) // good, it failed
|
|
|
|
|
{
|
|
|
|
|
if ( !quiet )
|
|
|
|
|
INFO_PRINTLN( "Formatting failed as expected." );
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
throw std::runtime_error( "Formatting succeeded (-e indicates failure was expected)" );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( !success )
|
|
|
|
|
throw std::runtime_error( "Error formatting file" );
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-16 00:08:06 +01:00
|
|
|
void add_dependency_info( const fs::path& filepath_src,
|
|
|
|
|
std::set<fs::path>* removed_dependencies = nullptr,
|
|
|
|
|
std::set<fs::path>* new_dependencies = nullptr )
|
|
|
|
|
{
|
|
|
|
|
auto filename_dep = fs::path( filepath_src ).replace_extension( ".dep" );
|
|
|
|
|
|
|
|
|
|
auto& dependencies = owner_dependencies[filepath_src];
|
|
|
|
|
auto previous_dependencies = dependencies;
|
|
|
|
|
|
|
|
|
|
VERBOSE_PRINTLN( "Dependencies for: {}", filepath_src );
|
|
|
|
|
for ( const auto& dependency : previous_dependencies )
|
|
|
|
|
{
|
|
|
|
|
if ( auto itr = dependency_owners.find( dependency ); itr != dependency_owners.end() )
|
|
|
|
|
{
|
|
|
|
|
// Remove deleted file from owners
|
|
|
|
|
itr->second.erase( filepath_src );
|
|
|
|
|
auto remaining = itr->second.size();
|
|
|
|
|
VERBOSE_PRINTLN( " - Removed {}, remaining owners={}", dependency, remaining );
|
|
|
|
|
if ( remaining == 0 )
|
|
|
|
|
{
|
|
|
|
|
dependency_owners.erase( itr );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dependencies.clear();
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
std::ifstream ifs( filename_dep.c_str() );
|
|
|
|
|
if ( ifs.is_open() )
|
|
|
|
|
{
|
|
|
|
|
std::string depname;
|
|
|
|
|
while ( getline( ifs, depname ) )
|
|
|
|
|
{
|
|
|
|
|
fs::path depnamepath = fs::canonical( fs::path( depname ) );
|
|
|
|
|
auto& owners = dependency_owners[depnamepath];
|
|
|
|
|
// Add this source as a dependency by:
|
|
|
|
|
// (1) placing `filename_src` in the set of owners for `depnamepath`.
|
|
|
|
|
owners.emplace( filepath_src );
|
|
|
|
|
// (2) placing `depnamepath` in the set of dependencies for this `filename_src`.
|
|
|
|
|
dependencies.emplace( depnamepath );
|
|
|
|
|
VERBOSE_PRINTLN( " - Added {}, owners={}", depnamepath, owners.size() );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Could not load dependency information -- maybe failed compilation? We
|
|
|
|
|
// still add this source as a dependency of itself, such that it will be
|
|
|
|
|
// recompiled on next save.
|
|
|
|
|
//
|
|
|
|
|
// On failed compilation, the existing `.dep`
|
|
|
|
|
// remains, so we will use that information for recompilation (eg. a source
|
|
|
|
|
// failed to compile due to a bad include, changing the include should still
|
|
|
|
|
// recompile the source.)
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
dependency_owners[filepath_src] = std::set<fs::path>{ filepath_src };
|
|
|
|
|
dependencies.emplace( filepath_src );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( removed_dependencies && new_dependencies )
|
|
|
|
|
{
|
|
|
|
|
std::set_difference( previous_dependencies.begin(), previous_dependencies.end(),
|
|
|
|
|
dependencies.begin(), dependencies.end(),
|
|
|
|
|
std::inserter( *removed_dependencies, removed_dependencies->begin() ) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::set_difference( dependencies.begin(), dependencies.end(), previous_dependencies.begin(),
|
|
|
|
|
previous_dependencies.end(),
|
|
|
|
|
std::inserter( *new_dependencies, new_dependencies->begin() ) );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-18 23:41:43 +01:00
|
|
|
/**
|
|
|
|
|
* Compiles the single given file (inc, src, hsr, asp), if needed
|
|
|
|
|
*
|
|
|
|
|
* Takes into account compilercfg.OnlyCompileUpdatedScripts and force_update
|
|
|
|
|
*
|
|
|
|
|
* @param path path of the file to be compiled
|
|
|
|
|
* @return TRUE if the file was compiled, FALSE otherwise (eg. the file is up-to-date)
|
|
|
|
|
*/
|
2016-02-19 19:26:35 +01:00
|
|
|
bool compile_file( const char* path )
|
2015-11-14 11:40:25 +01:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
std::string fname( path );
|
|
|
|
|
std::string filename_src = fname, ext( "" );
|
2015-11-14 11:40:25 +01:00
|
|
|
|
2016-12-15 13:34:06 +01:00
|
|
|
std::string::size_type pos = fname.rfind( '.' );
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( pos != std::string::npos )
|
|
|
|
|
ext = fname.substr( pos );
|
2015-11-14 11:40:25 +01:00
|
|
|
|
|
|
|
|
if ( !ext.compare( ".inc" ) )
|
|
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
compile_inc( path );
|
|
|
|
|
return true;
|
2015-11-14 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( ext.compare( ".src" ) != 0 && ext.compare( ".hsr" ) != 0 && ext.compare( ".asp" ) != 0 )
|
2015-11-14 11:40:25 +01:00
|
|
|
{
|
2024-01-12 06:51:44 +01:00
|
|
|
compiler_error( "Didn't find '.src', '.hsr', or '.asp' extension on source filename '{}'!",
|
|
|
|
|
path );
|
2016-02-19 19:26:35 +01:00
|
|
|
throw std::runtime_error( "Error in source filename" );
|
2015-11-14 11:40:25 +01:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
std::string filename_ecl = fname.replace( pos, 4, ".ecl" );
|
|
|
|
|
std::string filename_lst = fname.replace( pos, 4, ".lst" );
|
|
|
|
|
std::string filename_dep = fname.replace( pos, 4, ".dep" );
|
|
|
|
|
std::string filename_dbg = fname.replace( pos, 4, ".dbg" );
|
2015-11-14 11:40:25 +01:00
|
|
|
|
|
|
|
|
if ( compilercfg.OnlyCompileUpdatedScripts && !force_update )
|
|
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
bool all_old = true;
|
|
|
|
|
unsigned int ecl_timestamp = Clib::GetFileTimestamp( filename_ecl.c_str() );
|
|
|
|
|
if ( Clib::GetFileTimestamp( filename_src.c_str() ) >= ecl_timestamp )
|
|
|
|
|
{
|
2020-08-03 04:17:31 -07:00
|
|
|
if ( compilercfg.VerbosityLevel > 0 )
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "{} is newer than {}", filename_src, filename_ecl );
|
2016-02-19 19:26:35 +01:00
|
|
|
all_old = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( all_old )
|
|
|
|
|
{
|
|
|
|
|
std::ifstream ifs( filename_dep.c_str() );
|
|
|
|
|
// if the file doesn't exist, gotta build.
|
|
|
|
|
if ( ifs.is_open() )
|
|
|
|
|
{
|
2015-11-14 11:40:25 +01:00
|
|
|
std::string depname;
|
2016-02-19 19:26:35 +01:00
|
|
|
while ( getline( ifs, depname ) )
|
|
|
|
|
{
|
|
|
|
|
if ( Clib::GetFileTimestamp( depname.c_str() ) >= ecl_timestamp )
|
|
|
|
|
{
|
2020-08-03 04:17:31 -07:00
|
|
|
if ( compilercfg.VerbosityLevel > 0 )
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "{} is newer than {}", depname, filename_ecl );
|
2016-02-19 19:26:35 +01:00
|
|
|
all_old = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-08-03 04:17:31 -07:00
|
|
|
if ( compilercfg.VerbosityLevel > 0 )
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "{} does not exist.", filename_dep );
|
2016-02-19 19:26:35 +01:00
|
|
|
all_old = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ( all_old )
|
|
|
|
|
{
|
|
|
|
|
if ( !quiet && compilercfg.DisplayUpToDateScripts )
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "{} is up-to-date.", filename_ecl );
|
2016-02-19 19:26:35 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
2015-11-14 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
2020-08-05 00:01:07 -07:00
|
|
|
|
2015-11-14 11:40:25 +01:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( !quiet )
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "Compiling: {}", path );
|
2015-11-14 11:40:25 +01:00
|
|
|
|
2021-03-04 17:39:14 +01:00
|
|
|
std::unique_ptr<Compiler::Compiler> compiler = create_compiler();
|
2020-08-03 23:11:03 -07:00
|
|
|
|
2020-08-04 22:42:46 -07:00
|
|
|
bool success = compiler->compile_file( path );
|
2015-11-14 11:40:25 +01:00
|
|
|
|
2020-08-16 17:22:16 -07:00
|
|
|
em_parse_tree_cache.keep_some();
|
|
|
|
|
inc_parse_tree_cache.keep_some();
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( expect_compile_failure )
|
|
|
|
|
{
|
2020-08-03 23:11:03 -07:00
|
|
|
if ( !success ) // good, it failed
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
if ( !quiet )
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "Compilation failed as expected." );
|
2016-02-19 19:26:35 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
throw std::runtime_error( "Compilation succeeded (-e indicates failure was expected)" );
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-11-14 11:40:25 +01:00
|
|
|
|
2020-08-03 23:11:03 -07:00
|
|
|
if ( !success )
|
2016-02-19 19:26:35 +01:00
|
|
|
throw std::runtime_error( "Error compiling file" );
|
2015-11-14 11:40:25 +01:00
|
|
|
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( !quiet )
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "Writing: {}", filename_ecl );
|
2015-11-14 11:40:25 +01:00
|
|
|
|
2020-08-04 22:42:46 -07:00
|
|
|
if ( !compiler->write_ecl( filename_ecl ) )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
throw std::runtime_error( "Error writing output file" );
|
|
|
|
|
}
|
2015-11-14 11:40:25 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( compilercfg.GenerateListing )
|
|
|
|
|
{
|
|
|
|
|
if ( !quiet )
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "Writing: {}", filename_lst );
|
2020-08-04 22:42:46 -07:00
|
|
|
compiler->write_listing( filename_lst );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
else if ( Clib::FileExists( filename_lst.c_str() ) )
|
|
|
|
|
{
|
|
|
|
|
if ( !quiet )
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "Deleting: {}", filename_lst );
|
2015-11-14 11:40:25 +01:00
|
|
|
Clib::RemoveFile( filename_lst );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2015-11-14 11:40:25 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( compilercfg.GenerateDebugInfo )
|
|
|
|
|
{
|
|
|
|
|
if ( !quiet )
|
|
|
|
|
{
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "Writing: {}", filename_dbg );
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( compilercfg.GenerateDebugTextInfo )
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "Writing: {}.txt", filename_dbg );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2020-08-04 22:42:46 -07:00
|
|
|
compiler->write_dbg( filename_dbg, compilercfg.GenerateDebugTextInfo );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
else if ( Clib::FileExists( filename_dbg.c_str() ) )
|
|
|
|
|
{
|
|
|
|
|
if ( !quiet )
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "Deleting: {}", filename_dbg );
|
2015-11-14 11:40:25 +01:00
|
|
|
Clib::RemoveFile( filename_dbg );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2015-11-14 11:40:25 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( compilercfg.GenerateDependencyInfo )
|
|
|
|
|
{
|
|
|
|
|
if ( !quiet )
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "Writing: {}", filename_dep );
|
2020-08-04 22:42:46 -07:00
|
|
|
compiler->write_included_filenames( filename_dep );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
else if ( Clib::FileExists( filename_dep.c_str() ) )
|
|
|
|
|
{
|
|
|
|
|
if ( !quiet )
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "Deleting: {}", filename_dep );
|
2015-11-14 11:40:25 +01:00
|
|
|
Clib::RemoveFile( filename_dep );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2015-11-14 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-26 21:21:44 +01:00
|
|
|
bool process_file( const char* path )
|
|
|
|
|
{
|
|
|
|
|
if ( format_source )
|
|
|
|
|
{
|
|
|
|
|
return format_file( path );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return compile_file( path );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-16 00:08:06 +01:00
|
|
|
void process_file_wrapper( const char* path, std::set<fs::path>* removed_dependencies = nullptr,
|
|
|
|
|
std::set<fs::path>* new_dependencies = nullptr )
|
2015-11-14 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2024-02-26 21:21:44 +01:00
|
|
|
if ( process_file( path ) )
|
2016-02-19 19:26:35 +01:00
|
|
|
++summary.CompiledScripts;
|
|
|
|
|
else
|
|
|
|
|
++summary.UpToDateScripts;
|
2015-11-14 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
catch ( std::exception& )
|
|
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
++summary.CompiledScripts;
|
|
|
|
|
++summary.ScriptsWithCompileErrors;
|
|
|
|
|
if ( !keep_building )
|
|
|
|
|
throw;
|
2015-11-14 11:40:25 +01:00
|
|
|
}
|
2024-03-16 00:08:06 +01:00
|
|
|
|
|
|
|
|
if ( watch_source )
|
|
|
|
|
{
|
|
|
|
|
fs::path filepath = fs::canonical( fs::path( path ) );
|
|
|
|
|
auto ext = filepath.extension().generic_string();
|
|
|
|
|
if ( ext.compare( ".src" ) == 0 || ext.compare( ".hsr" ) == 0 || ext.compare( ".asp" ) == 0 )
|
|
|
|
|
{
|
|
|
|
|
add_dependency_info( filepath, removed_dependencies, new_dependencies );
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-11-14 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool setting_value( const char* arg )
|
|
|
|
|
{
|
|
|
|
|
// format of arg is -C or -C-
|
|
|
|
|
if ( arg[2] == '\0' )
|
2016-02-19 19:26:35 +01:00
|
|
|
return true;
|
2015-11-14 11:40:25 +01:00
|
|
|
else if ( arg[2] == '-' )
|
2016-02-19 19:26:35 +01:00
|
|
|
return false;
|
2015-11-14 11:40:25 +01:00
|
|
|
else if ( arg[2] == '+' )
|
2016-02-19 19:26:35 +01:00
|
|
|
return true;
|
2015-11-14 11:40:25 +01:00
|
|
|
else
|
2016-02-19 19:26:35 +01:00
|
|
|
return true;
|
2015-11-14 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
int readargs( int argc, char** argv )
|
2015-11-14 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
bool unknown_opt = false;
|
|
|
|
|
|
|
|
|
|
for ( int i = 1; i < argc; i++ )
|
|
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
const char* arg = argv[i];
|
2015-11-14 11:40:25 +01:00
|
|
|
#ifdef __linux__
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( arg[0] == '-' )
|
2015-11-14 11:40:25 +01:00
|
|
|
#else
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( arg[0] == '/' || arg[0] == '-' )
|
2015-11-14 11:40:25 +01:00
|
|
|
#endif
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
switch ( arg[1] )
|
|
|
|
|
{
|
2024-03-16 00:08:06 +01:00
|
|
|
case 'W':
|
|
|
|
|
watch_source = true;
|
|
|
|
|
compilercfg.GenerateDependencyInfo = true;
|
|
|
|
|
keep_building = true;
|
|
|
|
|
compilercfg.ThreadedCompilation =
|
|
|
|
|
false; // limitation since dependency gathering is not thread-safe
|
|
|
|
|
break;
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
case 'A': // skip it at this point.
|
|
|
|
|
break;
|
2015-11-14 11:40:25 +01:00
|
|
|
|
2019-10-07 21:01:26 +02:00
|
|
|
case 'c':
|
|
|
|
|
compilercfg.ErrorOnFileCaseMissmatch = setting_value( arg );
|
|
|
|
|
break;
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
case 'C': // skip it at this point.
|
|
|
|
|
++i; // and skip its parameter.
|
|
|
|
|
break;
|
2015-11-14 11:40:25 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
case 'd':
|
|
|
|
|
debug = 1;
|
|
|
|
|
break;
|
2015-11-14 11:40:25 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
case 'D':
|
|
|
|
|
compilercfg.GenerateDependencyInfo = setting_value( arg );
|
|
|
|
|
break;
|
2015-11-14 11:40:25 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
case 'e':
|
|
|
|
|
expect_compile_failure = true;
|
|
|
|
|
break;
|
2015-11-14 11:40:25 +01:00
|
|
|
|
|
|
|
|
#ifdef WIN32
|
2016-02-19 19:26:35 +01:00
|
|
|
case 'E':
|
|
|
|
|
{
|
|
|
|
|
std::string path = &argv[i][2];
|
|
|
|
|
CfgPathEnv = "ECOMPILE_CFG_PATH=" + path;
|
|
|
|
|
_putenv( CfgPathEnv.c_str() );
|
|
|
|
|
}
|
|
|
|
|
break;
|
2015-11-14 11:40:25 +01:00
|
|
|
#endif
|
|
|
|
|
|
2020-08-04 22:42:46 -07:00
|
|
|
case 'g':
|
2021-03-04 17:39:14 +01:00
|
|
|
{
|
|
|
|
|
auto value = setting_value( arg );
|
|
|
|
|
if ( !value )
|
|
|
|
|
{
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "The OG Compiler has been removed." );
|
2021-03-04 17:39:14 +01:00
|
|
|
unknown_opt = true;
|
|
|
|
|
}
|
2020-08-05 00:01:07 -07:00
|
|
|
break;
|
2021-03-04 17:39:14 +01:00
|
|
|
}
|
2020-08-04 22:42:46 -07:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
case 'q':
|
|
|
|
|
quiet = true;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'w':
|
|
|
|
|
compilercfg.DisplayWarnings = setting_value( arg );
|
|
|
|
|
if ( argv[i][2] == 'P' )
|
|
|
|
|
compilercfg.ParanoiaWarnings = true;
|
|
|
|
|
break;
|
|
|
|
|
case 'y':
|
|
|
|
|
compilercfg.ErrorOnWarning = setting_value( arg );
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'l':
|
|
|
|
|
compilercfg.GenerateListing = setting_value( arg );
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'i':
|
|
|
|
|
include_debug = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'r': // -r[i] [dir] is okay
|
|
|
|
|
// Only suboption allowed is '-ri' (.inc recurse)
|
|
|
|
|
if ( argv[i][2] && argv[i][2] != 'i' )
|
|
|
|
|
{
|
|
|
|
|
// BZZZZT! *error*
|
|
|
|
|
unknown_opt = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Only skip next parameter if it's not an option!!
|
2015-11-14 11:40:25 +01:00
|
|
|
#ifdef __linux__
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( i + 1 < argc && argv[i + 1][0] != '-' )
|
2015-11-14 11:40:25 +01:00
|
|
|
#else
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( i + 1 < argc && argv[i + 1][0] != '/' && argv[i + 1][0] != '-' )
|
2015-11-14 11:40:25 +01:00
|
|
|
#endif
|
2016-02-19 19:26:35 +01:00
|
|
|
++i;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 't':
|
|
|
|
|
show_timing_details = true;
|
|
|
|
|
if ( argv[i][2] == 'v' )
|
|
|
|
|
timing_quiet_override = true;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 's':
|
|
|
|
|
// show_source = true;
|
|
|
|
|
compilercfg.DisplaySummary = true;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'a':
|
|
|
|
|
compilercfg.CompileAspPages = setting_value( arg );
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'm':
|
|
|
|
|
compilercfg.OptimizeObjectMembers = false;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'b':
|
|
|
|
|
keep_building = true;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'u':
|
|
|
|
|
compilercfg.OnlyCompileUpdatedScripts = setting_value( arg );
|
|
|
|
|
if ( compilercfg.OnlyCompileUpdatedScripts )
|
|
|
|
|
compilercfg.GenerateDependencyInfo = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2024-02-26 21:21:44 +01:00
|
|
|
case 'F':
|
|
|
|
|
{
|
|
|
|
|
if ( argv[i][2] && argv[i][2] == 'i' )
|
|
|
|
|
format_source_inplace = true;
|
|
|
|
|
format_source = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
case 'f':
|
|
|
|
|
force_update = true;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'v':
|
|
|
|
|
int vlev;
|
|
|
|
|
vlev = atoi( &argv[i][2] );
|
|
|
|
|
if ( !vlev )
|
|
|
|
|
vlev = 1;
|
2020-07-28 22:12:12 -07:00
|
|
|
compilercfg.VerbosityLevel = vlev;
|
2016-02-19 19:26:35 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'x':
|
|
|
|
|
compilercfg.GenerateDebugInfo = setting_value( arg );
|
|
|
|
|
compilercfg.GenerateDebugTextInfo = ( argv[i][2] == 't' );
|
|
|
|
|
break;
|
2015-11-14 11:40:25 +01:00
|
|
|
|
|
|
|
|
#ifdef WIN32
|
2016-02-19 19:26:35 +01:00
|
|
|
case 'P':
|
|
|
|
|
{
|
|
|
|
|
std::string path = &argv[i][2];
|
|
|
|
|
EmPathEnv = "ECOMPILE_PATH_EM=" + path;
|
|
|
|
|
IncPathEnv = "ECOMPILE_PATH_INC=" + path;
|
|
|
|
|
_putenv( EmPathEnv.c_str() );
|
|
|
|
|
_putenv( IncPathEnv.c_str() );
|
|
|
|
|
}
|
|
|
|
|
break;
|
2015-11-14 11:40:25 +01:00
|
|
|
#endif
|
2016-02-19 19:26:35 +01:00
|
|
|
case 'T':
|
2018-07-29 15:51:58 +02:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
compilercfg.ThreadedCompilation = true;
|
2018-07-29 15:51:58 +02:00
|
|
|
int count = atoi( &argv[i][2] );
|
|
|
|
|
compilercfg.NumberOfThreads = count;
|
2016-02-19 19:26:35 +01:00
|
|
|
break;
|
2018-07-29 15:51:58 +02:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
default:
|
|
|
|
|
unknown_opt = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( unknown_opt )
|
|
|
|
|
{
|
2024-01-12 06:51:44 +01:00
|
|
|
ERROR_PRINTLN( "Unknown option: {}", argv[i] );
|
2016-02-19 19:26:35 +01:00
|
|
|
return 1;
|
|
|
|
|
}
|
2015-11-14 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-16 17:22:16 -07:00
|
|
|
void apply_configuration()
|
|
|
|
|
{
|
|
|
|
|
em_parse_tree_cache.configure( compilercfg.EmParseTreeCacheSize );
|
|
|
|
|
inc_parse_tree_cache.configure( compilercfg.IncParseTreeCacheSize );
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-30 07:21:20 +01:00
|
|
|
void recurse_collect( const fs::path& basedir, std::set<std::string>* files, bool inc_files )
|
2015-11-14 11:40:25 +01:00
|
|
|
{
|
2021-12-30 07:21:20 +01:00
|
|
|
if ( !fs::is_directory( basedir ) )
|
2016-02-19 19:26:35 +01:00
|
|
|
return;
|
2021-12-30 07:21:20 +01:00
|
|
|
std::error_code ec;
|
|
|
|
|
for ( auto dir_itr = fs::recursive_directory_iterator( basedir, ec );
|
|
|
|
|
dir_itr != fs::recursive_directory_iterator(); ++dir_itr )
|
2015-11-14 11:40:25 +01:00
|
|
|
{
|
2021-12-30 07:21:20 +01:00
|
|
|
if ( auto fn = dir_itr->path().filename().u8string(); !fn.empty() && *fn.begin() == '.' )
|
|
|
|
|
{
|
|
|
|
|
if ( dir_itr->is_directory() )
|
|
|
|
|
dir_itr.disable_recursion_pending();
|
2016-02-19 19:26:35 +01:00
|
|
|
continue;
|
2021-12-30 07:21:20 +01:00
|
|
|
}
|
|
|
|
|
else if ( !dir_itr->is_regular_file() )
|
|
|
|
|
continue;
|
|
|
|
|
const auto ext = dir_itr->path().extension();
|
|
|
|
|
if ( inc_files )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
2021-12-30 07:21:20 +01:00
|
|
|
if ( !ext.compare( ".inc" ) )
|
|
|
|
|
files->insert( dir_itr->path().u8string() );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2021-12-30 07:21:20 +01:00
|
|
|
else if ( !ext.compare( ".src" ) || !ext.compare( ".hsr" ) ||
|
|
|
|
|
( compilercfg.CompileAspPages && !ext.compare( ".asp" ) ) )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
2021-12-30 07:21:20 +01:00
|
|
|
files->insert( dir_itr->path().u8string() );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2015-11-14 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
2021-12-30 07:21:20 +01:00
|
|
|
|
2024-02-26 21:21:44 +01:00
|
|
|
void serial_process( const std::set<std::string>& files )
|
2015-11-14 11:40:25 +01:00
|
|
|
{
|
2021-12-30 07:21:20 +01:00
|
|
|
for ( const auto& file : files )
|
2015-11-14 11:40:25 +01:00
|
|
|
{
|
2018-04-29 14:44:50 +02:00
|
|
|
if ( Clib::exit_signalled )
|
|
|
|
|
return;
|
2024-02-26 21:21:44 +01:00
|
|
|
process_file_wrapper( file.c_str() );
|
2015-11-14 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-26 21:21:44 +01:00
|
|
|
void parallel_process( const std::set<std::string>& files )
|
2015-11-14 11:40:25 +01:00
|
|
|
{
|
2018-04-29 14:44:50 +02:00
|
|
|
std::atomic<unsigned> compiled_scripts( 0 );
|
|
|
|
|
std::atomic<unsigned> uptodate_scripts( 0 );
|
|
|
|
|
std::atomic<unsigned> error_scripts( 0 );
|
|
|
|
|
std::atomic<bool> par_keep_building( true );
|
2015-11-14 11:40:25 +01:00
|
|
|
{
|
2018-04-29 14:44:50 +02:00
|
|
|
unsigned int thread_count = std::max( 2u, std::thread::hardware_concurrency() * 2 );
|
2018-07-29 15:51:58 +02:00
|
|
|
if ( compilercfg.NumberOfThreads )
|
|
|
|
|
thread_count = static_cast<unsigned>( compilercfg.NumberOfThreads );
|
2018-04-29 14:44:50 +02:00
|
|
|
threadhelp::TaskThreadPool pool( thread_count, "ecompile" );
|
|
|
|
|
summary.ThreadCount = pool.size();
|
|
|
|
|
for ( const auto& file : files )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
2021-12-30 07:21:20 +01:00
|
|
|
pool.push(
|
|
|
|
|
[&]()
|
2018-04-29 14:44:50 +02:00
|
|
|
{
|
2021-12-30 07:21:20 +01:00
|
|
|
if ( !par_keep_building || Clib::exit_signalled )
|
|
|
|
|
return;
|
|
|
|
|
try
|
|
|
|
|
{
|
2024-02-26 21:21:44 +01:00
|
|
|
if ( process_file( file.c_str() ) )
|
2021-12-30 07:21:20 +01:00
|
|
|
++compiled_scripts;
|
|
|
|
|
else
|
|
|
|
|
++uptodate_scripts;
|
|
|
|
|
}
|
|
|
|
|
catch ( std::exception& e )
|
|
|
|
|
{
|
|
|
|
|
++compiled_scripts;
|
|
|
|
|
++error_scripts;
|
2024-01-12 06:51:44 +01:00
|
|
|
compiler_error( "failed to compile {}: {}", file, e.what() );
|
2021-12-30 07:21:20 +01:00
|
|
|
if ( !keep_building )
|
|
|
|
|
{
|
|
|
|
|
par_keep_building = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch ( ... )
|
|
|
|
|
{
|
|
|
|
|
par_keep_building = false;
|
|
|
|
|
Clib::force_backtrace();
|
|
|
|
|
}
|
|
|
|
|
} );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2015-11-14 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
summary.CompiledScripts = compiled_scripts;
|
|
|
|
|
summary.UpToDateScripts = uptodate_scripts;
|
|
|
|
|
summary.ScriptsWithCompileErrors = error_scripts;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-16 00:08:06 +01:00
|
|
|
void DisplaySummary( const Tools::Timer<>& timer )
|
|
|
|
|
{
|
|
|
|
|
std::string tmp = "Compilation Summary:\n";
|
|
|
|
|
if ( summary.ThreadCount )
|
|
|
|
|
tmp += fmt::format( " Used {} threads\n", summary.ThreadCount );
|
|
|
|
|
if ( summary.CompiledScripts )
|
|
|
|
|
tmp += fmt::format( " Compiled {} script{} in {} ms.\n", summary.CompiledScripts,
|
|
|
|
|
( summary.CompiledScripts == 1 ? "" : "s" ), timer.ellapsed() );
|
|
|
|
|
|
|
|
|
|
if ( summary.ScriptsWithCompileErrors )
|
|
|
|
|
tmp += fmt::format( " {} of those script{} had errors.\n", summary.ScriptsWithCompileErrors,
|
|
|
|
|
( summary.ScriptsWithCompileErrors == 1 ? "" : "s" ) );
|
|
|
|
|
|
|
|
|
|
if ( summary.UpToDateScripts )
|
|
|
|
|
tmp += fmt::format( " {} script{} already up-to-date.\n", summary.UpToDateScripts,
|
|
|
|
|
( summary.UpToDateScripts == 1 ? " was" : "s were" ) );
|
|
|
|
|
|
|
|
|
|
if ( show_timing_details )
|
|
|
|
|
{
|
|
|
|
|
tmp += fmt::format( " build workspace: {}\n",
|
|
|
|
|
(long long)summary.profile.build_workspace_micros / 1000 );
|
|
|
|
|
tmp += fmt::format( " - load *.em: {}\n",
|
|
|
|
|
(long long)summary.profile.load_em_micros / 1000 );
|
|
|
|
|
tmp += fmt::format( " - parse *.em: {} ({})\n",
|
|
|
|
|
(long long)summary.profile.parse_em_micros / 1000,
|
|
|
|
|
(long)summary.profile.parse_em_count );
|
|
|
|
|
tmp += fmt::format( " - ast *.em: {}\n",
|
|
|
|
|
(long long)summary.profile.ast_em_micros / 1000 );
|
|
|
|
|
tmp += fmt::format( " - parse *.inc: {} ({})\n",
|
|
|
|
|
(long long)summary.profile.parse_inc_micros / 1000,
|
|
|
|
|
(long)summary.profile.parse_inc_count );
|
|
|
|
|
tmp += fmt::format( " - ast *.inc: {}\n",
|
|
|
|
|
(long long)summary.profile.ast_inc_micros / 1000 );
|
|
|
|
|
tmp += fmt::format( " - parse *.src: {} ({})\n",
|
|
|
|
|
(long long)summary.profile.parse_src_micros / 1000,
|
|
|
|
|
(long)summary.profile.parse_src_count );
|
|
|
|
|
tmp += fmt::format( " - ast *.src: {}\n",
|
|
|
|
|
(long long)summary.profile.ast_src_micros / 1000 );
|
|
|
|
|
tmp += fmt::format( " resolve functions: {}\n",
|
|
|
|
|
(long long)summary.profile.ast_resolve_functions_micros / 1000 );
|
|
|
|
|
tmp += fmt::format( " register constants: {}\n",
|
|
|
|
|
(long long)summary.profile.register_const_declarations_micros / 1000 );
|
|
|
|
|
tmp += fmt::format( " analyze: {}\n",
|
|
|
|
|
(long long)summary.profile.analyze_micros / 1000 );
|
|
|
|
|
tmp += fmt::format( " optimize: {}\n",
|
|
|
|
|
(long long)summary.profile.optimize_micros / 1000 );
|
|
|
|
|
tmp += fmt::format( " disambiguate: {}\n",
|
|
|
|
|
(long long)summary.profile.disambiguate_micros / 1000 );
|
|
|
|
|
tmp += fmt::format( " generate code: {}\n",
|
|
|
|
|
(long long)summary.profile.codegen_micros / 1000 );
|
|
|
|
|
tmp += fmt::format( " prune cache (sel): {}\n",
|
|
|
|
|
(long long)summary.profile.prune_cache_select_micros / 1000 );
|
|
|
|
|
tmp += fmt::format( " prune cache (del): {}\n",
|
|
|
|
|
(long long)summary.profile.prune_cache_delete_micros / 1000 );
|
|
|
|
|
tmp += "\n";
|
|
|
|
|
tmp += fmt::format( " - ambiguities: {}\n", (long)summary.profile.ambiguities );
|
|
|
|
|
tmp += fmt::format( " - cache hits: {}\n", (long)summary.profile.cache_hits );
|
|
|
|
|
tmp += fmt::format( " - cache misses: {}\n", (long)summary.profile.cache_misses );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
INFO_PRINTLN( tmp );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EnterWatchMode()
|
|
|
|
|
{
|
|
|
|
|
std::list<WatchFileMessage> watch_messages;
|
|
|
|
|
std::set<fs::path> to_compile;
|
|
|
|
|
efsw::FileWatcher fileWatcher;
|
|
|
|
|
EfswFileWatchListener listener( fileWatcher,
|
|
|
|
|
std::set<fs::path>{ ".src", ".hsr", ".asp", ".inc", ".em" } );
|
|
|
|
|
|
|
|
|
|
auto handle_compile_file = [&]( const fs::path& filepath )
|
|
|
|
|
{
|
|
|
|
|
// Existing file, compile all owners dependent on it.
|
|
|
|
|
if ( auto itr = dependency_owners.find( filepath ); itr != dependency_owners.end() )
|
|
|
|
|
{
|
|
|
|
|
to_compile.insert( itr->second.begin(), itr->second.end() );
|
|
|
|
|
}
|
|
|
|
|
// New file, compile only this file (if it is compilable).
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
auto ext = filepath.extension();
|
|
|
|
|
if ( ext.compare( ".src" ) == 0 || ext.compare( ".hsr" ) == 0 || ext.compare( ".asp" ) == 0 )
|
|
|
|
|
{
|
|
|
|
|
to_compile.emplace( filepath );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
auto handle_delete_file = [&]( const fs::path& filepath )
|
|
|
|
|
{
|
|
|
|
|
to_compile.erase( filepath );
|
|
|
|
|
if ( auto itr = owner_dependencies.find( filepath ); itr != owner_dependencies.end() )
|
|
|
|
|
{
|
|
|
|
|
// For all dependencies, remove the deleted file from set of owners for
|
|
|
|
|
// that dependency.
|
|
|
|
|
for ( const auto& depnamepath : itr->second )
|
|
|
|
|
{
|
|
|
|
|
// If dependency exists in map of dependency -> owners
|
|
|
|
|
if ( auto owners_itr = dependency_owners.find( depnamepath );
|
|
|
|
|
owners_itr != dependency_owners.end() )
|
|
|
|
|
{
|
|
|
|
|
// Erase filepath from set of owners
|
|
|
|
|
owners_itr->second.erase( filepath );
|
|
|
|
|
|
|
|
|
|
// If owners set is empty, this dependency is no longer used by
|
|
|
|
|
// anything.
|
|
|
|
|
if ( owners_itr->second.empty() )
|
|
|
|
|
{
|
|
|
|
|
// Erase from map of dependency -> owners.
|
|
|
|
|
dependency_owners.erase( owners_itr );
|
|
|
|
|
listener.remove_file( depnamepath );
|
|
|
|
|
VERBOSE_PRINTLN( "Remove watch file {}", depnamepath );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
owner_dependencies.erase( itr );
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
auto add_dir = [&]( const std::string& elem )
|
|
|
|
|
{
|
|
|
|
|
fs::path dir( elem );
|
|
|
|
|
if ( fs::exists( dir ) )
|
|
|
|
|
{
|
|
|
|
|
auto dirpath = fs::canonical( dir );
|
|
|
|
|
if ( listener.add_watch_dir( dirpath ) )
|
|
|
|
|
{
|
|
|
|
|
VERBOSE_PRINTLN( "Add watch dir {}", dirpath );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for ( const auto& dep_owners : dependency_owners )
|
|
|
|
|
{
|
|
|
|
|
listener.add_file( dep_owners.first );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for ( const auto& directory : compiled_dirs )
|
|
|
|
|
{
|
|
|
|
|
listener.add_dir( directory );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for ( const auto& elem : compilercfg.PackageRoot )
|
|
|
|
|
{
|
|
|
|
|
add_dir( elem );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
add_dir( compilercfg.ModuleDirectory );
|
|
|
|
|
add_dir( compilercfg.IncludeDirectory );
|
|
|
|
|
add_dir( compilercfg.PolScriptRoot );
|
|
|
|
|
|
|
|
|
|
fileWatcher.watch();
|
|
|
|
|
|
|
|
|
|
INFO_PRINTLN( "Entering watch mode. Watching {} files and {} directories. Ctrl-C to stop...",
|
|
|
|
|
dependency_owners.size(), compiled_dirs.size() );
|
|
|
|
|
|
|
|
|
|
while ( !Clib::exit_signalled )
|
|
|
|
|
{
|
|
|
|
|
std::this_thread::sleep_for( std::chrono::seconds( 1 ) );
|
|
|
|
|
listener.take_messages( watch_messages );
|
|
|
|
|
if ( !watch_messages.empty() )
|
|
|
|
|
{
|
|
|
|
|
for ( auto const& message : watch_messages )
|
|
|
|
|
{
|
|
|
|
|
const auto& filepath = message.filepath;
|
|
|
|
|
const auto& old_filepath = message.old_filepath;
|
|
|
|
|
VERBOSE_PRINTLN( "Event: filename={}, old_filename={}", filepath, old_filepath );
|
|
|
|
|
|
|
|
|
|
// created or modified
|
|
|
|
|
if ( old_filepath.empty() )
|
|
|
|
|
{
|
|
|
|
|
handle_compile_file( filepath );
|
|
|
|
|
}
|
|
|
|
|
// deleted
|
|
|
|
|
else if ( filepath.empty() )
|
|
|
|
|
{
|
|
|
|
|
handle_delete_file( old_filepath );
|
|
|
|
|
}
|
|
|
|
|
// moved
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
handle_delete_file( old_filepath );
|
|
|
|
|
handle_compile_file( filepath );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
watch_messages.clear();
|
|
|
|
|
|
|
|
|
|
if ( !to_compile.empty() )
|
|
|
|
|
{
|
|
|
|
|
summary.CompiledScripts = 0;
|
|
|
|
|
summary.UpToDateScripts = 0;
|
|
|
|
|
summary.ScriptsWithCompileErrors = 0;
|
|
|
|
|
em_parse_tree_cache.clear();
|
|
|
|
|
inc_parse_tree_cache.clear();
|
|
|
|
|
|
|
|
|
|
VERBOSE_PRINTLN( "To compile: {}", to_compile );
|
|
|
|
|
|
|
|
|
|
Tools::Timer<> timer;
|
|
|
|
|
for ( const auto& filepath : to_compile )
|
|
|
|
|
{
|
|
|
|
|
if ( Clib::exit_signalled )
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::set<fs::path> removed_dependencies;
|
|
|
|
|
std::set<fs::path> new_dependencies;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
process_file_wrapper( filepath.generic_string().c_str(), &removed_dependencies,
|
|
|
|
|
&new_dependencies );
|
|
|
|
|
}
|
|
|
|
|
catch ( ... )
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VERBOSE_PRINTLN( "New dependencies: {} Removed dependencies: {}", new_dependencies,
|
|
|
|
|
removed_dependencies );
|
|
|
|
|
|
|
|
|
|
for ( const auto& depnamepath : removed_dependencies )
|
|
|
|
|
{
|
|
|
|
|
// If a removed dependency has no owner set is empty, we can remove
|
|
|
|
|
// the listener for that dependency.
|
|
|
|
|
if ( dependency_owners.find( depnamepath ) == dependency_owners.end() )
|
|
|
|
|
{
|
|
|
|
|
if ( listener.remove_file( depnamepath ) )
|
|
|
|
|
{
|
|
|
|
|
VERBOSE_PRINTLN( "Remove watch file {}", depnamepath );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for ( const auto& depnamepath : new_dependencies )
|
|
|
|
|
{
|
|
|
|
|
if ( listener.add_file( depnamepath ) )
|
|
|
|
|
{
|
|
|
|
|
VERBOSE_PRINTLN( "Add watch file {}", depnamepath );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
timer.stop();
|
|
|
|
|
if ( compilercfg.DisplaySummary && !quiet )
|
|
|
|
|
{
|
|
|
|
|
DisplaySummary( timer );
|
|
|
|
|
}
|
|
|
|
|
to_compile.clear();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-12-18 23:41:43 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Runs the compilation threads
|
|
|
|
|
*/
|
2015-11-14 11:40:25 +01:00
|
|
|
void AutoCompile()
|
|
|
|
|
{
|
|
|
|
|
bool save = compilercfg.OnlyCompileUpdatedScripts;
|
|
|
|
|
compilercfg.OnlyCompileUpdatedScripts = compilercfg.UpdateOnlyOnAutoCompile;
|
2021-12-30 07:21:20 +01:00
|
|
|
std::set<std::string> files;
|
2024-03-16 00:08:06 +01:00
|
|
|
compiled_dirs.emplace( fs::canonical( compilercfg.PolScriptRoot ) );
|
2021-12-30 07:21:20 +01:00
|
|
|
recurse_collect( fs::path( compilercfg.PolScriptRoot ), &files, false );
|
|
|
|
|
for ( const auto& pkg : Plib::systemstate.packages )
|
2024-03-16 00:08:06 +01:00
|
|
|
{
|
|
|
|
|
compiled_dirs.emplace( fs::canonical( pkg->dir() ) );
|
2021-12-30 07:21:20 +01:00
|
|
|
recurse_collect( fs::path( pkg->dir() ), &files, false );
|
2024-03-16 00:08:06 +01:00
|
|
|
}
|
2015-11-14 11:40:25 +01:00
|
|
|
if ( compilercfg.ThreadedCompilation )
|
2024-02-26 21:21:44 +01:00
|
|
|
parallel_process( files );
|
|
|
|
|
else
|
|
|
|
|
serial_process( files );
|
|
|
|
|
compilercfg.OnlyCompileUpdatedScripts = save;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AutoFormat()
|
|
|
|
|
{
|
|
|
|
|
bool save = compilercfg.OnlyCompileUpdatedScripts;
|
|
|
|
|
compilercfg.OnlyCompileUpdatedScripts = compilercfg.UpdateOnlyOnAutoCompile;
|
|
|
|
|
std::set<std::string> files;
|
|
|
|
|
recurse_collect( fs::path( compilercfg.PolScriptRoot ), &files, false );
|
|
|
|
|
for ( const auto& pkg : Plib::systemstate.packages )
|
|
|
|
|
recurse_collect( fs::path( pkg->dir() ), &files, false );
|
|
|
|
|
if ( compilercfg.ThreadedCompilation )
|
|
|
|
|
parallel_process( files );
|
2015-11-14 11:40:25 +01:00
|
|
|
else
|
2024-02-26 21:21:44 +01:00
|
|
|
serial_process( files );
|
2015-11-14 11:40:25 +01:00
|
|
|
compilercfg.OnlyCompileUpdatedScripts = save;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-18 23:41:43 +01:00
|
|
|
/**
|
|
|
|
|
* Takes decisions, runs, the compilation, prints summary and cleans after
|
|
|
|
|
*/
|
2019-10-05 13:19:38 +02:00
|
|
|
bool run( int argc, char** argv, int* res )
|
2015-11-14 11:40:25 +01:00
|
|
|
{
|
2018-04-29 14:44:50 +02:00
|
|
|
Clib::enable_exit_signaller();
|
2015-12-18 23:41:43 +01:00
|
|
|
// Load and analyze the package structure
|
2016-02-19 19:26:35 +01:00
|
|
|
for ( const auto& elem : compilercfg.PackageRoot )
|
2015-11-14 11:40:25 +01:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
Plib::load_packages( elem, true /* quiet */ );
|
2015-11-14 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
Plib::replace_packages();
|
|
|
|
|
Plib::check_package_deps();
|
|
|
|
|
|
2015-12-18 23:41:43 +01:00
|
|
|
// Determine the run mode and do the compile itself
|
2015-11-14 11:40:25 +01:00
|
|
|
Tools::Timer<> timer;
|
|
|
|
|
bool any = false;
|
|
|
|
|
|
|
|
|
|
for ( int i = 1; i < argc; i++ )
|
|
|
|
|
{
|
|
|
|
|
#ifdef __linux__
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( argv[i][0] == '-' )
|
2015-11-14 11:40:25 +01:00
|
|
|
#else
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( argv[i][0] == '/' || argv[i][0] == '-' )
|
2015-11-14 11:40:25 +01:00
|
|
|
#endif
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
if ( argv[i][1] == 'A' )
|
|
|
|
|
{
|
|
|
|
|
compilercfg.UpdateOnlyOnAutoCompile = ( argv[i][2] == 'u' );
|
|
|
|
|
any = true;
|
|
|
|
|
|
|
|
|
|
AutoCompile();
|
|
|
|
|
}
|
|
|
|
|
else if ( argv[i][1] == 'r' )
|
|
|
|
|
{
|
|
|
|
|
any = true;
|
|
|
|
|
std::string dir( "." );
|
|
|
|
|
bool compile_inc = ( argv[i][2] == 'i' ); // compile .inc files
|
|
|
|
|
|
|
|
|
|
++i;
|
|
|
|
|
if ( i < argc && argv[i] && argv[i][0] != '-' )
|
|
|
|
|
dir.assign( argv[i] );
|
|
|
|
|
|
2021-12-30 07:21:20 +01:00
|
|
|
std::set<std::string> files;
|
2024-03-16 00:08:06 +01:00
|
|
|
compiled_dirs.emplace( fs::canonical( dir ) );
|
2021-12-30 07:21:20 +01:00
|
|
|
recurse_collect( fs::path( dir ), &files, compile_inc );
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( compilercfg.ThreadedCompilation )
|
2024-02-26 21:21:44 +01:00
|
|
|
parallel_process( files );
|
2016-02-19 19:26:35 +01:00
|
|
|
else
|
2024-02-26 21:21:44 +01:00
|
|
|
serial_process( files );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
else if ( argv[i][1] == 'C' )
|
|
|
|
|
{
|
|
|
|
|
++i; // skip the config file pathname
|
|
|
|
|
}
|
|
|
|
|
// and skip any other option.
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
any = true;
|
2015-11-14 11:40:25 +01:00
|
|
|
#ifdef _WIN32
|
2024-03-16 00:08:06 +01:00
|
|
|
Clib::forspec( argv[i], []( const char* pathname ) { process_file_wrapper( pathname ); } );
|
2015-11-14 11:40:25 +01:00
|
|
|
#else
|
2024-02-26 21:21:44 +01:00
|
|
|
process_file_wrapper( argv[i] );
|
2015-11-14 11:40:25 +01:00
|
|
|
#endif
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2015-11-14 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( !any && compilercfg.AutoCompileByDefault )
|
|
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
any = true;
|
|
|
|
|
AutoCompile();
|
2015-11-14 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
2015-12-18 23:41:43 +01:00
|
|
|
// Execution is completed: start final/cleanup tasks
|
2015-11-14 11:40:25 +01:00
|
|
|
timer.stop();
|
|
|
|
|
|
|
|
|
|
if ( any && compilercfg.DisplaySummary && !quiet )
|
|
|
|
|
{
|
2024-03-16 00:08:06 +01:00
|
|
|
DisplaySummary( timer );
|
|
|
|
|
}
|
2022-01-16 08:47:34 +01:00
|
|
|
|
2024-03-16 00:08:06 +01:00
|
|
|
if ( watch_source )
|
|
|
|
|
{
|
|
|
|
|
EnterWatchMode();
|
2015-11-14 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
2024-03-16 00:08:06 +01:00
|
|
|
Plib::systemstate.deinitialize();
|
|
|
|
|
|
2019-10-05 13:19:38 +02:00
|
|
|
if ( summary.ScriptsWithCompileErrors )
|
|
|
|
|
*res = 1;
|
|
|
|
|
else
|
|
|
|
|
*res = 0;
|
2015-11-14 11:40:25 +01:00
|
|
|
return any;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void read_config_file( int argc, char* argv[] )
|
|
|
|
|
{
|
|
|
|
|
for ( int i = 1; i < argc; i++ )
|
|
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( argv[i][0] == '/' || argv[i][0] == '-' )
|
|
|
|
|
{
|
|
|
|
|
// -C cfgpath
|
|
|
|
|
if ( argv[i][1] == 'C' )
|
|
|
|
|
{
|
|
|
|
|
++i;
|
|
|
|
|
if ( i == argc )
|
|
|
|
|
throw std::runtime_error( "-C specified without pathname" );
|
|
|
|
|
|
|
|
|
|
compilercfg.Read( std::string( argv[i] ) );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-11-14 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check ECOMPILE_CFG_PATH environment variable
|
|
|
|
|
const char* env_ecompile_cfg_path = getenv( "ECOMPILE_CFG_PATH" );
|
2018-04-29 14:44:50 +02:00
|
|
|
if ( env_ecompile_cfg_path != nullptr )
|
2015-11-14 11:40:25 +01:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
compilercfg.Read( std::string( env_ecompile_cfg_path ) );
|
|
|
|
|
return;
|
2015-11-14 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// no -C arg, so use binary path (hope it's right..sigh.)
|
|
|
|
|
std::string cfgpath = PROG_CONFIG::programDir() + "ecompile.cfg";
|
|
|
|
|
if ( Clib::FileExists( "ecompile.cfg" ) )
|
|
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
compilercfg.Read( "ecompile.cfg" );
|
2015-11-14 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
else if ( Clib::FileExists( cfgpath ) )
|
|
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
compilercfg.Read( cfgpath );
|
2015-11-14 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-01-12 06:51:44 +01:00
|
|
|
ERROR_PRINTLN( "Could not find {}; using defaults.", cfgpath );
|
2016-02-19 19:26:35 +01:00
|
|
|
compilercfg.SetDefaults();
|
2015-11-14 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-18 23:41:43 +01:00
|
|
|
/**
|
|
|
|
|
* This is the main entry point for ecompile program
|
|
|
|
|
*/
|
2015-11-14 11:40:25 +01:00
|
|
|
int ECompileMain::main()
|
|
|
|
|
{
|
2018-12-23 13:55:47 +01:00
|
|
|
Clib::Logging::global_logger->disableFileLog();
|
|
|
|
|
|
2016-12-14 17:05:34 +01:00
|
|
|
const std::vector<std::string>& binArgs = programArgs();
|
2016-02-19 19:26:35 +01:00
|
|
|
|
|
|
|
|
/**********************************************
|
|
|
|
|
* TODO: rework the following cruft from former uotool.cpp
|
|
|
|
|
**********************************************/
|
2015-11-14 11:40:25 +01:00
|
|
|
#ifdef _WIN32
|
2016-02-19 19:26:35 +01:00
|
|
|
Clib::MiniDumper::Initialize();
|
2015-11-14 11:40:25 +01:00
|
|
|
#endif
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
ECompile::read_config_file( s_argc, s_argv );
|
|
|
|
|
|
2024-03-16 00:08:06 +01:00
|
|
|
/**********************************************
|
|
|
|
|
* show help
|
|
|
|
|
**********************************************/
|
|
|
|
|
if ( binArgs.size() == 1 && !compilercfg.AutoCompileByDefault )
|
|
|
|
|
{
|
|
|
|
|
showHelp();
|
|
|
|
|
return 0; // return "okay"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
watch_source = compilercfg.WatchModeByDefault;
|
|
|
|
|
if ( watch_source )
|
|
|
|
|
{
|
|
|
|
|
compilercfg.GenerateDependencyInfo = true;
|
|
|
|
|
keep_building = true;
|
|
|
|
|
compilercfg.ThreadedCompilation =
|
|
|
|
|
false; // limitation since dependency gathering is not thread-safe
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
int res = ECompile::readargs( s_argc, s_argv );
|
|
|
|
|
if ( res )
|
2019-10-05 13:19:38 +02:00
|
|
|
{
|
|
|
|
|
showHelp();
|
2016-02-19 19:26:35 +01:00
|
|
|
return res;
|
2019-10-05 13:19:38 +02:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
|
2020-08-16 17:22:16 -07:00
|
|
|
ECompile::apply_configuration();
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( !ECompile::quiet )
|
|
|
|
|
{
|
|
|
|
|
// vX.YY
|
2024-01-20 12:38:25 +08:00
|
|
|
INFO_PRINTLN( "EScript Compiler v1.{}\n{}\n", ESCRIPT_FILE_VER_CURRENT, POL_COPYRIGHT );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
|
2019-10-05 13:19:38 +02:00
|
|
|
int prog_res = 1;
|
|
|
|
|
bool didanything = ECompile::run( s_argc, s_argv, &prog_res );
|
2016-02-19 19:26:35 +01:00
|
|
|
|
|
|
|
|
if ( !didanything )
|
|
|
|
|
{
|
|
|
|
|
showHelp();
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2019-10-05 13:19:38 +02:00
|
|
|
return prog_res;
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2018-12-23 13:55:47 +01:00
|
|
|
} // namespace ECompile
|
|
|
|
|
} // namespace Pol
|
2015-11-14 11:40:25 +01:00
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
int main( int argc, char* argv[] )
|
2015-11-14 11:40:25 +01:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
Pol::ECompile::s_argc = argc;
|
|
|
|
|
Pol::ECompile::s_argv = argv;
|
2015-11-14 11:40:25 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Pol::ECompile::ECompileMain* ECompileMain = new Pol::ECompile::ECompileMain();
|
|
|
|
|
ECompileMain->start( argc, argv );
|
2015-11-14 11:40:25 +01:00
|
|
|
}
|