mirror of
https://github.com/daylinmorgan/forge.git
synced 2024-11-23 16:30:44 -06:00
chore: ccnz -> forge
This commit is contained in:
parent
9dc6353e8b
commit
4485f832f0
13 changed files with 447 additions and 174 deletions
13
.forge.cfg
Normal file
13
.forge.cfg
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# example ccnz config file
|
||||||
|
nimble
|
||||||
|
|
||||||
|
[target]
|
||||||
|
x86_64-linux-gnu
|
||||||
|
x86_64-linux-musl
|
||||||
|
x86_64-macos-none
|
||||||
|
x86_64-windows-gnu
|
||||||
|
|
||||||
|
[bin]
|
||||||
|
src/forge
|
||||||
|
src/forgecc
|
||||||
|
|
5
.github/workflows/nightly.yml
vendored
5
.github/workflows/nightly.yml
vendored
|
@ -24,8 +24,9 @@ jobs:
|
||||||
name: check latest commit is less than a day
|
name: check latest commit is less than a day
|
||||||
if: ${{ github.event_name == 'schedule' }}
|
if: ${{ github.event_name == 'schedule' }}
|
||||||
run: |
|
run: |
|
||||||
test -n "$(git rev-list --since="24 hours" HEAD)" \
|
if [[ -n "$(git rev-list --since='24 hours' HEAD)" ]]; then
|
||||||
&& echo "quit=true" >> "$GITHUB_OUTPUT"
|
echo "quit=true" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
build-artifacts:
|
build-artifacts:
|
||||||
needs: check-commits
|
needs: check-commits
|
||||||
|
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 Daylin Morgan
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -1,3 +1,10 @@
|
||||||
# ccnz compiles nim w/zig
|
# forge
|
||||||
|
|
||||||
|
A toolchain to forge your multi-platform `nim` binaries.
|
||||||
|
|
||||||
|
## install
|
||||||
|
|
||||||
|
```sh
|
||||||
|
nimble install https://github.com/daylinmorgan/forge
|
||||||
|
```
|
||||||
|
|
||||||
|
|
46
ccnz.nimble
46
ccnz.nimble
|
@ -1,46 +0,0 @@
|
||||||
version = "2023.1001"
|
|
||||||
author = "Daylin Morgan"
|
|
||||||
description = "ccnz compiles nim w/zig"
|
|
||||||
license = "MIT"
|
|
||||||
srcDir = "src"
|
|
||||||
bin = @["ccnz", "ccnzcc"]
|
|
||||||
binDir = "bin"
|
|
||||||
|
|
||||||
|
|
||||||
requires "nim >= 2.0.0",
|
|
||||||
"cligen"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import strformat
|
|
||||||
const targets = [
|
|
||||||
"x86_64-linux-gnu",
|
|
||||||
"x86_64-linux-musl",
|
|
||||||
"x86_64-macos-none",
|
|
||||||
"x86_64-windows-gnu"
|
|
||||||
]
|
|
||||||
|
|
||||||
task release, "build release assets":
|
|
||||||
mkdir "dist"
|
|
||||||
for target in targets:
|
|
||||||
let ext = if target == "x86_64-windows-gnu": ".cmd" else: ""
|
|
||||||
for app in @["ccnz", "ccnzcc"]:
|
|
||||||
let outdir = &"dist/{target}/"
|
|
||||||
exec &"ccnz cc --target {target} --nimble -- --out:{outdir}{app}{ext} -d:release src/{app}"
|
|
||||||
|
|
||||||
task bundle, "package build assets":
|
|
||||||
cd "dist"
|
|
||||||
for target in targets:
|
|
||||||
let
|
|
||||||
app = projectName()
|
|
||||||
cmd =
|
|
||||||
if target == "x86_64-windows-gnu":
|
|
||||||
&"7z a {app}_{target}.zip {target}"
|
|
||||||
else:
|
|
||||||
&"tar czf {app}_{target}.tar.gz {target}"
|
|
||||||
|
|
||||||
cpFile("../README.md", &"{target}/README.md")
|
|
||||||
exec cmd
|
|
||||||
|
|
||||||
|
|
||||||
|
|
30
forge.nimble
Normal file
30
forge.nimble
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
version = "2023.1001"
|
||||||
|
author = "Daylin Morgan"
|
||||||
|
description = "build nim binaries for all the platforms"
|
||||||
|
license = "MIT"
|
||||||
|
srcDir = "src"
|
||||||
|
bin = @["forge", "forgecc"]
|
||||||
|
binDir = "bin"
|
||||||
|
|
||||||
|
|
||||||
|
requires "nim >= 2.0.0",
|
||||||
|
"cligen"
|
||||||
|
|
||||||
|
import strformat
|
||||||
|
|
||||||
|
task release, "build release assets":
|
||||||
|
version = (gorgeEx "git describe --tags --always").output
|
||||||
|
exec &"forge release -v {version} -V"
|
||||||
|
|
||||||
|
task bundle, "package build assets":
|
||||||
|
withDir "dist":
|
||||||
|
for dir in listDirs("."):
|
||||||
|
let cmd = if "windows" in dir:
|
||||||
|
&"7z a {dir}.zip {dir}"
|
||||||
|
else:
|
||||||
|
&"tar czf {dir}.tar.gz {dir}"
|
||||||
|
cpFile("../README.md", &"{dir}/README.md")
|
||||||
|
exec cmd
|
||||||
|
|
||||||
|
|
||||||
|
|
72
src/ccnz.nim
72
src/ccnz.nim
|
@ -1,72 +0,0 @@
|
||||||
import std/[osproc, strformat, strutils, tables, terminal]
|
|
||||||
import ccnz/utils
|
|
||||||
|
|
||||||
proc genFlags(target: string, args: seq[string]): seq[string] =
|
|
||||||
let targetList = zigTargets()
|
|
||||||
if target notin targetList:
|
|
||||||
errQuit &"unknown target: {target}", "", "must be one of:",
|
|
||||||
targetList.columns
|
|
||||||
|
|
||||||
addFlag "cpu"
|
|
||||||
addFlag "os"
|
|
||||||
|
|
||||||
result &= @[
|
|
||||||
"--cc:clang",
|
|
||||||
&"--clang.exe='ccnzcc'",
|
|
||||||
&"--clang.linkerexe='ccnzcc'",
|
|
||||||
# &"--passC:\"-target {target} -fno-sanitize=undefined\"",
|
|
||||||
&"--passC:'-target {target}'",
|
|
||||||
# &"--passL:\"-target {target} -fno-sanitize=undefined\"",
|
|
||||||
&"--passL:'-target {target}'",
|
|
||||||
]
|
|
||||||
|
|
||||||
proc targets() =
|
|
||||||
## show available targets
|
|
||||||
let targetList = zigTargets()
|
|
||||||
styledEcho styleBright, fgGreen, "available targets:"
|
|
||||||
echo targetList.columns
|
|
||||||
|
|
||||||
proc cc(target: string, dryrun: bool = false, nimble: bool = false, args: seq[string]) =
|
|
||||||
## compile with zig cc
|
|
||||||
let ccArgs = genFlags(target, args)
|
|
||||||
if args.len == 0:
|
|
||||||
errQuit "expected additional arguments i.e. -- -d:release src/main.nim\n"
|
|
||||||
|
|
||||||
let rest =
|
|
||||||
if args[0] == "c":
|
|
||||||
args[1..^1]
|
|
||||||
else:
|
|
||||||
args
|
|
||||||
|
|
||||||
let baseCmd = if nimble: "nimble" else: "nim"
|
|
||||||
let cmd = (@[baseCmd] & @["c"] & ccArgs & rest).join(" ")
|
|
||||||
if dryrun:
|
|
||||||
stderr.write cmd, "\n"
|
|
||||||
else:
|
|
||||||
quit(execCmd cmd)
|
|
||||||
|
|
||||||
when isMainModule:
|
|
||||||
import cligen
|
|
||||||
zigExists()
|
|
||||||
|
|
||||||
const
|
|
||||||
customMulti = "${doc}Usage:\n $command {SUBCMD} [sub-command options & parameters]\n\nsubcommands:\n$subcmds"
|
|
||||||
vsn = staticExec "git describe --tags --always HEAD"
|
|
||||||
|
|
||||||
|
|
||||||
if clCfg.useMulti == "": clCfg.useMulti = customMulti
|
|
||||||
if clCfg.helpAttr.len == 0:
|
|
||||||
clCfg.helpAttr = {"cmd": "\e[1;36m", "clDescrip": "", "clDflVal": "\e[33m",
|
|
||||||
"clOptKeys": "\e[32m", "clValType": "\e[31m", "args": "\e[3m"}.toTable
|
|
||||||
clCfg.helpAttrOff = {"cmd": "\e[m", "clDescrip": "\e[m", "clDflVal": "\e[m",
|
|
||||||
"clOptKeys": "\e[m", "clValType": "\e[m", "args": "\e[m"}.toTable
|
|
||||||
|
|
||||||
var vsnCfg = clCfg
|
|
||||||
vsnCfg.version = vsn
|
|
||||||
|
|
||||||
|
|
||||||
dispatchMulti(["multi", cf = vsnCfg], [cc, help = {
|
|
||||||
"dryrun": "show command instead of executing",
|
|
||||||
"nimble": "use nimble as base command for compiling"
|
|
||||||
}, short = {"dryrun": 'n'}],
|
|
||||||
[targets])
|
|
|
@ -1,3 +0,0 @@
|
||||||
import ccnz/utils
|
|
||||||
|
|
||||||
callZig("cc")
|
|
155
src/forge.nim
Normal file
155
src/forge.nim
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
import std/[os, osproc, strformat, strutils, tables, terminal]
|
||||||
|
|
||||||
|
import forge/[config, utils, term]
|
||||||
|
|
||||||
|
proc genFlags(triplet: Triplet, args: seq[string] = @[]): seq[string] =
|
||||||
|
addFlag "cpu"
|
||||||
|
addFlag "os"
|
||||||
|
|
||||||
|
result &= @[
|
||||||
|
"--cc:clang",
|
||||||
|
&"--clang.exe='forgecc'",
|
||||||
|
&"--clang.linkerexe='forgecc'",
|
||||||
|
# &"--passC:\"-target {target} -fno-sanitize=undefined\"",
|
||||||
|
&"--passC:'-target {triplet}'",
|
||||||
|
# &"--passL:\"-target {target} -fno-sanitize=undefined\"",
|
||||||
|
&"--passL:'-target {triplet}'",
|
||||||
|
]
|
||||||
|
|
||||||
|
proc targets() =
|
||||||
|
## show available targets
|
||||||
|
let targetList = zigTargets()
|
||||||
|
termEcho styleBright, fgGreen, "available targets:"
|
||||||
|
stderr.writeLine targetList.columns
|
||||||
|
|
||||||
|
proc cc(target: string, dryrun: bool = false, nimble: bool = false, args: seq[string]) =
|
||||||
|
## compile with zig cc
|
||||||
|
if args.len == 0:
|
||||||
|
termErrQuit "expected additional arguments i.e. -- -d:release src/main.nim"
|
||||||
|
|
||||||
|
let
|
||||||
|
targets = zigTargets()
|
||||||
|
ccArgs = genFlags(parseTriplet(target, targets), args)
|
||||||
|
rest = parseArgs(args)
|
||||||
|
baseCmd = if nimble: "nimble" else: "nim"
|
||||||
|
cmd = (@[baseCmd] & @["c"] & ccArgs & rest).join(" ")
|
||||||
|
|
||||||
|
if dryrun:
|
||||||
|
stderr.writeLine cmd
|
||||||
|
else:
|
||||||
|
quit(execCmd cmd)
|
||||||
|
|
||||||
|
proc release(
|
||||||
|
target: seq[string] = @[],
|
||||||
|
bin: seq[string] = @[],
|
||||||
|
args: seq[string],
|
||||||
|
outdir: string = "dist",
|
||||||
|
format: string = "",
|
||||||
|
name: string = "",
|
||||||
|
version: string = "",
|
||||||
|
dryrun: bool = false,
|
||||||
|
nimble: bool = false,
|
||||||
|
configFile: string = ".forge.cfg",
|
||||||
|
verbose: bool = false,
|
||||||
|
) =
|
||||||
|
## generate release assets for n>=1 targets
|
||||||
|
##
|
||||||
|
## format argument:
|
||||||
|
## format is a template string used for each target directory
|
||||||
|
## available fields are name, version, target
|
||||||
|
## default: ${name}-v${verison}-${target}
|
||||||
|
##
|
||||||
|
## if name or version are not specified they will be inferred from the local .nimble file
|
||||||
|
|
||||||
|
var cfg = newConfig(
|
||||||
|
target,
|
||||||
|
bin,
|
||||||
|
outdir,
|
||||||
|
format,
|
||||||
|
name,
|
||||||
|
version,
|
||||||
|
nimble,
|
||||||
|
configFile
|
||||||
|
)
|
||||||
|
if cfg.targets.len == 0:
|
||||||
|
termErrQuit "expected at least 1 target"
|
||||||
|
if cfg.bins.len == 0:
|
||||||
|
termErrQuit "expected at least 1 bin"
|
||||||
|
|
||||||
|
if verbose:
|
||||||
|
termEcho $cfg
|
||||||
|
|
||||||
|
if dryrun:
|
||||||
|
termEcho styleBright, fgBlue, "dry run...see below for commands"
|
||||||
|
|
||||||
|
let
|
||||||
|
targets = zigTargets()
|
||||||
|
baseCmd = if nimble or cfg.nimble: "nimble" else: "nim"
|
||||||
|
rest = parseArgs(args)
|
||||||
|
|
||||||
|
termEcho styleBright, fgYellow,
|
||||||
|
&"compiling {cfg.bins.len} binaries for {cfg.targets.len} targets"
|
||||||
|
|
||||||
|
for t, tArgs in cfg.targets:
|
||||||
|
for b, bArgs in cfg.bins:
|
||||||
|
var cmdParts: seq[string] = @[]
|
||||||
|
let outFlag = &"--outdir:'" & (
|
||||||
|
outdir / formatDirName(cfg.format, cfg.name, cfg.version, t)
|
||||||
|
) & "'"
|
||||||
|
|
||||||
|
cmdParts &= @[baseCmd, "c"]
|
||||||
|
cmdParts.add genFlags(parseTriplet(t, targets), rest)
|
||||||
|
cmdParts.add "-d:release"
|
||||||
|
cmdParts.add rest
|
||||||
|
cmdParts.add outFlag
|
||||||
|
for a in @[targs, bargs]:
|
||||||
|
if a != "": cmdParts.add a
|
||||||
|
cmdParts.add b
|
||||||
|
|
||||||
|
let cmd = cmdParts.join(" ")
|
||||||
|
if dryrun:
|
||||||
|
stderr.writeLine cmd
|
||||||
|
else:
|
||||||
|
if verbose:
|
||||||
|
termEcho styleBright, "cmd: ", ansiResetCode, cmd
|
||||||
|
let errCode = execCmd cmd
|
||||||
|
if errCode != 0:
|
||||||
|
termErrQuit "problems executing cmd " & cmd
|
||||||
|
|
||||||
|
when isMainModule:
|
||||||
|
import cligen
|
||||||
|
zigExists()
|
||||||
|
|
||||||
|
const
|
||||||
|
customMulti = "${doc}Usage:\n $command {SUBCMD} [sub-command options & parameters]\n\nsubcommands:\n$subcmds"
|
||||||
|
vsn = staticExec "git describe --tags --always HEAD"
|
||||||
|
|
||||||
|
|
||||||
|
if clCfg.useMulti == "": clCfg.useMulti = customMulti
|
||||||
|
if clCfg.helpAttr.len == 0:
|
||||||
|
clCfg.helpAttr = {"cmd": "\e[1;36m", "clDescrip": "", "clDflVal": "\e[33m",
|
||||||
|
"clOptKeys": "\e[32m", "clValType": "\e[31m", "args": "\e[3m"}.toTable
|
||||||
|
clCfg.helpAttrOff = {"cmd": "\e[m", "clDescrip": "\e[m", "clDflVal": "\e[m",
|
||||||
|
"clOptKeys": "\e[m", "clValType": "\e[m", "args": "\e[m"}.toTable
|
||||||
|
|
||||||
|
var vsnCfg = clCfg
|
||||||
|
vsnCfg.version = vsn
|
||||||
|
|
||||||
|
|
||||||
|
dispatchMulti(["multi", cf = vsnCfg], [cc, help = {
|
||||||
|
"dryrun": "show command instead of executing",
|
||||||
|
"nimble": "use nimble as base command for compiling"
|
||||||
|
}],
|
||||||
|
[targets],
|
||||||
|
[release,
|
||||||
|
help = {
|
||||||
|
"target": "set target, may be repeated",
|
||||||
|
"bin": "set bin, may be repeated",
|
||||||
|
"dryrun": "show command instead of executing",
|
||||||
|
"format": "set format, see help above",
|
||||||
|
"nimble": "use nimble as base command for compiling",
|
||||||
|
"config-file": "path to config"
|
||||||
|
},
|
||||||
|
short = {"verbose": 'V'}
|
||||||
|
]
|
||||||
|
)
|
128
src/forge/config.nim
Normal file
128
src/forge/config.nim
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
import std/[parsecfg, tables, os, strutils, strformat]
|
||||||
|
|
||||||
|
type
|
||||||
|
Config* = object
|
||||||
|
targets*: OrderedTableRef[string, string]
|
||||||
|
bins*: OrderedTableRef[string, string]
|
||||||
|
outdir*: string
|
||||||
|
format*: string
|
||||||
|
name*: string
|
||||||
|
version*: string
|
||||||
|
nimble*: bool
|
||||||
|
|
||||||
|
proc `$`*(c: Config): string =
|
||||||
|
var lines: seq[string] = @[]
|
||||||
|
lines.add "config ="
|
||||||
|
lines.add "| nimble " & $c.nimble
|
||||||
|
lines.add "| outdir " & c.outdir
|
||||||
|
lines.add "| format " & c.format
|
||||||
|
lines.add "| version " & c.version
|
||||||
|
lines.add "| targets:"
|
||||||
|
for target, args in c.targets:
|
||||||
|
lines.add "| " & target & (if args != "": "|" & args else: "")
|
||||||
|
lines.add "| bins:"
|
||||||
|
for bin, args in c.bins:
|
||||||
|
lines.add "| " & bin & (if args != "": "|" & args else: "")
|
||||||
|
|
||||||
|
lines.join("\n")
|
||||||
|
|
||||||
|
proc loadConfigFile*(f: string): Config =
|
||||||
|
let
|
||||||
|
dict = loadConfig(f)
|
||||||
|
base = dict.getOrDefault("")
|
||||||
|
|
||||||
|
result.targets = newOrderedTable[string, string]()
|
||||||
|
result.bins = newOrderedTable[string, string]()
|
||||||
|
|
||||||
|
result.nimble = base.hasKey("nimble")
|
||||||
|
result.outdir = base.getOrDefault("outdir")
|
||||||
|
result.name = base.getOrDefault("name")
|
||||||
|
result.version = base.getOrDefault("version")
|
||||||
|
result.format = base.getOrDefault("format")
|
||||||
|
if dict.hasKey("target"):
|
||||||
|
result.targets = dict.getOrDefault("target")
|
||||||
|
if dict.hasKey("bin"):
|
||||||
|
result.bins = dict.getOrDefault("bin")
|
||||||
|
|
||||||
|
proc inferName(s: string, nimbleFile: string): string =
|
||||||
|
if s != "":
|
||||||
|
return s
|
||||||
|
elif nimbleFile != "":
|
||||||
|
return nimbleFile.rsplit(".", maxsplit = 1)[0]
|
||||||
|
|
||||||
|
proc findNimbleFile(): string =
|
||||||
|
var candidates: seq[string]
|
||||||
|
for kind, path in walkDir(getCurrentDir(), relative = true):
|
||||||
|
case kind:
|
||||||
|
of pcFile, pcLinkToFile:
|
||||||
|
if path.endsWith(".nimble"):
|
||||||
|
candidates.add path
|
||||||
|
else: discard
|
||||||
|
|
||||||
|
# nimble will probably prevent this,
|
||||||
|
# but not sure about atlas or bespoke builds
|
||||||
|
if candidates.len > 1:
|
||||||
|
echo "found multiple nimble files: " & candidates.join(", ")
|
||||||
|
echo "cannot infer name or version"
|
||||||
|
elif candidates.len == 1:
|
||||||
|
return candidates[0]
|
||||||
|
|
||||||
|
proc inferVersion(s: string, nimbleFile: string): string =
|
||||||
|
if s != "": return s
|
||||||
|
|
||||||
|
# TODO: catch io errors?
|
||||||
|
let nimbleCfg = loadConfig(nimbleFile)
|
||||||
|
return nimbleCfg.getSectionValue("", "version")
|
||||||
|
|
||||||
|
proc inferBin(nimbleFile: string): string =
|
||||||
|
let
|
||||||
|
pkgName = nimbleFile.split(".")[0]
|
||||||
|
default = "src" / &"{pkgName}.nim"
|
||||||
|
backup = &"{pkgName}.nim"
|
||||||
|
|
||||||
|
if default.fileExists(): return default
|
||||||
|
if backup.fileExists(): return backup
|
||||||
|
|
||||||
|
|
||||||
|
proc newConfig*(
|
||||||
|
targets: seq[string],
|
||||||
|
bins: seq[string],
|
||||||
|
outdir: string,
|
||||||
|
format: string,
|
||||||
|
name: string,
|
||||||
|
version: string,
|
||||||
|
nimble: bool,
|
||||||
|
configFile: string
|
||||||
|
): Config =
|
||||||
|
|
||||||
|
let nimbleFile = findNimbleFile()
|
||||||
|
|
||||||
|
if configFile.fileExists:
|
||||||
|
result = loadConfigFile(configFile)
|
||||||
|
else:
|
||||||
|
# no seg faults here...
|
||||||
|
result.targets = newOrderedTable[string, string]()
|
||||||
|
result.bins = newOrderedTable[string, string]()
|
||||||
|
|
||||||
|
result.nimble = result.nimble or nimble
|
||||||
|
|
||||||
|
if result.outdir == "" or (result.outdir != "dist" and outdir != "dist"):
|
||||||
|
result.outdir = outdir
|
||||||
|
|
||||||
|
if result.name == "":
|
||||||
|
result.name = inferName(name, nimbleFile)
|
||||||
|
if result.version == "":
|
||||||
|
result.version = inferVersion(version, nimbleFile)
|
||||||
|
if result.format == "":
|
||||||
|
if format != "": result.format = format
|
||||||
|
else: result.format = "${name}-v${version}-${target}"
|
||||||
|
|
||||||
|
for t in targets:
|
||||||
|
result.targets[t] = ""
|
||||||
|
for b in bins:
|
||||||
|
result.bins[b] = ""
|
||||||
|
|
||||||
|
if result.bins.len == 0 and nimbleFile != "":
|
||||||
|
let bin = inferBin(nimbleFile)
|
||||||
|
if bin != "":
|
||||||
|
result.bins[bin] = ""
|
17
src/forge/term.nim
Normal file
17
src/forge/term.nim
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import std/terminal
|
||||||
|
|
||||||
|
# TODO support NO_COLOR for these
|
||||||
|
let prefix = ansiForegroundColorCode(fgMagenta, bright = true) & "forge" &
|
||||||
|
ansiResetCode & ansiForegroundColorCode(fgYellow) & " || " & ansiResetCode
|
||||||
|
|
||||||
|
template termEcho*(args: varargs[untyped]) =
|
||||||
|
stderr.styledWriteLine(prefix, args)
|
||||||
|
|
||||||
|
template termErr*(args: varargs[untyped]) =
|
||||||
|
stderr.styledWriteLine(prefix, fgRed, "error ", fgDefault, args)
|
||||||
|
|
||||||
|
template termErrQuit*(args: varargs[untyped]) =
|
||||||
|
termErr(args)
|
||||||
|
quit 1
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,25 @@
|
||||||
import std/[json, macros, math, os, osproc, strutils, terminal, sequtils]
|
import std/[json, macros, math, os, osproc, sequtils, strutils, strformat, terminal]
|
||||||
|
|
||||||
proc errQuit*(msg: varargs[string]) =
|
import term
|
||||||
stderr.write msg.join("\n") & "\n"
|
|
||||||
quit 1
|
proc columns*(items: seq[string]): string =
|
||||||
|
## return a list of items as equally spaced columns
|
||||||
|
let
|
||||||
|
maxWidth = max(items.mapIt(it.len))
|
||||||
|
nColumns = floor((terminalWidth() + 1) / (maxWidth + 1)).int
|
||||||
|
result = (
|
||||||
|
items.mapIt(it.alignLeft(maxWidth + 1))
|
||||||
|
).distribute(
|
||||||
|
(items.len / nColumns).int + 1
|
||||||
|
).mapIt(it.join("")).join("\n")
|
||||||
|
|
||||||
|
template parseArgs*(args: seq[string]): seq[string] =
|
||||||
|
if args.len == 0:
|
||||||
|
args
|
||||||
|
elif args[0] == "c":
|
||||||
|
args[1..^1]
|
||||||
|
else:
|
||||||
|
args
|
||||||
|
|
||||||
# based on https://github.com/enthus1ast/zigcc
|
# based on https://github.com/enthus1ast/zigcc
|
||||||
template callZig*(zigCmd: string) =
|
template callZig*(zigCmd: string) =
|
||||||
|
@ -21,11 +38,33 @@ template callZig*(zigCmd: string) =
|
||||||
close process
|
close process
|
||||||
quit exitCode
|
quit exitCode
|
||||||
|
|
||||||
|
|
||||||
|
type
|
||||||
|
Triplet* = object
|
||||||
|
cpu: string
|
||||||
|
os: string
|
||||||
|
libc: string
|
||||||
|
|
||||||
|
proc `$`*(t: Triplet): string = &"{t.cpu}-{t.os}-{t.libc}"
|
||||||
|
|
||||||
|
proc parseTriplet*(s: string, targets: seq[string]): Triplet =
|
||||||
|
if s notin targets:
|
||||||
|
termErr &"unknown target: {s}", "", "must be one of:"
|
||||||
|
stderr.writeLine targets.columns
|
||||||
|
quit 1
|
||||||
|
|
||||||
|
|
||||||
|
let parts = s.split("-")
|
||||||
|
result.cpu = parts[0]
|
||||||
|
result.os = parts[1]
|
||||||
|
result.libc = parts[2]
|
||||||
|
|
||||||
proc zigExists*() =
|
proc zigExists*() =
|
||||||
if (findExe "zig") == "":
|
if (findExe "zig") == "":
|
||||||
errQuit "zig not found",
|
termErr "zig not found"
|
||||||
"ccnz requires a working installation of zig",
|
termErr " forge requires a working installation of zig"
|
||||||
"see: https://ziglang.org/download/"
|
termErr " see: https://ziglang.org/download/"
|
||||||
|
quit 1
|
||||||
|
|
||||||
proc zigTargets*(): seq[string] =
|
proc zigTargets*(): seq[string] =
|
||||||
let (output, _) = execCmdEx "zig targets"
|
let (output, _) = execCmdEx "zig targets"
|
||||||
|
@ -34,7 +73,7 @@ proc zigTargets*(): seq[string] =
|
||||||
macro addFlag*(arg: untyped): untyped =
|
macro addFlag*(arg: untyped): untyped =
|
||||||
let
|
let
|
||||||
flag = "--" & arg.strVal & ":"
|
flag = "--" & arg.strVal & ":"
|
||||||
inferProc = newCall("infer" & arg.strVal, newIdentNode("target"))
|
inferProc = newCall("infer" & arg.strVal, newIdentNode("triplet"))
|
||||||
|
|
||||||
quote do:
|
quote do:
|
||||||
if `flag` notin args:
|
if `flag` notin args:
|
||||||
|
@ -43,30 +82,24 @@ macro addFlag*(arg: untyped): untyped =
|
||||||
result.add `flag` & selected
|
result.add `flag` & selected
|
||||||
|
|
||||||
|
|
||||||
proc inferOs*(target: string): string =
|
proc inferOs*(t: Triplet): string =
|
||||||
if "windows" in target:
|
case t.os:
|
||||||
"Windows"
|
of "windows", "linux": t.os.capitalizeAscii()
|
||||||
elif "macos" in target:
|
of "macos": "MacOSX"
|
||||||
"MacOSX"
|
of "wasm": "Linux"
|
||||||
elif "linux" in target:
|
else: ""
|
||||||
"Linux"
|
|
||||||
elif "wasm" in target:
|
|
||||||
"Linux"
|
|
||||||
else:
|
|
||||||
""
|
|
||||||
|
|
||||||
proc inferCpu*(target: string): string =
|
proc inferCpu*(t: Triplet): string =
|
||||||
# Available options are:
|
# Available options are:
|
||||||
# i386, m68k, alpha, powerpc, powerpc64, powerpc64el, sparc,
|
# i386, m68k, alpha, powerpc, powerpc64, powerpc64el, sparc,
|
||||||
# vm, hppa, ia64, amd64, mips, mipsel, arm, arm64, js,
|
# vm, hppa, ia64, amd64, mips, mipsel, arm, arm64, js,
|
||||||
# nimvm, avr, msp430, sparc64, mips64, mips64el, riscv32,
|
# nimvm, avr, msp430, sparc64, mips64, mips64el, riscv32,
|
||||||
# riscv64, esp, wasm32, e2k, loongarch64
|
# riscv64, esp, wasm32, e2k, loongarch64
|
||||||
#
|
|
||||||
let candidate = target.split("-")[0]
|
|
||||||
# NOTE: I don't know what the _be eb means but if nim
|
# NOTE: I don't know what the _be eb means but if nim
|
||||||
# can't handle them then maybe an error would be better
|
# can't handle them then maybe an error would be better
|
||||||
result =
|
result =
|
||||||
case candidate:
|
case t.cpu:
|
||||||
of "x86_64":
|
of "x86_64":
|
||||||
"amd64"
|
"amd64"
|
||||||
of "aarch64", "aarch64_be":
|
of "aarch64", "aarch64_be":
|
||||||
|
@ -79,35 +112,21 @@ proc inferCpu*(target: string): string =
|
||||||
"powerpc64le"
|
"powerpc64le"
|
||||||
# remain the same
|
# remain the same
|
||||||
of "m68k", "mips64el", "mipsel", "mips", "powerpc", "powerpc64", "riscv64",
|
of "m68k", "mips64el", "mipsel", "mips", "powerpc", "powerpc64", "riscv64",
|
||||||
"sparc", "sparc64", "wasm32":
|
"sparc", "sparc64", "wasm32": t.cpu
|
||||||
candidate
|
|
||||||
else:
|
else:
|
||||||
""
|
""
|
||||||
|
|
||||||
# s390x-linux-gnu
|
proc formatDirName*(formatstr: string, name: string, version: string,
|
||||||
# s390x-linux-musl
|
target: string): string =
|
||||||
# sparc-linux-gnu
|
var vsn = version
|
||||||
# sparc64-linux-gnu
|
if ("v$version" in formatstr or "v${version}" in formatstr) and
|
||||||
# wasm32-freestanding-musl
|
vsn.startsWith("v"):
|
||||||
# wasm32-wasi-musl
|
vsn = vsn[1..^1]
|
||||||
# x86_64-linux-gnu
|
try:
|
||||||
# x86_64-linux-gnux32
|
result = formatstr % ["name", name, "version", vsn, "target", target]
|
||||||
# x86_64-linux-musl
|
except ValueError as e:
|
||||||
# x86_64-windows-gnu
|
termErrQuit e.msg
|
||||||
# x86_64-macos-none
|
|
||||||
# x86_64-macos-none
|
|
||||||
# x86_64-macos-none
|
|
||||||
#
|
|
||||||
proc columns*(items: seq[string]): string =
|
|
||||||
## return a list of items as equally spaced columns
|
|
||||||
let
|
|
||||||
maxWidth = max(items.mapIt(it.len))
|
|
||||||
nColumns = floor((terminalWidth() + 1) / (maxWidth + 1)).int
|
|
||||||
result = (
|
|
||||||
items.mapIt(it.alignLeft(maxWidth + 1))
|
|
||||||
).distribute(
|
|
||||||
(items.len / nColumns).int + 1
|
|
||||||
).mapIt(it.join("")).join("\n")
|
|
||||||
|
|
||||||
|
|
||||||
|
if result == "":
|
||||||
|
termErrQuit &"error processing formatstr: {formatstr}"
|
||||||
|
|
3
src/forgecc.nim
Normal file
3
src/forgecc.nim
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
import forge/utils
|
||||||
|
|
||||||
|
callZig("cc")
|
Loading…
Reference in a new issue