summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/tomcrypt/private/config.nim26
-rw-r--r--src/tomcrypt/tomcrypt.nim3
-rw-r--r--tomcrypt.nimble18
-rw-r--r--tools/builder.nim263
-rw-r--r--tools/libtomcrypt.nim31
5 files changed, 341 insertions, 0 deletions
diff --git a/src/tomcrypt/private/config.nim b/src/tomcrypt/private/config.nim
new file mode 100644
index 0000000..99c73c7
--- /dev/null
+++ b/src/tomcrypt/private/config.nim
@@ -0,0 +1,26 @@
+import os
+
+template currentSourceDir(): string =
+ ## Return the directory the current source file resides in.
+ parentDir(currentSourcePath())
+
+when not defined(tomcryptPrefix):
+ const tomcryptPrefix = currentSourceDir()
+
+when not defined(tomcryptIncPath):
+ const tomcryptIncPath = tomcryptPrefix / "include"
+
+when defined(vcc):
+ {.passC:"/I" & tomcryptIncPath.}
+else:
+ {.passC:"-I" & tomcryptIncPath.}
+
+when not defined(tomcryptLibPath):
+ const tomcryptLibPath = tomcryptPrefix / "lib"
+
+when defined(vcc):
+ const libraryPath = tomcryptLibPath / "tomcrypt.lib"
+else:
+ const libraryPath = tomcryptLibPath / "libtomcrypt.a"
+
+{.passL:libraryPath.}
diff --git a/src/tomcrypt/tomcrypt.nim b/src/tomcrypt/tomcrypt.nim
new file mode 100644
index 0000000..9bb42ad
--- /dev/null
+++ b/src/tomcrypt/tomcrypt.nim
@@ -0,0 +1,3 @@
+# tomcrypt_nim
+# Copyright Oskari Timperi
+# libtomcrypt for Nim
diff --git a/tomcrypt.nimble b/tomcrypt.nimble
new file mode 100644
index 0000000..dbb71ad
--- /dev/null
+++ b/tomcrypt.nimble
@@ -0,0 +1,18 @@
+# Package
+
+version = "0.1.0"
+author = "Oskari Timperi"
+description = "libtomcrypt for Nim"
+license = "MIT"
+srcDir = "src"
+
+# Dependencies
+
+requires "nim >= 0.18.0"
+requires "tommath"
+
+before install:
+ if not existsEnv("TOMCRYPT_NO_CLONE"):
+ exec "git clone --branch v1.18.1 --depth 1 https://github.com/libtom/libtomcrypt.git /tmp/source-libtomcrypt"
+
+ exec "nim c -r tools/libtomcrypt.nim"
diff --git a/tools/builder.nim b/tools/builder.nim
new file mode 100644
index 0000000..4207bf2
--- /dev/null
+++ b/tools/builder.nim
@@ -0,0 +1,263 @@
+import os
+import osproc
+import sequtils
+import strformat
+import strutils
+
+type
+ Compiler* {.pure.} = enum
+ Gcc
+ Vcc
+ Clang
+
+ CompilerInfo* = tuple[
+ name: string,
+ compilerC: string,
+ compilerCxx: string,
+ compileTmpl: string,
+ linkStaticTmpl: string,
+ includeTmpl: string,
+ defineTmpl: string,
+ ]
+
+ PublicHeader = ref object
+ destination: string
+ source: string
+
+ StaticLibrary* = ref object of RootObj
+ name*: string
+ sources*: seq[string]
+ defines*: seq[string]
+ compilerOptions*: seq[string]
+ includeDirectories*: seq[string]
+ buildDirectory*: string
+ publicHeaders*: seq[PublicHeader]
+
+template compiler(name, settings: untyped): untyped =
+ proc name: CompilerInfo {.compileTime.} = settings
+
+compiler(gcc):
+ result = (
+ name: "gcc",
+ compilerC: "gcc",
+ compilerCxx: "g++",
+ compileTmpl: "$compiler -c $options $includes -o $obj $source",
+ linkStaticTmpl: "ar rcs $library $obj",
+ includeTmpl: " -I$path",
+ defineTmpl: " -D$define"
+ )
+
+compiler(vcc):
+ result = (
+ name: "vcc",
+ compilerC: "cl",
+ compilerCxx: "cl",
+ compileTmpl: "$compiler /c $options $includes /Fo$obj $source",
+ linkStaticTmpl: "lib /OUT:$library $obj",
+ includeTmpl: " /I$path",
+ defineTmpl: " /D$define"
+ )
+
+compiler(clang):
+ result = gcc()
+ result.name = "clang"
+ result.compilerC = "clang"
+ result.compilerCxx = "clang++"
+
+const
+ Compilers* = [
+ gcc(),
+ vcc(),
+ clang(),
+ ]
+
+proc getCompiler*(): CompilerInfo {.compileTime.} =
+ ## Return the compiler info.
+ when hostOS == "windows":
+ result = Compilers[Compiler.Vcc.int]
+ elif hostOS == "macosx":
+ result = Compilers[Compiler.Clang.int]
+ else:
+ result = Compilers[Compiler.Gcc.int]
+
+proc newStaticLibrary*(name: string,
+ sourceDir: string): StaticLibrary =
+ ## Initialize a new static library.
+ ##
+ ## Args:
+ ## name: The logical name of the library. The platform specific
+ ## filename is built from this name.
+ ## sourceDir: The source directory of the library. Relative filenames
+ ## are resolved relating to this directory.
+ new(result)
+ result.name = name
+ result.sources = @[]
+ result.defines = @[]
+ result.compilerOptions = @[]
+ result.includeDirectories = @[]
+ result.buildDirectory = getTempDir() / &"build-{name}"
+ result.publicHeaders = @[]
+
+proc addIncludeDirectory*(library: StaticLibrary, dir: string) =
+ ## Add an include directory for the library.
+ add(library.includeDirectories, dir)
+
+proc addSourceFiles*(library: StaticLibrary, sources: varargs[string]) =
+ for source in sources:
+ var source = source
+ if not isAbsolute(source):
+ source = expandFilename(source)
+ add(library.sources, source)
+
+proc addSourceFilesWithPattern*(library: StaticLibrary, pattern: string) =
+ for file in walkFiles(pattern):
+ addSourceFiles(library, file)
+
+proc addPublicHeaders*(library: StaticLibrary, destination: string,
+ headers: varargs[string]) =
+ for header in headers:
+ add(library.publicHeaders, PublicHeader(destination: destination,
+ source: header))
+
+proc prefix(library: StaticLibrary): string =
+ ## Return the static library prefix.
+ when defined(windows):
+ result = ""
+ else:
+ result = "lib"
+
+proc suffix(library: StaticLibrary): string =
+ ## Return the static library suffix (extension).
+ when defined(windows):
+ result = ".lib"
+ else:
+ result = ".a"
+
+proc fullName(library: StaticLibrary): string =
+ ## Return the full name of a static library.
+ result = &"{library.prefix}{library.name}{library.suffix}"
+
+proc fullPath(library: StaticLibrary): string =
+ ## Return the full path of a static library
+ result = library.buildDirectory / fullName(library)
+
+proc relativePath(path, start: string): string =
+ ## Return the relative version of path.
+ ##
+ ## The returned path is relative to start. The procedure is translated into
+ ## Nim from Python's relpath() from posixpath.py.
+ let separators = { DirSep, AltSep }
+
+ var startList: seq[string] = @[]
+ for part in split(expandFilename(start), separators):
+ add(startList, part)
+
+ var pathList: seq[string] = @[]
+ for part in split(expandFilename(path), separators):
+ add(pathList, part)
+
+ let minLen = min(len(startList), len(pathList))
+
+ var commonLen = 0
+
+ for value in zip(startList, pathList):
+ if value.a == value.b:
+ inc(commonLen)
+ else:
+ break
+
+ let relList = cycle([ParDir], len(startList) - commonLen) & pathList[commonLen..^1]
+
+ if len(relList) == 0:
+ return $CurDir
+
+ result = joinPath(relList)
+
+proc objectFilename(library: StaticLibrary, source: string): string =
+ ## Return the absolute object file path of a source file.
+ var source = relativePath(source, getAppDir())
+ source = changeFileExt(source, "obj")
+ source = replace(source, "..", "__")
+ result = library.buildDirectory / source
+
+proc createParentDir(filename: string) =
+ ## Create the parent directory of a file.
+ let parent = parentDir(filename)
+ createDir(parent)
+
+proc echoAndExec(command: string): int =
+ echo(command)
+ result = execCmd(command)
+
+proc compile(library: StaticLibrary): bool =
+ ## Compile the sources of a static library.
+ var includes = ""
+ for path in library.includeDirectories:
+ includes &= getCompiler().includeTmpl % ["path", path]
+
+ var defines = ""
+ for define in library.defines:
+ defines &= getCompiler().defineTmpl % ["define", define]
+
+ var options = ""
+ for option in library.compilerOptions:
+ options &= " " & option
+
+ for source in library.sources:
+ let obj = objectFilename(library, source)
+
+ createParentDir(obj)
+
+ let (_, _, ext) = splitFile(source)
+
+ let compilerExe =
+ if ext == ".c":
+ getCompiler().compilerC
+ else:
+ getCompiler().compilerCxx
+
+ let tmpl = getCompiler().compileTmpl
+
+ let command = tmpl % [
+ "compiler", compilerExe,
+ "options", defines & options,
+ "includes", includes,
+ "obj", obj,
+ "source", source
+ ]
+
+ if echoAndExec(command) != 0:
+ return false
+
+ result = true
+
+proc link(library: StaticLibrary): bool =
+ ## Link the static library.
+ let outputPath = fullPath(library)
+
+ for source in library.sources:
+ let obj = objectFilename(library, source)
+
+ let command = getCompiler().linkStaticTmpl % [
+ "library", outputPath,
+ "obj", obj
+ ]
+
+ if echoAndExec(command) != 0:
+ return false
+
+ result = true
+
+proc build*(library: StaticLibrary): bool =
+ result = false
+ if compile(library):
+ result = link(library)
+
+proc install*(library: StaticLibrary, destdir: string) =
+ createDir(destdir / "lib")
+ copyFile(fullPath(library), destdir / "lib" / fullName(library))
+
+ for header in library.publicHeaders:
+ let filename = extractFilename(header.source)
+ createDir(destdir / header.destination)
+ copyFile(header.source, destdir / header.destination / filename)
diff --git a/tools/libtomcrypt.nim b/tools/libtomcrypt.nim
new file mode 100644
index 0000000..bb15c89
--- /dev/null
+++ b/tools/libtomcrypt.nim
@@ -0,0 +1,31 @@
+import os
+import strutils
+
+import builder
+
+# Import for tommathIncDir
+import tommath / private / config
+
+let sourceDir = expandFilename("/tmp/source-libtomcrypt")
+
+let libtomcrypt = newStaticLibrary("tomcrypt", sourceDir)
+
+add(libtomcrypt.defines, "USE_LTM")
+add(libtomcrypt.defines, "LTM_DESC")
+add(libtomcrypt.defines, "LTC_SOURCE")
+
+when not defined(vcc):
+ add(libtomcrypt.compilerOptions, "-O3 -funroll-loops -fomit-frame-pointer")
+
+for file in walkDirRec(sourceDir / "src", {pcFile}, {pcDir}):
+ if endsWith(file, ".c"):
+ addSourceFiles(libtomcrypt, file)
+
+addIncludeDirectory(libtomcrypt, sourceDir / "src" / "headers")
+addIncludeDirectory(libtomcrypt, tommathIncDir)
+
+for file in walkFiles(sourceDir / "src" / "headers" / "*.h"):
+ addPublicHeaders(libtomcrypt, "include", expandFilename(file))
+
+if build(libtomcrypt):
+ install(libtomcrypt, getAppDir() / ".." / "src" / "tomcrypt" / "private")