• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

polserver / polserver / 12937667606

23 Jan 2025 08:39PM UTC coverage: 57.971% (+0.2%) from 57.723%
12937667606

push

github

web-flow
more dead code from old compiler (#751)

0 of 3 new or added lines in 1 file covered. (0.0%)

2 existing lines in 2 files now uncovered.

41395 of 71407 relevant lines covered (57.97%)

383582.82 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

60.12
/pol-core/ecompile/ECompileMain.cpp
1
#include "ECompileMain.h"
2

3
#include <cstdio>
4
#include <exception>
5
#include <filesystem>
6
#include <iosfwd>
7
#include <memory>
8
#include <stdlib.h>
9
#include <string>
10
#include <system_error>
11
#include <time.h>
12

13
#include "EfswFileWatchListener.h"
14

15
#include "bscript/compiler/Compiler.h"
16
#include "bscript/compiler/Profile.h"
17
#include "bscript/compiler/file/SourceFileCache.h"
18
#include "bscript/compilercfg.h"
19
#include "bscript/escriptv.h"
20
#include "bscript/executor.h"
21
#include "bscript/executortype.h"
22
#include "bscript/filefmt.h"
23
#include "clib/Program/ProgramConfig.h"
24
#include "clib/Program/ProgramMain.h"
25
#include "clib/esignal.h"
26
#include "clib/fileutil.h"
27
#include "clib/logfacility.h"
28
#include "clib/mdump.h"
29
#include "clib/passert.h"
30
#include "clib/threadhelp.h"
31
#include "clib/timer.h"
32
#include "plib/pkg.h"
33
#include "plib/systemstate.h"
34

35
#define VERBOSE_PRINTLN                 \
36
  if ( compilercfg.VerbosityLevel > 0 ) \
37
  INFO_PRINTLN
38

39
namespace Pol
40
{
41
namespace ECompile
42
{
43
namespace fs = std::filesystem;
44
using namespace Pol::Core;
45
using namespace Pol::Plib;
46
using namespace Pol::Bscript;
47

48
///////////////////////////////////////////////////////////////////////////////
49

50

51
///////////////////////////////////////////////////////////////////////////////
52

53
ECompileMain::ECompileMain() : Pol::Clib::ProgramMain() {}
1,976✔
54
ECompileMain::~ECompileMain() {}
×
55
///////////////////////////////////////////////////////////////////////////////
56

57
void ECompileMain::showHelp()
×
58
{
59
  INFO_PRINTLN(
×
60
      "Usage:\n"
61
      "    \n"
62
      "  ECOMPILE [options] filespec [filespec ...]\n"
63
      "    \n"
64
      "  Output is : filespec.ecl\n"
65
      "  Options:\n"
66
      "   Options: \n"
67
      "       -F           format filespec (print result)\n"
68
      "       -Fi          format filespec (inplace)\n"
69
      "       -a           compile *.asp pages also\n"
70
      "       -A           automatically compile scripts in main and enabled packages\n"
71
      "       -Au          (as '-A' but only compile updated files)\n"
72
      "       -b           keep building other scripts after errors\n"
73
      "       -c           treat wrong capitalization in include directives as error\n"
74
      "       -C cfgpath   path to configuration (replaces ecompile.cfg)\n"
75
      "       -d           display confusing compiler parse information\n"
76
      "       -D           write dependency information\n"
77
      "       -e           report error on successful compilation (used for testing)\n"
78
#ifdef WIN32
79
      "       -Ecfgpath    set or change the ECOMPILE_CFG_PATH evironment variable\n"
80
#endif
81

82
      "       -i           include intrusive debug info in .ecl file\n"
83
      "       -l           generate listfile\n"
84
      "       -m           don't optimize object members\n"
85
#ifdef WIN32
86
      "       -Pdir        set or change the EM and INC files Environment Variables\n"
87
#endif
88
      "       -q           quiet mode (suppress normal output)\n"
89
      "       -r [dir]     recurse folder [from 'dir'] (defaults to current folder)\n"
90
      "       -ri [dir]    (as '-r' but only compile .inc files)\n"
91
      "       -t[v]        show timing/profiling information [override quiet mode]\n"
92
      "       -u           compile only updated scripts (.src newer than .ecl)\n"
93
      "       -f           force compile even if up-to-date\n"
94
      "       -s           display summary if -q is not set\n"
95
      "       -T[N]        use threaded compilation, force N threads to run\n"
96
      "       -vN          verbosity level\n"
97
      "       -w           display warnings\n"
98
      "       -W           watch mode\n"
99
      "       -y           treat warnings as errors\n"
100
      "       -x           write external .dbg file\n"
101
      "       -xt          write external .dbg.txt info file\n"
102
      "\n"
103
      " NOTE:\n"
104
      "   If <filespec> are required after an empty -r[i] option, you MUST specify\n"
105
      "   a literal [dir] of '.' (no quotes) or options will not parse correctly." );
106
}
×
107
static int s_argc;
108
static char** s_argv;
109

110
int debug = 0;
111
bool quiet = false;
112
bool keep_building = false;
113
bool force_update = false;
114
bool format_source = false;
115
bool format_source_inplace = false;
116
bool show_timing_details = false;
117
bool timing_quiet_override = false;
118
bool expect_compile_failure = false;
119
bool dont_optimize_object_members = false;
120
bool watch_source = false;
121
std::string EmPathEnv;   // "ECOMPILE_PATH_EM=xxx"
122
std::string IncPathEnv;  // ECOMPILE_PATH_INC=yyy"
123
std::string CfgPathEnv;  // ECOMPILE_CFG_PATH=zzz"
124

125
struct Summary
126
{
127
  unsigned UpToDateScripts = 0;
128
  unsigned CompiledScripts = 0;
129
  unsigned ScriptsWithCompileErrors = 0;
130
  size_t ThreadCount = 0;
131
  Compiler::Profile profile;
132
} summary;
133

134
struct Comparison
135
{
136
  std::atomic<long long> CompileTimeV1Micros{};
137
  std::atomic<long long> CompileTimeV2Micros{};
138
  std::atomic<long> MatchingResult{};
139
  std::atomic<long> NonMatchingResult{};
140
  std::atomic<long> MatchingOutput{};
141
  std::atomic<long> NonMatchingOutput{};
142
} comparison;
143

144
Compiler::SourceFileCache em_parse_tree_cache( summary.profile );
145
Compiler::SourceFileCache inc_parse_tree_cache( summary.profile );
146

147
using DependencyInfo = std::map<fs::path, std::set<fs::path>>;
148
// Map owner (sources) -> dependencies
149
DependencyInfo owner_dependencies;
150
// Map dependency -> owners (sources)
151
DependencyInfo dependency_owners;
152

153
std::set<fs::path> compiled_dirs;
154

155
std::unique_ptr<Compiler::Compiler> create_compiler()
2,198✔
156
{
157
  auto compiler = std::make_unique<Compiler::Compiler>( em_parse_tree_cache, inc_parse_tree_cache,
158
                                                        summary.profile );
2,198✔
159
  return compiler;
2,198✔
160
}
161

162
void load_packages()
1,976✔
163
{
164
  // No need to load packages if only formatting sources
165
  if ( !format_source )
1,976✔
166
  {
167
    // Load and analyze the package structure
168
    for ( const auto& elem : compilercfg.PackageRoot )
2,796✔
169
    {
170
      Plib::load_packages( elem, true /* quiet */ );
1,398✔
171
    }
172
    Plib::replace_packages();
1,398✔
173
    Plib::check_package_deps();
1,398✔
174
  }
175
}
1,976✔
176

177
void compile_inc( const std::string& path )
×
178
{
179
  if ( !quiet )
×
180
    INFO_PRINTLN( "Compiling: {}", path );
×
181

182
  std::unique_ptr<Compiler::Compiler> compiler = create_compiler();
×
183

184
  compiler->set_include_compile_mode();
×
185
  bool res = compiler->compile_file( path );
×
186

187
  if ( !res )
×
188
    throw std::runtime_error( "Error compiling file" );
×
189
}
×
190

191
std::vector<unsigned char> file_contents( const std::string& pathname, std::ios::openmode openmode )
×
192
{
193
  std::ifstream ifs( pathname, openmode );
×
194
  return std::vector<unsigned char>( std::istreambuf_iterator<char>( ifs ), {} );
×
195
}
×
196

197
std::vector<unsigned char> binary_contents( const std::string& pathname )
×
198
{
199
  std::ifstream input1( pathname, std::ios::binary );
×
200
  std::vector<unsigned char> buffer( std::istreambuf_iterator<char>( input1 ), {} );
×
201
  return buffer;
×
202
}
×
203

204
std::vector<std::string> instruction_filenames( const std::vector<unsigned>& ins_filenums,
×
205
                                                const std::vector<std::string>& filenames )
206
{
207
  std::vector<std::string> result;
×
208
  result.reserve( ins_filenums.size() );
×
209

210
  for ( auto& ins_filenum : ins_filenums )
×
211
  {
212
    result.push_back( filenames.at( ins_filenum ) );
×
213
  }
214
  return result;
×
215
}
×
216

217
bool format_file( const std::string& path )
578✔
218
{
219
  std::string ext( "" );
578✔
220

221
  std::string::size_type pos = path.rfind( '.' );
578✔
222
  if ( pos != std::string::npos )
578✔
223
    ext = path.substr( pos );
578✔
224

225
  if ( ext.compare( ".src" ) != 0 && ext.compare( ".inc" ) != 0 && ext.compare( ".em" ) != 0 )
578✔
226
  {
NEW
227
    ERROR_PRINTLN(
×
228
        "Didn't find '.src', '.inc', or '.em' extension on source filename '{}'! ..Ignoring",
229
        path );
230
    return true;
×
231
  }
232

233
  if ( !quiet )
578✔
234
    INFO_PRINTLN( "Formatting: {}", path );
×
235

236
  std::unique_ptr<Compiler::Compiler> compiler = create_compiler();
578✔
237

238
  bool success =
239
      compiler->format_file( path.c_str(), ext.compare( ".em" ) == 0, format_source_inplace );
578✔
240

241
  if ( expect_compile_failure )
578✔
242
  {
243
    if ( !success )  // good, it failed
×
244
    {
245
      if ( !quiet )
×
246
        INFO_PRINTLN( "Formatting failed as expected." );
×
247
      return true;
×
248
    }
249
    else
250
    {
251
      throw std::runtime_error( "Formatting succeeded (-e indicates failure was expected)" );
×
252
    }
253
  }
254

255
  if ( !success )
578✔
256
    throw std::runtime_error( "Error formatting file" );
×
257
  return true;
578✔
258
}
578✔
259

260
void add_dependency_info( const fs::path& filepath_src,
119✔
261
                          std::set<fs::path>* removed_dependencies = nullptr,
262
                          std::set<fs::path>* new_dependencies = nullptr )
263
{
264
  auto filename_dep = fs::path( filepath_src ).replace_extension( ".dep" );
119✔
265

266
  auto& dependencies = owner_dependencies[filepath_src];
119✔
267
  auto previous_dependencies = dependencies;
119✔
268

269
  VERBOSE_PRINTLN( "Dependencies for: {}", filepath_src );
119✔
270
  for ( const auto& dependency : previous_dependencies )
228✔
271
  {
272
    if ( auto itr = dependency_owners.find( dependency ); itr != dependency_owners.end() )
109✔
273
    {
274
      // Remove deleted file from owners
275
      itr->second.erase( filepath_src );
109✔
276
      auto remaining = itr->second.size();
109✔
277
      VERBOSE_PRINTLN( "  - Removed {}, remaining owners={}", dependency, remaining );
109✔
278
      if ( remaining == 0 )
109✔
279
      {
280
        dependency_owners.erase( itr );
13✔
281
      }
282
    }
283
  }
284

285
  dependencies.clear();
119✔
286

287
  {
288
    std::ifstream ifs( filename_dep.c_str() );
119✔
289
    if ( ifs.is_open() )
119✔
290
    {
291
      std::string depname;
119✔
292
      while ( getline( ifs, depname ) )
934✔
293
      {
294
        fs::path depnamepath = fs::canonical( fs::path( depname ) );
815✔
295
        auto& owners = dependency_owners[depnamepath];
815✔
296
        // Add this source as a dependency by:
297
        // (1) placing `filename_src` in the set of owners for `depnamepath`.
298
        owners.emplace( filepath_src );
815✔
299
        // (2) placing `depnamepath` in the set of dependencies for this `filename_src`.
300
        dependencies.emplace( depnamepath );
815✔
301
        VERBOSE_PRINTLN( "  - Added {}, owners={}", depnamepath, owners.size() );
815✔
302
      }
815✔
303
    }
119✔
304

305
    // Could not load dependency information -- maybe failed compilation? We
306
    // still add this source as a dependency of itself, such that it will be
307
    // recompiled on next save.
308
    //
309
    // On failed compilation, the existing `.dep`
310
    // remains, so we will use that information for recompilation (eg. a source
311
    // failed to compile due to a bad include, changing the include should still
312
    // recompile the source.)
313
    else
314
    {
315
      dependency_owners[filepath_src] = std::set<fs::path>{ filepath_src };
×
316
      dependencies.emplace( filepath_src );
×
317
    }
318
  }
119✔
319

320
  if ( removed_dependencies && new_dependencies )
119✔
321
  {
322
    std::set_difference( previous_dependencies.begin(), previous_dependencies.end(),
14✔
323
                         dependencies.begin(), dependencies.end(),
324
                         std::inserter( *removed_dependencies, removed_dependencies->begin() ) );
325

326

327
    std::set_difference( dependencies.begin(), dependencies.end(), previous_dependencies.begin(),
14✔
328
                         previous_dependencies.end(),
329
                         std::inserter( *new_dependencies, new_dependencies->begin() ) );
330
  }
331
}
119✔
332

333
/**
334
 * Compiles the single given file (inc, src, hsr, asp), if needed
335
 *
336
 * Takes into account compilercfg.OnlyCompileUpdatedScripts and force_update
337
 *
338
 * @param path path of the file to be compiled
339
 * @return TRUE if the file was compiled, FALSE otherwise (eg. the file is up-to-date)
340
 */
341
bool compile_file( const std::string& path )
1,620✔
342
{
343
  std::string ext( "" );
1,620✔
344

345
  std::string::size_type pos = path.rfind( '.' );
1,620✔
346
  if ( pos != std::string::npos )
1,620✔
347
    ext = path.substr( pos );
1,620✔
348

349
  if ( !ext.compare( ".inc" ) )
1,620✔
350
  {
351
    compile_inc( path );
×
352
    return true;
×
353
  }
354

355
  if ( ext.compare( ".src" ) != 0 && ext.compare( ".hsr" ) != 0 && ext.compare( ".asp" ) != 0 )
1,620✔
356
  {
NEW
357
    ERROR_PRINTLN( "Didn't find '.src', '.hsr', or '.asp' extension on source filename '{}'!",
×
358
                   path );
UNCOV
359
    throw std::runtime_error( "Error in source filename" );
×
360
  }
361
  std::string fname = path;
1,620✔
362
  std::string filename_ecl = fname.replace( pos, 4, ".ecl" );
1,620✔
363
  std::string filename_lst = fname.replace( pos, 4, ".lst" );
1,620✔
364
  std::string filename_dep = fname.replace( pos, 4, ".dep" );
1,620✔
365
  std::string filename_dbg = fname.replace( pos, 4, ".dbg" );
1,620✔
366

367
  if ( compilercfg.OnlyCompileUpdatedScripts && !force_update )
1,620✔
368
  {
369
    bool all_old = true;
1,515✔
370
    unsigned int ecl_timestamp = Clib::GetFileTimestamp( filename_ecl.c_str() );
1,515✔
371
    if ( Clib::GetFileTimestamp( path.c_str() ) >= ecl_timestamp )
1,515✔
372
    {
373
      if ( compilercfg.VerbosityLevel > 0 )
1,505✔
374
        INFO_PRINTLN( "{} is newer than {}", path, filename_ecl );
109✔
375
      all_old = false;
1,505✔
376
    }
377

378
    if ( all_old )
1,515✔
379
    {
380
      std::ifstream ifs( filename_dep.c_str() );
10✔
381
      // if the file doesn't exist, gotta build.
382
      if ( ifs.is_open() )
10✔
383
      {
384
        std::string depname;
9✔
385
        while ( getline( ifs, depname ) )
83✔
386
        {
387
          if ( Clib::GetFileTimestamp( depname.c_str() ) >= ecl_timestamp )
83✔
388
          {
389
            if ( compilercfg.VerbosityLevel > 0 )
9✔
390
              INFO_PRINTLN( "{} is newer than {}", depname, filename_ecl );
9✔
391
            all_old = false;
9✔
392
            break;
9✔
393
          }
394
        }
395
      }
9✔
396
      else
397
      {
398
        if ( compilercfg.VerbosityLevel > 0 )
1✔
399
          INFO_PRINTLN( "{} does not exist.", filename_dep );
1✔
400
        all_old = false;
1✔
401
      }
402
    }
10✔
403
    if ( all_old )
1,515✔
404
    {
405
      if ( !quiet && compilercfg.DisplayUpToDateScripts )
×
406
        INFO_PRINTLN( "{} is up-to-date.", filename_ecl );
×
407
      return false;
×
408
    }
409
  }
410

411

412
  {
413
    if ( !quiet )
1,620✔
414
      INFO_PRINTLN( "Compiling: {}", path );
224✔
415

416
    std::unique_ptr<Compiler::Compiler> compiler = create_compiler();
1,620✔
417

418
    bool success = compiler->compile_file( path.c_str() );
1,620✔
419

420
    em_parse_tree_cache.keep_some();
1,620✔
421
    inc_parse_tree_cache.keep_some();
1,620✔
422

423
    if ( expect_compile_failure )
1,620✔
424
    {
425
      if ( !success )  // good, it failed
×
426
      {
427
        if ( !quiet )
×
428
          INFO_PRINTLN( "Compilation failed as expected." );
×
429
        return true;
×
430
      }
431
      else
432
      {
433
        throw std::runtime_error( "Compilation succeeded (-e indicates failure was expected)" );
×
434
      }
435
    }
436

437
    if ( !success )
1,620✔
438
      throw std::runtime_error( "Error compiling file" );
246✔
439

440

441
    if ( !quiet )
1,374✔
442
      INFO_PRINTLN( "Writing:   {}", filename_ecl );
220✔
443

444
    if ( !compiler->write_ecl( filename_ecl ) )
1,374✔
445
    {
446
      throw std::runtime_error( "Error writing output file" );
×
447
    }
448

449
    if ( compilercfg.GenerateListing )
1,374✔
450
    {
451
      if ( !quiet )
1,154✔
452
        INFO_PRINTLN( "Writing:   {}", filename_lst );
×
453
      compiler->write_listing( filename_lst );
1,154✔
454
    }
455
    else if ( Clib::FileExists( filename_lst.c_str() ) )
220✔
456
    {
457
      if ( !quiet )
×
458
        INFO_PRINTLN( "Deleting:  {}", filename_lst );
×
459
      Clib::RemoveFile( filename_lst );
×
460
    }
461

462
    if ( compilercfg.GenerateDebugInfo )
1,374✔
463
    {
464
      if ( !quiet )
1,259✔
465
      {
466
        INFO_PRINTLN( "Writing:   {}", filename_dbg );
105✔
467
        if ( compilercfg.GenerateDebugTextInfo )
105✔
468
          INFO_PRINTLN( "Writing:   {}.txt", filename_dbg );
×
469
      }
470
      compiler->write_dbg( filename_dbg, compilercfg.GenerateDebugTextInfo );
1,259✔
471
    }
472
    else if ( Clib::FileExists( filename_dbg.c_str() ) )
115✔
473
    {
474
      if ( !quiet )
105✔
475
        INFO_PRINTLN( "Deleting:  {}", filename_dbg );
105✔
476
      Clib::RemoveFile( filename_dbg );
105✔
477
    }
478

479
    if ( compilercfg.GenerateDependencyInfo )
1,374✔
480
    {
481
      if ( !quiet )
115✔
482
        INFO_PRINTLN( "Writing:   {}", filename_dep );
115✔
483
      compiler->write_included_filenames( filename_dep );
115✔
484
    }
485
    else if ( Clib::FileExists( filename_dep.c_str() ) )
1,259✔
486
    {
487
      if ( !quiet )
×
488
        INFO_PRINTLN( "Deleting:  {}", filename_dep );
×
489
      Clib::RemoveFile( filename_dep );
×
490
    }
491
  }
1,620✔
492
  return true;
1,374✔
493
}
2,850✔
494

495
bool process_file( const std::string& path )
2,198✔
496
{
497
  if ( format_source )
2,198✔
498
    return format_file( path );
578✔
499
  return compile_file( path );
1,620✔
500
}
501

502
void process_file_wrapper( const std::string& path,
2,198✔
503
                           std::set<fs::path>* removed_dependencies = nullptr,
504
                           std::set<fs::path>* new_dependencies = nullptr )
505
{
506
  try
507
  {
508
    if ( process_file( path ) )
2,198✔
509
      ++summary.CompiledScripts;
1,952✔
510
    else
511
      ++summary.UpToDateScripts;
×
512
  }
513
  catch ( std::exception& )
246✔
514
  {
515
    ++summary.CompiledScripts;
246✔
516
    ++summary.ScriptsWithCompileErrors;
246✔
517
    if ( !keep_building )
246✔
518
      throw;
242✔
519
  }
246✔
520

521
  if ( watch_source )
1,956✔
522
  {
523
    fs::path filepath = fs::canonical( fs::path( path ) );
119✔
524
    auto ext = filepath.extension().generic_string();
119✔
525
    if ( ext.compare( ".src" ) == 0 || ext.compare( ".hsr" ) == 0 || ext.compare( ".asp" ) == 0 )
119✔
526
    {
527
      add_dependency_info( filepath, removed_dependencies, new_dependencies );
119✔
528
    }
529
  }
119✔
530
}
1,956✔
531

532
bool setting_value( const char* arg )
1,397✔
533
{
534
  // format of arg is -C or -C-
535
  if ( arg[2] == '\0' )
1,397✔
536
    return true;
1,397✔
537
  else if ( arg[2] == '-' )
×
538
    return false;
×
539
  else if ( arg[2] == '+' )
×
540
    return true;
×
541
  else
542
    return true;
×
543
}
544

545

546
int readargs( int argc, char** argv )
1,976✔
547
{
548
  bool unknown_opt = false;
1,976✔
549

550
  for ( int i = 1; i < argc; i++ )
9,877✔
551
  {
552
    const char* arg = argv[i];
7,901✔
553
#ifdef __linux__
554
    if ( arg[0] == '-' )
7,901✔
555
#else
556
    if ( arg[0] == '/' || arg[0] == '-' )
557
#endif
558
    {
559
      switch ( arg[1] )
5,927✔
560
      {
561
      case 'W':
1✔
562
        watch_source = true;
1✔
563
        compilercfg.GenerateDependencyInfo = true;
1✔
564
        keep_building = true;
1✔
565
        compilercfg.ThreadedCompilation =
1✔
566
            false;  // limitation since dependency gathering is not thread-safe
567
        break;
1✔
568

569
      case 'A':  // skip it at this point.
2✔
570
        break;
2✔
571

572
      case 'c':
×
573
        compilercfg.ErrorOnFileCaseMissmatch = setting_value( arg );
×
574
        break;
×
575

576
      case 'C':  // skip it at this point.
1,974✔
577
        ++i;     // and skip its parameter.
1,974✔
578
        break;
1,974✔
579

580
      case 'd':
×
581
        compilercfg.DisplayDebugs = setting_value( arg );
×
582
        break;
×
583

584
      case 'D':
×
585
        compilercfg.GenerateDependencyInfo = setting_value( arg );
×
586
        break;
×
587

588
      case 'e':
×
589
        expect_compile_failure = true;
×
590
        break;
×
591

592
#ifdef WIN32
593
      case 'E':
594
      {
595
        std::string path = &argv[i][2];
596
        CfgPathEnv = "ECOMPILE_CFG_PATH=" + path;
597
        _putenv( CfgPathEnv.c_str() );
598
      }
599
      break;
600
#endif
601

602
      case 'g':
×
603
      {
604
        auto value = setting_value( arg );
×
605
        if ( !value )
×
606
        {
607
          INFO_PRINTLN( "The OG Compiler has been removed." );
×
608
          unknown_opt = true;
×
609
        }
610
        break;
×
611
      }
612

613
      case 'q':
1,974✔
614
        quiet = true;
1,974✔
615
        break;
1,974✔
616

617
      case 'w':
×
618
        compilercfg.DisplayWarnings = setting_value( arg );
×
619
        if ( argv[i][2] == 'P' )
×
620
          compilercfg.ParanoiaWarnings = true;
×
621
        break;
×
622
      case 'y':
×
623
        compilercfg.ErrorOnWarning = setting_value( arg );
×
624
        break;
×
625

626
      case 'l':
1,396✔
627
        compilercfg.GenerateListing = setting_value( arg );
1,396✔
628
        break;
1,396✔
629

630
      case 'i':
×
631
        include_debug = 1;
×
632
        break;
×
633

634
      case 'r':  // -r[i] [dir] is okay
×
635
        // Only suboption allowed is '-ri' (.inc recurse)
636
        if ( argv[i][2] && argv[i][2] != 'i' )
×
637
        {
638
          // BZZZZT! *error*
639
          unknown_opt = true;
×
640
          break;
×
641
        }
642

643
// Only skip next parameter if it's not an option!!
644
#ifdef __linux__
645
        if ( i + 1 < argc && argv[i + 1][0] != '-' )
×
646
#else
647
        if ( i + 1 < argc && argv[i + 1][0] != '/' && argv[i + 1][0] != '-' )
648
#endif
649
          ++i;
×
650
        break;
×
651

652
      case 't':
×
653
        show_timing_details = true;
×
654
        if ( argv[i][2] == 'v' )
×
655
          timing_quiet_override = true;
×
656
        break;
×
657

658
      case 's':
×
659
        // show_source = true;
660
        compilercfg.DisplaySummary = true;
×
661
        break;
×
662

663
      case 'a':
×
664
        compilercfg.CompileAspPages = setting_value( arg );
×
665
        break;
×
666

667
      case 'm':
×
668
        compilercfg.OptimizeObjectMembers = false;
×
669
        break;
×
670

671
      case 'b':
×
672
        keep_building = true;
×
673
        break;
×
674

675
      case 'u':
×
676
        compilercfg.OnlyCompileUpdatedScripts = setting_value( arg );
×
677
        if ( compilercfg.OnlyCompileUpdatedScripts )
×
678
          compilercfg.GenerateDependencyInfo = true;
×
679
        break;
×
680

681
      case 'F':
578✔
682
      {
683
        if ( argv[i][2] && argv[i][2] == 'i' )
578✔
684
          format_source_inplace = true;
578✔
685
        format_source = true;
578✔
686
        break;
578✔
687
      }
688

689
      case 'f':
×
690
        force_update = true;
×
691
        break;
×
692

693
      case 'v':
1✔
694
        int vlev;
695
        vlev = atoi( &argv[i][2] );
1✔
696
        if ( !vlev )
1✔
697
          vlev = 1;
1✔
698
        compilercfg.VerbosityLevel = vlev;
1✔
699
        break;
1✔
700

701
      case 'x':
1✔
702
        compilercfg.GenerateDebugInfo = setting_value( arg );
1✔
703
        compilercfg.GenerateDebugTextInfo = ( argv[i][2] == 't' );
1✔
704
        break;
1✔
705

706
#ifdef WIN32
707
      case 'P':
708
      {
709
        std::string path = &argv[i][2];
710
        EmPathEnv = "ECOMPILE_PATH_EM=" + path;
711
        IncPathEnv = "ECOMPILE_PATH_INC=" + path;
712
        _putenv( EmPathEnv.c_str() );
713
        _putenv( IncPathEnv.c_str() );
714
      }
715
      break;
716
#endif
717
      case 'T':
×
718
      {
719
        compilercfg.ThreadedCompilation = true;
×
720
        int count = atoi( &argv[i][2] );
×
721
        compilercfg.NumberOfThreads = count;
×
722
        break;
×
723
      }
724
      default:
×
725
        unknown_opt = true;
×
726
        break;
×
727
      }
728
    }
729

730
    if ( unknown_opt )
7,901✔
731
    {
732
      ERROR_PRINTLN( "Unknown option: {}", argv[i] );
×
733
      return 1;
×
734
    }
735
  }
736
  return 0;
1,976✔
737
}
738

739
void apply_configuration()
1,976✔
740
{
741
  em_parse_tree_cache.configure( compilercfg.EmParseTreeCacheSize );
1,976✔
742
  inc_parse_tree_cache.configure( compilercfg.IncParseTreeCacheSize );
1,976✔
743
}
1,976✔
744

745
void recurse_call( const std::vector<fs::path>& basedirs, bool inc_files,
2✔
746
                   const std::function<void( const std::string& )>& callback )
747
{
748
  std::set<std::string> files;
2✔
749
  for ( const auto& basedir : basedirs )
8✔
750
  {
751
    if ( !fs::is_directory( basedir ) )
6✔
752
      continue;
×
753
    std::error_code ec;
6✔
754
    for ( auto dir_itr = fs::recursive_directory_iterator( basedir, ec );
6✔
755
          dir_itr != fs::recursive_directory_iterator(); ++dir_itr )
1,586✔
756
    {
757
      if ( Clib::exit_signalled )
790✔
758
        return;
×
759
      if ( auto fn = dir_itr->path().filename().u8string(); !fn.empty() && *fn.begin() == '.' )
790✔
760
      {
761
        if ( dir_itr->is_directory() )
4✔
762
          dir_itr.disable_recursion_pending();
2✔
763
        continue;
4✔
764
      }
765
      else if ( !dir_itr->is_regular_file() )
786✔
766
        continue;
790✔
767
      const auto ext = dir_itr->path().extension();
689✔
768
      if ( inc_files )
689✔
769
      {
770
        if ( !ext.compare( ".inc" ) )
×
771
          if ( files.insert( dir_itr->path().u8string() ).second )
×
772
            callback( dir_itr->path().u8string() );
×
773
      }
774
      else if ( !ext.compare( ".src" ) || !ext.compare( ".hsr" ) ||
1,166✔
775
                ( compilercfg.CompileAspPages && !ext.compare( ".asp" ) ) )
477✔
776
      {
777
        if ( files.insert( dir_itr->path().u8string() ).second )
212✔
778
          callback( dir_itr->path().u8string() );
210✔
779
      }
780
    }
695✔
781
  }
782
}
2✔
783

784
void process_dirs( const std::vector<fs::path>& dirs, bool compile_inc )
2✔
785
{
786
  if ( !compilercfg.ThreadedCompilation )
2✔
787
  {
788
    recurse_call( dirs, compile_inc,
2✔
789
                  []( const std::string& file ) { process_file_wrapper( file ); } );
210✔
790
    return;
2✔
791
  }
792
  std::atomic<unsigned> compiled_scripts( 0 );
×
793
  std::atomic<unsigned> uptodate_scripts( 0 );
×
794
  std::atomic<unsigned> error_scripts( 0 );
×
795
  std::atomic<bool> par_keep_building( true );
×
796
  {
797
    unsigned int thread_count = std::max( 2u, std::thread::hardware_concurrency() * 2 );
×
798
    if ( compilercfg.NumberOfThreads )
×
799
      thread_count = static_cast<unsigned>( compilercfg.NumberOfThreads );
×
800
    threadhelp::TaskThreadPool pool( thread_count, "ecompile" );
×
801
    summary.ThreadCount = pool.size();
×
802
    auto callback = [&]( const std::string& file )
×
803
    {
804
      pool.push(
×
805
          [&, file]()
×
806
          {
807
            if ( !par_keep_building || Clib::exit_signalled )
×
808
              return;
×
809
            try
810
            {
811
              if ( process_file( file ) )
×
812
                ++compiled_scripts;
×
813
              else
814
                ++uptodate_scripts;
×
815
            }
816
            catch ( std::exception& e )
×
817
            {
818
              ++compiled_scripts;
×
819
              ++error_scripts;
×
NEW
820
              ERROR_PRINTLN( "failed to compile {}: {}", file, e.what() );
×
821
              if ( !keep_building )
×
822
                par_keep_building = false;
×
823
            }
×
824
            catch ( ... )
×
825
            {
826
              par_keep_building = false;
×
827
              Clib::force_backtrace();
×
828
            }
×
829
          } );
830
    };
×
831
    recurse_call( dirs, compile_inc, callback );
×
832
  }
×
833
  summary.CompiledScripts = compiled_scripts;
×
834
  summary.UpToDateScripts = uptodate_scripts;
×
835
  summary.ScriptsWithCompileErrors = error_scripts;
×
836
}
837

838
void DisplaySummary( const Tools::Timer<>& timer )
7✔
839
{
840
  std::string tmp = "Compilation Summary:\n";
7✔
841
  if ( summary.ThreadCount )
7✔
842
    tmp += fmt::format( "    Used {} threads\n", summary.ThreadCount );
×
843
  if ( summary.CompiledScripts )
7✔
844
    tmp += fmt::format( "    Compiled {} script{} in {} ms.\n", summary.CompiledScripts,
7✔
845
                        ( summary.CompiledScripts == 1 ? "" : "s" ), timer.ellapsed() );
21✔
846

847
  if ( summary.ScriptsWithCompileErrors )
7✔
848
    tmp += fmt::format( "    {} of those script{} had errors.\n", summary.ScriptsWithCompileErrors,
1✔
849
                        ( summary.ScriptsWithCompileErrors == 1 ? "" : "s" ) );
3✔
850

851
  if ( summary.UpToDateScripts )
7✔
852
    tmp += fmt::format( "    {} script{} already up-to-date.\n", summary.UpToDateScripts,
×
853
                        ( summary.UpToDateScripts == 1 ? " was" : "s were" ) );
×
854

855
  if ( show_timing_details )
7✔
856
  {
857
    tmp += fmt::format( "    build workspace: {}\n",
×
858
                        (long long)summary.profile.build_workspace_micros / 1000 );
×
859
    tmp += fmt::format( "        - load *.em:   {}\n",
×
860
                        (long long)summary.profile.load_em_micros / 1000 );
×
861
    tmp += fmt::format( "       - parse *.em:   {} ({})\n",
×
862
                        (long long)summary.profile.parse_em_micros / 1000,
×
863
                        (long)summary.profile.parse_em_count );
×
864
    tmp += fmt::format( "         - ast *.em:   {}\n",
×
865
                        (long long)summary.profile.ast_em_micros / 1000 );
×
866
    tmp += fmt::format( "      - parse *.inc:   {} ({})\n",
×
867
                        (long long)summary.profile.parse_inc_micros / 1000,
×
868
                        (long)summary.profile.parse_inc_count );
×
869
    tmp += fmt::format( "        - ast *.inc:   {}\n",
×
870
                        (long long)summary.profile.ast_inc_micros / 1000 );
×
871
    tmp += fmt::format( "      - parse *.src:   {} ({})\n",
×
872
                        (long long)summary.profile.parse_src_micros / 1000,
×
873
                        (long)summary.profile.parse_src_count );
×
874
    tmp += fmt::format( "        - ast *.src:   {}\n",
×
875
                        (long long)summary.profile.ast_src_micros / 1000 );
×
876
    tmp += fmt::format( "  resolve functions:   {}\n",
×
877
                        (long long)summary.profile.ast_resolve_functions_micros / 1000 );
×
878
    tmp += fmt::format( " register constants: {}\n",
×
879
                        (long long)summary.profile.register_const_declarations_micros / 1000 );
×
880
    tmp += fmt::format( "            analyze: {}\n",
×
881
                        (long long)summary.profile.analyze_micros / 1000 );
×
882
    tmp += fmt::format( "           optimize: {}\n",
×
883
                        (long long)summary.profile.optimize_micros / 1000 );
×
884
    tmp += fmt::format( "       disambiguate: {}\n",
×
885
                        (long long)summary.profile.disambiguate_micros / 1000 );
×
886
    tmp += fmt::format( "      generate code: {}\n",
×
887
                        (long long)summary.profile.codegen_micros / 1000 );
×
888
    tmp += fmt::format( "  prune cache (sel): {}\n",
×
889
                        (long long)summary.profile.prune_cache_select_micros / 1000 );
×
890
    tmp += fmt::format( "  prune cache (del): {}\n",
×
891
                        (long long)summary.profile.prune_cache_delete_micros / 1000 );
×
892
    tmp += "\n";
×
893
    tmp += fmt::format( "      - ambiguities: {}\n", (long)summary.profile.ambiguities );
×
894
    tmp += fmt::format( "       - cache hits: {}\n", (long)summary.profile.cache_hits );
×
895
    tmp += fmt::format( "     - cache misses: {}\n", (long)summary.profile.cache_misses );
×
896
  }
897

898
  INFO_PRINTLN( tmp );
7✔
899
}
7✔
900

901
void EnterWatchMode()
1✔
902
{
903
  std::list<WatchFileMessage> watch_messages;
1✔
904
  std::set<fs::path> to_compile;
1✔
905
  efsw::FileWatcher fileWatcher;
1✔
906
  EfswFileWatchListener listener( fileWatcher,
907
                                  std::set<fs::path>{ ".src", ".hsr", ".asp", ".inc", ".em" } );
6✔
908

909
  auto handle_compile_file = [&]( const fs::path& filepath )
5✔
910
  {
911
    // Existing file, compile all owners dependent on it.
912
    if ( auto itr = dependency_owners.find( filepath ); itr != dependency_owners.end() )
5✔
913
    {
914
      to_compile.insert( itr->second.begin(), itr->second.end() );
4✔
915
    }
916
    // New file, compile only this file (if it is compilable).
917
    else
918
    {
919
      auto ext = filepath.extension();
1✔
920
      if ( ext.compare( ".src" ) == 0 || ext.compare( ".hsr" ) == 0 || ext.compare( ".asp" ) == 0 )
1✔
921
      {
922
        to_compile.emplace( filepath );
1✔
923
      }
924
    }
1✔
925
  };
5✔
926

927
  auto handle_delete_file = [&]( const fs::path& filepath )
1✔
928
  {
929
    to_compile.erase( filepath );
1✔
930
    if ( auto itr = owner_dependencies.find( filepath ); itr != owner_dependencies.end() )
1✔
931
    {
932
      // For all dependencies, remove the deleted file from set of owners for
933
      // that dependency.
934
      for ( const auto& depnamepath : itr->second )
4✔
935
      {
936
        // If dependency exists in map of dependency -> owners
937
        if ( auto owners_itr = dependency_owners.find( depnamepath );
3✔
938
             owners_itr != dependency_owners.end() )
3✔
939
        {
940
          // Erase filepath from set of owners
941
          owners_itr->second.erase( filepath );
3✔
942

943
          // If owners set is empty, this dependency is no longer used by
944
          // anything.
945
          if ( owners_itr->second.empty() )
3✔
946
          {
947
            //  Erase from map of dependency -> owners.
948
            dependency_owners.erase( owners_itr );
1✔
949
            listener.remove_file( depnamepath );
1✔
950
            VERBOSE_PRINTLN( "Remove watch file {}", depnamepath );
1✔
951
          }
952
        }
953
      }
954
      owner_dependencies.erase( itr );
1✔
955
    }
956
  };
1✔
957

958
  auto add_dir = [&]( const std::string& elem )
4✔
959
  {
960
    fs::path dir( elem );
4✔
961
    if ( fs::exists( dir ) )
4✔
962
    {
963
      auto dirpath = fs::canonical( dir );
4✔
964
      if ( listener.add_watch_dir( dirpath ) )
4✔
965
      {
966
        VERBOSE_PRINTLN( "Add watch dir {}", dirpath );
4✔
967
      }
968
    }
4✔
969
  };
4✔
970

971
  for ( const auto& dep_owners : dependency_owners )
126✔
972
  {
973
    listener.add_file( dep_owners.first );
125✔
974
  }
975

976
  for ( const auto& directory : compiled_dirs )
4✔
977
  {
978
    listener.add_dir( directory );
3✔
979
  }
980

981
  for ( const auto& elem : compilercfg.PackageRoot )
2✔
982
  {
983
    add_dir( elem );
1✔
984
  }
985

986
  add_dir( compilercfg.ModuleDirectory );
1✔
987
  add_dir( compilercfg.IncludeDirectory );
1✔
988
  add_dir( compilercfg.PolScriptRoot );
1✔
989

990
  fileWatcher.watch();
1✔
991

992
  INFO_PRINTLN( "Entering watch mode. Watching {} files and {} directories. Ctrl-C to stop...",
1✔
993
                dependency_owners.size(), compiled_dirs.size() );
1✔
994

995
  while ( !Clib::exit_signalled )
8✔
996
  {
997
    std::this_thread::sleep_for( std::chrono::seconds( 1 ) );
6✔
998
    listener.take_messages( watch_messages );
6✔
999
    if ( !watch_messages.empty() )
6✔
1000
    {
1001
      for ( auto const& message : watch_messages )
11✔
1002
      {
1003
        const auto& filepath = message.filepath;
6✔
1004
        const auto& old_filepath = message.old_filepath;
6✔
1005
        VERBOSE_PRINTLN( "Event: filename={}, old_filename={}", filepath, old_filepath );
6✔
1006

1007
        // created or modified
1008
        if ( old_filepath.empty() )
6✔
1009
        {
1010
          handle_compile_file( filepath );
5✔
1011
        }
1012
        // deleted
1013
        else if ( filepath.empty() )
1✔
1014
        {
1015
          handle_delete_file( old_filepath );
1✔
1016
        }
1017
        // moved
1018
        else
1019
        {
1020
          handle_delete_file( old_filepath );
×
1021
          handle_compile_file( filepath );
×
1022
        }
1023
      }
1024
      watch_messages.clear();
5✔
1025

1026
      if ( !to_compile.empty() )
5✔
1027
      {
1028
        summary.CompiledScripts = 0;
5✔
1029
        summary.UpToDateScripts = 0;
5✔
1030
        summary.ScriptsWithCompileErrors = 0;
5✔
1031
        em_parse_tree_cache.clear();
5✔
1032
        inc_parse_tree_cache.clear();
5✔
1033

1034
        VERBOSE_PRINTLN( "To compile: {}", to_compile );
5✔
1035

1036
        Tools::Timer<> timer;
5✔
1037
        for ( const auto& filepath : to_compile )
19✔
1038
        {
1039
          if ( Clib::exit_signalled )
14✔
1040
          {
1041
            break;
×
1042
          }
1043

1044
          std::set<fs::path> removed_dependencies;
14✔
1045
          std::set<fs::path> new_dependencies;
14✔
1046
          try
1047
          {
1048
            process_file_wrapper( filepath.generic_string(), &removed_dependencies,
14✔
1049
                                  &new_dependencies );
1050
          }
1051
          catch ( ... )
×
1052
          {
1053
          }
×
1054

1055
          VERBOSE_PRINTLN( "New dependencies: {} Removed dependencies: {}", new_dependencies,
14✔
1056
                           removed_dependencies );
1057

1058
          for ( const auto& depnamepath : removed_dependencies )
14✔
1059
          {
1060
            // If a removed dependency has no owner set is empty, we can remove
1061
            // the listener for that dependency.
1062
            if ( dependency_owners.find( depnamepath ) == dependency_owners.end() )
×
1063
            {
1064
              if ( listener.remove_file( depnamepath ) )
×
1065
              {
1066
                VERBOSE_PRINTLN( "Remove watch file {}", depnamepath );
×
1067
              }
1068
            }
1069
          }
1070

1071
          for ( const auto& depnamepath : new_dependencies )
17✔
1072
          {
1073
            if ( listener.add_file( depnamepath ) )
3✔
1074
            {
1075
              VERBOSE_PRINTLN( "Add watch file {}", depnamepath );
1✔
1076
            }
1077
          }
1078
        }
14✔
1079

1080
        timer.stop();
5✔
1081
        if ( compilercfg.DisplaySummary && !quiet )
5✔
1082
        {
1083
          DisplaySummary( timer );
5✔
1084
        }
1085
        to_compile.clear();
5✔
1086
      }
5✔
1087
    }
1088
  }
1089
}
2✔
1090

1091
/**
1092
 * Runs the compilation threads
1093
 */
1094
void AutoCompile()
2✔
1095
{
1096
  bool save = compilercfg.OnlyCompileUpdatedScripts;
2✔
1097
  compilercfg.OnlyCompileUpdatedScripts = compilercfg.UpdateOnlyOnAutoCompile;
2✔
1098
  std::vector<fs::path> dirs;
2✔
1099
  compiled_dirs.emplace( fs::canonical( compilercfg.PolScriptRoot ) );
2✔
1100

1101
  dirs.emplace_back( compilercfg.PolScriptRoot );
2✔
1102
  for ( const auto& pkg : Plib::systemstate.packages )
6✔
1103
  {
1104
    compiled_dirs.emplace( fs::canonical( pkg->dir() ) );
4✔
1105
    dirs.emplace_back( pkg->dir() );
4✔
1106
  }
1107
  process_dirs( dirs, false );
2✔
1108
  compilercfg.OnlyCompileUpdatedScripts = save;
2✔
1109
}
2✔
1110

1111
/**
1112
 * Takes decisions, runs, the compilation, prints summary and cleans after
1113
 */
1114
bool run( int argc, char** argv, int* res )
1,976✔
1115
{
1116
  Clib::enable_exit_signaller();
1,976✔
1117

1118
  load_packages();
1,976✔
1119

1120
  // Determine the run mode and do the compile itself
1121
  Tools::Timer<> timer;
1,976✔
1122
  bool any = false;
1,976✔
1123

1124
  for ( int i = 1; i < argc; i++ )
9,635✔
1125
  {
1126
#ifdef __linux__
1127
    if ( argv[i][0] == '-' )
7,901✔
1128
#else
1129
    if ( argv[i][0] == '/' || argv[i][0] == '-' )
1130
#endif
1131
    {
1132
      if ( argv[i][1] == 'A' )
5,927✔
1133
      {
1134
        compilercfg.UpdateOnlyOnAutoCompile = ( argv[i][2] == 'u' );
2✔
1135
        any = true;
2✔
1136

1137
        AutoCompile();
2✔
1138
      }
1139
      else if ( argv[i][1] == 'r' )
5,925✔
1140
      {
1141
        any = true;
×
1142
        std::string dir( "." );
×
1143
        bool compile_inc = ( argv[i][2] == 'i' );  // compile .inc files
×
1144

1145
        ++i;
×
1146
        if ( i < argc && argv[i] && argv[i][0] != '-' )
×
1147
          dir.assign( argv[i] );
×
1148

1149
        compiled_dirs.emplace( fs::canonical( dir ) );
×
1150
        process_dirs( { dir }, compile_inc );
×
1151
      }
×
1152
      else if ( argv[i][1] == 'C' )
5,925✔
1153
      {
1154
        ++i;  // skip the config file pathname
1,974✔
1155
      }
1156
      // and skip any other option.
1157
    }
1158
    else
1159
    {
1160
      any = true;
1,974✔
1161
#ifdef _WIN32
1162
      Clib::forspec( argv[i], []( const char* pathname ) { process_file_wrapper( pathname ); } );
1163
#else
1164
      process_file_wrapper( argv[i] );
2,458✔
1165
#endif
1166
    }
1167
  }
1168

1169
  if ( !any && compilercfg.AutoCompileByDefault )
1,734✔
1170
  {
1171
    any = true;
×
1172
    AutoCompile();
×
1173
  }
1174

1175
  // Execution is completed: start final/cleanup tasks
1176
  timer.stop();
1,734✔
1177

1178
  if ( any && compilercfg.DisplaySummary && !quiet )
1,734✔
1179
  {
1180
    DisplaySummary( timer );
2✔
1181
  }
1182

1183
  if ( watch_source )
1,734✔
1184
  {
1185
    EnterWatchMode();
1✔
1186
  }
1187

1188
  Plib::systemstate.deinitialize();
1,734✔
1189

1190
  if ( summary.ScriptsWithCompileErrors )
1,734✔
1191
    *res = 1;
×
1192
  else
1193
    *res = 0;
1,734✔
1194
  return any;
1,734✔
1195
}
1,976✔
1196

1197
void read_config_file( int argc, char* argv[] )
1,976✔
1198
{
1199
  for ( int i = 1; i < argc; i++ )
5,929✔
1200
  {
1201
    if ( argv[i][0] == '/' || argv[i][0] == '-' )
5,927✔
1202
    {
1203
      // -C cfgpath
1204
      if ( argv[i][1] == 'C' )
5,927✔
1205
      {
1206
        ++i;
1,974✔
1207
        if ( i == argc )
1,974✔
1208
          throw std::runtime_error( "-C specified without pathname" );
×
1209

1210
        compilercfg.Read( std::string( argv[i] ) );
1,974✔
1211
        return;
1,974✔
1212
      }
1213
    }
1214
  }
1215

1216
  // check ECOMPILE_CFG_PATH environment variable
1217
  const char* env_ecompile_cfg_path = getenv( "ECOMPILE_CFG_PATH" );
2✔
1218
  if ( env_ecompile_cfg_path != nullptr )
2✔
1219
  {
1220
    compilercfg.Read( std::string( env_ecompile_cfg_path ) );
×
1221
    return;
×
1222
  }
1223

1224
  // no -C arg, so use binary path (hope it's right..sigh.)
1225
  std::string cfgpath = PROG_CONFIG::programDir() + "ecompile.cfg";
2✔
1226
  if ( Clib::FileExists( "ecompile.cfg" ) )
2✔
1227
  {
1228
    compilercfg.Read( "ecompile.cfg" );
2✔
1229
  }
1230
  else if ( Clib::FileExists( cfgpath ) )
×
1231
  {
1232
    compilercfg.Read( cfgpath );
×
1233
  }
1234
  else
1235
  {
1236
    ERROR_PRINTLN( "Could not find {}; using defaults.", cfgpath );
×
1237
    compilercfg.SetDefaults();
×
1238
  }
1239
}
2✔
1240

1241
/**
1242
 * This is the main entry point for ecompile program
1243
 */
1244
int ECompileMain::main()
1,976✔
1245
{
1246
  Clib::Logging::global_logger->disableFileLog();
1,976✔
1247

1248
  const std::vector<std::string>& binArgs = programArgs();
1,976✔
1249

1250
/**********************************************
1251
 * TODO: rework the following cruft from former uotool.cpp
1252
 **********************************************/
1253
#ifdef _WIN32
1254
  Clib::MiniDumper::Initialize();
1255
#endif
1256

1257
  ECompile::read_config_file( s_argc, s_argv );
1,976✔
1258

1259
  /**********************************************
1260
   * show help
1261
   **********************************************/
1262
  if ( binArgs.size() == 1 && !compilercfg.AutoCompileByDefault )
1,976✔
1263
  {
1264
    showHelp();
×
1265
    return 0;  // return "okay"
×
1266
  }
1267

1268
  watch_source = compilercfg.WatchModeByDefault;
1,976✔
1269
  if ( watch_source )
1,976✔
1270
  {
1271
    compilercfg.GenerateDependencyInfo = true;
×
1272
    keep_building = true;
×
1273
    compilercfg.ThreadedCompilation =
×
1274
        false;  // limitation since dependency gathering is not thread-safe
1275
  }
1276

1277
  int res = ECompile::readargs( s_argc, s_argv );
1,976✔
1278
  if ( res )
1,976✔
1279
  {
1280
    showHelp();
×
1281
    return res;
×
1282
  }
1283

1284
  ECompile::apply_configuration();
1,976✔
1285

1286
  if ( !ECompile::quiet )
1,976✔
1287
  {
1288
    // vX.YY
1289
    INFO_PRINTLN( "EScript Compiler v1.{}\n{}\n", ESCRIPT_FILE_VER_CURRENT, POL_COPYRIGHT );
2✔
1290
  }
1291

1292
  int prog_res = 1;
1,976✔
1293
  bool didanything = ECompile::run( s_argc, s_argv, &prog_res );
1,976✔
1294

1295
  if ( !didanything )
1,734✔
1296
  {
1297
    showHelp();
×
1298
    return 1;
×
1299
  }
1300
  return prog_res;
1,734✔
1301
}
1302
}  // namespace ECompile
1303
}  // namespace Pol
1304

1305
///////////////////////////////////////////////////////////////////////////////
1306
///////////////////////////////////////////////////////////////////////////////
1307
///////////////////////////////////////////////////////////////////////////////
1308

1309
int main( int argc, char* argv[] )
1,976✔
1310
{
1311
  Pol::ECompile::s_argc = argc;
1,976✔
1312
  Pol::ECompile::s_argv = argv;
1,976✔
1313

1314
  Pol::ECompile::ECompileMain* ECompileMain = new Pol::ECompile::ECompileMain();
1,976✔
1315
  ECompileMain->start( argc, argv );
1,976✔
1316
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc