Merge branch 'master' of github.com:Araq/Nimrod

This commit is contained in:
Araq 2012-02-17 02:16:50 +01:00
commit 547e8aa418
4 changed files with 336 additions and 2 deletions

View file

@ -122,3 +122,9 @@ flags = "/Q"
[C_Compiler] [C_Compiler]
path = r"" path = r""
flags = "-w" flags = "-w"
[deb]
buildDepends: "gcc (>= 4:4.3.2)"
pkgDepends: "gcc (>= 4:4.3.2)"
shortDesc: "The Nimrod Compiler"
licenses: "bin/nimrod,gpl2;lib/*,lgpl;"

View file

@ -377,4 +377,17 @@ proc getClockStr*(): string {.rtl, extern: "nt$1".} =
result = intToStr(ti.hour, 2) & ':' & intToStr(ti.minute, 2) & result = intToStr(ti.hour, 2) & ':' & intToStr(ti.minute, 2) &
':' & intToStr(ti.second, 2) ':' & intToStr(ti.second, 2)
proc `$`*(day: TWeekDay): string =
## stingify operator for ``TWeekDay``.
let lookup: array[TWeekDay, string] = ["Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday", "Sunday"]
return lookup[day]
proc `$`*(m: TMonth): string =
## stingify operator for ``TMonth``.
let lookup: array[TMonth, string] = ["January", "February", "March", "April",
"May", "June", "July", "August", "September", "October", "November",
"December"]
return lookup[m]
{.pop.} {.pop.}

View file

