diff --git a/nimterop/build.nim b/nimterop/build.nim index 6fa44cb..ece2e33 100644 --- a/nimterop/build.nim +++ b/nimterop/build.nim @@ -4,6 +4,15 @@ import os except findExe, sleep import regex +type + BuildType* = enum + btAutoconf, btCmake + + BuildStatus = object + built: bool + buildPath: string + error: string + # build specific debug since we cannot import globals (yet) var gDebug* = false @@ -771,20 +780,7 @@ proc getNumProcs(): string = else: "1" -proc buildLibrary(lname, outdir, conFlags, cmakeFlags, makeFlags: string): string = - var - conDeps = false - conDepStr = "" - cmakeDeps = false - cmakeDepStr = "" - lpath = findFile(lname, outdir, regex = true) - makeFlagsProc = &"-j {getNumProcs()} {makeFlags}" - made = false - makePath = outdir - - if lpath.len != 0: - return lpath - +proc buildWithCmake(outdir, flags: string): BuildStatus = if not fileExists(outdir / "Makefile"): if fileExists(outdir / "CMakeLists.txt"): if findExe("cmake").len != 0: @@ -806,36 +802,58 @@ proc buildLibrary(lname, outdir, conFlags, cmakeFlags, makeFlags: string): strin gen = "Unix Makefiles".quoteShell if findExe("ccache").len != 0: gen &= " -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache" - makePath = outdir / "buildcache" - cmake(makePath, "Makefile", &".. -G {gen} {cmakeFlags}") - cmakeDeps = true + result.buildPath = outdir / "buildcache" + cmake(result.buildPath, "Makefile", &".. -G {gen} {flags}") + result.built = true else: - cmakeDepStr &= "cmake executable missing" + result.error = "cmake capable but cmake executable missing" + else: + result.buildPath = outdir - if not cmakeDeps: - if findExe("bash").len != 0: - for file in @["configure", "configure.ac", "configure.in", "autogen.sh", "build/autogen.sh"]: - if fileExists(outdir / file): - configure(outdir, "Makefile", conFlags) - conDeps = true - - break - else: - conDepStr &= "bash executable missing" - - if fileExists(makePath / "Makefile"): - make(makePath, lname, makeFlagsProc, regex = true) - made = true +proc buildWithAutoConf(outdir, flags: string): BuildStatus = + if not fileExists(outdir / "Makefile"): + if findExe("bash").len != 0: + for file in @["configure", "configure.ac", "configure.in", "autogen.sh", "build/autogen.sh"]: + if fileExists(outdir / file): + configure(outdir, "Makefile", flags) + result.buildPath = outdir + result.built = true + break + else: + result.error = "configure capable but bash executable missing" + else: + result.buildPath = outdir +proc buildLibrary(lname, outdir, conFlags, cmakeFlags, makeFlags: string, buildTypes: openArray[BuildType]): string = var - error = "" - if not cmakeDeps and cmakeDepStr.len != 0: - error &= &"cmake capable but {cmakeDepStr}\n" - if not conDeps and conDepStr.len != 0: - error &= &"configure capable but {conDepStr}\n" - if error.len == 0: - error = "No build files found in " & outdir - doAssert cmakeDeps or conDeps or made, &"\n# Build configuration failed - {error}\n" + lpath = findFile(lname, outdir, regex = true) + makeFlagsProc = &"-j {getNumProcs()} {makeFlags}" + makePath = outdir + + if lpath.len != 0: + return lpath + + var buildStatus: BuildStatus + + for buildType in buildTypes: + case buildType + of btCmake: + buildStatus = buildWithCmake(makePath, cmakeFlags) + of btAutoconf: + buildStatus = buildWithAutoConf(makePath, conFlags) + + if buildStatus.built: + break + + if buildStatus.buildPath.len > 0: + let libraryExists = findFile(lname, buildStatus.buildPath, regex = true).len > 0 + + if not libraryExists and fileExists(buildStatus.buildPath / "Makefile"): + make(buildStatus.buildPath, lname, makeFlagsProc, regex = true) + buildStatus.built = true + + let error = if buildStatus.error.len > 0: buildStatus.error else: "No build files found in " & outdir + doAssert buildStatus.built, &"\n# Build configuration failed - {error}\n" result = findFile(lname, outdir, regex = true) @@ -903,7 +921,7 @@ macro isDefined*(def: untyped): untyped = macro getHeader*(header: static[string], giturl: static[string] = "", dlurl: static[string] = "", outdir: static[string] = "", conFlags: static[string] = "", cmakeFlags: static[string] = "", makeFlags: static[string] = "", - altNames: static[string] = ""): untyped = + altNames: static[string] = "", buildTypes: static[openArray[BuildType]] = [btCmake, btAutoconf]): untyped = ## Get the path to a header file for wrapping with ## `cImport() `_ or ## `c2nImport() `_. @@ -946,6 +964,9 @@ macro getHeader*(header: static[string], giturl: static[string] = "", dlurl: sta ## with cmake. In this case, `altNames = "z,zlib"`. Comma separate for multiple alternate names without ## spaces. ## + ## `buildTypes` specifies a list of in order build strategies to use when building the downloaded source + ## files. Default is [btCmake, btAutoconf] + ## ## The original header name is not included by default if `altNames` is set since it could cause the ## wrong lib to be selected. E.g. `SDL2/SDL.h` could pick `libSDL.so` even if `altNames = "SDL2"`. ## Explicitly include it in `altNames` like the `zlib` example when required. @@ -1056,7 +1077,7 @@ macro getHeader*(header: static[string], giturl: static[string] = "", dlurl: sta when stdPath.len != 0 and stdLPath.len != 0: stdLPath else: - buildLibrary(`lname`, `outdir`, `conFlags`, `cmakeFlags`, `makeFlags`) + buildLibrary(`lname`, `outdir`, `conFlags`, `cmakeFlags`, `makeFlags`, `buildTypes`) # Header path - search again in case header is generated in build `path`* =