nimbus.nim: use a custom build script

This commit is contained in:
Anna “CyberTailor” 2023-04-25 20:21:27 +05:00
parent f43973d392
commit 10b0b6501b
Signed by: CyberTaIlor
GPG Key ID: E7B76EDC50864BB1
8 changed files with 186 additions and 46 deletions

View File

@ -2,6 +2,8 @@
* ninjasyntax.nim (build): don't escape args automatically
* nimbus.nim: use a custom build script
2023-04-25 Anna <cyber@sysrq.in>
* nimbus.nim: drop support for patched Nim compilers

View File

@ -0,0 +1,66 @@
# SPDX-FileCopyrightText: 2023 Anna <cyber@sysrq.in>
# SPDX-License-Identifier: BSD-3-Clause
## This module is used to generate a NimScript file that, when executed, tells
## Nim to generate a build script in a custom JSON format.
import std/strutils
import common, options
proc writeBuilderScript*(f: File, options: Options) =
f.write("""#!/usr/bin/env nim e
import std/[os, parseopt, strformat, strutils]
mode = Verbose
const
nimBin = $1.quoteShell
nimFlags = $2
nimCache = $3
type
Options = object
target: string
inFile: string
outFile: string
paths: seq[string]
proc build(options: Options) =
var paths = ""
if options.paths.len != 0:
paths = "-p:" & options.paths.join(" -p:")
exec fmt"{nimBin} {nimFlags} c --genScript:on --nimcache:{nimCache.quoteShell}" &
fmt" -o:{options.outFile.quoteShell} {paths} {options.inFile.quoteShell}"
let txt2deps = findExe("txt2deps")
if txt2deps.len != 0:
let nimDepsFile = nimCache / options.target.addFileExt("deps")
let gccDepsFile = options.target.addFileExt("d")
exec fmt"{txt2deps} -T:{options.target.quoteShell}" &
fmt" -i:{nimDepsFile.quoteShell} -o:{gccDepsFile.quoteShell}"
proc parseCmdLine(): Options =
for kind, key, val in getOpt():
case kind
of cmdArgument:
result.inFile = key
of cmdShortOption:
case key.normalize()
of "t":
result.target = val
result.outFile = val.addFileExt(ExeExt)
of "p":
result.paths.add(val)
else:
discard
of cmdEnd, cmdLongOption:
discard
let opts = parseCmdLine()
build(opts)
""" % [options.getNimBin().tripleQuoted,
options.getNimFlags().tripleQuoted,
options.getNimCache().tripleQuoted])

View File

@ -1,4 +1,5 @@
# SPDX-FileCopyrightText: Copyright (C) Dominik Picheta. All rights reserved.
# SPDX-FileCopyrightText: 2022-2023 Anna <cyber@sysrq.in>
# SPDX-License-Identifier: BSD-3-Clause
import std/strutils
@ -13,6 +14,7 @@ const
packageMetadataFileName* = "nimblemeta.json"
nimCacheDirName* = "nimcache"
builderFileName* = "builder.nims"
installerFileName* = "installer.nims"
testerFileName* = "tester.nims"
queryToolFileName* = "querytool.nims"
@ -32,4 +34,5 @@ const
]
func tripleQuoted*(s: string): string =
## Applies """triple quotes""" to a string.
return '"'.repeat(3) & s & '"'.repeat(3)

View File

@ -2,7 +2,7 @@
# SPDX-FileCopyrightText: 2023 Anna <cyber@sysrq.in>
# SPDX-License-Identifier: BSD-3-Clause
import std/[logging, os, parseopt, strutils]
import std/[logging, os, parseopt, strformat, strutils]
import common
@ -21,7 +21,7 @@ type
cmdLine*: seq[string] # only flags, not arguments
const
help* = """
help* = fmt"""
Usage: nimbus [-h] [--debug] [--nimbleDir:path] [--binDir:path] [--nim:path]
[--url:url] [nim opts...] sourceDir [buildDir]
@ -30,15 +30,15 @@ positional arguments:
buildDir
optional arguments:
-h, --help show this help message and exit
-h, --help Show this help message and exit.
--debug Show debugging information.
--nimbleDir:path Nimble directory (default: $1).
--binDir:path Executable directory (default: $2).
--nimbleDir:path Nimble directory (default: {defaultNimbleDir}).
--binDir:path Executable directory (default: {defaultBinDir}).
--nim:path Nim compiler (default: nim).
--url:url Package URL.
Unrecognized flags are passed to the Nim compiler.
""" % [defaultNimbleDir, defaultBinDir]
""".strip()
proc writeHelp*() =
echo(help)

