1
/**
2
 * Entry point for DMD.
3
 *
4
 * This modules defines the entry point (main) for DMD, as well as related
5
 * utilities needed for arguments parsing, path manipulation, etc...
6
 * This file is not shared with other compilers which use the DMD front-end.
7
 *
8
 * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
9
 * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
10
 * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
11
 * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/mars.d, _mars.d)
12
 * Documentation:  https://dlang.org/phobos/dmd_mars.html
13
 * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/mars.d
14
 */
15

16
module dmd.mars;
17

18
import core.stdc.ctype;
19
import core.stdc.limits;
20
import core.stdc.stdio;
21
import core.stdc.stdlib;
22
import core.stdc.string;
23

24
import dmd.arraytypes;
25
import dmd.astcodegen;
26
import dmd.gluelayer;
27
import dmd.builtin;
28
import dmd.cond;
29
import dmd.console;
30
import dmd.compiler;
31
import dmd.dinifile;
32
import dmd.dinterpret;
33
import dmd.dmodule;
34
import dmd.doc;
35
import dmd.dsymbol;
36
import dmd.dsymbolsem;
37
import dmd.dtemplate;
38
import dmd.dtoh;
39
import dmd.errors;
40
import dmd.expression;
41
import dmd.globals;
42
import dmd.hdrgen;
43
import dmd.id;
44
import dmd.identifier;
45
import dmd.inline;
46
import dmd.json;
47
version (NoMain) {} else
48
{
49
    import dmd.lib;
50
    import dmd.link;
51
    import dmd.vsoptions;
52
}
53
import dmd.mtype;
54
import dmd.objc;
55
import dmd.root.array;
56
import dmd.root.file;
57
import dmd.root.filename;
58
import dmd.root.man;
59
import dmd.root.outbuffer;
60
import dmd.root.response;
61
import dmd.root.rmem;
62
import dmd.root.string;
63
import dmd.root.stringtable;
64
import dmd.semantic2;
65
import dmd.semantic3;
66
import dmd.target;
67
import dmd.utils;
68

69
/**
70
 * Print DMD's logo on stdout
71
 */
72
private void logo()
73
{
74 1
    printf("DMD%llu D Compiler %.*s\n%.*s %.*s\n",
75
        cast(ulong)size_t.sizeof * 8,
76
        cast(int) global._version.length - 1, global._version.ptr,
77
        cast(int)global.copyright.length, global.copyright.ptr,
78
        cast(int)global.written.length, global.written.ptr
79
    );
80
}
81

82
/**
83
Print DMD's logo with more debug information and error-reporting pointers.
84

85
Params:
86
    stream = output stream to print the information on
87
*/
88
extern(C) void printInternalFailure(FILE* stream)
89
{
90 0
    fputs(("---\n" ~
91
    "ERROR: This is a compiler bug.\n" ~
92
            "Please report it via https://issues.dlang.org/enter_bug.cgi\n" ~
93
            "with, preferably, a reduced, reproducible example and the information below.\n" ~
94
    "DustMite (https://github.com/CyberShadow/DustMite/wiki) can help with the reduction.\n" ~
95
    "---\n").ptr, stream);
96 0
    stream.fprintf("DMD %.*s\n", cast(int) global._version.length - 1, global._version.ptr);
97 0
    stream.printPredefinedVersions;
98 0
    stream.printGlobalConfigs();
99 0
    fputs("---\n".ptr, stream);
100
}
101

102
/**
103
 * Print DMD's usage message on stdout
104
 */
105
private void usage()
106
{
107
    import dmd.cli : CLIUsage;
108 1
    logo();
109 1
    auto help = CLIUsage.usage;
110 1
    const inifileCanon = FileName.canonicalName(global.inifilename);
111 1
    printf("
112
Documentation: https://dlang.org/
113
Config file: %.*s
114
Usage:
115
  dmd [<option>...] <file>...
116
  dmd [<option>...] -run <file> [<arg>...]
117

118
Where:
119
  <file>           D source file
120
  <arg>            Argument to pass when running the resulting program
121

122
<option>:
123
  @<cmdfile>       read arguments from cmdfile
124
%.*s", cast(int)inifileCanon.length, inifileCanon.ptr, cast(int)help.length, &help[0]);
125
}
126

127
/**
128
 * DMD's real entry point
129
 *
130
 * Parses command line arguments and config file, open and read all
131
 * provided source file and do semantic analysis on them.
132
 *
133
 * Params:
134
 *   argc = Number of arguments passed via command line
135
 *   argv = Array of string arguments passed via command line
136
 *
137
 * Returns:
138
 *   Application return code
139
 */
140
version (NoMain) {} else
141
private int tryMain(size_t argc, const(char)** argv, ref Param params)
142
{
143 1
    Strings files;
144 1
    Strings libmodules;
145 1
    global._init();
146
    // Check for malformed input
147 1
    if (argc < 1 || !argv)
148
    {
149
    Largs:
150 0
        error(Loc.initial, "missing or null command line arguments");
151 0
        fatal();
152
    }
153
    // Convert argc/argv into arguments[] for easier handling
154 1
    Strings arguments = Strings(argc);
155 1
    for (size_t i = 0; i < argc; i++)
156
    {
157 1
        if (!argv[i])
158 0
            goto Largs;
159 1
        arguments[i] = argv[i];
160
    }
161 1
    if (!responseExpand(arguments)) // expand response files
162 0
        error(Loc.initial, "can't open response file");
163
    //for (size_t i = 0; i < arguments.dim; ++i) printf("arguments[%d] = '%s'\n", i, arguments[i]);
164 1
    files.reserve(arguments.dim - 1);
165
    // Set default values
166 1
    params.argv0 = arguments[0].toDString;
167

168
    // Temporary: Use 32 bits OMF as the default on Windows, for config parsing
169
    static if (TARGET.Windows)
170
    {
171
        params.is64bit = false;
172
        params.mscoff = false;
173
    }
174

175 1
    global.inifilename = parse_conf_arg(&arguments);
176 1
    if (global.inifilename)
177
    {
178
        // can be empty as in -conf=
179 1
        if (global.inifilename.length && !FileName.exists(global.inifilename))
180 0
            error(Loc.initial, "Config file '%.*s' does not exist.",
181
                  cast(int)global.inifilename.length, global.inifilename.ptr);
182
    }
183
    else
184
    {
185
        version (Windows)
186
        {
187
            global.inifilename = findConfFile(params.argv0, "sc.ini");
188
        }
189
        else version (Posix)
190
        {
191 1
            global.inifilename = findConfFile(params.argv0, "dmd.conf");
192
        }
193
        else
194
        {
195
            static assert(0, "fix this");
196
        }
197
    }
198
    // Read the configuration file
199 1
    const iniReadResult = global.inifilename.toCStringThen!(fn => File.read(fn.ptr));
200 1
    const inifileBuffer = iniReadResult.buffer.data;
201
    /* Need path of configuration file, for use in expanding @P macro
202
     */
203 1
    const(char)[] inifilepath = FileName.path(global.inifilename);
204 1
    Strings sections;
205 1
    StringTable!(char*) environment;
206 1
    environment._init(7);
207
    /* Read the [Environment] section, so we can later
208
     * pick up any DFLAGS settings.
209
     */
210 1
    sections.push("Environment");
211 1
    parseConfFile(environment, global.inifilename, inifilepath, inifileBuffer, &sections);
212

213 1
    const(char)[] arch = params.is64bit ? "64" : "32"; // use default
214 1
    arch = parse_arch_arg(&arguments, arch);
215

216
    // parse architecture from DFLAGS read from [Environment] section
217
    {
218 1
        Strings dflags;
219 1
        getenv_setargv(readFromEnv(environment, "DFLAGS"), &dflags);
220 1
        environment.reset(7); // erase cached environment updates
221 1
        arch = parse_arch_arg(&dflags, arch);
222
    }
223

224 1
    bool is64bit = arch[0] == '6';
225

226
    version(Windows) // delete LIB entry in [Environment] (necessary for optlink) to allow inheriting environment for MS-COFF
227
        if (is64bit || arch == "32mscoff")
228
            environment.update("LIB", 3).value = null;
229

230
    // read from DFLAGS in [Environment{arch}] section
231 1
    char[80] envsection = void;
232 1
    sprintf(envsection.ptr, "Environment%.*s", cast(int) arch.length, arch.ptr);
233 1
    sections.push(envsection.ptr);
234 1
    parseConfFile(environment, global.inifilename, inifilepath, inifileBuffer, &sections);
235 1
    getenv_setargv(readFromEnv(environment, "DFLAGS"), &arguments);
236 1
    updateRealEnvironment(environment);
237 1
    environment.reset(1); // don't need environment cache any more
238

239 1
    if (parseCommandLine(arguments, argc, params, files))
240
    {
241 1
        Loc loc;
242 1
        errorSupplemental(loc, "run `dmd` to print the compiler manual");
243 1
        errorSupplemental(loc, "run `dmd -man` to open browser on manual");
244 1
        return EXIT_FAILURE;
245
    }
246

247 1
    if (params.usage)
248
    {
249 1
        usage();
250 1
        return EXIT_SUCCESS;
251
    }
252

253 1
    if (params.logo)
254
    {
255 1
        logo();
256 1
        return EXIT_SUCCESS;
257
    }
258

259
    /*
260
    Prints a supplied usage text to the console and
261
    returns the exit code for the help usage page.
262

263
    Returns:
264
        `EXIT_SUCCESS` if no errors occurred, `EXIT_FAILURE` otherwise
265
    */
266
    static int printHelpUsage(string help)
267
    {
268 1
        printf("%.*s", cast(int)help.length, &help[0]);
269 1
        return global.errors ? EXIT_FAILURE : EXIT_SUCCESS;
270
    }
271

272
    /*
273
    Generates code to check for all `params` whether any usage page
274
    has been requested.
275
    If so, the generated code will print the help page of the flag
276
    and return with an exit code.
277

278
    Params:
279
        params = parameters with `Usage` suffices in `params` for which
280
        their truthness should be checked.
281

282
    Returns: generated code for checking the usage pages of the provided `params`.
283
    */
284
    static string generateUsageChecks(string[] params)
285
    {
286 0
        string s;
287 0
        foreach (n; params)
288
        {
289 0
            s ~= q{
290
                if (params.}~n~q{Usage)
291
                    return printHelpUsage(CLIUsage.}~n~q{Usage);
292
            };
293
        }
294 0
        return s;
295
    }
296
    import dmd.cli : CLIUsage;
297
    mixin(generateUsageChecks(["mcpu", "transition", "check", "checkAction",
298
        "preview", "revert", "externStd"]));
299

300 1
    if (params.manual)
301
    {
302
        version (Windows)
303
        {
304
            browse("http://dlang.org/dmd-windows.html");
305
        }
306
        version (linux)
307
        {
308 0
            browse("http://dlang.org/dmd-linux.html");
309
        }
310
        version (OSX)
311
        {
312
            browse("http://dlang.org/dmd-osx.html");
313
        }
314
        version (FreeBSD)
315
        {
316
            browse("http://dlang.org/dmd-freebsd.html");
317
        }
318
        /*NOTE: No regular builds for openbsd/dragonflybsd (yet) */
319
        /*
320
        version (OpenBSD)
321
        {
322
            browse("http://dlang.org/dmd-openbsd.html");
323
        }
324
        version (DragonFlyBSD)
325
        {
326
            browse("http://dlang.org/dmd-dragonflybsd.html");
327
        }
328
        */
329 0
        return EXIT_SUCCESS;
330
    }
331

332 1
    if (params.color)
333 1
        global.console = Console.create(core.stdc.stdio.stderr);
334

335 1
    setTarget(params);           // set target operating system
336 1
    setTargetCPU(params);
337 1
    if (params.is64bit != is64bit)
338 0
        error(Loc.initial, "the architecture must not be changed in the %s section of %.*s",
339
              envsection.ptr, cast(int)global.inifilename.length, global.inifilename.ptr);
340

341 1
    if (global.errors)
342
    {
343 0
        fatal();
344
    }
345 1
    if (files.dim == 0)
346
    {
347 1
        if (params.jsonFieldFlags)
348
        {
349 1
            generateJson(null);
350 1
            return EXIT_SUCCESS;
351
        }
352 0
        usage();
353 0
        return EXIT_FAILURE;
354
    }
355

356 1
    reconcileCommands(params, files.dim);
357

358
    // Add in command line versions
359 1
    if (params.versionids)
360 1
        foreach (charz; *params.versionids)
361 1
            VersionCondition.addGlobalIdent(charz.toDString());
362 1
    if (params.debugids)
363 1
        foreach (charz; *params.debugids)
364 1
            DebugCondition.addGlobalIdent(charz.toDString());
365

366 1
    setTarget(params);
367

368
    // Predefined version identifiers
369 1
    addDefaultVersionIdentifiers(params);
370

371 1
    setDefaultLibrary();
372

373
    // Initialization
374 1
    Type._init();
375 1
    Id.initialize();
376 1
    Module._init();
377 1
    target._init(params);
378 1
    Expression._init();
379 1
    Objc._init();
380
    import dmd.filecache : FileCache;
381 1
    FileCache._init();
382

383
    version(CRuntime_Microsoft)
384
    {
385
        import dmd.root.longdouble;
386
        initFPU();
387
    }
388
    import dmd.root.ctfloat : CTFloat;
389 1
    CTFloat.initialize();
390

391 1
    if (params.verbose)
392
    {
393 1
        stdout.printPredefinedVersions();
394 1
        stdout.printGlobalConfigs();
395
    }
396
    //printf("%d source files\n",files.dim);
397

398
    // Build import search path
399

400
    static Strings* buildPath(Strings* imppath)
401
    {
402 1
        Strings* result = null;
403 1
        if (imppath)
404
        {
405 1
            foreach (const path; *imppath)
406
            {
407 1
                Strings* a = FileName.splitPath(path);
408 1
                if (a)
409
                {
410 1
                    if (!result)
411 1
                        result = new Strings();
412 1
                    result.append(a);
413
                }
414
            }
415
        }
416 1
        return result;
417
    }
418

419 1
    if (params.mixinFile)
420
    {
421 1
        params.mixinOut = cast(OutBuffer*)Mem.check(calloc(1, OutBuffer.sizeof));
422 1
        atexit(&flushMixins); // see comment for flushMixins
423
    }
424 1
    scope(exit) flushMixins();
425 1
    global.path = buildPath(params.imppath);
426 1
    global.filePath = buildPath(params.fileImppath);
427

428 1
    if (params.addMain)
429 1
        files.push("__main.d");
430
    // Create Modules
431 1
    Modules modules = createModules(files, libmodules);
432
    // Read files
433
    // Start by "reading" the special files (__main.d, __stdin.d)
434 1
    foreach (m; modules)
435
    {
436 1
        if (params.addMain && m.srcfile.toString() == "__main.d")
437
        {
438 1
            auto data = arraydup("int main(){return 0;}\0\0\0\0"); // need 2 trailing nulls for sentinel and 2 for lexer
439 1
            m.srcBuffer = new FileBuffer(cast(ubyte[]) data[0 .. $-4]);
440
        }
441 1
        else if (m.srcfile.toString() == "__stdin.d")
442
        {
443 1
            auto buffer = readFromStdin();
444 1
            m.srcBuffer = new FileBuffer(buffer.extractSlice());
445
        }
446
    }
447

448 1
    foreach (m; modules)
449
    {
450 1
        m.read(Loc.initial);
451
    }
452

453
    // Parse files
454 1
    bool anydocfiles = false;
455 1
    size_t filecount = modules.dim;
456 1
    for (size_t filei = 0, modi = 0; filei < filecount; filei++, modi++)
457
    {
458 1
        Module m = modules[modi];
459 1
        if (params.verbose)
460 1
            message("parse     %s", m.toChars());
461 1
        if (!Module.rootModule)
462 1
            Module.rootModule = m;
463 1
        m.importedFrom = m; // m.isRoot() == true
464 1
        if (!params.oneobj || modi == 0 || m.isDocFile)
465 1
            m.deleteObjFile();
466

467 1
        m.parse();
468 1
        if (m.isHdrFile)
469
        {
470
            // Remove m's object file from list of object files
471 1
            for (size_t j = 0; j < params.objfiles.length; j++)
472
            {
473 1
                if (m.objfile.toChars() == params.objfiles[j])
474
                {
475 1
                    params.objfiles.remove(j);
476 1
                    break;
477
                }
478
            }
479 1
            if (params.objfiles.length == 0)
480 1
                params.link = false;
481
        }
482 1
        if (m.isDocFile)
483
        {
484 1
            anydocfiles = true;
485 1
            gendocfile(m);
486
            // Remove m from list of modules
487 1
            modules.remove(modi);
488 1
            modi--;
489
            // Remove m's object file from list of object files
490 1
            for (size_t j = 0; j < params.objfiles.length; j++)
491
            {
492 1
                if (m.objfile.toChars() == params.objfiles[j])
493
                {
494 1
                    params.objfiles.remove(j);
495 1
                    break;
496
                }
497
            }
498 1
            if (params.objfiles.length == 0)
499 1
                params.link = false;
500
        }
501
    }
502

503 1
    if (anydocfiles && modules.dim && (params.oneobj || params.objname))
504
    {
505 0
        error(Loc.initial, "conflicting Ddoc and obj generation options");
506 0
        fatal();
507
    }
508 1
    if (global.errors)
509 1
        fatal();
510

511 1
    if (params.doHdrGeneration)
512
    {
513
        /* Generate 'header' import files.
514
         * Since 'header' import files must be independent of command
515
         * line switches and what else is imported, they are generated
516
         * before any semantic analysis.
517
         */
518 1
        foreach (m; modules)
519
        {
520 1
            if (m.isHdrFile)
521 0
                continue;
522 1
            if (params.verbose)
523 0
                message("import    %s", m.toChars());
524 1
            genhdrfile(m);
525
        }
526
    }
527 1
    if (global.errors)
528 0
        removeHdrFilesAndFail(params, modules);
529

530
    // load all unconditional imports for better symbol resolving
531 1
    foreach (m; modules)
532
    {
533 1
        if (params.verbose)
534 1
            message("importall %s", m.toChars());
535 1
        m.importAll(null);
536
    }
537 1
    if (global.errors)
538 1
        removeHdrFilesAndFail(params, modules);
539

540 1
    backend_init();
541

542
    // Do semantic analysis
543 1
    foreach (m; modules)
544
    {
545 1
        if (params.verbose)
546 1
            message("semantic  %s", m.toChars());
547 1
        m.dsymbolSemantic(null);
548
    }
549
    //if (global.errors)
550
    //    fatal();
551 1
    Module.dprogress = 1;
552 1
    Module.runDeferredSemantic();
553 1
    if (Module.deferred.dim)
554
    {
555 0
        for (size_t i = 0; i < Module.deferred.dim; i++)
556
        {
557 0
            Dsymbol sd = Module.deferred[i];
558 0
            sd.error("unable to resolve forward reference in definition");
559
        }
560
        //fatal();
561
    }
562

563
    // Do pass 2 semantic analysis
564 1
    foreach (m; modules)
565
    {
566 1
        if (params.verbose)
567 1
            message("semantic2 %s", m.toChars());
568 1
        m.semantic2(null);
569
    }
570 1
    Module.runDeferredSemantic2();
571 1
    if (global.errors)
572 1
        removeHdrFilesAndFail(params, modules);
573

574
    // Do pass 3 semantic analysis
575 1
    foreach (m; modules)
576
    {
577 1
        if (params.verbose)
578 1
            message("semantic3 %s", m.toChars());
579 1
        m.semantic3(null);
580
    }
581 1
    if (includeImports)
582
    {
583
        // Note: DO NOT USE foreach here because Module.amodules.dim can
584
        //       change on each iteration of the loop
585 1
        for (size_t i = 0; i < compiledImports.dim; i++)
586
        {
587 1
            auto m = compiledImports[i];
588 1
            assert(m.isRoot);
589 1
            if (params.verbose)
590 0
                message("semantic3 %s", m.toChars());
591 1
            m.semantic3(null);
592 1
            modules.push(m);
593
        }
594
    }
595 1
    Module.runDeferredSemantic3();
596 1
    if (global.errors)
597 1
        removeHdrFilesAndFail(params, modules);
598

599
    // Scan for functions to inline
600 1
    foreach (m; modules)
601
    {
602 1
        if (params.useInline || m.hasAlwaysInlines)
603
        {
604 1
            if (params.verbose)
605 0
                message("inline scan %s", m.toChars());
606 1
            inlineScanModule(m);
607
        }
608
    }
609

610
    // Do not attempt to generate output files if errors or warnings occurred
611 1
    if (global.errors || global.warnings)
612 1
        removeHdrFilesAndFail(params, modules);
613

614
    // inlineScan incrementally run semantic3 of each expanded functions.
615
    // So deps file generation should be moved after the inlining stage.
616 1
    if (OutBuffer* ob = params.moduleDeps)
617
    {
618 1
        foreach (i; 1 .. modules[0].aimports.dim)
619 1
            semantic3OnDependencies(modules[0].aimports[i]);
620 1
        Module.runDeferredSemantic3();
621

622 1
        const data = (*ob)[];
623 1
        if (params.moduleDepsFile)
624 1
            writeFile(Loc.initial, params.moduleDepsFile, data);
625
        else
626 1
            printf("%.*s", cast(int)data.length, data.ptr);
627
    }
628

629 1
    printCtfePerformanceStats();
630 1
    printTemplateStats();
631

632 1
    Library library = null;
633 1
    if (params.lib)
634
    {
635 1
        if (params.objfiles.length == 0)
636
        {
637 1
            error(Loc.initial, "no input files");
638 1
            return EXIT_FAILURE;
639
        }
640 1
        library = Library.factory();
641 1
        library.setFilename(params.objdir, params.libname);
642
        // Add input object and input library files to output library
643 1
        foreach (p; libmodules)
644 1
            library.addObject(p.toDString(), null);
645
    }
646
    // Generate output files
647 1
    if (params.doJsonGeneration)
648
    {
649 1
        generateJson(&modules);
650
    }
651 1
    if (!global.errors && params.doDocComments)
652
    {
653 1
        foreach (m; modules)
654
        {
655 1
            gendocfile(m);
656
        }
657
    }
658 1
    if (params.vcg_ast)
659
    {
660
        import dmd.hdrgen;
661 1
        foreach (mod; modules)
662
        {
663 1
            auto buf = OutBuffer();
664 1
            buf.doindent = 1;
665 1
            moduleToBuffer(&buf, mod);
666

667
            // write the output to $(filename).cg
668 1
            auto cgFilename = FileName.addExt(mod.srcfile.toString(), "cg");
669 1
            File.write(cgFilename.ptr, buf[]);
670
        }
671
    }
672

673 1
    if (global.params.doCxxHdrGeneration)
674 1
        genCppHdrFiles(modules);
675

676 1
    if (global.errors)
677 1
        fatal();
678

679 1
    if (!params.obj)
680
    {
681
    }
682 1
    else if (params.oneobj)
683
    {
684 1
        Module firstm;    // first module we generate code for
685 1
        foreach (m; modules)
686
        {
687 1
            if (m.isHdrFile)
688 1
                continue;
689 1
            if (!firstm)
690
            {
691 1
                firstm = m;
692 1
                obj_start(m.srcfile.toChars());
693
            }
694 1
            if (params.verbose)
695 1
                message("code      %s", m.toChars());
696 1
            genObjFile(m, false);
697
        }
698 1
        if (!global.errors && firstm)
699
        {
700 1
            obj_end(library, firstm.objfile.toChars());
701
        }
702
    }
703
    else
704
    {
705 1
        foreach (m; modules)
706
        {
707 1
            if (m.isHdrFile)
708 0
                continue;
709 1
            if (params.verbose)
710 0
                message("code      %s", m.toChars());
711 1
            obj_start(m.srcfile.toChars());
712 1
            genObjFile(m, params.multiobj);
713 1
            obj_end(library, m.objfile.toChars());
714 1
            obj_write_deferred(library);
715 1
            if (global.errors && !params.lib)
716 0
                m.deleteObjFile();
717
        }
718
    }
719 1
    if (params.lib && !global.errors)
720 1
        library.write();
721 1
    backend_term();
722 1
    if (global.errors)
723 1
        fatal();
724 1
    int status = EXIT_SUCCESS;
725 1
    if (!params.objfiles.length)
726
    {
727 1
        if (params.link)
728 0
            error(Loc.initial, "no object files to link");
729
    }
730
    else
731
    {
732 1
        if (params.link)
733 1
            status = runLINK();
734 1
        if (params.run)
735
        {
736 1
            if (!status)
737
            {
738 1
                status = runProgram();
739
                /* Delete .obj files and .exe file
740
                 */
741 1
                foreach (m; modules)
742
                {
743 1
                    m.deleteObjFile();
744 1
                    if (params.oneobj)
745 1
                        break;
746
                }
747 1
                params.exefile.toCStringThen!(ef => File.remove(ef.ptr));
748
            }
749
        }
750
    }
751 1
    if (global.errors || global.warnings)
752 1
        removeHdrFilesAndFail(params, modules);
753

754 1
    return status;
755
}
756

757
private FileBuffer readFromStdin()
758
{
759
    enum bufIncrement = 128 * 1024;
760 1
    size_t pos = 0;
761 1
    size_t sz = bufIncrement;
762

763 1
    ubyte* buffer = null;
764
    for (;;)
765
    {
766 1
        buffer = cast(ubyte*)mem.xrealloc(buffer, sz + 4); // +2 for sentinel and +2 for lexer
767

768
        // Fill up buffer
769
        do
770
        {
771 1
            assert(sz > pos);
772 1
            size_t rlen = fread(buffer + pos, 1, sz - pos, stdin);
773 1
            pos += rlen;
774 1
            if (ferror(stdin))
775
            {
776
                import core.stdc.errno;
777 0
                error(Loc.initial, "cannot read from stdin, errno = %d", errno);
778 0
                fatal();
779
            }
780 1
            if (feof(stdin))
781
            {
782
                // We're done
783 1
                assert(pos < sz + 2);
784 1
                buffer[pos] = '\0';
785 1
                buffer[pos + 1] = '\0';
786 1
                buffer[pos + 2] = '\0';
787 1
                buffer[pos + 3] = '\0';
788 1
                return FileBuffer(buffer[0 .. pos]);
789
            }
790 0
        } while (pos < sz);
791

792
        // Buffer full, expand
793 0
        sz += bufIncrement;
794
    }
795

796 0
    assert(0);
797
}
798

799
extern (C++) void generateJson(Modules* modules)
800
{
801 1
    OutBuffer buf;
802 1
    json_generate(&buf, modules);
803

804
    // Write buf to file
805 1
    const(char)[] name = global.params.jsonfilename;
806 1
    if (name == "-")
807
    {
808
        // Write to stdout; assume it succeeds
809 1
        size_t n = fwrite(buf[].ptr, 1, buf.length, stdout);
810 1
        assert(n == buf.length); // keep gcc happy about return values
811
    }
812
    else
813
    {
814
        /* The filename generation code here should be harmonized with Module.setOutfilename()
815
         */
816 1
        const(char)[] jsonfilename;
817 1
        if (name)
818
        {
819 1
            jsonfilename = FileName.defaultExt(name, global.json_ext);
820
        }
821
        else
822
        {
823 1
            if (global.params.objfiles.length == 0)
824
            {
825 1
                error(Loc.initial, "cannot determine JSON filename, use `-Xf=<file>` or provide a source file");
826 1
                fatal();
827
            }
828
            // Generate json file name from first obj name
829 1
            const(char)[] n = global.params.objfiles[0].toDString;
830 1
            n = FileName.name(n);
831
            //if (!FileName::absolute(name))
832
            //    name = FileName::combine(dir, name);
833 1
            jsonfilename = FileName.forceExt(n, global.json_ext);
834
        }
835 1
        writeFile(Loc.initial, jsonfilename, buf[]);
836
    }
837
}
838

839

840
version (NoMain) {} else
841
{
842
    // in druntime:
843
    alias MainFunc = extern(C) int function(char[][] args);
844
    extern (C) int _d_run_main(int argc, char** argv, MainFunc dMain);
845

846
    // When using a C main, host DMD may not link against host druntime by default.
847
    version (DigitalMars)
848
    {
849
        version (Win64)
850
            pragma(lib, "phobos64");
851
        else version (Win32)
852
        {
853
            version (CRuntime_Microsoft)
854
                pragma(lib, "phobos32mscoff");
855
            else
856
                pragma(lib, "phobos");
857
        }
858
    }
859

860
    extern extern(C) __gshared string[] rt_options;
861

862
    /**
863
     * DMD's entry point, C main.
864
     *
865
     * Without `-lowmem`, we need to switch to the bump-pointer allocation scheme
866
     * right from the start, before any module ctors are run, so we need this hook
867
     * before druntime is initialized and `_Dmain` is called.
868
     *
869
     * Returns:
870
     *   Return code of the application
871
     */
872
    extern (C) int main(int argc, char** argv)
873
    {
874
        static if (isGCAvailable)
875
        {
876 1
            bool lowmem = false;
877 1
            foreach (i; 1 .. argc)
878
            {
879 1
                if (strcmp(argv[i], "-lowmem") == 0)
880
                {
881 1
                    lowmem = true;
882 1
                    break;
883
                }
884
            }
885 1
            if (!lowmem)
886
            {
887 1
                __gshared string[] disable_options = [ "gcopt=disable:1" ];
888 1
                rt_options = disable_options;
889 1
                mem.disableGC();
890
            }
891
        }
892

893
        // initialize druntime and call _Dmain() below
894 1
        return _d_run_main(argc, argv, &_Dmain);
895
    }
896

897
    /**
898
     * Manual D main (for druntime initialization), which forwards to `tryMain`.
899
     *
900
     * Returns:
901
     *   Return code of the application
902
     */
903
    extern (C) int _Dmain(char[][])
904
    {
905
        import core.runtime;
906
        import core.memory;
907
        static if (!isGCAvailable)
908
            GC.disable();
909

910
        version(D_Coverage)
911
        {
912
            // for now we need to manually set the source path
913
            string dirName(string path, char separator)
914
            {
915 0
                for (size_t i = path.length - 1; i > 0; i--)
916
                {
917 0
                    if (path[i] == separator)
918 0
                        return path[0..i];
919
                }
920 0
                return path;
921
            }
922
            version (Windows)
923
                enum sourcePath = dirName(dirName(dirName(__FILE_FULL_PATH__, '\\'), '\\'), '\\');
924
            else
925
                enum sourcePath = dirName(dirName(dirName(__FILE_FULL_PATH__, '/'), '/'), '/');
926

927 1
            dmd_coverSourcePath(sourcePath);
928 1
            dmd_coverDestPath(sourcePath);
929 1
            dmd_coverSetMerge(true);
930
        }
931

932 0
        scope(failure) stderr.printInternalFailure;
933

934 1
        auto args = Runtime.cArgs();
935 1
        return tryMain(args.argc, cast(const(char)**)args.argv, global.params);
936
    }
937
} // !NoMain
938

939
/**
940
 * Parses an environment variable containing command-line flags
941
 * and append them to `args`.
942
 *
943
 * This function is used to read the content of DFLAGS.
944
 * Flags are separated based on spaces and tabs.
945
 *
946
 * Params:
947
 *   envvalue = The content of an environment variable
948
 *   args     = Array to append the flags to, if any.
949
 */
950
void getenv_setargv(const(char)* envvalue, Strings* args)
951
{
952 1
    if (!envvalue)
953 1
        return;
954

955 1
    char* env = mem.xstrdup(envvalue); // create our own writable copy
956
    //printf("env = '%s'\n", env);
957 1
    while (1)
958
    {
959 1
        switch (*env)
960
        {
961 0
        case ' ':
962 0
        case '\t':
963 0
            env++;
964 0
            break;
965

966 1
        case 0:
967 1
            return;
968

969 1
        default:
970
        {
971 1
            args.push(env); // append
972 1
            auto p = env;
973 1
            auto slash = 0;
974 1
            bool instring = false;
975 1
            while (1)
976
            {
977 1
                auto c = *env++;
978 1
                switch (c)
979
                {
980 0
                case '"':
981 0
                    p -= (slash >> 1);
982 0
                    if (slash & 1)
983
                    {
984 0
                        p--;
985 0
                        goto default;
986
                    }
987 0
                    instring ^= true;
988 0
                    slash = 0;
989 0
                    continue;
990

991 1
                case ' ':
992 1
                case '\t':
993 1
                    if (instring)
994 0
                        goto default;
995 1
                    *p = 0;
996
                    //if (wildcard)
997
                    //    wildcardexpand();     // not implemented
998 1
                    break;
999

1000 0
                case '\\':
1001 0
                    slash++;
1002 0
                    *p++ = c;
1003 0
                    continue;
1004

1005 1
                case 0:
1006 1
                    *p = 0;
1007
                    //if (wildcard)
1008
                    //    wildcardexpand();     // not implemented
1009 1
                    return;
1010

1011 1
                default:
1012 1
                    slash = 0;
1013 1
                    *p++ = c;
1014 1
                    continue;
1015
                }
1016 1
                break;
1017
            }
1018 1
            break;
1019
        }
1020
        }
1021
    }
1022
}
1023

1024
/**
1025
 * Parse command line arguments for the last instance of -m32, -m64 or -m32mscoff
1026
 * to detect the desired architecture.
1027
 *
1028
 * Params:
1029
 *   args = Command line arguments
1030
 *   arch = Default value to use for architecture.
1031
 *          Should be "32" or "64"
1032
 *
1033
 * Returns:
1034
 *   "32", "64" or "32mscoff" if the "-m32", "-m64", "-m32mscoff" flags were passed,
1035
 *   respectively. If they weren't, return `arch`.
1036
 */
1037
const(char)[] parse_arch_arg(Strings* args, const(char)[] arch)
1038
{
1039 1
    foreach (const p; *args)
1040
    {
1041 1
        const(char)[] arg = p.toDString;
1042

1043 1
        if (arg.length && arg[0] == '-')
1044
        {
1045 1
            if (arg[1 .. $] == "m32" || arg[1 .. $] == "m32mscoff" || arg[1 .. $] == "m64")
1046 1
                arch = arg[2 .. $];
1047 1
            else if (arg[1 .. $] == "run")
1048 1
                break;
1049
        }
1050
    }
1051 1
    return arch;
1052
}
1053

1054

1055
/**
1056
 * Parse command line arguments for the last instance of -conf=path.
1057
 *
1058
 * Params:
1059
 *   args = Command line arguments
1060
 *
1061
 * Returns:
1062
 *   The 'path' in -conf=path, which is the path to the config file to use
1063
 */
1064
const(char)[] parse_conf_arg(Strings* args)
1065
{
1066 1
    const(char)[] conf;
1067 1
    foreach (const p; *args)
1068
    {
1069 1
        const(char)[] arg = p.toDString;
1070 1
        if (arg.length && arg[0] == '-')
1071
        {
1072 1
            if(arg.length >= 6 && arg[1 .. 6] == "conf="){
1073 1
                conf = arg[6 .. $];
1074
            }
1075 1
            else if (arg[1 .. $] == "run")
1076 1
                break;
1077
        }
1078
    }
1079 1
    return conf;
1080
}
1081

1082

1083
/**
1084
 * Set the default and debug libraries to link against, if not already set
1085
 *
1086
 * Must be called after argument parsing is done, as it won't
1087
 * override any value.
1088
 * Note that if `-defaultlib=` or `-debuglib=` was used,
1089
 * we don't override that either.
1090
 */
1091
private void setDefaultLibrary()
1092
{
1093 1
    if (global.params.defaultlibname is null)
1094
    {
1095
        static if (TARGET.Windows)
1096
        {
1097
            if (global.params.is64bit)
1098
                global.params.defaultlibname = "phobos64";
1099
            else if (global.params.mscoff)
1100
                global.params.defaultlibname = "phobos32mscoff";
1101
            else
1102
                global.params.defaultlibname = "phobos";
1103
        }
1104
        else static if (TARGET.Linux || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.Solaris || TARGET.DragonFlyBSD)
1105
        {
1106 1
            global.params.defaultlibname = "libphobos2.a";
1107
        }
1108
        else static if (TARGET.OSX)
1109
        {
1110
            global.params.defaultlibname = "phobos2";
1111
        }
1112
        else
1113
        {
1114
            static assert(0, "fix this");
1115
        }
1116
    }
1117 1
    else if (!global.params.defaultlibname.length)  // if `-defaultlib=` (i.e. an empty defaultlib)
1118 1
        global.params.defaultlibname = null;
1119

1120 1
    if (global.params.debuglibname is null)
1121 1
        global.params.debuglibname = global.params.defaultlibname;
1122
}
1123

1124
/*************************************
1125
 * Set the `is` target fields of `params` according
1126
 * to the TARGET value.
1127
 * Params:
1128
 *      params = where the `is` fields are
1129
 */
1130
void setTarget(ref Param params)
1131
{
1132
    static if (TARGET.Windows)
1133
        params.isWindows = true;
1134
    else static if (TARGET.Linux)
1135 1
        params.isLinux = true;
1136
    else static if (TARGET.OSX)
1137
        params.isOSX = true;
1138
    else static if (TARGET.FreeBSD)
1139
        params.isFreeBSD = true;
1140
    else static if (TARGET.OpenBSD)
1141
        params.isOpenBSD = true;
1142
    else static if (TARGET.Solaris)
1143
        params.isSolaris = true;
1144
    else static if (TARGET.DragonFlyBSD)
1145
        params.isDragonFlyBSD = true;
1146
    else
1147
        static assert(0, "unknown TARGET");
1148
}
1149

1150
/**
1151
 * Add default `version` identifier for dmd, and set the
1152
 * target platform in `params`.
1153
 * https://dlang.org/spec/version.html#predefined-versions
1154
 *
1155
 * Needs to be run after all arguments parsing (command line, DFLAGS environment
1156
 * variable and config file) in order to add final flags (such as `X86_64` or
1157
 * the `CRuntime` used).
1158
 *
1159
 * Params:
1160
 *      params = which target to compile for (set by `setTarget()`)
1161
 */
1162
void addDefaultVersionIdentifiers(const ref Param params)
1163
{
1164 1
    VersionCondition.addPredefinedGlobalIdent("DigitalMars");
1165 1
    if (params.isWindows)
1166
    {
1167 0
        VersionCondition.addPredefinedGlobalIdent("Windows");
1168 0
        if (global.params.mscoff)
1169
        {
1170 0
            VersionCondition.addPredefinedGlobalIdent("CRuntime_Microsoft");
1171 0
            VersionCondition.addPredefinedGlobalIdent("CppRuntime_Microsoft");
1172
        }
1173
        else
1174
        {
1175 0
            VersionCondition.addPredefinedGlobalIdent("CRuntime_DigitalMars");
1176 0
            VersionCondition.addPredefinedGlobalIdent("CppRuntime_DigitalMars");
1177
        }
1178
    }
1179 1
    else if (params.isLinux)
1180
    {
1181 1
        VersionCondition.addPredefinedGlobalIdent("Posix");
1182 1
        VersionCondition.addPredefinedGlobalIdent("linux");
1183 1
        VersionCondition.addPredefinedGlobalIdent("ELFv1");
1184
        // Note: This should be done with a target triplet, to support cross compilation.
1185
        // However DMD currently does not support it, so this is a simple
1186
        // fix to make DMD compile on Musl-based systems such as Alpine.
1187
        // See https://github.com/dlang/dmd/pull/8020
1188
        // And https://wiki.osdev.org/Target_Triplet
1189
        version (CRuntime_Musl)
1190
            VersionCondition.addPredefinedGlobalIdent("CRuntime_Musl");
1191
        else
1192 1
            VersionCondition.addPredefinedGlobalIdent("CRuntime_Glibc");
1193 1
        VersionCondition.addPredefinedGlobalIdent("CppRuntime_Gcc");
1194
    }
1195 0
    else if (params.isOSX)
1196
    {
1197 0
        VersionCondition.addPredefinedGlobalIdent("Posix");
1198 0
        VersionCondition.addPredefinedGlobalIdent("OSX");
1199 0
        VersionCondition.addPredefinedGlobalIdent("CppRuntime_Clang");
1200
        // For legacy compatibility
1201 0
        VersionCondition.addPredefinedGlobalIdent("darwin");
1202
    }
1203 0
    else if (params.isFreeBSD)
1204
    {
1205 0
        VersionCondition.addPredefinedGlobalIdent("Posix");
1206 0
        VersionCondition.addPredefinedGlobalIdent("FreeBSD");
1207 0
        VersionCondition.addPredefinedGlobalIdent("ELFv1");
1208 0
        VersionCondition.addPredefinedGlobalIdent("CppRuntime_Clang");
1209
    }
1210 0
    else if (params.isOpenBSD)
1211
    {
1212 0
        VersionCondition.addPredefinedGlobalIdent("Posix");
1213 0
        VersionCondition.addPredefinedGlobalIdent("OpenBSD");
1214 0
        VersionCondition.addPredefinedGlobalIdent("ELFv1");
1215 0
        VersionCondition.addPredefinedGlobalIdent("CppRuntime_Gcc");
1216
    }
1217 0
    else if (params.isDragonFlyBSD)
1218
    {
1219 0
        VersionCondition.addPredefinedGlobalIdent("Posix");
1220 0
        VersionCondition.addPredefinedGlobalIdent("DragonFlyBSD");
1221 0
        VersionCondition.addPredefinedGlobalIdent("ELFv1");
1222 0
        VersionCondition.addPredefinedGlobalIdent("CppRuntime_Gcc");
1223
    }
1224 0
    else if (params.isSolaris)
1225
    {
1226 0
        VersionCondition.addPredefinedGlobalIdent("Posix");
1227 0
        VersionCondition.addPredefinedGlobalIdent("Solaris");
1228 0
        VersionCondition.addPredefinedGlobalIdent("ELFv1");
1229 0
        VersionCondition.addPredefinedGlobalIdent("CppRuntime_Sun");
1230
    }
1231
    else
1232
    {
1233 0
        assert(0);
1234
    }
1235 1
    VersionCondition.addPredefinedGlobalIdent("LittleEndian");
1236 1
    VersionCondition.addPredefinedGlobalIdent("D_Version2");
1237 1
    VersionCondition.addPredefinedGlobalIdent("all");
1238

1239 1
    if (params.cpu >= CPU.sse2)
1240
    {
1241 1
        VersionCondition.addPredefinedGlobalIdent("D_SIMD");
1242 1
        if (params.cpu >= CPU.avx)
1243 1
            VersionCondition.addPredefinedGlobalIdent("D_AVX");
1244 1
        if (params.cpu >= CPU.avx2)
1245 1
            VersionCondition.addPredefinedGlobalIdent("D_AVX2");
1246
    }
1247

1248 1
    if (params.is64bit)
1249
    {
1250 1
        VersionCondition.addPredefinedGlobalIdent("D_InlineAsm_X86_64");
1251 1
        VersionCondition.addPredefinedGlobalIdent("X86_64");
1252 1
        if (params.isWindows)
1253
        {
1254 0
            VersionCondition.addPredefinedGlobalIdent("Win64");
1255
        }
1256
    }
1257
    else
1258
    {
1259 1
        VersionCondition.addPredefinedGlobalIdent("D_InlineAsm"); //legacy
1260 1
        VersionCondition.addPredefinedGlobalIdent("D_InlineAsm_X86");
1261 1
        VersionCondition.addPredefinedGlobalIdent("X86");
1262 1
        if (params.isWindows)
1263
        {
1264 0
            VersionCondition.addPredefinedGlobalIdent("Win32");
1265
        }
1266
    }
1267

1268 1
    if (params.isLP64)
1269 1
        VersionCondition.addPredefinedGlobalIdent("D_LP64");
1270 1
    if (params.doDocComments)
1271 1
        VersionCondition.addPredefinedGlobalIdent("D_Ddoc");
1272 1
    if (params.cov)
1273 1
        VersionCondition.addPredefinedGlobalIdent("D_Coverage");
1274 1
    if (params.pic != PIC.fixed)
1275 1
        VersionCondition.addPredefinedGlobalIdent(params.pic == PIC.pic ? "D_PIC" : "D_PIE");
1276 1
    if (params.useUnitTests)
1277 1
        VersionCondition.addPredefinedGlobalIdent("unittest");
1278 1
    if (params.useAssert == CHECKENABLE.on)
1279 1
        VersionCondition.addPredefinedGlobalIdent("assert");
1280 1
    if (params.useArrayBounds == CHECKENABLE.off)
1281 1
        VersionCondition.addPredefinedGlobalIdent("D_NoBoundsChecks");
1282 1
    if (params.betterC)
1283
    {
1284 1
        VersionCondition.addPredefinedGlobalIdent("D_BetterC");
1285
    }
1286
    else
1287
    {
1288 1
        VersionCondition.addPredefinedGlobalIdent("D_ModuleInfo");
1289 1
        VersionCondition.addPredefinedGlobalIdent("D_Exceptions");
1290 1
        VersionCondition.addPredefinedGlobalIdent("D_TypeInfo");
1291
    }
1292

1293 1
    VersionCondition.addPredefinedGlobalIdent("D_HardFloat");
1294
}
1295

1296
private void printPredefinedVersions(FILE* stream)
1297
{
1298 1
    if (global.versionids)
1299
    {
1300 1
        OutBuffer buf;
1301 1
        foreach (const str; *global.versionids)
1302
        {
1303 1
            buf.writeByte(' ');
1304 1
            buf.writestring(str.toChars());
1305
        }
1306 1
        stream.fprintf("predefs  %s\n", buf.peekChars());
1307
    }
1308
}
1309

1310
extern(C) void printGlobalConfigs(FILE* stream)
1311
{
1312 1
    stream.fprintf("binary    %.*s\n", cast(int)global.params.argv0.length, global.params.argv0.ptr);
1313 1
    stream.fprintf("version   %.*s\n", cast(int) global._version.length - 1, global._version.ptr);
1314 1
    const iniOutput = global.inifilename ? global.inifilename : "(none)";
1315 1
    stream.fprintf("config    %.*s\n", cast(int)iniOutput.length, iniOutput.ptr);
1316
    // Print DFLAGS environment variable
1317
    {
1318 1
        StringTable!(char*) environment;
1319 1
        environment._init(0);
1320 1
        Strings dflags;
1321 1
        getenv_setargv(readFromEnv(environment, "DFLAGS"), &dflags);
1322 1
        environment.reset(1);
1323 1
        OutBuffer buf;
1324 1
        foreach (flag; dflags[])
1325
        {
1326 1
            bool needsQuoting;
1327 1
            foreach (c; flag.toDString())
1328
            {
1329 1
                if (!(isalnum(c) || c == '_'))
1330
                {
1331 1
                    needsQuoting = true;
1332 1
                    break;
1333
                }
1334
            }
1335

1336 1
            if (flag.strchr(' '))
1337 0
                buf.printf("'%s' ", flag);
1338
            else
1339 1
                buf.printf("%s ", flag);
1340
        }
1341

1342 1
        auto res = buf[] ? buf[][0 .. $ - 1] : "(none)";
1343 1
        stream.fprintf("DFLAGS    %.*s\n", cast(int)res.length, res.ptr);
1344
    }
1345
}
1346

1347
/****************************************
1348
 * Determine the instruction set to be used, i.e. set params.cpu
1349
 * by combining the command line setting of
1350
 * params.cpu with the target operating system.
1351
 * Params:
1352
 *      params = parameters set by command line switch
1353
 */
1354

1355
private void setTargetCPU(ref Param params)
1356
{
1357 1
    if (target.isXmmSupported())
1358
    {
1359 1
        switch (params.cpu)
1360
        {
1361 1
            case CPU.baseline:
1362 1
                params.cpu = CPU.sse2;
1363 1
                break;
1364

1365 1
            case CPU.native:
1366
            {
1367
                import core.cpuid;
1368 1
                params.cpu = core.cpuid.avx2 ? CPU.avx2 :
1369 0
                             core.cpuid.avx  ? CPU.avx  :
1370 0
                                               CPU.sse2;
1371 1
                break;
1372
            }
1373

1374 1
            default:
1375 1
                break;
1376
        }
1377
    }
1378
    else
1379 1
        params.cpu = CPU.x87;   // cannot support other instruction sets
1380
}
1381

1382
/**************************************
1383
 * we want to write the mixin expansion file also on error, but there
1384
 * are too many ways to terminate dmd (e.g. fatal() which calls exit(EXIT_FAILURE)),
1385
 * so we can't rely on scope(exit) ... in tryMain() actually being executed
1386
 * so we add atexit(&flushMixins); for those fatal exits (with the GC still valid)
1387
 */
1388
extern(C) void flushMixins()
1389
{
1390 1
    if (!global.params.mixinOut)
1391 1
        return;
1392

1393 1
    assert(global.params.mixinFile);
1394 1
    File.write(global.params.mixinFile, (*global.params.mixinOut)[]);
1395

1396 1
    global.params.mixinOut.destroy();
1397 1
    global.params.mixinOut = null;
1398
}
1399

1400
/****************************************************
1401
 * Parse command line arguments.
1402
 *
1403
 * Prints message(s) if there are errors.
1404
 *
1405
 * Params:
1406
 *      arguments = command line arguments
1407
 *      argc = argument count
1408
 *      params = set to result of parsing `arguments`
1409
 *      files = set to files pulled from `arguments`
1410
 * Returns:
1411
 *      true if errors in command line
1412
 */
1413

1414
bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param params, ref Strings files)
1415
{
1416 1
    bool errors;
1417

1418
    void error(Args ...)(const(char)* format, Args args)
1419
    {
1420 1
        dmd.errors.error(Loc.initial, format, args);
1421 1
        errors = true;
1422
    }
1423

1424
    /**
1425
     * Print an error messsage about an invalid switch.
1426
     * If an optional supplemental message has been provided,
1427
     * it will be printed too.
1428
     *
1429
     * Params:
1430
     *  p = 0 terminated string
1431
     *  availableOptions = supplemental help message listing the available options
1432
     */
1433
    void errorInvalidSwitch(const(char)* p, string availableOptions = null)
1434
    {
1435 1
        error("Switch `%s` is invalid", p);
1436 1
        if (availableOptions !is null)
1437 1
            errorSupplemental(Loc.initial, "%.*s", cast(int)availableOptions.length, availableOptions.ptr);
1438
    }
1439

1440
    enum CheckOptions { success, error, help }
1441

1442
    /*
1443
    Checks whether the CLI options contains a valid argument or a help argument.
1444
    If a help argument has been used, it will set the `usageFlag`.
1445

1446
    Params:
1447
        p = string as a D array
1448
        usageFlag = parameter for the usage help page to set (by `ref`)
1449
        missingMsg = error message to use when no argument has been provided
1450

1451
    Returns:
1452
        `success` if a valid argument has been passed and it's not a help page
1453
        `error` if an error occurred (e.g. `-foobar`)
1454
        `help` if a help page has been request (e.g. `-flag` or `-flag=h`)
1455
    */
1456
    CheckOptions checkOptions(const(char)[] p, ref bool usageFlag, string missingMsg)
1457
    {
1458
        // Checks whether a flag has no options (e.g. -foo or -foo=)
1459 1
        if (p.length == 0 || p == "=")
1460
        {
1461 1
            .error(Loc.initial, "%.*s", cast(int)missingMsg.length, missingMsg.ptr);
1462 1
            errors = true;
1463 1
            usageFlag = true;
1464 1
            return CheckOptions.help;
1465
        }
1466 1
        if (p[0] != '=')
1467 1
            return CheckOptions.error;
1468 1
        p = p[1 .. $];
1469
        /* Checks whether the option pointer supplied is a request
1470
           for the help page, e.g. -foo=j */
1471 1
        if ((p == "h" || p == "?") || // -flag=h || -flag=?
1472 1
             p == "help")
1473
        {
1474 1
            usageFlag = true;
1475 1
            return CheckOptions.help;
1476
        }
1477 1
        return CheckOptions.success;
1478
    }
1479

1480
    static string checkOptionsMixin(string usageFlag, string missingMsg)
1481
    {
1482 0
        return q{
1483
            final switch (checkOptions(arg[len - 1 .. $], params.}~usageFlag~","~
1484
                          `"`~missingMsg~`"`~q{))
1485
            {
1486
                case CheckOptions.error:
1487
                    goto Lerror;
1488
                case CheckOptions.help:
1489
                    return false;
1490
                case CheckOptions.success:
1491
                    break;
1492
            }
1493
        };
1494
    }
1495

1496
    import dmd.cli : Usage;
1497
    bool parseCLIOption(string name, Usage.Feature[] features)(ref Param params, const(char)[] p)
1498
    {
1499
        // Parse:
1500
        //      -<name>=<feature>
1501 1
        const(char)[] ps = p[name.length + 1 .. $];
1502 1
        const(char)[] ident = ps[1 .. $];
1503 1
        if (Identifier.isValidIdentifier(ident))
1504
        {
1505
            string generateTransitionsText()
1506
            {
1507
                import dmd.cli : Usage;
1508 0
                string buf = `case "all":`;
1509 0
                foreach (t; features)
1510
                {
1511 0
                    if (t.deprecated_)
1512 0
                        continue;
1513

1514 0
                    buf ~= `params.`~t.paramName~` = true;`;
1515
                }
1516 0
                buf ~= "return true;\n";
1517

1518 0
                foreach (t; features)
1519
                {
1520 0
                    buf ~= `case "`~t.name~`":`;
1521 0
                    if (t.deprecated_)
1522 0
                        buf ~= "deprecation(Loc.initial, \"`-"~name~"="~t.name~"` no longer has any effect.\"); ";
1523 0
                    buf ~= `params.`~t.paramName~` = true; return true;`;
1524
                }
1525 0
                return buf;
1526
            }
1527

1528 1
            switch (ident)
1529
            {
1530
                mixin(generateTransitionsText());
1531 1
            default:
1532 1
                return false;
1533
            }
1534
        }
1535 1
        return false;
1536
    }
1537

1538
    version (none)
1539
    {
1540
        for (size_t i = 0; i < arguments.dim; i++)
1541
        {
1542
            printf("arguments[%d] = '%s'\n", i, arguments[i]);
1543
        }
1544
    }
1545 1
    for (size_t i = 1; i < arguments.dim; i++)
1546
    {
1547 1
        const(char)* p = arguments[i];
1548 1
        const(char)[] arg = p.toDString();
1549 1
        if (*p != '-')
1550
        {
1551
            static if (TARGET.Windows)
1552
            {
1553
                const ext = FileName.ext(arg);
1554
                if (ext.length && FileName.equals(ext, "exe"))
1555
                {
1556
                    params.objname = arg;
1557
                    continue;
1558
                }
1559
                if (arg == "/?")
1560
                {
1561
                    params.usage = true;
1562
                    return false;
1563
                }
1564
            }
1565 1
            files.push(p);
1566 1
            continue;
1567
        }
1568

1569 1
        if (arg == "-allinst")               // https://dlang.org/dmd.html#switch-allinst
1570 1
            params.allInst = true;
1571 1
        else if (arg == "-de")               // https://dlang.org/dmd.html#switch-de
1572 1
            params.useDeprecated = DiagnosticReporting.error;
1573 1
        else if (arg == "-d")                // https://dlang.org/dmd.html#switch-d
1574 1
            params.useDeprecated = DiagnosticReporting.off;
1575 1
        else if (arg == "-dw")               // https://dlang.org/dmd.html#switch-dw
1576 1
            params.useDeprecated = DiagnosticReporting.inform;
1577 1
        else if (arg == "-c")                // https://dlang.org/dmd.html#switch-c
1578 1
            params.link = false;
1579 1
        else if (startsWith(p + 1, "checkaction")) // https://dlang.org/dmd.html#switch-checkaction
1580
        {
1581
            /* Parse:
1582
             *    -checkaction=D|C|halt|context
1583
             */
1584
            enum len = "-checkaction=".length;
1585
            mixin(checkOptionsMixin("checkActionUsage",
1586
                "`-check=<behavior>` requires a behavior"));
1587 1
            switch (arg[len .. $])
1588
            {
1589 0
            case "D":
1590 0
                params.checkAction = CHECKACTION.D;
1591 0
                break;
1592 0
            case "C":
1593 0
                params.checkAction = CHECKACTION.C;
1594 0
                break;
1595 0
            case "halt":
1596 0
                params.checkAction = CHECKACTION.halt;
1597 0
                break;
1598 1
            case "context":
1599 1
                params.checkAction = CHECKACTION.context;
1600 1
                break;
1601 1
            default:
1602 1
                errorInvalidSwitch(p);
1603 1
                params.checkActionUsage = true;
1604 1
                return false;
1605
            }
1606
        }
1607 1
        else if (startsWith(p + 1, "check")) // https://dlang.org/dmd.html#switch-check
1608
        {
1609
            enum len = "-check=".length;
1610
            mixin(checkOptionsMixin("checkUsage",
1611
                "`-check=<action>` requires an action"));
1612
            /* Parse:
1613
             *    -check=[assert|bounds|in|invariant|out|switch][=[on|off]]
1614
             */
1615

1616
            // Check for legal option string; return true if so
1617
            static bool check(const(char)[] checkarg, string name, ref CHECKENABLE ce)
1618
            {
1619 1
                if (checkarg.length >= name.length &&
1620 1
                    checkarg[0 .. name.length] == name)
1621
                {
1622 1
                    checkarg = checkarg[name.length .. $];
1623

1624 1
                    if (checkarg.length == 0 ||
1625 1
                        checkarg == "=on")
1626
                    {
1627 0
                        ce = CHECKENABLE.on;
1628 0
                        return true;
1629
                    }
1630 1
                    else if (checkarg == "=off")
1631
                    {
1632 1
                        ce = CHECKENABLE.off;
1633 1
                        return true;
1634
                    }
1635
                }
1636 1
                return false;
1637
            }
1638

1639 1
            const(char)[] checkarg = arg[len .. $];
1640 1
            if (!(check(checkarg, "assert",    params.useAssert     ) ||
1641 1
                  check(checkarg, "bounds",    params.useArrayBounds) ||
1642 1
                  check(checkarg, "in",        params.useIn         ) ||
1643 1
                  check(checkarg, "invariant", params.useInvariants ) ||
1644 1
                  check(checkarg, "out",       params.useOut        ) ||
1645 1
                  check(checkarg, "switch",    params.useSwitchError)))
1646
            {
1647 1
                errorInvalidSwitch(p);
1648 1
                params.checkUsage = true;
1649 1
                return false;
1650
            }
1651
        }
1652 1
        else if (startsWith(p + 1, "color")) // https://dlang.org/dmd.html#switch-color
1653
        {
1654
            // Parse:
1655
            //      -color
1656
            //      -color=auto|on|off
1657 1
            if (p[6] == '=')
1658
            {
1659 1
                switch(arg[7 .. $])
1660
                {
1661 1
                case "on":
1662 1
                    params.color = true;
1663 1
                    break;
1664 1
                case "off":
1665 1
                    params.color = false;
1666 1
                    break;
1667 1
                case "auto":
1668 1
                    break;
1669 1
                default:
1670 1
                    errorInvalidSwitch(p, "Available options for `-color` are `on`, `off` and `auto`");
1671 1
                    return true;
1672
                }
1673
            }
1674 0
            else if (p[6])
1675 0
                goto Lerror;
1676
            else
1677 0
                params.color = true;
1678
        }
1679 1
        else if (startsWith(p + 1, "conf=")) // https://dlang.org/dmd.html#switch-conf
1680
        {
1681
            // ignore, already handled above
1682
        }
1683 1
        else if (startsWith(p + 1, "cov")) // https://dlang.org/dmd.html#switch-cov
1684
        {
1685 1
            params.cov = true;
1686
            // Parse:
1687
            //      -cov
1688
            //      -cov=ctfe
1689
            //      -cov=nnn
1690 1
            if (arg == "-cov=ctfe")
1691
            {
1692 1
                params.ctfe_cov = true;
1693
            }
1694 1
            else if (p[4] == '=')
1695
            {
1696 1
                if (!params.covPercent.parseDigits(p.toDString()[5 .. $], 100))
1697
                {
1698 1
                    errorInvalidSwitch(p, "Only a number between 0 and 100 can be passed to `-cov=<num>`");
1699 1
                    return true;
1700
                }
1701
            }
1702 1
            else if (p[4])
1703 0
                goto Lerror;
1704
        }
1705 1
        else if (arg == "-shared")
1706 1
            params.dll = true;
1707 1
        else if (arg == "-fPIC")
1708
        {
1709
            static if (TARGET.Linux || TARGET.OSX || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.Solaris || TARGET.DragonFlyBSD)
1710
            {
1711 1
                params.pic = PIC.pic;
1712
            }
1713
            else
1714
            {
1715
                goto Lerror;
1716
            }
1717
        }
1718 1
        else if (arg == "-fPIE")
1719
        {
1720
            static if (TARGET.Linux || TARGET.OSX || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.Solaris || TARGET.DragonFlyBSD)
1721
            {
1722 1
                params.pic = PIC.pie;
1723
            }
1724
            else
1725
            {
1726
                goto Lerror;
1727
            }
1728
        }
1729 1
        else if (arg == "-map") // https://dlang.org/dmd.html#switch-map
1730 0
            params.map = true;
1731 1
        else if (arg == "-multiobj")
1732 0
            params.multiobj = true;
1733 1
        else if (startsWith(p + 1, "mixin="))
1734
        {
1735 1
            auto tmp = p + 6 + 1;
1736 1
            if (!tmp[0])
1737 0
                goto Lnoarg;
1738 1
            params.mixinFile = mem.xstrdup(tmp);
1739
        }
1740 1
        else if (arg == "-g") // https://dlang.org/dmd.html#switch-g
1741 1
            params.symdebug = 1;
1742 1
        else if (arg == "-gf")
1743
        {
1744 1
            if (!params.symdebug)
1745 1
                params.symdebug = 1;
1746 1
            params.symdebugref = true;
1747
        }
1748 1
        else if (arg == "-gs")  // https://dlang.org/dmd.html#switch-gs
1749 0
            params.alwaysframe = true;
1750 1
        else if (arg == "-gx")  // https://dlang.org/dmd.html#switch-gx
1751 1
            params.stackstomp = true;
1752 1
        else if (arg == "-lowmem") // https://dlang.org/dmd.html#switch-lowmem
1753
        {
1754
            static if (isGCAvailable)
1755
            {
1756
                // ignore, already handled in C main
1757
            }
1758
            else
1759
            {
1760
                error("switch '%s' requires DMD to be built with '-version=GC'", arg.ptr);
1761
                continue;
1762
            }
1763
        }
1764 1
        else if (arg.length > 6 && arg[0..6] == "--DRT-")
1765
        {
1766 0
            continue; // skip druntime options, e.g. used to configure the GC
1767
        }
1768 1
        else if (arg == "-m32") // https://dlang.org/dmd.html#switch-m32
1769
        {
1770
            static if (TARGET.DragonFlyBSD) {
1771
                error("-m32 is not supported on DragonFlyBSD, it is 64-bit only");
1772
            } else {
1773 1
                params.is64bit = false;
1774 1
                params.mscoff = false;
1775
            }
1776
        }
1777 1
        else if (arg == "-m64") // https://dlang.org/dmd.html#switch-m64
1778
        {
1779 1
            params.is64bit = true;
1780
            static if (TARGET.Windows)
1781
            {
1782
                params.mscoff = true;
1783
            }
1784
        }
1785 1
        else if (arg == "-m32mscoff") // https://dlang.org/dmd.html#switch-m32mscoff
1786
        {
1787
            static if (TARGET.Windows)
1788
            {
1789
                params.is64bit = 0;
1790
                params.mscoff = true;
1791
            }
1792
            else
1793
            {
1794 0
                error("-m32mscoff can only be used on windows");
1795
            }
1796
        }
1797 1
        else if (startsWith(p + 1, "mscrtlib="))
1798
        {
1799
            static if (TARGET.Windows)
1800
            {
1801
                params.mscrtlib = arg[10 .. $];
1802
            }
1803
            else
1804
            {
1805 0
                error("-mscrtlib");
1806
            }
1807
        }
1808 1
        else if (startsWith(p + 1, "profile")) // https://dlang.org/dmd.html#switch-profile
1809
        {
1810
            // Parse:
1811
            //      -profile
1812
            //      -profile=gc
1813 1
            if (p[8] == '=')
1814
            {
1815 1
                if (arg[9 .. $] == "gc")
1816 1
                    params.tracegc = true;
1817
                else
1818
                {
1819 1
                    errorInvalidSwitch(p, "Only `gc` is allowed for `-profile`");
1820 1
                    return true;
1821
                }
1822
            }
1823 1
            else if (p[8])
1824 0
                goto Lerror;
1825
            else
1826 1
                params.trace = true;
1827
        }
1828 1
        else if (arg == "-v") // https://dlang.org/dmd.html#switch-v
1829 1
            params.verbose = true;
1830 1
        else if (arg == "-vcg-ast")
1831 1
            params.vcg_ast = true;
1832 1
        else if (arg == "-vtls") // https://dlang.org/dmd.html#switch-vtls
1833 1
            params.vtls = true;
1834 1
        else if (arg == "-vtemplates") // https://dlang.org/dmd.html#switch-vtemplates
1835 1
            params.vtemplates = true;
1836 1
        else if (arg == "-vcolumns") // https://dlang.org/dmd.html#switch-vcolumns
1837 1
            params.showColumns = true;
1838 1
        else if (arg == "-vgc") // https://dlang.org/dmd.html#switch-vgc
1839 1
            params.vgc = true;
1840 1
        else if (startsWith(p + 1, "verrors")) // https://dlang.org/dmd.html#switch-verrors
1841
        {
1842 1
            if (p[8] != '=')
1843
            {
1844 0
                errorInvalidSwitch(p, "Expected argument following `-verrors , e.g. `-verrors=100`");
1845 0
                return true;
1846
            }
1847 1
            if (startsWith(p + 9, "spec"))
1848
            {
1849 1
                params.showGaggedErrors = true;
1850
            }
1851 1
            else if (startsWith(p + 9, "context"))
1852
            {
1853 1
                params.printErrorContext = true;
1854
            }
1855 1
            else if (!params.errorLimit.parseDigits(p.toDString()[9 .. $]))
1856
            {
1857 1
                errorInvalidSwitch(p, "Only number, `spec`, or `context` are allowed for `-verrors`");
1858 1
                return true;
1859
            }
1860
        }
1861 1
        else if (startsWith(p + 1, "verror-style="))
1862
        {
1863 1
            const(char)[] style = arg["verror-style=".length + 1 .. $];
1864

1865 1
            switch (style)
1866
            {
1867 0
            case "digitalmars":
1868 0
                params.messageStyle = MessageStyle.digitalmars;
1869 0
                break;
1870 1
            case "gnu":
1871 1
                params.messageStyle = MessageStyle.gnu;
1872 1
                break;
1873 0
            default:
1874 0
                error("unknown error style '%.*s', must be 'digitalmars' or 'gnu'", cast(int) style.length, style.ptr);
1875
            }
1876
        }
1877 1
        else if (startsWith(p + 1, "mcpu")) // https://dlang.org/dmd.html#switch-mcpu
1878
        {
1879
            enum len = "-mcpu=".length;
1880
            // Parse:
1881
            //      -mcpu=identifier
1882
            mixin(checkOptionsMixin("mcpuUsage",
1883
                "`-mcpu=<architecture>` requires an architecture"));
1884 1
            if (Identifier.isValidIdentifier(p + len))
1885
            {
1886 1
                const ident = p + len;
1887 1
                switch (ident.toDString())
1888
                {
1889 0
                case "baseline":
1890 0
                    params.cpu = CPU.baseline;
1891 0
                    break;
1892 1
                case "avx":
1893 1
                    params.cpu = CPU.avx;
1894 1
                    break;
1895 1
                case "avx2":
1896 1
                    params.cpu = CPU.avx2;
1897 1
                    break;
1898 1
                case "native":
1899 1
                    params.cpu = CPU.native;
1900 1
                    break;
1901 1
                default:
1902 1
                    errorInvalidSwitch(p, "Only `baseline`, `avx`, `avx2` or `native` are allowed for `-mcpu`");
1903 1
                    params.mcpuUsage = true;
1904 1
                    return false;
1905
                }
1906
            }
1907
            else
1908
            {
1909 0
                errorInvalidSwitch(p, "Only `baseline`, `avx`, `avx2` or `native` are allowed for `-mcpu`");
1910 0
                params.mcpuUsage = true;
1911 0
                return false;
1912
            }
1913
        }
1914 1
        else if (startsWith(p + 1, "extern-std")) // https://dlang.org/dmd.html#switch-extern-std
1915
        {
1916
            enum len = "-extern-std=".length;
1917
            // Parse:
1918
            //      -extern-std=identifier
1919
            mixin(checkOptionsMixin("externStdUsage",
1920
                "`-extern-std=<standard>` requires a standard"));
1921 1
            const(char)[] cpprev = arg[len .. $];
1922

1923 1
            switch (cpprev)
1924
            {
1925 1
            case "c++98":
1926 1
                params.cplusplus = CppStdRevision.cpp98;
1927 1
                break;
1928 1
            case "c++11":
1929 1
                params.cplusplus = CppStdRevision.cpp11;
1930 1
                break;
1931 0
            case "c++14":
1932 0
                params.cplusplus = CppStdRevision.cpp14;
1933 0
                break;
1934 0
            case "c++17":
1935 0
                params.cplusplus = CppStdRevision.cpp17;
1936 0
                break;
1937 1
            default:
1938 1
                error("Switch `%s` is invalid", p);
1939 1
                params.externStdUsage = true;
1940 1
                return false;
1941
            }
1942
        }
1943 1
        else if (startsWith(p + 1, "transition")) // https://dlang.org/dmd.html#switch-transition
1944
        {
1945
            enum len = "-transition=".length;
1946
            // Parse:
1947
            //      -transition=number
1948
            mixin(checkOptionsMixin("transitionUsage",
1949
                "`-transition=<name>` requires a name"));
1950 1
            if (!parseCLIOption!("transition", Usage.transitions)(params, arg))
1951
            {
1952
                // Legacy -transition flags
1953
                // Before DMD 2.085, DMD `-transition` was used for all language flags
1954
                // These are kept for backwards compatibility, but no longer documented
1955 1
                if (isdigit(cast(char)p[len]))
1956
                {
1957 1
                    uint num;
1958 1
                    if (!num.parseDigits(p.toDString()[len .. $]))
1959 0
                        goto Lerror;
1960

1961
                    // Bugzilla issue number
1962 1
                    switch (num)
1963
                    {
1964 0
                        case 3449:
1965 0
                            params.vfield = true;
1966 0
                            break;
1967 0
                        case 14_246:
1968 0
                            params.dtorFields = true;
1969 0
                            break;
1970 0
                        case 14_488:
1971 0
                            params.vcomplex = true;
1972 0
                            break;
1973 0
                        case 16_997:
1974 0
                            params.fix16997 = true;
1975 0
                            break;
1976 1
                        default:
1977 1
                            error("Transition `%s` is invalid", p);
1978 1
                            params.transitionUsage = true;
1979 1
                            return false;
1980
                    }
1981
                }
1982 1
                else if (Identifier.isValidIdentifier(p + len))
1983
                {
1984 1
                    const ident = p + len;
1985 1
                    switch (ident.toDString())
1986
                    {
1987 0
                        case "dtorfields":
1988 0
                            params.dtorFields = true;
1989 0
                            break;
1990 0
                        case "intpromote":
1991 0
                            params.fix16997 = true;
1992 0
                            break;
1993 0
                        case "markdown":
1994 0
                            params.markdown = true;
1995 0
                            break;
1996 1
                        default:
1997 1
                            error("Transition `%s` is invalid", p);
1998 1
                            params.transitionUsage = true;
1999 1
                            return false;
2000
                    }
2001
                }
2002 0
                errorInvalidSwitch(p);
2003 0
                params.transitionUsage = true;
2004 0
                return false;
2005
            }
2006
        }
2007 1
        else if (startsWith(p + 1, "preview") ) // https://dlang.org/dmd.html#switch-preview
2008
        {
2009
            enum len = "-preview=".length;
2010
            // Parse:
2011
            //      -preview=name
2012
            mixin(checkOptionsMixin("previewUsage",
2013
                "`-preview=<name>` requires a name"));
2014

2015 1
            if (!parseCLIOption!("preview", Usage.previews)(params, arg))
2016
            {
2017 0
                error("Preview `%s` is invalid", p);
2018 0
                params.previewUsage = true;
2019 0
                return false;
2020
            }
2021

2022 1
            if (params.useDIP1021)
2023 1
                params.vsafe = true;    // dip1021 implies dip1000
2024

2025
            // copy previously standalone flags from -transition
2026
            // -preview=dip1000 implies -preview=dip25 too
2027 1
            if (params.vsafe)
2028 1
                params.useDIP25 = true;
2029
        }
2030 1
        else if (startsWith(p + 1, "revert") ) // https://dlang.org/dmd.html#switch-revert
2031
        {
2032
            enum len = "-revert=".length;
2033
            // Parse:
2034
            //      -revert=name
2035
            mixin(checkOptionsMixin("revertUsage",
2036
                "`-revert=<name>` requires a name"));
2037

2038 1
            if (!parseCLIOption!("revert", Usage.reverts)(params, arg))
2039
            {
2040 0
                error("Revert `%s` is invalid", p);
2041 0
                params.revertUsage = true;
2042 0
                return false;
2043
            }
2044

2045 1
            if (params.noDIP25)
2046 1
                params.useDIP25 = false;
2047
        }
2048 1
        else if (arg == "-w")   // https://dlang.org/dmd.html#switch-w
2049 1
            params.warnings = DiagnosticReporting.error;
2050 1
        else if (arg == "-wi")  // https://dlang.org/dmd.html#switch-wi
2051 1
            params.warnings = DiagnosticReporting.inform;
2052 1
        else if (arg == "-O")   // https://dlang.org/dmd.html#switch-O
2053 1
            params.optimize = true;
2054 1
        else if (p[1] == 'o')
2055
        {
2056 1
            const(char)* path;
2057 1
            switch (p[2])
2058
            {
2059 1
            case '-':                       // https://dlang.org/dmd.html#switch-o-
2060 1
                params.obj = false;
2061 1
                break;
2062 1
            case 'd':                       // https://dlang.org/dmd.html#switch-od
2063 1
                if (!p[3])
2064 0
                    goto Lnoarg;
2065 1
                path = p + 3 + (p[3] == '=');
2066
                version (Windows)
2067
                {
2068
                    path = toWinPath(path);
2069
                }
2070 1
                params.objdir = path.toDString;
2071 1
                break;
2072 1
            case 'f':                       // https://dlang.org/dmd.html#switch-of
2073 1
                if (!p[3])
2074 0
                    goto Lnoarg;
2075 1
                path = p + 3 + (p[3] == '=');
2076
                version (Windows)
2077
                {
2078
                    path = toWinPath(path);
2079
                }
2080 1
                params.objname = path.toDString;
2081 1
                break;
2082 0
            case 'p':                       // https://dlang.org/dmd.html#switch-op
2083 0
                if (p[3])
2084 0
                    goto Lerror;
2085 0
                params.preservePaths = true;
2086 0
                break;
2087 0
            case 0:
2088 0
                error("-o no longer supported, use -of or -od");
2089 0
                break;
2090 0
            default:
2091 0
                goto Lerror;
2092
            }
2093
        }
2094 1
        else if (p[1] == 'D')       // https://dlang.org/dmd.html#switch-D
2095
        {
2096 1
            params.doDocComments = true;
2097 1
            switch (p[2])
2098
            {
2099 1
            case 'd':               // https://dlang.org/dmd.html#switch-Dd
2100 1
                if (!p[3])
2101 0
                    goto Lnoarg;
2102 1
                params.docdir = (p + 3 + (p[3] == '=')).toDString();
2103 1
                break;
2104 1
            case 'f':               // https://dlang.org/dmd.html#switch-Df
2105 1
                if (!p[3])
2106 0
                    goto Lnoarg;
2107 1
                params.docname = (p + 3 + (p[3] == '=')).toDString();
2108 1
                break;
2109 1
            case 0:
2110 1
                break;
2111 0
            default:
2112 0
                goto Lerror;
2113
            }
2114
        }
2115 1
        else if (p[1] == 'H' && p[2] == 'C')  // https://dlang.org/dmd.html#switch-HC
2116
        {
2117 1
            params.doCxxHdrGeneration = true;
2118 1
            switch (p[3])
2119
            {
2120 0
            case 'd':               // https://dlang.org/dmd.html#switch-HCd
2121 0
                if (!p[4])
2122 0
                    goto Lnoarg;
2123 0
                params.cxxhdrdir = (p + 4 + (p[4] == '=')).toDString;
2124 0
                break;
2125 0
            case 'f':               // https://dlang.org/dmd.html#switch-HCf
2126 0
                if (!p[4])
2127 0
                    goto Lnoarg;
2128 0
                params.cxxhdrname = (p + 4 + (p[4] == '=')).toDString;
2129 0
                break;
2130 1
            case 0:
2131 1
                break;
2132 0
            default:
2133 0
                goto Lerror;
2134
            }
2135
        }
2136 1
        else if (p[1] == 'H')       // https://dlang.org/dmd.html#switch-H
2137
        {
2138 1
            params.doHdrGeneration = true;
2139 1
            switch (p[2])
2140
            {
2141 1
            case 'd':               // https://dlang.org/dmd.html#switch-Hd
2142 1
                if (!p[3])
2143 0
                    goto Lnoarg;
2144 1
                params.hdrdir = (p + 3 + (p[3] == '=')).toDString;
2145 1
                break;
2146 1
            case 'f':               // https://dlang.org/dmd.html#switch-Hf
2147 1
                if (!p[3])
2148 0
                    goto Lnoarg;
2149 1
                params.hdrname = (p + 3 + (p[3] == '=')).toDString;
2150 1
                break;
2151 1
            case 0:
2152 1
                break;
2153 0
            default:
2154 0
                goto Lerror;
2155
            }
2156
        }
2157 1
        else if (startsWith(p + 1, "Xcc="))
2158
        {
2159
            // Linking code is guarded by version (Posix):
2160
            static if (TARGET.Linux || TARGET.OSX || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.Solaris || TARGET.DragonFlyBSD)
2161
            {
2162 1
                params.linkswitches.push(p + 5);
2163 1
                params.linkswitchIsForCC.push(true);
2164
            }
2165
            else
2166
            {
2167
                goto Lerror;
2168
            }
2169
        }
2170 1
        else if (p[1] == 'X')       // https://dlang.org/dmd.html#switch-X
2171
        {
2172 1
            params.doJsonGeneration = true;
2173 1
            switch (p[2])
2174
            {
2175 1
            case 'f':               // https://dlang.org/dmd.html#switch-Xf
2176 1
                if (!p[3])
2177 0
                    goto Lnoarg;
2178 1
                params.jsonfilename = (p + 3 + (p[3] == '=')).toDString;
2179 1
                break;
2180 1
            case 'i':
2181 1
                if (!p[3])
2182 1
                    goto Lnoarg;
2183 1
                if (p[3] != '=')
2184 1
                    goto Lerror;
2185 1
                if (!p[4])
2186 1
                    goto Lnoarg;
2187

2188
                {
2189 1
                    auto flag = tryParseJsonField(p + 4);
2190 1
                    if (!flag)
2191
                    {
2192 1
                        error("unknown JSON field `-Xi=%s`, expected one of " ~ jsonFieldNames, p + 4);
2193 1
                        continue;
2194
                    }
2195 1
                    global.params.jsonFieldFlags |= flag;
2196
                }
2197 1
                break;
2198 1
            case 0:
2199 1
                break;
2200 0
            default:
2201 0
                goto Lerror;
2202
            }
2203
        }
2204 1
        else if (arg == "-ignore")      // https://dlang.org/dmd.html#switch-ignore
2205 1
            params.ignoreUnsupportedPragmas = true;
2206 1
        else if (arg == "-inline")      // https://dlang.org/dmd.html#switch-inline
2207
        {
2208 1
            params.useInline = true;
2209 1
            params.hdrStripPlainFunctions = false;
2210
        }
2211 1
        else if (arg == "-i")
2212 1
            includeImports = true;
2213 1
        else if (startsWith(p + 1, "i="))
2214
        {
2215 1
            includeImports = true;
2216 1
            if (!p[3])
2217
            {
2218 1
                error("invalid option '%s', module patterns cannot be empty", p);
2219
            }
2220
            else
2221
            {
2222
                // NOTE: we could check that the argument only contains valid "module-pattern" characters.
2223
                //       Invalid characters doesn't break anything but an error message to the user might
2224
                //       be nice.
2225 1
                includeModulePatterns.push(p + 3);
2226
            }
2227
        }
2228 1
        else if (arg == "-dip25")       // https://dlang.org/dmd.html#switch-dip25
2229 1
            params.useDIP25 = true;
2230 1
        else if (arg == "-dip1000")
2231
        {
2232 1
            params.useDIP25 = true;
2233 1
            params.vsafe = true;
2234
        }
2235 1
        else if (arg == "-dip1008")
2236
        {
2237 1
            params.ehnogc = true;
2238
        }
2239 1
        else if (arg == "-lib")         // https://dlang.org/dmd.html#switch-lib
2240 1
            params.lib = true;
2241 1
        else if (arg == "-nofloat")
2242 0
            params.nofloat = true;
2243 1
        else if (arg == "-quiet")
2244
        {
2245
            // Ignore
2246
        }
2247 1
        else if (arg == "-release")     // https://dlang.org/dmd.html#switch-release
2248 1
            params.release = true;
2249 1
        else if (arg == "-betterC")     // https://dlang.org/dmd.html#switch-betterC
2250 1
            params.betterC = true;
2251 1
        else if (arg == "-noboundscheck") // https://dlang.org/dmd.html#switch-noboundscheck
2252
        {
2253 1
            params.boundscheck = CHECKENABLE.off;
2254
        }
2255 1
        else if (startsWith(p + 1, "boundscheck")) // https://dlang.org/dmd.html#switch-boundscheck
2256
        {
2257
            // Parse:
2258
            //      -boundscheck=[on|safeonly|off]
2259 1
            if (p[12] == '=')
2260
            {
2261 1
                const(char)[] boundscheck = arg[13 .. $];
2262

2263 1
                switch (boundscheck)
2264
                {
2265 1
                case "on":
2266 1
                    params.boundscheck = CHECKENABLE.on;
2267 1
                    break;
2268 1
                case "safeonly":
2269 1
                    params.boundscheck = CHECKENABLE.safeonly;
2270 1
                    break;
2271 1
                case "off":
2272 1
                    params.boundscheck = CHECKENABLE.off;
2273 1
                    break;
2274 0
                default:
2275 0
                    goto Lerror;
2276
                }
2277
            }
2278
            else
2279 0
                goto Lerror;
2280
        }
2281 1
        else if (arg == "-unittest")
2282 1
            params.useUnitTests = true;
2283 1
        else if (p[1] == 'I')              // https://dlang.org/dmd.html#switch-I
2284
        {
2285 1
            if (!params.imppath)
2286 1
                params.imppath = new Strings();
2287 1
            params.imppath.push(p + 2 + (p[2] == '='));
2288
        }
2289 1
        else if (p[1] == 'm' && p[2] == 'v' && p[3] == '=') // https://dlang.org/dmd.html#switch-mv
2290
        {
2291 1
            if (p[4] && strchr(p + 5, '='))
2292
            {
2293 1
                params.modFileAliasStrings.push(p + 4);
2294
            }
2295
            else
2296 0
                goto Lerror;
2297
        }
2298 1
        else if (p[1] == 'J')             // https://dlang.org/dmd.html#switch-J
2299
        {
2300 1
            if (!params.fileImppath)
2301 1
                params.fileImppath = new Strings();
2302 1
            params.fileImppath.push(p + 2 + (p[2] == '='));
2303
        }
2304 1
        else if (startsWith(p + 1, "debug") && p[6] != 'l') // https://dlang.org/dmd.html#switch-debug
2305
        {
2306
            // Parse:
2307
            //      -debug
2308
            //      -debug=number
2309
            //      -debug=identifier
2310 1
            if (p[6] == '=')
2311
            {
2312 1
                if (isdigit(cast(char)p[7]))
2313
                {
2314 1
                    if (!params.debuglevel.parseDigits(p.toDString()[7 .. $]))
2315 0
                        goto Lerror;
2316
                }
2317 1
                else if (Identifier.isValidIdentifier(p + 7))
2318
                {
2319 1
                    if (!params.debugids)
2320 1
                        params.debugids = new Array!(const(char)*);
2321 1
                    params.debugids.push(p + 7);
2322
                }
2323
                else
2324 0
                    goto Lerror;
2325
            }
2326 1
            else if (p[6])
2327 0
                goto Lerror;
2328
            else
2329 1
                params.debuglevel = 1;
2330
        }
2331 1
        else if (startsWith(p + 1, "version")) // https://dlang.org/dmd.html#switch-version
2332
        {
2333
            // Parse:
2334
            //      -version=number
2335
            //      -version=identifier
2336 1
            if (p[8] == '=')
2337
            {
2338 1
                if (isdigit(cast(char)p[9]))
2339
                {
2340 1
                    if (!params.versionlevel.parseDigits(p.toDString()[9 .. $]))
2341 0
                        goto Lerror;
2342
                }
2343 1
                else if (Identifier.isValidIdentifier(p + 9))
2344
                {
2345 1
                    if (!params.versionids)
2346 1
                        params.versionids = new Array!(const(char)*);
2347 1
                    params.versionids.push(p + 9);
2348
                }
2349
                else
2350 0
                    goto Lerror;
2351
            }
2352
            else
2353 0
                goto Lerror;
2354
        }
2355 1
        else if (arg == "--b")
2356 0
            params.debugb = true;
2357 1
        else if (arg == "--c")
2358 0
            params.debugc = true;
2359 1
        else if (arg == "--f")
2360 0
            params.debugf = true;
2361 1
        else if (arg == "--help" ||
2362 1
                 arg == "-h")
2363
        {
2364 1
            params.usage = true;
2365 1
            return false;
2366
        }
2367 1
        else if (arg == "--r")
2368 0
            params.debugr = true;
2369 1
        else if (arg == "--version")
2370
        {
2371 1
            params.logo = true;
2372 1
            return false;
2373
        }
2374 1
        else if (arg == "--x")
2375 0
            params.debugx = true;
2376 1
        else if (arg == "--y")
2377 0
            params.debugy = true;
2378 1
        else if (p[1] == 'L')                        // https://dlang.org/dmd.html#switch-L
2379
        {
2380 1
            params.linkswitches.push(p + 2 + (p[2] == '='));
2381 1
            params.linkswitchIsForCC.push(false);
2382
        }
2383 1
        else if (startsWith(p + 1, "defaultlib="))   // https://dlang.org/dmd.html#switch-defaultlib
2384
        {
2385 1
            params.defaultlibname = (p + 1 + 11).toDString;
2386
        }
2387 1
        else if (startsWith(p + 1, "debuglib="))     // https://dlang.org/dmd.html#switch-debuglib
2388
        {
2389 0
            params.debuglibname = (p + 1 + 9).toDString;
2390
        }
2391 1
        else if (startsWith(p + 1, "deps"))          // https://dlang.org/dmd.html#switch-deps
2392
        {
2393 1
            if (params.moduleDeps)
2394
            {
2395 0
                error("-deps[=file] can only be provided once!");
2396 0
                break;
2397
            }
2398 1
            if (p[5] == '=')
2399
            {
2400 1
                params.moduleDepsFile = (p + 1 + 5).toDString;
2401 1
                if (!params.moduleDepsFile[0])
2402 0
                    goto Lnoarg;
2403
            }
2404 1
            else if (p[5] != '\0')
2405
            {
2406
                // Else output to stdout.
2407 0
                goto Lerror;
2408
            }
2409 1
            params.moduleDeps = new OutBuffer();
2410
        }
2411 1
        else if (arg == "-main")             // https://dlang.org/dmd.html#switch-main
2412
        {
2413 1
            params.addMain = true;
2414
        }
2415 1
        else if (startsWith(p + 1, "man"))   // https://dlang.org/dmd.html#switch-man
2416
        {
2417 0
            params.manual = true;
2418 0
            return false;
2419
        }
2420 1
        else if (arg == "-run")              // https://dlang.org/dmd.html#switch-run
2421
        {
2422 1
            params.run = true;
2423 1
            size_t length = argc - i - 1;
2424 1
            if (length)
2425
            {
2426 1
                const(char)[] runarg = arguments[i + 1].toDString();
2427 1
                const(char)[] ext = FileName.ext(runarg);
2428 1
                if (ext && FileName.equals(ext, "d") == 0 && FileName.equals(ext, "di") == 0)
2429
                {
2430 1
                    error("-run must be followed by a source file, not '%s'", arguments[i + 1]);
2431 1
                    break;
2432
                }
2433 1
                if (runarg == "-")
2434 1
                    files.push("__stdin.d");
2435
                else
2436 1
                    files.push(arguments[i + 1]);
2437 1
                params.runargs.setDim(length - 1);
2438 1
                for (size_t j = 0; j < length - 1; ++j)
2439
                {
2440 1
                    params.runargs[j] = arguments[i + 2 + j];
2441
                }
2442 1
                i += length;
2443
            }
2444
            else
2445
            {
2446 0
                params.run = false;
2447 0
                goto Lnoarg;
2448
            }
2449
        }
2450 1
        else if (p[1] == '\0')
2451 1
            files.push("__stdin.d");
2452
        else
2453
        {
2454
        Lerror:
2455 1
            error("unrecognized switch '%s'", arguments[i]);
2456 1
            continue;
2457
        Lnoarg:
2458 1
            error("argument expected for switch '%s'", arguments[i]);
2459 1
            continue;
2460
        }
2461
    }
2462 1
    return errors;
2463
}
2464

2465
/***********************************************
2466
 * Adjust gathered command line switches and reconcile them.
2467
 * Params:
2468
 *      params = switches gathered from command line,
2469
 *               and update in place
2470
 *      numSrcFiles = number of source files
2471
 */
2472
version (NoMain) {} else
2473
private void reconcileCommands(ref Param params, size_t numSrcFiles)
2474
{
2475
    static if (TARGET.OSX)
2476
    {
2477
        params.pic = PIC.pic;
2478
    }
2479
    static if (TARGET.Linux || TARGET.OSX || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.Solaris || TARGET.DragonFlyBSD)
2480
    {
2481 1
        if (params.lib && params.dll)
2482 0
            error(Loc.initial, "cannot mix -lib and -shared");
2483
    }
2484
    static if (TARGET.Windows)
2485
    {
2486
        if (params.mscoff && !params.mscrtlib)
2487
        {
2488
            VSOptions vsopt;
2489
            vsopt.initialize();
2490
            params.mscrtlib = vsopt.defaultRuntimeLibrary(params.is64bit).toDString;
2491
        }
2492
    }
2493

2494
    // Target uses 64bit pointers.
2495 1
    params.isLP64 = params.is64bit;
2496

2497 1
    if (params.boundscheck != CHECKENABLE._default)
2498
    {
2499 1
        if (params.useArrayBounds == CHECKENABLE._default)
2500 1
            params.useArrayBounds = params.boundscheck;
2501
    }
2502

2503 1
    if (params.useUnitTests)
2504
    {
2505 1
        if (params.useAssert == CHECKENABLE._default)
2506 1
            params.useAssert = CHECKENABLE.on;
2507
    }
2508

2509 1
    if (params.release)
2510
    {
2511 1
        if (params.useInvariants == CHECKENABLE._default)
2512 1
            params.useInvariants = CHECKENABLE.off;
2513

2514 1
        if (params.useIn == CHECKENABLE._default)
2515 1
            params.useIn = CHECKENABLE.off;
2516

2517 1
        if (params.useOut == CHECKENABLE._default)
2518 1
            params.useOut = CHECKENABLE.off;
2519

2520 1
        if (params.useArrayBounds == CHECKENABLE._default)
2521 1
            params.useArrayBounds = CHECKENABLE.safeonly;
2522

2523 1
        if (params.useAssert == CHECKENABLE._default)
2524 1
            params.useAssert = CHECKENABLE.off;
2525

2526 1
        if (params.useSwitchError == CHECKENABLE._default)
2527 1
            params.useSwitchError = CHECKENABLE.off;
2528
    }
2529
    else
2530
    {
2531 1
        if (params.useInvariants == CHECKENABLE._default)
2532 1
            params.useInvariants = CHECKENABLE.on;
2533

2534 1
        if (params.useIn == CHECKENABLE._default)
2535 1
            params.useIn = CHECKENABLE.on;
2536

2537 1
        if (params.useOut == CHECKENABLE._default)
2538 1
            params.useOut = CHECKENABLE.on;
2539

2540 1
        if (params.useArrayBounds == CHECKENABLE._default)
2541 1
            params.useArrayBounds = CHECKENABLE.on;
2542

2543 1
        if (params.useAssert == CHECKENABLE._default)
2544 1
            params.useAssert = CHECKENABLE.on;
2545

2546 1
        if (params.useSwitchError == CHECKENABLE._default)
2547 1
            params.useSwitchError = CHECKENABLE.on;
2548
    }
2549

2550 1
    if (params.betterC)
2551
    {
2552 1
        params.checkAction = CHECKACTION.C;
2553 1
        params.useModuleInfo = false;
2554 1
        params.useTypeInfo = false;
2555 1
        params.useExceptions = false;
2556
    }
2557

2558

2559 1
    if (!params.obj || params.lib)
2560 1
        params.link = false;
2561 1
    if (params.link)
2562
    {
2563 1
        params.exefile = params.objname;
2564 1
        params.oneobj = true;
2565 1
        if (params.objname)
2566
        {
2567
            /* Use this to name the one object file with the same
2568
             * name as the exe file.
2569
             */
2570 1
            params.objname = FileName.forceExt(params.objname, global.obj_ext);
2571
            /* If output directory is given, use that path rather than
2572
             * the exe file path.
2573
             */
2574 1
            if (params.objdir)
2575
            {
2576 1
                const(char)[] name = FileName.name(params.objname);
2577 1
                params.objname = FileName.combine(params.objdir, name);
2578
            }
2579
        }
2580
    }
2581 1
    else if (params.run)
2582
    {
2583 1
        error(Loc.initial, "flags conflict with -run");
2584 1
        fatal();
2585
    }
2586 1
    else if (params.lib)
2587
    {
2588 1
        params.libname = params.objname;
2589 1
        params.objname = null;
2590
        // Haven't investigated handling these options with multiobj
2591 1
        if (!params.cov && !params.trace)
2592 1
            params.multiobj = true;
2593
    }
2594
    else
2595
    {
2596 1
        if (params.objname && numSrcFiles)
2597
        {
2598 1
            params.oneobj = true;
2599
            //error("multiple source files, but only one .obj name");
2600
            //fatal();
2601
        }
2602
    }
2603

2604 1
    if (params.noDIP25)
2605 1
        params.useDIP25 = false;
2606
}
2607

