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

polserver / polserver / 21047054485

15 Jan 2026 09:31PM UTC coverage: 60.507% (-0.001%) from 60.508%
21047054485

push

github

web-flow
Clang Tidy default constructor  (#852)

* trigger clang tidy

* Automated clang-tidy change: modernize-use-equals-default

* compile test

---------

Co-authored-by: Clang Tidy <clang-tidy@users.noreply.github.com>

58 of 75 new or added lines in 41 files covered. (77.33%)

1 existing line in 1 file now uncovered.

44460 of 73479 relevant lines covered (60.51%)

507363.1 hits per line

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

62.31
/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/clib.h"
26
#include "clib/esignal.h"
27
#include "clib/fileutil.h"
28
#include "clib/logfacility.h"
29
#include "clib/mdump.h"
30
#include "clib/passert.h"
31
#include "clib/threadhelp.h"
32
#include "clib/timer.h"
33
#include "plib/pkg.h"
34
#include "plib/systemstate.h"
35

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

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

49
///////////////////////////////////////////////////////////////////////////////
50

51

52
///////////////////////////////////////////////////////////////////////////////
53

54
ECompileMain::ECompileMain() : Pol::Clib::ProgramMain() {}
2,956✔
NEW
55
ECompileMain::~ECompileMain() = default;
×
56
///////////////////////////////////////////////////////////////////////////////
57

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

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

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

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

137
Compiler::SourceFileCache em_parse_tree_cache( summary.profile );
138
Compiler::SourceFileCache inc_parse_tree_cache( summary.profile );
139

140
using DependencyInfo = std::map<fs::path, std::set<fs::path>>;
141
// Map owner (sources) -> dependencies
142
DependencyInfo owner_dependencies;
143
// Map dependency -> owners (sources)
144
DependencyInfo dependency_owners;
145

146
std::set<fs::path> compiled_dirs;
147

148
std::unique_ptr<Compiler::Compiler> create_compiler()
3,208✔
149
{
150
  auto compiler = std::make_unique<Compiler::Compiler>( em_parse_tree_cache, inc_parse_tree_cache,
151
                                                        summary.profile );
3,208✔
152
  return compiler;
3,208✔
153
}
154

155
void load_packages()
2,956✔
156
{
157
  // No need to load packages if only formatting sources
158
  if ( !format_source )
2,956✔
159
  {
160
    // Load and analyze the package structure
161
    for ( const auto& elem : compilercfg.PackageRoot )
4,592✔
162
    {
163
      Plib::load_packages( elem, true /* quiet */ );
2,296✔
164
    }
165
    Plib::replace_packages();
2,296✔
166
    Plib::check_package_deps();
2,296✔
167
  }
168
}
2,956✔
169

170
void compile_inc( const std::string& path )
×
171
{
172
  if ( !quiet )
×
173
    INFO_PRINTLN( "Compiling: {}", path );
×
174

175
  std::unique_ptr<Compiler::Compiler> compiler = create_compiler();
×
176

177
  compiler->set_include_compile_mode();
×
178
  bool res = compiler->compile_file( path );
×
179

180
  if ( !res )
×
181
    throw std::runtime_error( "Error compiling file" );
×
182
}
×
183

184
bool format_file( const std::string& path )
660✔
185
{
186
  std::string ext( "" );
660✔
187

188
  std::string::size_type pos = path.rfind( '.' );
660✔
189
  if ( pos != std::string::npos )
660✔
190
    ext = path.substr( pos );
660✔
191

192
  if ( ext.compare( ".src" ) != 0 && ext.compare( ".inc" ) != 0 && ext.compare( ".em" ) != 0 )
660✔
193
  {
194
    ERROR_PRINTLN(
×
195
        "Didn't find '.src', '.inc', or '.em' extension on source filename '{}'! ..Ignoring",
196
        path );
197
    return true;
×
198
  }
199

200
  if ( !quiet )
660✔
201
    INFO_PRINTLN( "Formatting: {}", path );
×
202

203
  std::unique_ptr<Compiler::Compiler> compiler = create_compiler();
660✔
204

205
  bool success =
206
      compiler->format_file( path.c_str(), ext.compare( ".em" ) == 0, format_source_inplace );
660✔
207

208
  if ( expect_compile_failure )
660✔
209
  {
210
    if ( !success )  // good, it failed
×
211
    {
212
      if ( !quiet )
×
213
        INFO_PRINTLN( "Formatting failed as expected." );
×
214
      return true;
×
215
    }
216
    else
217
    {
218
      throw std::runtime_error( "Formatting succeeded (-e indicates failure was expected)" );
×
219
    }
220
  }
221

222
  if ( !success )
660✔
223
    throw std::runtime_error( "Error formatting file" );
×
224
  return true;
660✔
225
}
660✔
226

227
void add_dependency_info( const fs::path& filepath_src,
134✔
228
                          std::set<fs::path>* removed_dependencies = nullptr,
229
                          std::set<fs::path>* new_dependencies = nullptr )
230
{
231
  auto filename_dep = fs::path( filepath_src ).replace_extension( ".dep" );
134✔
232

233
  auto& dependencies = owner_dependencies[filepath_src];
134✔
234
  auto previous_dependencies = dependencies;
134✔
235

236
  VERBOSE_PRINTLN( "Dependencies for: {}", filepath_src );
134✔
237
  for ( const auto& dependency : previous_dependencies )
246✔
238
  {
239
    if ( auto itr = dependency_owners.find( dependency ); itr != dependency_owners.end() )
112✔
240
    {
241
      // Remove deleted file from owners
242
      itr->second.erase( filepath_src );
112✔
243
      auto remaining = itr->second.size();
112✔
244
      VERBOSE_PRINTLN( "  - Removed {}, remaining owners={}", dependency, remaining );
112✔
245
      if ( remaining == 0 )
112✔
246
      {
247
        dependency_owners.erase( itr );
13✔
248
      }
249
    }
250
  }
251

252
  dependencies.clear();
134✔
253

254
  {
255
    std::ifstream ifs( filename_dep.c_str() );
134✔
256
    if ( ifs.is_open() )
134✔
257
    {
258
      std::string depname;
134✔
259
      while ( getline( ifs, depname ) )
1,102✔
260
      {
261
        fs::path depnamepath = fs::canonical( fs::path( depname ) );
968✔
262
        auto& owners = dependency_owners[depnamepath];
968✔
263
        // Add this source as a dependency by:
264
        // (1) placing `filename_src` in the set of owners for `depnamepath`.
265
        owners.emplace( filepath_src );
968✔
266
        // (2) placing `depnamepath` in the set of dependencies for this `filename_src`.
267
        dependencies.emplace( depnamepath );
968✔
268
        VERBOSE_PRINTLN( "  - Added {}, owners={}", depnamepath, owners.size() );
968✔
269
      }
968✔
270
    }
134✔
271

272
    // Could not load dependency information -- maybe failed compilation? We
273
    // still add this source as a dependency of itself, such that it will be
274
    // recompiled on next save.
275
    //
276
    // On failed compilation, the existing `.dep`
277
    // remains, so we will use that information for recompilation (eg. a source
278
    // failed to compile due to a bad include, changing the include should still
279
    // recompile the source.)
280
    else
281
    {
282
      dependency_owners[filepath_src] = std::set<fs::path>{ filepath_src };
×
283
      dependencies.emplace( filepath_src );
×
284
    }
285
  }
134✔
286

287
  if ( removed_dependencies && new_dependencies )
134✔
288
  {
289
    std::set_difference( previous_dependencies.begin(), previous_dependencies.end(),
14✔
290
                         dependencies.begin(), dependencies.end(),
291
                         std::inserter( *removed_dependencies, removed_dependencies->begin() ) );
292

293

294
    std::set_difference( dependencies.begin(), dependencies.end(), previous_dependencies.begin(),
14✔
295
                         previous_dependencies.end(),
296
                         std::inserter( *new_dependencies, new_dependencies->begin() ) );
297
  }
298
}
134✔
299

300
/**
301
 * Compiles the single given file (inc, src, hsr, asp), if needed
302
 *
303
 * Takes into account compilercfg.OnlyCompileUpdatedScripts and force_update
304
 *
305
 * @param path path of the file to be compiled
306
 * @return TRUE if the file was compiled, FALSE otherwise (eg. the file is up-to-date)
307
 */
308
bool compile_file( const std::string& path )
2,548✔
309
{
310
  std::string ext( "" );
2,548✔
311

312
  std::string::size_type pos = path.rfind( '.' );
2,548✔
313
  if ( pos != std::string::npos )
2,548✔
314
    ext = path.substr( pos );
2,548✔
315

316
  if ( !ext.compare( ".inc" ) )
2,548✔
317
  {
318
    compile_inc( path );
×
319
    return true;
×
320
  }
321

322
  if ( ext.compare( ".src" ) != 0 && ext.compare( ".hsr" ) != 0 && ext.compare( ".asp" ) != 0 )
2,548✔
323
  {
324
    ERROR_PRINTLN( "Didn't find '.src', '.hsr', or '.asp' extension on source filename '{}'!",
×
325
                   path );
326
    throw std::runtime_error( "Error in source filename" );
×
327
  }
328
  std::string fname = path;
2,548✔
329
  std::string filename_ecl = fname.replace( pos, 4, ".ecl" );
2,548✔
330
  std::string filename_lst = fname.replace( pos, 4, ".lst" );
2,548✔
331
  std::string filename_ast = fname.replace( pos, 4, ".ast" );
2,548✔
332
  std::string filename_dep = fname.replace( pos, 4, ".dep" );
2,548✔
333
  std::string filename_dbg = fname.replace( pos, 4, ".dbg" );
2,548✔
334

335
  if ( compilercfg.OnlyCompileUpdatedScripts && !force_update )
2,548✔
336
  {
337
    bool all_old = true;
2,428✔
338
    unsigned int ecl_timestamp = Clib::GetFileTimestamp( filename_ecl.c_str() );
2,428✔
339
    if ( Clib::GetFileTimestamp( path.c_str() ) >= ecl_timestamp )
2,428✔
340
    {
341
      if ( compilercfg.VerbosityLevel > 0 )
2,415✔
342
        INFO_PRINTLN( "{} is newer than {}", path, filename_ecl );
121✔
343
      all_old = false;
2,415✔
344
    }
345

346
    if ( all_old )
2,428✔
347
    {
348
      std::ifstream ifs( filename_dep.c_str() );
13✔
349
      // if the file doesn't exist, gotta build.
350
      if ( ifs.is_open() )
13✔
351
      {
352
        std::string depname;
12✔
353
        while ( getline( ifs, depname ) )
108✔
354
        {
355
          if ( Clib::GetFileTimestamp( depname.c_str() ) >= ecl_timestamp )
108✔
356
          {
357
            if ( compilercfg.VerbosityLevel > 0 )
12✔
358
              INFO_PRINTLN( "{} is newer than {}", depname, filename_ecl );
12✔
359
            all_old = false;
12✔
360
            break;
12✔
361
          }
362
        }
363
      }
12✔
364
      else
365
      {
366
        if ( compilercfg.VerbosityLevel > 0 )
1✔
367
          INFO_PRINTLN( "{} does not exist.", filename_dep );
1✔
368
        all_old = false;
1✔
369
      }
370
    }
13✔
371
    if ( all_old )
2,428✔
372
    {
373
      if ( !quiet && compilercfg.DisplayUpToDateScripts )
×
374
        INFO_PRINTLN( "{} is up-to-date.", filename_ecl );
×
375
      return false;
×
376
    }
377
  }
378

379

380
  {
381
    if ( !quiet )
2,548✔
382
      INFO_PRINTLN( "Compiling: {}", path );
2,548✔
383

384
    std::unique_ptr<Compiler::Compiler> compiler = create_compiler();
2,548✔
385

386
    bool success = compiler->compile_file( path.c_str() );
2,548✔
387

388
    em_parse_tree_cache.keep_some();
2,548✔
389
    inc_parse_tree_cache.keep_some();
2,548✔
390

391
    if ( expect_compile_failure )
2,548✔
392
    {
393
      if ( !success )  // good, it failed
×
394
      {
395
        if ( !quiet )
×
396
          INFO_PRINTLN( "Compilation failed as expected." );
×
397
        return true;
×
398
      }
399
      else
400
      {
401
        throw std::runtime_error( "Compilation succeeded (-e indicates failure was expected)" );
×
402
      }
403
    }
404

405
    if ( !success )
2,548✔
406
      throw std::runtime_error( "Error compiling file" );
313✔
407

408

409
    if ( !quiet )
2,235✔
410
      INFO_PRINTLN( "Writing:   {}", filename_ecl );
2,235✔
411

412
    if ( !compiler->write_ecl( filename_ecl ) )
2,235✔
413
    {
414
      throw std::runtime_error( "Error writing output file" );
×
415
    }
416

417
    if ( compilercfg.GenerateListing )
2,235✔
418
    {
419
      if ( !quiet )
1,985✔
420
        INFO_PRINTLN( "Writing:   {}", filename_lst );
1,985✔
421
      compiler->write_listing( filename_lst );
1,985✔
422
    }
423
    else if ( Clib::FileExists( filename_lst.c_str() ) )
250✔
424
    {
425
      if ( !quiet )
×
426
        INFO_PRINTLN( "Deleting:  {}", filename_lst );
×
427
      Clib::RemoveFile( filename_lst );
×
428
    }
429

430
    if ( compilercfg.GenerateAbstractSyntaxTree )
2,235✔
431
    {
432
      if ( !quiet )
8✔
433
        INFO_PRINTLN( "Writing:   {}", filename_ast );
8✔
434
      compiler->write_string_tree( filename_ast );
8✔
435
    }
436
    else if ( Clib::FileExists( filename_ast.c_str() ) )
2,227✔
437
    {
438
      if ( !quiet )
×
439
        INFO_PRINTLN( "Deleting:  {}", filename_ast );
×
440
      Clib::RemoveFile( filename_ast );
×
441
    }
442

443
    if ( compilercfg.GenerateDebugInfo )
2,235✔
444
    {
445
      if ( !quiet )
2,105✔
446
      {
447
        INFO_PRINTLN( "Writing:   {}", filename_dbg );
2,105✔
448
        if ( compilercfg.GenerateDebugTextInfo )
2,105✔
449
          INFO_PRINTLN( "Writing:   {}.txt", filename_dbg );
×
450
      }
451
      compiler->write_dbg( filename_dbg, compilercfg.GenerateDebugTextInfo );
2,105✔
452
    }
453
    else if ( Clib::FileExists( filename_dbg.c_str() ) )
130✔
454
    {
455
      if ( !quiet )
120✔
456
        INFO_PRINTLN( "Deleting:  {}", filename_dbg );
120✔
457
      Clib::RemoveFile( filename_dbg );
120✔
458
    }
459

460
    if ( compilercfg.GenerateDependencyInfo )
2,235✔
461
    {
462
      if ( !quiet )
130✔
463
        INFO_PRINTLN( "Writing:   {}", filename_dep );
130✔
464
      compiler->write_included_filenames( filename_dep );
130✔
465
    }
466
    else if ( Clib::FileExists( filename_dep.c_str() ) )
2,105✔
467
    {
468
      if ( !quiet )
×
469
        INFO_PRINTLN( "Deleting:  {}", filename_dep );
×
470
      Clib::RemoveFile( filename_dep );
×
471
    }
472
  }
2,548✔
473
  return true;
2,235✔
474
}
4,426✔
475

476
bool process_file( const std::string& path )
3,208✔
477
{
478
  if ( format_source )
3,208✔
479
    return format_file( path );
660✔
480
  return compile_file( path );
2,548✔
481
}
482

483
void process_file_wrapper( const std::string& path,
3,208✔
484
                           std::set<fs::path>* removed_dependencies = nullptr,
485
                           std::set<fs::path>* new_dependencies = nullptr )
486
{
487
  try
488
  {
489
    if ( process_file( path ) )
3,208✔
490
      ++summary.CompiledScripts;
2,895✔
491
    else
492
      ++summary.UpToDateScripts;
×
493
  }
494
  catch ( std::exception& )
313✔
495
  {
496
    ++summary.CompiledScripts;
313✔
497
    ++summary.ScriptsWithCompileErrors;
313✔
498
    if ( !keep_building )
313✔
499
      throw;
309✔
500
  }
313✔
501

502
  if ( watch_source )
2,899✔
503
  {
504
    fs::path filepath = fs::canonical( fs::path( path ) );
134✔
505
    auto ext = filepath.extension().generic_string();
134✔
506
    if ( ext.compare( ".src" ) == 0 || ext.compare( ".hsr" ) == 0 || ext.compare( ".asp" ) == 0 )
134✔
507
    {
508
      add_dependency_info( filepath, removed_dependencies, new_dependencies );
134✔
509
    }
510
  }
134✔
511
}
2,899✔
512

513
bool setting_value( const char* arg )
3,120✔
514
{
515
  // format of arg is -C or -C-
516
  if ( arg[2] == '\0' )
3,120✔
517
    return true;
3,120✔
518
  else if ( arg[2] == '-' )
×
519
    return false;
×
520
  else if ( arg[2] == '+' )
×
521
    return true;
×
522
  else
523
    return true;
×
524
}
525

526

527
int readargs( int argc, char** argv )
2,956✔
528
{
529
  bool unknown_opt = false;
2,956✔
530

531
  for ( int i = 1; i < argc; i++ )
13,308✔
532
  {
533
    const char* arg = argv[i];
10,352✔
534
#ifdef __linux__
535
    if ( arg[0] == '-' )
10,352✔
536
#else
537
    if ( arg[0] == '/' || arg[0] == '-' )
538
#endif
539
    {
540
      switch ( arg[1] )
7,398✔
541
      {
542
      case 'W':
1✔
543
        watch_source = true;
1✔
544
        compilercfg.GenerateDependencyInfo = true;
1✔
545
        keep_building = true;
1✔
546
        compilercfg.ThreadedCompilation =
1✔
547
            false;  // limitation since dependency gathering is not thread-safe
548
        break;
1✔
549

550
      case 'A':  // skip it at this point.
2✔
551
        break;
2✔
552

553
      case 'c':
×
554
        compilercfg.ErrorOnFileCaseMissmatch = setting_value( arg );
×
555
        break;
×
556

557
      case 'C':  // skip it at this point.
2,954✔
558
        ++i;     // and skip its parameter.
2,954✔
559
        break;
2,954✔
560

561
      case 'd':
×
562
        compilercfg.DisplayDebugs = setting_value( arg );
×
563
        break;
×
564

565
      case 'D':
×
566
        compilercfg.GenerateDependencyInfo = setting_value( arg );
×
567
        break;
×
568

569
      case 'e':
×
570
        expect_compile_failure = true;
×
571
        break;
×
572

573
#ifdef WIN32
574
      case 'E':
575
      {
576
        std::string path = &argv[i][2];
577
        CfgPathEnv = "ECOMPILE_CFG_PATH=" + path;
578
        _putenv( CfgPathEnv.c_str() );
579
      }
580
      break;
581
#endif
582

583
      case 'g':
×
584
      {
585
        auto value = setting_value( arg );
×
586
        if ( !value )
×
587
        {
588
          INFO_PRINTLN( "The OG Compiler has been removed." );
×
589
          unknown_opt = true;
×
590
        }
591
        break;
×
592
      }
593

594
      case 'q':
660✔
595
        quiet = true;
660✔
596
        break;
660✔
597

598
      case 'w':
×
599
        compilercfg.DisplayWarnings = setting_value( arg );
×
600
        if ( argv[i][2] == 'P' )
×
601
          compilercfg.ParanoiaWarnings = true;
×
602
        break;
×
603
      case 'y':
×
604
        compilercfg.ErrorOnWarning = setting_value( arg );
×
605
        break;
×
606

607
      case 'l':
2,294✔
608
        compilercfg.GenerateListing = setting_value( arg );
2,294✔
609
        break;
2,294✔
610

611
      case 'i':
×
612
        include_debug = 1;
×
613
        break;
×
614

615
      case 'r':  // -r[i] [dir] is okay
×
616
        // Only suboption allowed is '-ri' (.inc recurse)
617
        if ( argv[i][2] && argv[i][2] != 'i' )
×
618
        {
619
          // BZZZZT! *error*
620
          unknown_opt = true;
×
621
          break;
×
622
        }
623

624
// Only skip next parameter if it's not an option!!
625
#ifdef __linux__
626
        if ( i + 1 < argc && argv[i + 1][0] != '-' )
×
627
#else
628
        if ( i + 1 < argc && argv[i + 1][0] != '/' && argv[i + 1][0] != '-' )
629
#endif
630
          ++i;
×
631
        break;
×
632

633
      case 't':
×
634
        show_timing_details = true;
×
635
        if ( argv[i][2] == 'v' )
×
636
          timing_quiet_override = true;
×
637
        break;
×
638

639
      case 's':
×
640
        // show_source = true;
641
        compilercfg.DisplaySummary = true;
×
642
        break;
×
643

644
      case 'a':
×
645
        compilercfg.CompileAspPages = setting_value( arg );
×
646
        break;
×
647

648
      case 'm':
×
649
        compilercfg.OptimizeObjectMembers = false;
×
650
        break;
×
651

652
      case 'b':
×
653
        keep_building = true;
×
654
        break;
×
655

656
      case 'u':
×
657
        compilercfg.OnlyCompileUpdatedScripts = setting_value( arg );
×
658
        if ( compilercfg.OnlyCompileUpdatedScripts )
×
659
          compilercfg.GenerateDependencyInfo = true;
×
660
        break;
×
661

662
      case 'F':
660✔
663
      {
664
        if ( argv[i][2] && argv[i][2] == 'i' )
660✔
665
          format_source_inplace = true;
660✔
666
        format_source = true;
660✔
667
        break;
660✔
668
      }
669

670
      case 'f':
×
671
        force_update = true;
×
672
        break;
×
673

674
      case 'v':
1✔
675
        int vlev;
676
        vlev = atoi( &argv[i][2] );
1✔
677
        if ( !vlev )
1✔
678
          vlev = 1;
1✔
679
        compilercfg.VerbosityLevel = vlev;
1✔
680
        break;
1✔
681

682
      case 'x':
1✔
683
        compilercfg.GenerateDebugInfo = setting_value( arg );
1✔
684
        compilercfg.GenerateDebugTextInfo = ( argv[i][2] == 't' );
1✔
685
        break;
1✔
686

687
      case 'Z':
8✔
688
        compilercfg.GenerateAbstractSyntaxTree = setting_value( arg );
8✔
689
        break;
8✔
690

691
#ifdef WIN32
692
      case 'P':
693
      {
694
        std::string path = &argv[i][2];
695
        EmPathEnv = "ECOMPILE_PATH_EM=" + path;
696
        IncPathEnv = "ECOMPILE_PATH_INC=" + path;
697
        _putenv( EmPathEnv.c_str() );
698
        _putenv( IncPathEnv.c_str() );
699
      }
700
      break;
701
#endif
702
      case 'T':
×
703
      {
704
        compilercfg.ThreadedCompilation = true;
×
705
        int count = atoi( &argv[i][2] );
×
706
        compilercfg.NumberOfThreads = count;
×
707
        break;
×
708
      }
709
      case 'S':
817✔
710
        compilercfg.ShortCircuitEvaluation = setting_value( arg );
817✔
711
        break;
817✔
712
      default:
×
713
        unknown_opt = true;
×
714
        break;
×
715
      }
716
    }
717

718
    if ( unknown_opt )
10,352✔
719
    {
720
      ERROR_PRINTLN( "Unknown option: {}", argv[i] );
×
721
      return 1;
×
722
    }
723
  }
724
  return 0;
2,956✔
725
}
726

727
void apply_configuration()
2,956✔
728
{
729
  em_parse_tree_cache.configure( compilercfg.EmParseTreeCacheSize );
2,956✔
730
  inc_parse_tree_cache.configure( compilercfg.IncParseTreeCacheSize );
2,956✔
731
}
2,956✔
732

733
void recurse_call( const std::vector<fs::path>& basedirs, bool inc_files,
2✔
734
                   const std::function<void( const std::string& )>& callback )
735
{
736
  std::set<std::string> files;
2✔
737
  for ( const auto& basedir : basedirs )
8✔
738
  {
739
    if ( !fs::is_directory( basedir ) )
6✔
740
      continue;
×
741
    std::error_code ec;
6✔
742
    for ( auto dir_itr = fs::recursive_directory_iterator( basedir, ec );
6✔
743
          dir_itr != fs::recursive_directory_iterator(); ++dir_itr )
1,744✔
744
    {
745
      if ( Clib::exit_signalled )
869✔
746
        return;
×
747
      if ( auto fn = dir_itr->path().filename().string(); !fn.empty() && *fn.begin() == '.' )
869✔
748
      {
749
        if ( dir_itr->is_directory() )
4✔
750
          dir_itr.disable_recursion_pending();
2✔
751
        continue;
4✔
752
      }
753
      else if ( !dir_itr->is_regular_file() )
865✔
754
        continue;
869✔
755
      const auto ext = dir_itr->path().extension();
766✔
756
      const auto file = dir_itr->path().generic_string();
766✔
757
      if ( inc_files )
766✔
758
      {
759
        if ( !ext.compare( ".inc" ) )
×
760
          if ( files.insert( file ).second )
×
761
            callback( file );
×
762
      }
763
      else if ( !ext.compare( ".src" ) || !ext.compare( ".hsr" ) ||
1,290✔
764
                ( compilercfg.CompileAspPages && !ext.compare( ".asp" ) ) )
524✔
765
      {
766
        if ( files.insert( file ).second )
242✔
767
          callback( file );
240✔
768
      }
769
    }
772✔
770
  }
771
}
2✔
772

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

827
void DisplaySummary( const Tools::Timer<>& timer )
7✔
828
{
829
  std::string tmp = "Compilation Summary:\n";
7✔
830
  if ( summary.ThreadCount )
7✔
831
    tmp += fmt::format( "    Used {} threads\n", summary.ThreadCount );
×
832
  if ( summary.CompiledScripts )
7✔
833
    tmp += fmt::format( "    Compiled {} script{} in {} ms.\n", summary.CompiledScripts,
7✔
834
                        ( summary.CompiledScripts == 1 ? "" : "s" ), timer.ellapsed() );
21✔
835

836
  if ( summary.ScriptsWithCompileErrors )
7✔
837
    tmp += fmt::format( "    {} of those script{} had errors.\n", summary.ScriptsWithCompileErrors,
1✔
838
                        ( summary.ScriptsWithCompileErrors == 1 ? "" : "s" ) );
3✔
839

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

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

887
  INFO_PRINTLN( tmp );
7✔
888
}
7✔
889

890
void EnterWatchMode()
1✔
891
{
892
  std::list<WatchFileMessage> watch_messages;
1✔
893
  std::set<fs::path> to_compile;
1✔
894
  efsw::FileWatcher fileWatcher;
1✔
895
  EfswFileWatchListener listener( fileWatcher,
896
                                  std::set<fs::path>{ ".src", ".hsr", ".asp", ".inc", ".em" } );
6✔
897

898
  auto handle_compile_file = [&]( const fs::path& filepath )
5✔
899
  {
900
    // Existing file, compile all owners dependent on it.
901
    if ( auto itr = dependency_owners.find( filepath ); itr != dependency_owners.end() )
5✔
902
    {
903
      to_compile.insert( itr->second.begin(), itr->second.end() );
4✔
904
    }
905
    // New file, compile only this file (if it is compilable).
906
    else
907
    {
908
      auto ext = filepath.extension();
1✔
909
      if ( ext.compare( ".src" ) == 0 || ext.compare( ".hsr" ) == 0 || ext.compare( ".asp" ) == 0 )
1✔
910
      {
911
        to_compile.emplace( filepath );
1✔
912
      }
913
    }
1✔
914
  };
5✔
915

916
  auto handle_delete_file = [&]( const fs::path& filepath )
1✔
917
  {
918
    to_compile.erase( filepath );
1✔
919
    if ( auto itr = owner_dependencies.find( filepath ); itr != owner_dependencies.end() )
1✔
920
    {
921
      // For all dependencies, remove the deleted file from set of owners for
922
      // that dependency.
923
      for ( const auto& depnamepath : itr->second )
4✔
924
      {
925
        // If dependency exists in map of dependency -> owners
926
        if ( auto owners_itr = dependency_owners.find( depnamepath );
3✔
927
             owners_itr != dependency_owners.end() )
3✔
928
        {
929
          // Erase filepath from set of owners
930
          owners_itr->second.erase( filepath );
3✔
931

932
          // If owners set is empty, this dependency is no longer used by
933
          // anything.
934
          if ( owners_itr->second.empty() )
3✔
935
          {
936
            //  Erase from map of dependency -> owners.
937
            dependency_owners.erase( owners_itr );
1✔
938
            listener.remove_file( depnamepath );
1✔
939
            VERBOSE_PRINTLN( "Remove watch file {}", depnamepath );
1✔
940
          }
941
        }
942
      }
943
      owner_dependencies.erase( itr );
1✔
944
    }
945
  };
1✔
946

947
  auto add_dir = [&]( const std::string& elem )
4✔
948
  {
949
    fs::path dir( elem );
4✔
950
    if ( fs::exists( dir ) )
4✔
951
    {
952
      auto dirpath = fs::canonical( dir );
4✔
953
      if ( listener.add_watch_dir( dirpath ) )
4✔
954
      {
955
        VERBOSE_PRINTLN( "Add watch dir {}", dirpath );
4✔
956
      }
957
    }
4✔
958
  };
4✔
959

960
  for ( const auto& dep_owners : dependency_owners )
141✔
961
  {
962
    listener.add_file( dep_owners.first );
140✔
963
  }
964

965
  for ( const auto& directory : compiled_dirs )
4✔
966
  {
967
    listener.add_dir( directory );
3✔
968
  }
969

970
  for ( const auto& elem : compilercfg.PackageRoot )
2✔
971
  {
972
    add_dir( elem );
1✔
973
  }
974

975
  add_dir( compilercfg.ModuleDirectory );
1✔
976
  add_dir( compilercfg.IncludeDirectory );
1✔
977
  add_dir( compilercfg.PolScriptRoot );
1✔
978

979
  fileWatcher.watch();
1✔
980

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

984
  while ( !Clib::exit_signalled )
8✔
985
  {
986
    std::this_thread::sleep_for( std::chrono::seconds( 1 ) );
6✔
987
    listener.take_messages( watch_messages );
6✔
988
    if ( !watch_messages.empty() )
6✔
989
    {
990
      for ( auto const& message : watch_messages )
11✔
991
      {
992
        const auto& filepath = message.filepath;
6✔
993
        const auto& old_filepath = message.old_filepath;
6✔
994
        VERBOSE_PRINTLN( "Event: filename={}, old_filename={}", filepath, old_filepath );
6✔
995

996
        // created or modified
997
        if ( old_filepath.empty() )
6✔
998
        {
999
          handle_compile_file( filepath );
5✔
1000
        }
1001
        // deleted
1002
        else if ( filepath.empty() )
1✔
1003
        {
1004
          handle_delete_file( old_filepath );
1✔
1005
        }
1006
        // moved
1007
        else
1008
        {
1009
          handle_delete_file( old_filepath );
×
1010
          handle_compile_file( filepath );
×
1011
        }
1012
      }
1013
      watch_messages.clear();
5✔
1014

1015
      if ( !to_compile.empty() )
5✔
1016
      {
1017
        summary.CompiledScripts = 0;
5✔
1018
        summary.UpToDateScripts = 0;
5✔
1019
        summary.ScriptsWithCompileErrors = 0;
5✔
1020
        em_parse_tree_cache.clear();
5✔
1021
        inc_parse_tree_cache.clear();
5✔
1022

1023
        VERBOSE_PRINTLN( "To compile: {}", to_compile );
5✔
1024

1025
        Tools::Timer<> timer;
5✔
1026
        for ( const auto& filepath : to_compile )
19✔
1027
        {
1028
          if ( Clib::exit_signalled )
14✔
1029
          {
1030
            break;
×
1031
          }
1032

1033
          std::set<fs::path> removed_dependencies;
14✔
1034
          std::set<fs::path> new_dependencies;
14✔
1035
          try
1036
          {
1037
            process_file_wrapper( filepath.generic_string(), &removed_dependencies,
14✔
1038
                                  &new_dependencies );
1039
          }
1040
          catch ( ... )
×
1041
          {
1042
          }
×
1043

1044
          VERBOSE_PRINTLN( "New dependencies: {} Removed dependencies: {}", new_dependencies,
14✔
1045
                           removed_dependencies );
1046

1047
          for ( const auto& depnamepath : removed_dependencies )
14✔
1048
          {
1049
            // If a removed dependency has no owner set is empty, we can remove
1050
            // the listener for that dependency.
1051
            if ( dependency_owners.find( depnamepath ) == dependency_owners.end() )
×
1052
            {
1053
              if ( listener.remove_file( depnamepath ) )
×
1054
              {
1055
                VERBOSE_PRINTLN( "Remove watch file {}", depnamepath );
×
1056
              }
1057
            }
1058
          }
1059

1060
          for ( const auto& depnamepath : new_dependencies )
17✔
1061
          {
1062
            if ( listener.add_file( depnamepath ) )
3✔
1063
            {
1064
              VERBOSE_PRINTLN( "Add watch file {}", depnamepath );
1✔
1065
            }
1066
          }
1067
        }
14✔
1068

1069
        timer.stop();
5✔
1070
        if ( compilercfg.DisplaySummary && !quiet )
5✔
1071
        {
1072
          DisplaySummary( timer );
5✔
1073
        }
1074
        to_compile.clear();
5✔
1075
      }
5✔
1076
    }
1077
  }
1078
}
2✔
1079

1080
/**
1081
 * Runs the compilation threads
1082
 */
1083
void AutoCompile()
2✔
1084
{
1085
  bool save = compilercfg.OnlyCompileUpdatedScripts;
2✔
1086
  compilercfg.OnlyCompileUpdatedScripts = compilercfg.UpdateOnlyOnAutoCompile;
2✔
1087
  std::vector<fs::path> dirs;
2✔
1088
  compiled_dirs.emplace( fs::canonical( compilercfg.PolScriptRoot ) );
2✔
1089

1090
  dirs.emplace_back( compilercfg.PolScriptRoot );
2✔
1091
  for ( const auto& pkg : Plib::systemstate.packages )
6✔
1092
  {
1093
    compiled_dirs.emplace( fs::canonical( pkg->dir() ) );
4✔
1094
    dirs.emplace_back( pkg->dir() );
4✔
1095
  }
1096
  process_dirs( dirs, false );
2✔
1097
  compilercfg.OnlyCompileUpdatedScripts = save;
2✔
1098
}
2✔
1099

1100
/**
1101
 * Takes decisions, runs, the compilation, prints summary and cleans after
1102
 */
1103
bool run( int argc, char** argv, int* res )
2,956✔
1104
{
1105
  Clib::enable_exit_signaller();
2,956✔
1106

1107
  load_packages();
2,956✔
1108

1109
  // Determine the run mode and do the compile itself
1110
  Tools::Timer<> timer;
2,956✔
1111
  bool any = false;
2,956✔
1112

1113
  for ( int i = 1; i < argc; i++ )
12,999✔
1114
  {
1115
#ifdef __linux__
1116
    if ( argv[i][0] == '-' )
10,352✔
1117
#else
1118
    if ( argv[i][0] == '/' || argv[i][0] == '-' )
1119
#endif
1120
    {
1121
      if ( argv[i][1] == 'A' )
7,398✔
1122
      {
1123
        compilercfg.UpdateOnlyOnAutoCompile = ( argv[i][2] == 'u' );
2✔
1124
        any = true;
2✔
1125

1126
        AutoCompile();
2✔
1127
      }
1128
      else if ( argv[i][1] == 'r' )
7,396✔
1129
      {
1130
        any = true;
×
1131
        std::string dir( "." );
×
1132
        bool compile_inc = ( argv[i][2] == 'i' );  // compile .inc files
×
1133

1134
        ++i;
×
1135
        if ( i < argc && argv[i] && argv[i][0] != '-' )
×
1136
          dir.assign( argv[i] );
×
1137

1138
        compiled_dirs.emplace( fs::canonical( dir ) );
×
1139
        process_dirs( { dir }, compile_inc );
×
1140
      }
×
1141
      else if ( argv[i][1] == 'C' )
7,396✔
1142
      {
1143
        ++i;  // skip the config file pathname
2,954✔
1144
      }
1145
      // and skip any other option.
1146
    }
1147
    else
1148
    {
1149
      any = true;
2,954✔
1150
#ifdef _WIN32
1151
      Clib::forspec( argv[i], []( const char* pathname ) { process_file_wrapper( pathname ); } );
1152
#else
1153
      process_file_wrapper( argv[i] );
3,572✔
1154
#endif
1155
    }
1156
  }
1157

1158
  if ( !any && compilercfg.AutoCompileByDefault )
2,647✔
1159
  {
1160
    any = true;
×
1161
    AutoCompile();
×
1162
  }
1163

1164
  // Execution is completed: start final/cleanup tasks
1165
  timer.stop();
2,647✔
1166

1167
  if ( any && compilercfg.DisplaySummary && !quiet )
2,647✔
1168
  {
1169
    DisplaySummary( timer );
2✔
1170
  }
1171

1172
  if ( watch_source )
2,647✔
1173
  {
1174
    EnterWatchMode();
1✔
1175
  }
1176

1177
  Plib::systemstate.deinitialize();
2,647✔
1178

1179
  if ( summary.ScriptsWithCompileErrors )
2,647✔
1180
    *res = 1;
×
1181
  else
1182
    *res = 0;
2,647✔
1183
  return any;
2,647✔
1184
}
2,956✔
1185

1186
void read_config_file( int argc, char* argv[] )
2,956✔
1187
{
1188
  for ( int i = 1; i < argc; i++ )
7,400✔
1189
  {
1190
    if ( argv[i][0] == '/' || argv[i][0] == '-' )
7,398✔
1191
    {
1192
      // -C cfgpath
1193
      if ( argv[i][1] == 'C' )
7,398✔
1194
      {
1195
        ++i;
2,954✔
1196
        if ( i == argc )
2,954✔
1197
          throw std::runtime_error( "-C specified without pathname" );
×
1198

1199
        compilercfg.Read( std::string( argv[i] ) );
2,954✔
1200
        return;
2,954✔
1201
      }
1202
    }
1203
  }
1204

1205
  // check ECOMPILE_CFG_PATH environment variable
1206
  const char* env_ecompile_cfg_path = getenv( "ECOMPILE_CFG_PATH" );
2✔
1207
  if ( env_ecompile_cfg_path != nullptr )
2✔
1208
  {
1209
    compilercfg.Read( std::string( env_ecompile_cfg_path ) );
×
1210
    return;
×
1211
  }
1212

1213
  // no -C arg, so use binary path (hope it's right..sigh.)
1214
  std::string cfgpath = PROG_CONFIG::programDir() + "ecompile.cfg";
2✔
1215
  if ( Clib::FileExists( "ecompile.cfg" ) )
2✔
1216
  {
1217
    compilercfg.Read( "ecompile.cfg" );
2✔
1218
  }
1219
  else if ( Clib::FileExists( cfgpath ) )
×
1220
  {
1221
    compilercfg.Read( cfgpath );
×
1222
  }
1223
  else
1224
  {
1225
    ERROR_PRINTLN( "Could not find {}; using defaults.", cfgpath );
×
1226
    compilercfg.SetDefaults();
×
1227
  }
1228
}
2✔
1229

1230
/**
1231
 * This is the main entry point for ecompile program
1232
 */
1233
int ECompileMain::main()
2,956✔
1234
{
1235
  Clib::Logging::global_logger->disableFileLog();
2,956✔
1236

1237
  const std::vector<std::string>& binArgs = programArgs();
2,956✔
1238

1239
/**********************************************
1240
 * TODO: rework the following cruft from former uotool.cpp
1241
 **********************************************/
1242
#ifdef _WIN32
1243
  Clib::MiniDumper::Initialize();
1244
#endif
1245

1246
  ECompile::read_config_file( s_argc, s_argv );
2,956✔
1247

1248
  /**********************************************
1249
   * show help
1250
   **********************************************/
1251
  if ( binArgs.size() == 1 && !compilercfg.AutoCompileByDefault )
2,956✔
1252
  {
1253
    showHelp();
×
1254
    return 0;  // return "okay"
×
1255
  }
1256

1257
  watch_source = compilercfg.WatchModeByDefault;
2,956✔
1258
  if ( watch_source )
2,956✔
1259
  {
1260
    compilercfg.GenerateDependencyInfo = true;
×
1261
    keep_building = true;
×
1262
    compilercfg.ThreadedCompilation =
×
1263
        false;  // limitation since dependency gathering is not thread-safe
1264
  }
1265

1266
  int res = ECompile::readargs( s_argc, s_argv );
2,956✔
1267
  if ( res )
2,956✔
1268
  {
1269
    showHelp();
×
1270
    return res;
×
1271
  }
1272

1273
  ECompile::apply_configuration();
2,956✔
1274

1275
  if ( !ECompile::quiet )
2,956✔
1276
  {
1277
    // vX.YY
1278
    INFO_PRINTLN( "EScript Compiler v1.{}\n{}\n", ESCRIPT_FILE_VER_CURRENT, POL_COPYRIGHT );
2,296✔
1279
  }
1280

1281
  int prog_res = 1;
2,956✔
1282
  bool didanything = ECompile::run( s_argc, s_argv, &prog_res );
2,956✔
1283

1284
  if ( !didanything )
2,647✔
1285
  {
1286
    showHelp();
×
1287
    return 1;
×
1288
  }
1289
  return prog_res;
2,647✔
1290
}
1291
}  // namespace ECompile
1292
}  // namespace Pol
1293

1294
///////////////////////////////////////////////////////////////////////////////
1295
///////////////////////////////////////////////////////////////////////////////
1296
///////////////////////////////////////////////////////////////////////////////
1297

1298
int main( int argc, char* argv[] )
2,956✔
1299
{
1300
  Pol::ECompile::s_argc = argc;
2,956✔
1301
  Pol::ECompile::s_argv = argv;
2,956✔
1302

1303
  Pol::ECompile::ECompileMain* ECompileMain = new Pol::ECompile::ECompileMain();
2,956✔
1304
  ECompileMain->start( argc, argv );
2,956✔
1305
}
×
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