@ -0,0 +1,227 @@
import osproc, times, os, strutils
# http://www.debian.org/doc/manuals/maint-guide/
# Required files for debhelper.
# -- control
# -- copyright
# -- changelog
# -- rules
type
TDebOptions* = object
buildDepends*, pkgDepends*, shortDesc*: string
licenses*: seq[tuple[files, license: string]]
template addN(r: string): expr =
result.add(r & "\n")
proc createControl(pkgName, maintainer, shortDesc, desc: string,
buildDepends, pkgDepends: string = ""): string =
## pkgName: Should be the package name, no spaces.
## maintainer: firstName lastName <email>
## shortDesc: short description of the application
## desc: long description of the application
## buildDepends: what the build depends on (compiling from source),
## this needs to be in the format deb accepts. For example,
## for gcc: ``gcc (>= 4:4.3.2)``
## Multiple dependencies should be separated by commas.
## pkgDepends: Same as buildDepends except that this specifies the
## dependencies that the compiled application depends on.
result = ""
addN("Source: " & pkgName)
addN("Maintainer: " & maintainer)
addN("Section: misc")
addN("Priority: optional")
addN("Standards-Version: 3.9.2")
addN("Build-Depends: debhelper (>= 8)" &
(if buildDepends != "": ", " & buildDepends else: ""))
addN("\n")
addN("Package: " & pkgName)
addN("Architecture: any")
addN("Depends: ${shlibs:Depends}, ${misc:Depends}" &
(if pkgDepends != "": ", " & pkgDepends else: ""))
var formattedDesc = ""
for line in splitLines(desc):
if line == "":
formattedDesc.add(" .\n")
else:
formattedDesc.add(" " & line & "\n")
addN("Description: " & shortDesc & "\n" & formattedDesc)
proc createCopyright(pkgName, mtnName, mtnEmail, version: string,
licenses: seq[tuple[files, license: string]]): string =
## pkgName: Package name
## mtnName: Maintainer name
## mtnEmail: Maintainer email
## version: package version
## licenses: files: This specifies the files that the `license` covers,
## for example, it might be ``lib/*`` to cover the whole ``lib`` dir
## license: This specifies the license, for example gpl2, or lgpl.
result = ""
addN("Maintainer name: " & mtnName)
addN("Email-Address: " & mtnEmail)
addN("Date: " & $getTime())
addN("Package Name: " & pkgName)
addN("Version: " & version)
for f, license in items(licenses):
addN("Files: " & f)
addN("License: " & license)
proc formatDateTime(t: TTimeInfo, timezone: string): string =
var day = ($t.weekday)[0..2] & ", "
return "$1$2 $3 $4 $5:$6:$7 $8" % [day, intToStr(t.monthday, 2),
($t.month)[0..2], $t.year, intToStr(t.hour, 2), intToStr(t.minute, 2),
intToStr(t.second, 2), timezone]
proc createChangelog(pkgName, version, maintainer: string): string =
## pkgName: package name
## version: package version
## maintainer: firstName lastName <email>
result = ""
addN(pkgName & " (" & version & "-1) unstable; urgency=low")
addN("")
addN(" * Initial release.")
addN("")
addN(" -- " & maintainer & " " &
formatDateTime(getGmTime(getTime()), "+0000"))
proc createRules(): string =
## Creates a nimrod application-agnostic rules file for building deb packages.
## Please note: this assumes the c sources have been built and the
## ``build.sh`` and ``install.sh`` files are available.
result = ""
addN("#!/usr/bin/make -f")
addN("%:")
addN("\tdh $@\n")
addN("dh_install:")
addN("\tdh_install --sourcedir=debian/tmp")
addN("override_dh_auto_clean:")
addN("\tfind . -name *.o -exec rm {} \\;")
addN("override_dh_auto_build:")
addN("\t./build.sh")
addN("override_dh_auto_install:")
addN("\t./install.sh debian/tmp")
proc createIncludeBinaries(binaries: seq[string]): string =
return join(binaries, "\n")
proc createDotInstall(pkgName: string, binaries, config, docs,
lib: seq[string]): string =
result = ""
for b in binaries:
addN(pkgName / b & " " & "usr/bin/")
for c in config:
addN(pkgName / c & " " & "etc/")
for d in docs:
addN(pkgName / d & " " & "usr/share/doc/nimrod/")
for l1 in lib:
addN(pkgName / l1 & " " & "usr/lib/nimrod")
proc makeMtn(name, email: string): string =
return name & " <" & email & ">"
proc assertSuccess(exitCode: int) =
doAssert(exitCode == QuitSuccess)
proc prepDeb*(packName, version, mtnName, mtnEmail, shortDesc, desc: string,
licenses: seq[tuple[files, license: string]], binaries,
config, docs, lib: seq[string],
buildDepends, pkgDepends = "") =
## binaries/config/docs/lib: files relative to nimrod's root, that need to
## be installed.
let pkgName = packName.toLower()
var workingDir = getTempDir() / "niminst" / "deb"
var upstreamSource = (pkgName & "-" & version)
echo("Making sure build.sh and install.sh are +x")
assertSuccess execCmd("chmod +x \"" &
(workingDir / upstreamSource / "build.sh") & "\"")
assertSuccess execCmd("chmod +x \"" &
(workingDir / upstreamSource / "install.sh") & "\"")
var tarCmd = "tar pczf \"" &
(pkgName & "_" & version & ".orig.tar.gz") &
"\" \"" & upstreamSource & "\""
echo(tarCmd)
assertSuccess execCmd("cd \"" & workingDir & "\" && " & tarCmd)
echo("Creating necessary files in debian/")
createDir(workingDir / upstreamSource / "debian")
template writeDebian(f, s: string): expr =
writeFile(workingDir / upstreamSource / "debian" / f, s)
var controlFile = createControl(pkgName, makeMtn(mtnName, mtnEmail),
shortDesc, desc, buildDepends, pkgDepends)
echo("debian/control")
writeDebian("control", controlFile)
var copyrightFile = createCopyright(pkgName, mtnName, mtnEmail, version,
licenses)
echo("debian/copyright")
writeDebian("copyright", copyrightFile)
var changelogFile = createChangelog(pkgName, version,
makeMtn(mtnName, mtnEmail))
echo("debian/changelog")
writeDebian("changelog", changelogFile)
echo("debian/rules")
writeDebian("rules", createRules())
echo("debian/compat")
writeDebian("compat", "8")
echo("debian/" & pkgName & ".install")
writeDebian(pkgName & ".install",
createDotInstall(pkgName, binaries, config, docs, lib))
# Other things..
createDir(workingDir / upstreamSource / "debian" / "source")
echo("debian/source/format")
writeDebian("source" / "format",
"3.0 (quilt)")
echo("debian/source/include-binaries")
writeFile(workingDir / upstreamSource / "debian" / "source" / "include-binaries",
createIncludeBinaries(binaries))
echo("All done, you can now build.")
echo("Before you do however, make sure the files in " &
workingDir / upstreamSource / "debian" & " are correct.")
echo("Change your directory to: " & workingDir / upstreamSource)
echo("And execute `debuild -us -uc` to build the .deb")
when isMainModule:
#var controlFile = createControl("nimrod", "Dominik Picheta <morfeusz8@gmail.com>",
# "The Nimrod compiler", "Compiler for the Nimrod programming language", "gcc (>= 4:4.3.2)", "gcc (>= 4:4.3.2)")
#echo(controlFile)
#var copyrightFile = createCopyright("nimrod", "Dominik Picheta", "morfeusz8@a.b", "0.8.14",
# @[("bin/nimrod", "gpl2"), ("lib/*", "lgpl")])
#echo copyrightFile
#var changelogFile = createChangelog("nimrod", "0.8.14", "Dom P <m@b.c>")
#echo(changelogFile)
#echo(createRules())
prepDeb("nimrod", "0.8.14", "Dominik Picheta", "morfeusz8@gmail.com",
"The Nimrod compiler", "Compiler for the Nimrod programming language",
@[("bin/nimrod", "gpl2"), ("lib/*", "lgpl")],
@["bin/nimrod"], @["config/*"], @["doc/*"], @["lib/*"],
"gcc (>= 4:4.3.2)", "gcc (>= 4:4.3.2)")