2608
/**
2609
Creates the module based on the file provided
2610

2611
The file is dispatched in one of the various arrays
2612
(global.params.{ddocfiles,dllfiles,jsonfiles,etc...})
2613
according to its extension.
2614
If it is a binary file, it is added to libmodules.
2615

2616
Params:
2617
  file = File name to dispatch
2618
  libmodules = Array to which binaries (shared/static libs and object files)
2619
               will be appended
2620

2621
Returns:
2622
  A D module
2623
*/
2624
Module createModule(const(char)* file, ref Strings libmodules)
2625
{
2626 1
    const(char)[] name;
2627
    version (Windows)
2628
    {
2629
        file = toWinPath(file);
2630
    }
2631 1
    const(char)[] p = file.toDString();
2632 1
    p = FileName.name(p); // strip path
2633 1
    const(char)[] ext = FileName.ext(p);
2634 1
    if (!ext)
2635
    {
2636 1
        if (!p.length)
2637
        {
2638 0
            error(Loc.initial, "invalid file name '%s'", file);
2639 0
            fatal();
2640
        }
2641 1
        auto id = Identifier.idPool(p);
2642 1
        return new Module(file.toDString, id, global.params.doDocComments, global.params.doHdrGeneration);
2643
    }
2644

2645
    /* Deduce what to do with a file based on its extension
2646
        */
2647 1
    if (FileName.equals(ext, global.obj_ext))
2648
    {
2649 1
        global.params.objfiles.push(file);
2650 1
        libmodules.push(file);
2651 1
        return null;
2652
    }
2653 1
    if (FileName.equals(ext, global.lib_ext))
2654
    {
2655 1
        global.params.libfiles.push(file);
2656 1
        libmodules.push(file);
2657 1
        return null;
2658
    }
2659
    static if (TARGET.Linux || TARGET.OSX || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.Solaris || TARGET.DragonFlyBSD)
2660
    {
2661 1
        if (FileName.equals(ext, global.dll_ext))
2662
        {
2663 0
            global.params.dllfiles.push(file);
2664 0
            libmodules.push(file);
2665 0
            return null;
2666
        }
2667
    }
2668 1
    if (ext == global.ddoc_ext)
2669
    {
2670 1
        global.params.ddocfiles.push(file);
2671 1
        return null;
2672
    }
2673 1
    if (FileName.equals(ext, global.json_ext))
2674
    {
2675 0
        global.params.doJsonGeneration = true;
2676 0
        global.params.jsonfilename = file.toDString;
2677 0
        return null;
2678
    }
2679 1
    if (FileName.equals(ext, global.map_ext))
2680
    {
2681 0
        global.params.mapfile = file.toDString;
2682 0
        return null;
2683
    }
2684
    static if (TARGET.Windows)
2685
    {
2686
        if (FileName.equals(ext, "res"))
2687
        {
2688
            global.params.resfile = file.toDString;
2689
            return null;
2690
        }
2691
        if (FileName.equals(ext, "def"))
2692
        {
2693
            global.params.deffile = file.toDString;
2694
            return null;
2695
        }
2696
        if (FileName.equals(ext, "exe"))
2697
        {
2698
            assert(0); // should have already been handled
2699
        }
2700
    }
2701
    /* Examine extension to see if it is a valid
2702
        * D source file extension
2703
        */
2704 1
    if (FileName.equals(ext, global.mars_ext) || FileName.equals(ext, global.hdr_ext) || FileName.equals(ext, "dd"))
2705
    {
2706 1
        name = FileName.removeExt(p);
2707 1
        if (!name.length || name == ".." || name == ".")
2708
        {
2709 0
            error(Loc.initial, "invalid file name '%s'", file);
2710 0
            fatal();
2711
        }
2712
    }
2713
    else
2714
    {
2715 0
        error(Loc.initial, "unrecognized file extension %.*s", cast(int)ext.length, ext.ptr);
2716 0
        fatal();
2717
    }
2718

2719
    /* At this point, name is the D source file name stripped of
2720
     * its path and extension.
2721
     */
2722 1
    auto id = Identifier.idPool(name);
2723

2724 1
    return new Module(file.toDString, id, global.params.doDocComments, global.params.doHdrGeneration);
2725
}
2726

2727
/**
2728
Creates the list of modules based on the files provided
2729

2730
Files are dispatched in the various arrays
2731
(global.params.{ddocfiles,dllfiles,jsonfiles,etc...})
2732
according to their extension.
2733
Binary files are added to libmodules.
2734

2735
Params:
2736
  files = File names to dispatch
2737
  libmodules = Array to which binaries (shared/static libs and object files)
2738
               will be appended
2739

2740
Returns:
2741
  An array of path to D modules
2742
*/
2743
Modules createModules(ref Strings files, ref Strings libmodules)
2744
{
2745 1
    Modules modules;
2746 1
    modules.reserve(files.dim);
2747 1
    bool firstmodule = true;
2748 1
    for (size_t i = 0; i < files.dim; i++)
2749
    {
2750 1
        auto m = createModule(files[i], libmodules);
2751

2752 1
        if (m is null)
2753 1
            continue;
2754

2755 1
        modules.push(m);
2756 1
        if (firstmodule)
2757
        {
2758 1
            global.params.objfiles.push(m.objfile.toChars());
2759 1
            firstmodule = false;
2760
        }
2761
    }
2762 1
    return modules;
2763
}

Read our documentation on viewing source code .

Loading