View File

@ -1,26 +1,26 @@
# SPDX-FileCopyrightText: 2022 Anna <cyber@sysrq.in>
# SPDX-FileCopyrightText: 2022-2023 Anna <cyber@sysrq.in>
# SPDX-License-Identifier: BSD-3-Clause
import std/[os, strutils]
import std/strutils
import common, options
proc writeTesterScript*(f: File, options: Options) =
f.write("""#!/usr/bin/env nim e
import os, strformat, strutils
import std/[os, strformat, strutils]
const
nimBin = $1
nimBin = $1.quoteShell
nimFlags = $2
nimCacheDir = $3
nimCache = $3.quoteShell
withDir($4):
for test in listFiles("tests"):
if test.startsWith("tests/t") and test.endsWith(".nim"):
echo "-- Running test ", test, "..."
exec(fmt"{nimBin} --hints:off {nimFlags} r --nimcache:{nimCacheDir} {test.quoteShell}")
""" % [options.getNimBin().quoteShell.tripleQuoted,
""" % [options.getNimBin().tripleQuoted,
options.getNimFlags().tripleQuoted,
options.getNimCache().quoteShell.tripleQuoted,
options.getNimCache().tripleQuoted,
options.getSourceDir().tripleQuoted])

View File

@ -1,11 +1,24 @@
# SPDX-FileCopyrightText: 2022 Anna <cyber@sysrq.in>
# SPDX-FileCopyrightText: 2022-2023 Anna <cyber@sysrq.in>
# SPDX-License-Identifier: BSD-3-Clause
import std/[logging, os, sequtils, strtabs, strformat, strutils]
import std/strutils except escape
import std/[logging, os, sequtils, strtabs, strformat]
import nimbs/[common, dependencyresolver, installerscript, ninjasyntax,
nimbleexecutor, options, packageinfo, packagemetadata,
querytoolscript, testerscript, version]
import nimbs/[common, options]
import nimbs/[ninjasyntax]
import nimbs/[
dependencyresolver,
nimbleexecutor,
packageinfo,
packagemetadata,
version
]
import nimbs/[
builderscript,
installerscript,
querytoolscript,
testerscript
]
proc processDependencies(requires: seq[string], options: Options): seq[string] =
## Checks package dependencies and returns list of paths for the Nim compiler,
@ -21,17 +34,26 @@ proc processDependencies(requires: seq[string], options: Options): seq[string] =
else:
result.add(dep.getPath(options).quoteShell)
proc application(ninja: File, input, output: string, paths: seq[string]) =
debug(fmt"[build.ninja] Generating target for application '{output}'")
proc application(ninja: File, input, target: string, paths: seq[string]) =
debug(fmt"[build.ninja] Generating target for application '{target}'")
let depfile = quoteShell(output & ".d")
var vars = newStringTable()
vars["target"] = "$builddir" / target.escape(body = true)
vars["sourcefile"] = input.escape(body = true)
if paths.len != 0:
vars["paths"] = "-p:" & paths.join(" -p:")
vars["paths"] = escape("-p:" & paths.join(" -p:"), body = true)
ninja.build([output.escape],
rule = "nimc",
let jsonScript = "$nimcache" / target.addFileExt("json").escape
ninja.build([jsonScript],
rule = "genscript",
inputs = [input.escape, "$builder"],
variables = vars
)
ninja.build([target.addFileExt(ExeExt).escape],
rule = "jsonscript",
inputs = [input.escape],
implicit = [jsonScript],
variables = vars
)
@ -91,10 +113,11 @@ proc setup(options: Options) =
nimblemeta.writeMetaData(options.url)
nimblemeta.close()
echo "-- Generating installer script"
let installer = open(options.getBuildDir() / installerFileName, fmWrite)
installer.writeInstallerScript(pkgInfo, options)
installer.close()
if pkgInfo.bin.len != 0:
echo "-- Generating builder script"
let builder = open(options.getBuildDir() / builderFileName, fmWrite)
builder.writeBuilderScript(options)
builder.close()
if "test" notin tasks and dirExists(options.getSourceDir() / "tests"):
echo "-- Generating tester script"
@ -103,6 +126,11 @@ proc setup(options: Options) =
tester.close()
nimbleTests = true
echo "-- Generating installer script"
let installer = open(options.getBuildDir() / installerFileName, fmWrite)
installer.writeInstallerScript(pkgInfo, options)
installer.close()
echo "-- Generating build.ninja"
let ninja = open(options.getBuildDir() / "build.ninja", fmWrite)
@ -114,10 +142,9 @@ proc setup(options: Options) =
debug("[build.ninja] Writing variables")
ninja.variable("nim", options.getNimBin().escape(body = true))
ninja.variable("nimbus", getAppFilename().escape(body = true))
ninja.variable("nimflags", options.getNimFlags().escape(body = true))
ninja.variable("sourcedir", options.getSourceDir().escape(body = true))
ninja.variable("nimcache", options.getNimCache().escape(body = true))
ninja.variable("cmdline", options.getCmdLine().escape(body = true))
ninja.variable("builder", builderFileName.escape(body = true))
ninja.newline()
debug("[build.ninja] Generating 'REGENERATE_BUILD' rule")
@ -135,6 +162,25 @@ proc setup(options: Options) =
pool = "console")
ninja.newline()
if pkgInfo.bin.len != 0:
debug("[build.ninja] Generating 'genscript' rule")
ninja.rule("genscript",
command = "$nim --hints:off e $builder -T:$target $paths $sourcefile",
description = "Generating build script for Nim application $out",
depfile = "$target".addFileExt("d"),
deps = "gcc",
pool = "console")
ninja.newline()
debug("[build.ninja] Generating 'jsonscript' rule")
ninja.rule("jsonscript",
command = "$nim jsonscript --nimcache:$nimcache -o:$out $sourcefile",
description = "Compiling Nim application $out",
depfile = "$target".addFileExt("d"),
deps = "gcc",
pool = "console")
ninja.newline()
if tasks.len != 0:
# most tasks are supposed to be run from the project root
debug("[build.ninja] Generating 'nimbletask' rule")
@ -144,16 +190,6 @@ proc setup(options: Options) =
pool = "console")
ninja.newline()
if pkgInfo.bin.len != 0:
debug("[build.ninja] Generating 'nimc' rule")
ninja.rule("nimc",
command = "$nim $nimflags c --nimcache:$nimcache -o:$out $paths $in",
description = "Compiling Nim application $out",
depfile = "$out.d",
deps = "gcc",
pool = "console")
ninja.newline()
debug("[build.ninja] Generating 'PHONY' target")
ninja.comment("Phony build target, always out of date")
ninja.build(["PHONY"], rule = "phony")
@ -176,9 +212,8 @@ proc setup(options: Options) =
ninja.newline()
for bin in pkgInfo.bin:
let output = bin.lastPathPart.addFileExt(ExeExt)
let input = pkgInfo.getSourceDir(options) / bin.addFileExt("nim")
ninja.application(input, output, depPaths)
ninja.application(input, bin.lastPathPart, depPaths)
ninja.newline()
debug("[build.ninja] Generating 'all' target")

View File

@ -0,0 +1,34 @@
# SPDX-FileCopyrightText: 2023 Anna <cyber@sysrq.in>
# SPDX-License-Identifier: BSD-3-Clause
discard """
disabled: "win"
"""
import std/[os, strutils, tempfiles]
import nimbs/[builderscript, options]
const outputExpected = """#!/usr/bin/env nim e
import std/[os, parseopt, strformat, strutils]
mode = Verbose
const
nimBin = @/usr/bin/nim@.quoteShell
nimFlags = @-d:release --threads:on@
nimCache = @build dir/nimcache@
""".replace("@", '"'.repeat(3))
let opts = Options(buildDir: "build dir",
nim: "/usr/bin/nim",
passNimFlags: @["-d:release", "--threads:on"])
let (cfile, path) = createTempFile("builderscript_", ".nims")
cfile.writeBuilderScript(opts)
cfile.setFilePos(0)
assert cfile.readAll().startsWith outputExpected
cfile.close()
removeFile(path)

View File

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2022 Anna <cyber@sysrq.in>
# SPDX-FileCopyrightText: 2022-2023 Anna <cyber@sysrq.in>
# SPDX-License-Identifier: BSD-3-Clause
discard """
@ -10,12 +10,12 @@ import nimbs/options, nimbs/testerscript
const outputExpected = """#!/usr/bin/env nim e
import os, strformat, strutils
import std/[os, strformat, strutils]
const
nimBin = @/usr/bin/nim@
nimBin = @/usr/bin/nim@.quoteShell
nimFlags = @-d:release --threads:on@
nimCacheDir = @'build dir/nimcache'@
nimCache = @build dir/nimcache@.quoteShell
withDir(@tests/testerscript@):
for test in listFiles("tests"):