View file

@ -14,7 +14,7 @@ when haveZipLib:
import zipfiles import zipfiles
import import
os, strutils, parseopt, parsecfg, strtabs, streams os, strutils, parseopt, parsecfg, strtabs, streams, debcreation
const const
maxOS = 20 # max number of OSes maxOS = 20 # max number of OSes
@ -30,7 +30,8 @@ type
actionNone, # action not yet known actionNone, # action not yet known
actionCSource # action: create C sources actionCSource # action: create C sources
actionInno, # action: create Inno Setup installer actionInno, # action: create Inno Setup installer
actionZip # action: create zip file actionZip, # action: create zip file
actionDeb # action: prepare deb package
TFileCategory = enum TFileCategory = enum
fcWinBin, # binaries for Windows fcWinBin, # binaries for Windows
@ -56,6 +57,7 @@ type
vars: PStringTable vars: PStringTable
app: TAppType app: TAppType
nimrodArgs: string nimrodArgs: string
debOpts: TDebOptions
const const
unixDirVars: array[fcConfig..fcLib, string] = [ unixDirVars: array[fcConfig..fcLib, string] = [
@ -86,6 +88,11 @@ proc initConfigData(c: var TConfigData) =
c.uninstallScript = false c.uninstallScript = false
c.vars = newStringTable(modeStyleInsensitive) c.vars = newStringTable(modeStyleInsensitive)
c.debOpts.buildDepends = ""
c.debOpts.pkgDepends = ""
c.debOpts.shortDesc = ""
c.debOpts.licenses = @[]
proc firstBinPath(c: TConfigData): string = proc firstBinPath(c: TConfigData): string =
if c.binPaths.len > 0: result = c.binPaths[0] if c.binPaths.len > 0: result = c.binPaths[0]
else: result = "" else: result = ""
@ -121,6 +128,7 @@ Command:
csource build C source code for source based installations csource build C source code for source based installations
zip build the ZIP file zip build the ZIP file
inno build the Inno Setup installer inno build the Inno Setup installer
deb create files for debhelper
Options: Options:
-o, --output:dir set the output directory -o, --output:dir set the output directory
--var:name=value set the value of a variable --var:name=value set the value of a variable
@ -145,6 +153,7 @@ proc parseCmdLine(c: var TConfigData) =
of "csource": incl(c.actions, actionCSource) of "csource": incl(c.actions, actionCSource)
of "zip": incl(c.actions, actionZip) of "zip": incl(c.actions, actionZip)
of "inno": incl(c.actions, actionInno) of "inno": incl(c.actions, actionInno)
of "deb": incl(c.actions, actionDeb)
else: quit(Usage) else: quit(Usage)
else: else:
c.infile = addFileExt(key.string, "ini") c.infile = addFileExt(key.string, "ini")
@ -266,6 +275,36 @@ proc parseIniFile(c: var TConfigData) =
of "innosetup": pathFlags(p, k.key, v, c.innoSetup) of "innosetup": pathFlags(p, k.key, v, c.innoSetup)
of "ccompiler": pathFlags(p, k.key, v, c.ccompiler) of "ccompiler": pathFlags(p, k.key, v, c.ccompiler)
of "linker": pathFlags(p, k.key, v, c.linker) of "linker": pathFlags(p, k.key, v, c.linker)
of "deb":
case normalize(k.key)
of "builddepends":
c.debOpts.buildDepends = v
of "packagedepends", "pkgdepends":
c.debOpts.pkgDepends = v
of "shortdesc":
c.debOpts.shortDesc = v
of "licenses":
# file,license;file,license;
var i = 0
var file = ""
var license = ""
var afterComma = false
while i < v.len():
case v[i]
of ',':
afterComma = true
of ';':
if file == "" or license == "":
quit(errorStr(p, "Invalid `licenses` key."))
c.debOpts.licenses.add((file, license))
afterComma = false
file = ""
license = ""
else:
if afterComma: license.add(v[i])
else: file.add(v[i])
inc(i)
else: quit(errorStr(p, "unknown variable: " & k.key))
else: quit(errorStr(p, "invalid section: " & section)) else: quit(errorStr(p, "invalid section: " & section))
of cfgOption: quit(errorStr(p, "syntax error")) of cfgOption: quit(errorStr(p, "syntax error"))
@ -415,6 +454,52 @@ when haveZipLib:
else: else:
quit("Cannot open for writing: " & n) quit("Cannot open for writing: " & n)
# -- prepare build files for .deb creation
proc debDist(c: var TConfigData) =
if not existsFile("build.sh"): quit("No build.sh found.")
if not existsFile("install.sh"): quit("No install.sh found.")
if c.debOpts.shortDesc == "": quit("shortDesc must be set in the .ini file.")
if c.debOpts.licenses.len == 0:
echo("[Warning] No licenses specified for .deb creation.")
# -- Copy files into /tmp/..
echo("Copying source to tmp/niminst/deb/")
var currentSource = getCurrentDir()
var workingDir = getTempDir() / "niminst" / "deb"
var upstreamSource = (c.name.toLower() & "-" & c.version)
createDir(workingDir / upstreamSource)
template copyNimDist(f, dest: string): stmt =
createDir((workingDir / upstreamSource / dest).splitFile.dir)
copyFile(currentSource / f, workingDir / upstreamSource / dest)
# Don't copy all files, only the ones specified in the config:
copyNimDist(buildShFile, buildShFile)
copyNimDist(installShFile, installShFile)
createDir(workingDir / upstreamSource / "build")
for f in walkFiles(c.libpath / "lib/*.h"):
copyNimDist(f, "build" / extractFilename(f))
for osA in 1..c.oses.len:
for cpuA in 1..c.cpus.len:
var dir = buildDir(osA, cpuA)
for k, f in walkDir(dir):
if k == pcFile: copyNimDist(f, dir / extractFilename(f))
for cat in items({fcConfig..fcOther, fcUnix}):
for f in items(c.cat[cat]): copyNimDist(f, f)
# -- Create necessary build files for debhelper.
let mtnName = c.vars["mtnname"]
let mtnEmail = c.vars["mtnemail"]
prepDeb(c.name, c.version, mtnName, mtnEmail, c.debOpts.shortDesc,
c.description, c.debOpts.licenses, c.cat[fcUnixBin], c.cat[fcConfig],
c.cat[fcDoc], c.cat[fcLib], c.debOpts.buildDepends,
c.debOpts.pkgDepends)
# ------------------- main ---------------------------------------------------- # ------------------- main ----------------------------------------------------
var c: TConfigData var c: TConfigData
@ -430,3 +515,6 @@ if actionZip in c.actions:
zipdist(c) zipdist(c)
else: else:
quit("libzip is not installed") quit("libzip is not installed")
if actionDeb in c.actions:
debDist(c)