summary refs log tree commit diff stats
path: root/compiler/nim.nim
blob: 90049bdfbfff7f0d1f7d8e9e92f318ac3f152c15 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#
#
#           The Nim Compiler
#        (c) Copyright 2015 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

when defined(gcc) and defined(windows):
  when defined(x86):
    {.link: "icons/nim.res".}
  else:
    {.link: "icons/nim_icon.o".}

when defined(amd64) and defined(windows) and defined(vcc):
  {.link: "icons/nim-amd64-windows-vcc.res".}
when defined(i386) and defined(windows) and defined(vcc):
  {.link: "icons/nim-i386-windows-vcc.res".}

import
  commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
  extccomp, strutils, os, osproc, platform, main, parseopt,
  nodejs, scriptconfig, idents, modulegraphs, lineinfos

when hasTinyCBackend:
  import tccgen

when defined(profiler) or defined(memProfiler):
  {.hint: "Profiling support is turned on!".}
  import nimprof

proc prependCurDir(f: string): string =
  when defined(unix):
    if os.isAbsolute(f): result = f
    else: result = "./" & f
  else:
    result = f

proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
  var p = parseopt.initOptParser(cmd)
  var argsCount = 0
  while true:
    parseopt.next(p)
    case p.kind
    of cmdEnd: break
    of cmdLongoption, cmdShortOption:
      if p.key == " ":
        p.key = "-"
        if processArgument(pass, p, argsCount, config): break
      else:
        processSwitch(pass, p, config)
    of cmdArgument:
      if processArgument(pass, p, argsCount, config): break
  if pass == passCmd2:
    if optRun notin config.globalOptions and config.arguments.len > 0 and config.command.normalize != "run":
      rawMessage(config, errGenerated, errArgsNeedRunOption)

proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
  condsyms.initDefines(conf.symbols)
  if paramCount() == 0:
    writeCommandLineUsage(conf, conf.helpWritten)
  else:
    # Process command line arguments:
    processCmdLine(passCmd1, "", conf)
    if conf.projectName == "-":
      conf.projectName = "stdinfile"
      conf.projectFull = "stdinfile"
      conf.projectPath = canonicalizePath(conf, getCurrentDir())
      conf.projectIsStdin = true
    elif conf.projectName != "":
      try:
        conf.projectFull = canonicalizePath(conf, conf.projectName)
      except OSError:
        conf.projectFull = conf.projectName
      let p = splitFile(conf.projectFull)
      let dir = if p.dir.len > 0: p.dir else: getCurrentDir()
      conf.projectPath = canonicalizePath(conf, dir)
      conf.projectName = p.name
    else:
      conf.projectPath = canonicalizePath(conf, getCurrentDir())
    loadConfigs(DefaultConfig, cache, conf) # load all config files
    let scriptFile = conf.projectFull.changeFileExt("nims")
    if fileExists(scriptFile):
      runNimScript(cache, scriptFile, freshDefines=false, conf)
      # 'nim foo.nims' means to just run the NimScript file and do nothing more:
      if scriptFile == conf.projectFull: return
    elif fileExists(conf.projectPath / "config.nims"):
      # directory wide NimScript file
      runNimScript(cache, conf.projectPath / "config.nims", freshDefines=false, conf)
    # now process command line arguments again, because some options in the
    # command line can overwite the config file's settings
    extccomp.initVars(conf)
    processCmdLine(passCmd2, "", conf)
    if conf.command == "":
      rawMessage(conf, errGenerated, "command missing")
    mainCommand(newModuleGraph(cache, conf))
    if optHints in conf.options and hintGCStats in conf.notes: echo(GC_getStatistics())
    #echo(GC_getStatistics())
    if conf.errorCounter == 0:
      when hasTinyCBackend:
        if conf.cmd == cmdRun:
          tccgen.run(conf.arguments)
      if optRun in conf.globalOptions:
        if conf.cmd == cmdCompileToJS:
          var ex: string
          if conf.outFile.len > 0:
            ex = conf.outFile.prependCurDir.quoteShell
          else:
            ex = quoteShell(
              completeCFilePath(conf, changeFileExt(conf.projectFull, "js").prependCurDir))
          execExternalProgram(conf, findNodeJs() & " " & ex & ' ' & conf.arguments)
        else:
          var binPath: string
          if conf.outFile.len > 0:
            # If the user specified an outFile path, use that directly.
            binPath = conf.outFile.prependCurDir
          else:
            # Figure out ourselves a valid binary name.
            binPath = changeFileExt(conf.projectFull, ExeExt).prependCurDir
          var ex = quoteShell(binPath)
          execExternalProgram(conf, ex & ' ' & conf.arguments)

when declared(GC_setMaxPause):
  GC_setMaxPause 2_000

when compileOption("gc", "v2") or compileOption("gc", "refc"):
  # the new correct mark&sweet collector is too slow :-/
  GC_disableMarkAndSweep()

when not defined(selftest):
  let conf = newConfigRef()
  handleCmdLine(newIdentCache(), conf)
  when declared(GC_setMaxPause):
    echo GC_getStatistics()
  msgQuit(int8(conf.errorCounter > 0))