aboutsummaryrefslogtreecommitdiff
path: root/src/nimpb_build.nim
blob: f1d4c0d3a8b496c9ee66f58b0282a24ed12487b1 (plain)
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
import os
import osproc
import streams
import strformat
import strtabs
import strutils

from nimpb_buildpkg/plugin import processFileDescriptorSet, ServiceGenerator, Service, ServiceMethod

export Service, ServiceMethod

when defined(windows):
    const compilerId = "win32"
elif defined(linux):
    when defined(i386):
        const arch = "x86_32"
    elif defined(amd64):
        const arch = "x86_64"
    elif defined(arm64):
        const arch = "aarch_64"
    else:
        {.fatal:"unsupported architecture".}
    const compilerId = "linux-" & arch
elif defined(macosx):
    when defined(amd64):
        const arch = "x86_64"
    else:
        {.fatal:"unsupported architecture".}
    const compilerId = "osx-" & arch
else:
    {.fatal:"unsupported platform".}

when defined(windows):
    const exeSuffix = ".exe"
else:
    const exeSuffix = ""

proc findCompiler(): string =
    let
        compilerName = &"protoc-{compilerId}{exeSuffix}"
        paths = @[
            getAppDir() / "src" / "nimpb_buildpkg" / "protobuf",
            getAppDir() / "nimpb_buildpkg" / "protobuf",
            parentDir(currentSourcePath()) / "nimpb_buildpkg" / "protobuf",
        ]

    for path in paths:
        if fileExists(path / compilerName):
            return path / compilerName

    raise newException(Exception, &"{compilerName} not found!")

proc builtinIncludeDir(compilerPath: string): string =
    parentDir(compilerPath) / "include"

template verboseEcho(x: untyped): untyped =
    if verbose:
        echo(x)

proc myTempDir(): string =
    result = getTempDir() / "nimpb_build_tmp"

proc compileProtos*(protos: openArray[string],
                    includes: openArray[string],
                    outdir: string,
                    serviceGenerator: ServiceGenerator = nil) =
    let command = findCompiler()
    var args: seq[string] = @[]

    var outputFilename = myTempDir() / "file-descriptor-set"
    createDir(myTempDir())

    add(args, "--include_imports")
    add(args, "--include_source_info")
    add(args, &"-o{outputFilename}")

    for incdir in includes:
        add(args, &"-I{incdir}")

    add(args, &"-I{builtinIncludeDir(command)}")

    for proto in protos:
        add(args, proto)

    var cmdline: string = quoteShell(command)
    for arg in args:
        cmdline &= " " & quoteShell(arg)

    let (outp, rc) = execCmdEx(cmdline)

    if rc != 0:
        raise newException(Exception, outp)

    processFileDescriptorSet(outputFilename, outdir, protos, serviceGenerator)


when isMainModule:
    proc usage() {.noreturn.} =
        echo(&"""
    {getAppFilename()} --out=OUTDIR [-IPATH [-IPATH]...] PROTOFILE...

        --out       The output directory for the generated files
        -I          Add a path to the set of include paths
    """)
        quit(QuitFailure)

    var includes: seq[string] = @[]
    var protos: seq[string] = @[]
    var outdir: string

    if paramCount() == 0:
        usage()

    for idx in 1..paramCount():
        let param = paramStr(idx)

        if param.startsWith("-I"):
            add(includes, param[2..^1])
        elif param.startsWith("--out="):
            outdir = param[6..^1]
        elif param == "--help":
            usage()
        else:
            add(protos, param)

    if outdir == nil:
        echo("error: --out is required")
        quit(QuitFailure)

    if len(protos) == 0:
        echo("error: no input files")
        quit(QuitFailure)

    compileProtos(protos, includes, outdir)