findFile w/regex, make -j, lib support for getHeader, noexcept / throw
This commit is contained in:
parent
7ef73147a6
commit
182d473973
3 changed files with 153 additions and 64 deletions
|
|
@ -36,12 +36,16 @@ proc testAll() =
|
||||||
execCmd "nim cpp -r tests/tnimterop_cpp.nim"
|
execCmd "nim cpp -r tests/tnimterop_cpp.nim"
|
||||||
execTest "tests/tpcre.nim"
|
execTest "tests/tpcre.nim"
|
||||||
|
|
||||||
## platform specific tests
|
# platform specific tests
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
execTest "tests/tmath.nim"
|
execTest "tests/tmath.nim"
|
||||||
if defined(OSX) or defined(Windows) or not existsEnv("TRAVIS"):
|
if defined(OSX) or defined(Windows) or not existsEnv("TRAVIS"):
|
||||||
tsoloud() # requires some libraries on linux, need them installed in TRAVIS
|
tsoloud() # requires some libraries on linux, need them installed in TRAVIS
|
||||||
|
|
||||||
|
# getHeader tests
|
||||||
|
withDir("tests"):
|
||||||
|
execCmd("nim e getheader.nims")
|
||||||
|
|
||||||
const htmldocsDir = "build/htmldocs"
|
const htmldocsDir = "build/htmldocs"
|
||||||
|
|
||||||
when (NimMajor, NimMinor, NimPatch) >= (0, 19, 9):
|
when (NimMajor, NimMinor, NimPatch) >= (0, 19, 9):
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import macros, osproc, sequtils, strformat, strutils
|
import macros, osproc, regex, sequtils, strformat, strutils
|
||||||
|
|
||||||
import os except findExe
|
import os except findExe
|
||||||
|
|
||||||
|
|
@ -194,6 +194,29 @@ proc gitPull*(url: string, outdir = "", plist = "", checkout = "") =
|
||||||
echo "# Pulling repository"
|
echo "# Pulling repository"
|
||||||
discard execAction(&"cd {outdirQ} && git pull --depth=1 origin master")
|
discard execAction(&"cd {outdirQ} && git pull --depth=1 origin master")
|
||||||
|
|
||||||
|
proc findFile*(file: string|Regex, dir: string, recurse = true, first = false): string =
|
||||||
|
## Find the file in the specified directory
|
||||||
|
##
|
||||||
|
## ``file`` can be a string or a regex object
|
||||||
|
##
|
||||||
|
## Turn off recursive search with ``recurse`` and stop on first match with
|
||||||
|
## ``first``. Without it, the shortest match is returned.
|
||||||
|
when file is Regex:
|
||||||
|
var
|
||||||
|
rm: RegexMatch
|
||||||
|
|
||||||
|
for f in walkDirRec(dir, followFilter = if recurse: {pcDir} else: {}):
|
||||||
|
let
|
||||||
|
fn = f.extractFilename()
|
||||||
|
when file is string:
|
||||||
|
if (result.len == 0 or result.len > f.len) and fn == file:
|
||||||
|
result = f
|
||||||
|
if first: break
|
||||||
|
else:
|
||||||
|
if (result.len == 0 or result.len > f.len) and fn.match(file, rm):
|
||||||
|
result = f
|
||||||
|
if first: break
|
||||||
|
|
||||||
proc configure*(path, check: string, flags = "") =
|
proc configure*(path, check: string, flags = "") =
|
||||||
## Run the GNU `configure` command to generate all Makefiles or other
|
## Run the GNU `configure` command to generate all Makefiles or other
|
||||||
## build scripts in the specified path
|
## build scripts in the specified path
|
||||||
|
|
@ -261,7 +284,7 @@ proc cmake*(path, check, flags: string) =
|
||||||
|
|
||||||
doAssert (path / check).fileExists(), "# cmake failed"
|
doAssert (path / check).fileExists(), "# cmake failed"
|
||||||
|
|
||||||
proc make*(path, check: string, flags = "") =
|
proc make*(path, check: string|Regex, flags = "") =
|
||||||
## Run the `make` command to build all binaries in the specified path
|
## Run the `make` command to build all binaries in the specified path
|
||||||
##
|
##
|
||||||
## `check` is a file that will be generated by the `make` command.
|
## `check` is a file that will be generated by the `make` command.
|
||||||
|
|
@ -272,7 +295,7 @@ proc make*(path, check: string, flags = "") =
|
||||||
##
|
##
|
||||||
## If make.exe is missing and mingw32-make.exe is available, it will
|
## If make.exe is missing and mingw32-make.exe is available, it will
|
||||||
## be copied over to make.exe in the same location.
|
## be copied over to make.exe in the same location.
|
||||||
if (path / check).fileExists():
|
if findFile(check, path).len != 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
echo "# Running make " & flags
|
echo "# Running make " & flags
|
||||||
|
|
@ -293,14 +316,7 @@ proc make*(path, check: string, flags = "") =
|
||||||
|
|
||||||
echo execAction(cmd)
|
echo execAction(cmd)
|
||||||
|
|
||||||
doAssert (path / check).fileExists(), "# make failed"
|
doAssert findFile(check, path).len != 0, "# make failed"
|
||||||
|
|
||||||
proc findFile*(file, dir: string): string =
|
|
||||||
## Find the file in the specified directory
|
|
||||||
for f in walkDirRec(dir):
|
|
||||||
if f.extractFilename() == file:
|
|
||||||
if result.len == 0 or result.len > f.len:
|
|
||||||
result = f
|
|
||||||
|
|
||||||
proc getGccPaths*(mode = "c"): seq[string] =
|
proc getGccPaths*(mode = "c"): seq[string] =
|
||||||
var
|
var
|
||||||
|
|
@ -308,7 +324,7 @@ proc getGccPaths*(mode = "c"): seq[string] =
|
||||||
mmode = if mode == "cpp": "c++" else: mode
|
mmode = if mode == "cpp": "c++" else: mode
|
||||||
inc = false
|
inc = false
|
||||||
|
|
||||||
(outp, ret) = gorgeEx(&"""{getEnv("CC", "gcc")} -Wp,-v -x{mmode} {nul}""")
|
(outp, _) = gorgeEx(&"""{getEnv("CC", "gcc")} -Wp,-v -x{mmode} {nul}""")
|
||||||
|
|
||||||
for line in outp.splitLines():
|
for line in outp.splitLines():
|
||||||
if "#include <...> search starts here" in line:
|
if "#include <...> search starts here" in line:
|
||||||
|
|
@ -317,11 +333,38 @@ proc getGccPaths*(mode = "c"): seq[string] =
|
||||||
elif "End of search list" in line:
|
elif "End of search list" in line:
|
||||||
break
|
break
|
||||||
if inc:
|
if inc:
|
||||||
result.add line.strip()
|
var
|
||||||
|
path = line.strip()
|
||||||
|
path.normalizePath()
|
||||||
|
if path notin result:
|
||||||
|
result.add path
|
||||||
|
|
||||||
|
proc getGccLibPaths*(mode = "c"): seq[string] =
|
||||||
|
var
|
||||||
|
nul = when defined(Windows): "nul" else: "/dev/null"
|
||||||
|
mmode = if mode == "cpp": "c++" else: mode
|
||||||
|
|
||||||
|
(outp, _) = gorgeEx(&"""{getEnv("CC", "gcc")} -v -x{mmode} {nul}""")
|
||||||
|
|
||||||
|
for line in outp.splitLines():
|
||||||
|
if "LIBRARY_PATH=" in line:
|
||||||
|
for path in line[13 .. ^1].split(PathSep):
|
||||||
|
var
|
||||||
|
path = path.strip()
|
||||||
|
path.normalizePath()
|
||||||
|
if path notin result:
|
||||||
|
result.add path
|
||||||
|
break
|
||||||
|
|
||||||
proc getStdPath(header: string): string =
|
proc getStdPath(header: string): string =
|
||||||
for inc in getGccPaths():
|
for inc in getGccPaths():
|
||||||
result = findFile(header, inc)
|
result = findFile(header, inc, recurse = false, first = true)
|
||||||
|
if result.len != 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
proc getStdLibPath(lname: string): string =
|
||||||
|
for lib in getGccLibPaths():
|
||||||
|
result = findFile(re(lname), lib, recurse = false, first = true)
|
||||||
if result.len != 0:
|
if result.len != 0:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
@ -369,44 +412,49 @@ proc getLocalPath(header, outdir: string): string =
|
||||||
if outdir.len != 0:
|
if outdir.len != 0:
|
||||||
result = findFile(header, outdir)
|
result = findFile(header, outdir)
|
||||||
|
|
||||||
proc buildLibrary(outdir, conFlags, conStaticLib, conDynLib, cmakeFlags, cmakeStaticLib, cmakeDynLib, makeFlags: string) =
|
proc getNumProcs(): string =
|
||||||
|
when defined(windows):
|
||||||
|
getEnv("NUMBER_OF_PROCESSORS").strip()
|
||||||
|
elif defined(linux):
|
||||||
|
execAction("nproc").strip()
|
||||||
|
elif defined(macosx):
|
||||||
|
execAction("sysctl -n hw.ncpu").strip()
|
||||||
|
else:
|
||||||
|
"1"
|
||||||
|
|
||||||
|
proc buildLibrary(lname, outdir, conFlags, cmakeFlags, makeFlags: string): string =
|
||||||
var
|
var
|
||||||
conDeps = false
|
conDeps = false
|
||||||
conDepStr = ""
|
conDepStr = ""
|
||||||
cmakeDeps = false
|
cmakeDeps = false
|
||||||
cmakeDepStr = ""
|
cmakeDepStr = ""
|
||||||
|
lpath = findFile(re(lname), outdir)
|
||||||
|
makeFlagsProc = &"-j {getNumProcs()} {makeFlags}"
|
||||||
|
|
||||||
|
if lpath.len != 0:
|
||||||
|
return lpath
|
||||||
|
|
||||||
if fileExists(outdir / "CMakeLists.txt"):
|
if fileExists(outdir / "CMakeLists.txt"):
|
||||||
if findExe("cmake").len != 0:
|
if findExe("cmake").len != 0:
|
||||||
if cmakeStaticLib.len != 0 or cmakeDynLib.len != 0:
|
var
|
||||||
var
|
gen = ""
|
||||||
gen = ""
|
when defined(windows):
|
||||||
when defined(windows):
|
if findExe("sh").len != 0:
|
||||||
if findExe("sh").len != 0:
|
gen = "MSYS Makefiles"
|
||||||
gen = "MSYS Makefiles"
|
|
||||||
else:
|
|
||||||
gen = "MinGW Makefiles"
|
|
||||||
else:
|
else:
|
||||||
gen = "Unix Makefiles"
|
gen = "MinGW Makefiles"
|
||||||
cmake(outdir / "build", "Makefile", &".. -G {gen.quoteShell} {cmakeFlags}")
|
|
||||||
cmakeDeps = true
|
|
||||||
let
|
|
||||||
check = if cmakeStaticLib.len != 0: cmakeStaticLib else: cmakeDynLib
|
|
||||||
make(outdir / "build", check, makeFlags)
|
|
||||||
else:
|
else:
|
||||||
cmakeDepStr &= "cmakeStatibLib / cmakeDynLib not specified"
|
gen = "Unix Makefiles"
|
||||||
|
cmake(outdir / "build", "Makefile", &".. -G {gen.quoteShell} {cmakeFlags}")
|
||||||
|
cmakeDeps = true
|
||||||
|
make(outdir / "build", re(lname), makeFlagsProc)
|
||||||
else:
|
else:
|
||||||
cmakeDepStr &= "cmake executable missing"
|
cmakeDepStr &= "cmake executable missing"
|
||||||
|
|
||||||
template cfgCommon() {.dirty.} =
|
template cfgCommon() {.dirty.} =
|
||||||
if (conStaticLib.len != 0 or conDynLib.len != 0):
|
configure(outdir, "Makefile", conFlags)
|
||||||
configure(outdir, "Makefile", conFlags)
|
conDeps = true
|
||||||
conDeps = true
|
make(outdir, re(lname), makeFlagsProc)
|
||||||
let
|
|
||||||
check = if conStaticLib.len != 0: conStaticLib else: conDynLib
|
|
||||||
make(outdir, check, makeFlags)
|
|
||||||
else:
|
|
||||||
conDepStr &= "conStaticLib / conDynLib not specified"
|
|
||||||
|
|
||||||
if not cmakeDeps:
|
if not cmakeDeps:
|
||||||
if not fileExists(outdir / "configure"):
|
if not fileExists(outdir / "configure"):
|
||||||
|
|
@ -437,53 +485,89 @@ proc buildLibrary(outdir, conFlags, conStaticLib, conDynLib, cmakeFlags, cmakeSt
|
||||||
error = "No build files found in " & outdir
|
error = "No build files found in " & outdir
|
||||||
doAssert cmakeDeps or conDeps, &"\n# Build configuration failed - {error}\n"
|
doAssert cmakeDeps or conDeps, &"\n# Build configuration failed - {error}\n"
|
||||||
|
|
||||||
|
result = findFile(re(lname), outdir)
|
||||||
|
|
||||||
|
proc getDynlibExt(): string =
|
||||||
|
when defined(windows):
|
||||||
|
result = ".dll"
|
||||||
|
elif defined(linux):
|
||||||
|
result = ".so[0-9.]*"
|
||||||
|
elif defined(macosx):
|
||||||
|
result = ".dylib[0-9.]*"
|
||||||
|
|
||||||
macro getHeader*(header: static[string], giturl: static[string] = "", dlurl: static[string] = "", outdir: static[string] = "",
|
macro getHeader*(header: static[string], giturl: static[string] = "", dlurl: static[string] = "", outdir: static[string] = "",
|
||||||
conFlags: static[string] = "", conStaticLib: static[string] = "", conDynLib: static[string] = "",
|
conFlags: static[string] = "", cmakeFlags: static[string] = "", makeFlags: static[string] = ""): untyped =
|
||||||
cmakeFlags: static[string] = "", cmakeStaticLib: static[string] = "", cmakeDynLib: static[string] = "",
|
|
||||||
makeFlags: static[string] = ""): untyped =
|
|
||||||
## Get the path to a header file for wrapping with
|
## Get the path to a header file for wrapping with
|
||||||
## `cImport() <cimport.html#cImport.m%2C%2Cstring%2Cstring%2Cstring>`_ or
|
## `cImport() <cimport.html#cImport.m%2C%2Cstring%2Cstring%2Cstring>`_ or
|
||||||
## `c2nImport() <cimport.html#c2nImport.m%2C%2Cstring%2Cstring%2Cstring>`_.
|
## `c2nImport() <cimport.html#c2nImport.m%2C%2Cstring%2Cstring%2Cstring>`_.
|
||||||
##
|
##
|
||||||
## Checks defines based on the header name (e.g. lzma from lzma.h), to use different
|
## This proc checks -d:xxx defines based on the header name (e.g. lzma from lzma.h),
|
||||||
## ways to obtain the source.
|
## and accordingly employs different ways to obtain the source.
|
||||||
##
|
##
|
||||||
## ``-d:xxxStd`` - search standard system paths. E.g. ``/usr/include`` and ``/usr/lib`` on Linux
|
## ``-d:xxxStd`` - search standard system paths. E.g. ``/usr/include`` and ``/usr/lib`` on Linux
|
||||||
## ``-d:xxxGit`` - clone source from a git repo specified in ``giturl``
|
## ``-d:xxxGit`` - clone source from a git repo specified in ``giturl``
|
||||||
## ``-d:xxxDL`` - download source from ``dlurl`` and extract if required
|
## ``-d:xxxDL`` - download source from ``dlurl`` and extract if required
|
||||||
##
|
##
|
||||||
## This allows a single wrapper to be used in different ways depending on the user's needs.
|
## This allows a single wrapper to be used in different ways depending on the user's needs.
|
||||||
## If no defines are specified, ``outdir`` will be searched for the header.
|
## If no -d:xxx defines are specified, ``outdir`` will be searched for the header.
|
||||||
##
|
##
|
||||||
## The library is then configured (either with cmake or autotools if possible) and then built
|
## The library is then configured (with cmake or autotools if possible) and built
|
||||||
## using make.
|
## using make, unless using ``-d:xxxStd`` which presumes that the system package
|
||||||
|
## manager was used to install prebuilt headers and binaries.
|
||||||
|
##
|
||||||
|
## The header path is stored in ``const xxxPath`` and can be used in a ``cImport()`` call
|
||||||
|
## in the calling wrapper. The dynamic library path is stored in ``const xxxLPath`` and can
|
||||||
|
## be used for the ``dynlib`` parameter (within quotes).
|
||||||
|
##
|
||||||
|
## ``-d:xxxStatic`` can be specified to statically link with the library instead. This
|
||||||
|
## will automatically add a ``{.passL.}`` call to the static library for convenience.
|
||||||
var
|
var
|
||||||
name = header.split(".")[0]
|
name = header.split(".")[0]
|
||||||
|
|
||||||
stdName = newIdentNode(name & "Std")
|
nameStd = newIdentNode(name & "Std")
|
||||||
gitName = newIdentNode(name & "Git")
|
nameGit = newIdentNode(name & "Git")
|
||||||
dlName = newIdentNode(name & "DL")
|
nameDL = newIdentNode(name & "DL")
|
||||||
|
|
||||||
|
nameStatic = newIdentNode(name & "Static")
|
||||||
|
|
||||||
path = newIdentNode(name & "Path")
|
path = newIdentNode(name & "Path")
|
||||||
|
lpath = newIdentNode(name & "LPath")
|
||||||
version = newIdentNode(name & "Version")
|
version = newIdentNode(name & "Version")
|
||||||
|
lname = newIdentNode(name & "LName")
|
||||||
|
|
||||||
|
lre = "(lib)?$1[0-9.\\-]*\\" % name
|
||||||
|
|
||||||
result = newNimNode(nnkStmtList)
|
result = newNimNode(nnkStmtList)
|
||||||
result.add(quote do:
|
result.add(quote do:
|
||||||
const `version`* {.strdefine.} = ""
|
const
|
||||||
|
`version`* {.strdefine.} = ""
|
||||||
when defined(`stdName`):
|
`lname` =
|
||||||
const `path`* = getStdPath(`header`)
|
when defined(`nameStatic`):
|
||||||
else:
|
`lre` & ".a"
|
||||||
const `path`* =
|
|
||||||
when defined(`gitName`):
|
|
||||||
getGitPath(`header`, `giturl`, `outdir`, `version`)
|
|
||||||
elif defined(`dlName`):
|
|
||||||
getDlPath(`header`, `dlurl`, `outdir`, `version`)
|
|
||||||
else:
|
else:
|
||||||
getLocalPath(`header`, `outdir`)
|
`lre` & getDynlibExt()
|
||||||
|
|
||||||
static:
|
when defined(`nameStd`):
|
||||||
doAssert `path`.len != 0, "\nHeader " & `header` & " not found - " & "missing/empty outdir or -d:$1Std -d:$1Git or -d:$1DL not specified" % `name`
|
const
|
||||||
|
`path`* = getStdPath(`header`)
|
||||||
|
`lpath`* = getStdLibPath(`lname`)
|
||||||
|
else:
|
||||||
|
const
|
||||||
|
`path`* =
|
||||||
|
when defined(`nameGit`):
|
||||||
|
getGitPath(`header`, `giturl`, `outdir`, `version`)
|
||||||
|
elif defined(`nameDL`):
|
||||||
|
getDlPath(`header`, `dlurl`, `outdir`, `version`)
|
||||||
|
else:
|
||||||
|
getLocalPath(`header`, `outdir`)
|
||||||
|
|
||||||
buildLibrary(`outdir`, `conFlags`, `conStaticLib`, `conDynLib`, `cmakeFlags`, `cmakeStaticLib`, `cmakeDynLib`, `makeFlags`)
|
`lpath`* = buildLibrary(`lname`, `outdir`, `conFlags`, `cmakeFlags`, `makeFlags`)
|
||||||
|
|
||||||
|
static:
|
||||||
|
doAssert `path`.len != 0, "\nHeader " & `header` & " not found - " & "missing/empty outdir or -d:$1Std -d:$1Git or -d:$1DL not specified" % `name`
|
||||||
|
doAssert `lpath`.len != 0, "\nLibrary " & `lname` & " not found"
|
||||||
|
echo "# Including library " & `lpath`
|
||||||
|
|
||||||
|
when defined(`nameStatic`):
|
||||||
|
{.passL: `lpath`.}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,7 @@ proc initGrammar(): Grammar =
|
||||||
(type_identifier)
|
(type_identifier)
|
||||||
)
|
)
|
||||||
{paramListGrammar}
|
{paramListGrammar}
|
||||||
|
(noexcept|throw_specifier?)
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue