diff --git a/README.md b/README.md index 2ed10c5..0e60711 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ From linux-amd64 --target linux-amd64-gnu.2.28 --target linux-amd64-gnu.2.31 --target linux-i386 + --target linux-arm64 --target macosx-amd64 --target macosx-arm64 --target windows-amd64 @@ -47,6 +48,7 @@ From linux-i386 --target linux-amd64-gnu.2.28 --target linux-amd64-gnu.2.31 --target linux-i386 + --target linux-arm64 --target macosx-amd64 --target macosx-arm64 --target windows-amd64 @@ -58,6 +60,7 @@ From macosx-amd64 --target linux-amd64-gnu.2.28 --target linux-amd64-gnu.2.31 --target linux-i386 + --target linux-arm64 --target macosx-amd64 --target macosx-arm64 --target windows-amd64 @@ -69,6 +72,7 @@ From macosx-arm64 --target linux-amd64-gnu.2.28 --target linux-amd64-gnu.2.31 --target linux-i386 + --target linux-arm64 --target macosx-amd64 --target macosx-arm64 --target windows-amd64 @@ -80,6 +84,7 @@ From windows-amd64 --target linux-amd64-gnu.2.28 --target linux-amd64-gnu.2.31 --target linux-i386 + --target linux-arm64 --target macosx-amd64 --target macosx-arm64 --target windows-amd64 @@ -91,6 +96,7 @@ From windows-arm64 --target linux-amd64-gnu.2.28 --target linux-amd64-gnu.2.31 --target linux-i386 + --target linux-arm64 --target macosx-amd64 --target macosx-arm64 --target windows-amd64 @@ -102,6 +108,7 @@ From windows-i386 --target linux-amd64-gnu.2.28 --target linux-amd64-gnu.2.31 --target linux-i386 + --target linux-arm64 --target macosx-amd64 --target macosx-arm64 --target windows-amd64 diff --git a/src/nimxc.nim b/src/nimxc.nim index c90a457..86bf9f6 100644 --- a/src/nimxc.nim +++ b/src/nimxc.nim @@ -14,8 +14,8 @@ type os: string cpu: string extra: string - InstallProc = proc(dir: string): void {.closure.} - ArgsProc = proc(dir: string): seq[string] {.closure.} + InstallProc = proc(dir: string, sdk: string): void {.closure.} + ArgsProc = proc(dir: string, sdk: string): seq[string] {.closure.} Bundle = tuple install: InstallProc args: ArgsProc @@ -39,6 +39,12 @@ proc targetExeExt*(target: Pair): string = else: return "" +proc getDir*(url: string): string = + let arname = url.extractFilename + if arname.endsWith(".zip"): + return arname.changeFileExt("") + return arname.changeFileExt("").changeFileExt("") + #====================================================================== # Target definitions #====================================================================== @@ -95,6 +101,25 @@ proc install_zig(src_url: string, toolchains: string) = raise ValueError.newException("Failed to compile zigcc") echo "Created zigcc at ", zigcc +proc install_sdk(src_url: string, toolchains: string) = + let dlcache = toolchains / "download" + let dlfilename = dlcache / src_url.extractFilename() + let dstsubdir = toolchains / dlfilename.extractFilename.changeFileExt("").changeFileExt("") + if not dstsubdir.dirExists: + if not dlfilename.fileExists: + # download it + createDir(dlcache) + echo &"Downloading {src_url} to {dlfilename} ..." + let client = newHttpClient() + defer: client.close() + client.downloadFile(src_url, dlfilename) + # extract it + echo &"Extracting {dlfilename} to {dstsubdir}" + var p = startProcess(findExe"tar", + args=["-x", "-C", toolchains, "-f", dlfilename], + options={poStdErrToStdOut, poParentStreams}) + doAssert p.waitForExit() == 0 + const zigcc_name = "zigcc".changeFileExt(ExeExt) # See https://nim-lang.org/docs/system.html#hostCPU for possible CPU arch values @@ -109,26 +134,29 @@ const nimOStoZigOS = { "macosx": "macos", }.toTable() -const zigVersion = "0.9.0" +const zigVersion = "0.10.1" + +const sdkurl = "https://github.com/vandot/nimxc/releases/download/sdk/macosx-sdk.14.2.tar.xz" const zigurls = { - "macosx-amd64": fmt"https://ziglang.org/download/{zigVersion}/zig-macos-x86_64-{zigVersion}.tar.xz", - "macosx-arm64": fmt"https://ziglang.org/download/{zigVersion}/zig-macos-aarch64-{zigVersion}.tar.xz", - "linux-amd64": fmt"https://ziglang.org/download/{zigVersion}/zig-linux-x86_64-{zigVersion}.tar.xz", - "linux-i386": fmt"https://ziglang.org/download/{zigVersion}/zig-linux-i386-{zigVersion}.tar.xz", - "windows-amd64": fmt"https://ziglang.org/download/{zigVersion}/zig-windows-x86_64-{zigVersion}.zip", - "windows-i386": fmt"https://ziglang.org/download/{zigVersion}/zig-windows-i386-{zigVersion}.zip", - "windows-arm64": fmt"https://ziglang.org/download/{zigVersion}/zig-windows-aarch64-{zigVersion}.zip", + "macosx-amd64": &"https://ziglang.org/download/{zigVersion}/zig-macos-x86_64-{zigVersion}.tar.xz", + "macosx-arm64": &"https://ziglang.org/download/{zigVersion}/zig-macos-aarch64-{zigVersion}.tar.xz", + "linux-amd64": &"https://ziglang.org/download/{zigVersion}/zig-linux-x86_64-{zigVersion}.tar.xz", + "linux-i386": &"https://ziglang.org/download/{zigVersion}/zig-linux-i386-{zigVersion}.tar.xz", + "linux-arm64": &"https://ziglang.org/download/{zigVersion}/zig-linux-aarch64-{zigVersion}.tar.xz", + "windows-amd64": &"https://ziglang.org/download/{zigVersion}/zig-windows-x86_64-{zigVersion}.zip", + "windows-i386": &"https://ziglang.org/download/{zigVersion}/zig-windows-i386-{zigVersion}.zip", + "windows-arm64": &"https://ziglang.org/download/{zigVersion}/zig-windows-aarch64-{zigVersion}.zip", }.toTable() -proc mkArgs(zig_root: string, target: Target): seq[string] = +proc mkArgs(zig_root: string, sdk_root: string, target: Target): seq[string] = ## Return the compiler args for the given target var zig_target = ( nimOStoZigOS.getOrDefault(target.os, target.os), nimArchToZigArch.getOrDefault(target.cpu, target.cpu), target.extra, ) - @[ + result = @[ "--cc:clang", "--cpu:" & target.cpu, "--os:" & target.os, @@ -140,6 +168,10 @@ proc mkArgs(zig_root: string, target: Target): seq[string] = &"--passC:-target {zig_target.zigfmt} -fno-sanitize=undefined", &"--passL:-target {zig_target.zigfmt} -fno-sanitize=undefined", ] + if "macosx" in $target: + result.add &"--passC:-I{sdk_root}/usr/include -fno-sanitize=undefined" + result.add &"--passL:-F{sdk_root}/System/Library/Frameworks -fno-sanitize=undefined" + result.add &"--passL:-L{sdk_root}/usr/lib -fno-sanitize=undefined" #---------------------------------------------------------------------- const targets : seq[Target] = @[ @@ -150,9 +182,10 @@ const targets : seq[Target] = @[ ("linux", "amd64", "gnu.2.27"), ("linux", "amd64", "gnu.2.28"), ("linux", "amd64", "gnu.2.31"), + ("linux", "arm64", ""), ("windows", "i386", ""), ("windows", "amd64", ""), - ("windows", "arm64", ""), + ("windows", "arm64", ""), ] for host, url in zigurls.pairs: @@ -161,22 +194,23 @@ for host, url in zigurls.pairs: let this_url = url if not host_systems.hasKey(this_host): host_systems[this_host] = newTable[Pair, Bundle]() - let arname = this_url.extractFilename - let dirname = if arname.endsWith(".zip"): - arname.changeFileExt("") - elif arname.endsWith(".tar.xz"): - arname.changeFileExt("").changeFileExt("") - else: - arname.changeFileExt("") + let dirname = getDir(url) + let sdkdirname = getDir(sdkurl) for target in targets: let targ: Target = (target.os, target.cpu, target.extra) # this is for closure purposes closureScope: let this_targ: Target = (targ.os, targ.cpu, targ.extra) - proc install(toolchains: string) {.closure.} = + proc install(toolchains: string, sdk: string) {.closure.} = install_zig(this_url, toolchains) - proc args(toolchains: string): seq[string] {.closure.} = + if "macosx" in $this_targ and hostOS != "windows": + install_sdk(sdkurl, toolchains) + proc args(toolchains: string, sdk: string): seq[string] {.closure.} = let zig_root = absolutePath(toolchains / dirname) - mkArgs(zig_root, this_targ) + let sdk_root = if sdk != "": + absolutePath(sdk) + else: + absolutePath(toolchains / sdkdirname) + mkArgs(zig_root, sdk_root, this_targ) let install_proc: InstallProc = install let args_proc: ArgsProc = args host_systems[host][$this_targ] = (install_proc, args_proc) @@ -184,8 +218,8 @@ for host, url in zigurls.pairs: # add nop targets for the host itself for key in host_systems.keys: block: - proc install(toolchains: string) = discard - proc args(toolchains: string): seq[string] = discard + proc install(toolchains: string, sdk: string) = discard + proc args(toolchains: string, sdk : string): seq[string] = discard let install_proc: InstallProc = install let args_proc: ArgsProc = args host_systems[key][key] = (install_proc, args_proc) @@ -202,21 +236,21 @@ proc get_bundle(host: Pair, target: Pair): Bundle = raise ValueError.newException(&"Target {target} unsupported on {host}. Acceptable targets: " & targets_for(host).join(", ")) return host_systems[host][target] -proc compile_args*(host: Pair, target: Pair, dir = ""): seq[string] = +proc compile_args*(host: Pair, target: Pair, dir = "", sdk = ""): seq[string] = ## Return the nim compile args to use to compile for the given target if host == target: return - get_bundle(host, target).args(dir) + get_bundle(host, target).args(dir, sdk) -proc install_toolchain*(host: Pair, target: Pair, dir = "") = +proc install_toolchain*(host: Pair, target: Pair, dir = "", sdk = "") = ## Install the toolchain for cross-compiling if host == target: return - get_bundle(host, target).install(dir) + get_bundle(host, target).install(dir, sdk) const DEFAULT_TOOLCHAIN_DIR* = expandTilde("~/.nimxc") -proc exec_nim_c*(host: Pair, target: Pair, toolchains: string, args: openArray[string]): int = +proc exec_nim_c*(host: Pair, target: Pair, toolchains: string, sdk: string, args: openArray[string]): int = ## Execute 'nim c' but cross-compile for the given `target` var full_args = @["c"] full_args.add(host.compile_args(target, toolchains)) @@ -266,7 +300,11 @@ when isMainModule: for host in toSeq(host_systems.keys).sorted: echo &"From {host}" for dst in toSeq(host_systems[host].keys).sorted: - echo &" --target {dst}" + let msg = if "windows" in host and "macosx" in dst: + &" --target {dst} (if MacOSX SDK is installed)" + else: + &" --target {dst}" + echo msg else: for targ in targets_for(THIS_HOST): echo &"--target {targ}" @@ -284,9 +322,12 @@ when isMainModule: option("-t", "--target", help="Target system.") flag("--no-auto-install", help="If given, don't attempt to install the toolchain if it's missing") option("-d", "--directory", help="Directory where toolchains were installed", default=some(DEFAULT_TOOLCHAIN_DIR)) + option("--sdk", help="Root directory where MacOSX SDK is installed") arg("args", nargs = -1, help="Options to be passed directly to 'nim c'") run: + if hostOS == "windows" and "macosx" in opts.target and opts.sdk == "": + quit("Cross-compiling to macosx targets without MacOSX SDK is not supported on Windows.") if not opts.no_auto_install: - THIS_HOST.install_toolchain(opts.target, opts.directory) - quit(THIS_HOST.exec_nim_c(opts.target, opts.directory, opts.args)) + THIS_HOST.install_toolchain(opts.target, opts.directory, opts.sdk) + quit(THIS_HOST.exec_nim_c(opts.target, opts.directory, opts.sdk, opts.args)) p.run() diff --git a/tests/test_everything.nim b/tests/test_everything.nim index fdecbd6..56525f4 100644 --- a/tests/test_everything.nim +++ b/tests/test_everything.nim @@ -12,7 +12,8 @@ var toskip = [ "ssl_from_macosx-amd64_to_linux-amd64", "sqlite_from_windows-amd64_to_linux-amd64-gnu.2.27", "sqlite_from_macosx-amd64_to_linux-amd64-gnu.2.27", - "sqlite_from_macosx-arm64_to_linux-amd64-gnu.2.27", + "sqlite_from_macosx-arm64_to_linux-amd64-gnu.2.27", ## undefined symbol: fcntl64 https://github.com/ziglang/zig/pull/15101 + "sqlite_from_linux-arm64_to_linux-amd64-gnu.2.27", ## undefined symbol: fcntl64 https://github.com/ziglang/zig/pull/15101 "regex_from_windows-amd64_to_linux-amd64", "regex_from_macosx-amd64_to_linux-amd64", ] @@ -36,6 +37,8 @@ var failed_tests: seq[string] if host_systems.hasKey(THIS_HOST): for target in host_systems[THIS_HOST].keys: + if "windows" in THIS_HOST and "macosx" in target: + continue for sample in samples: let testname = sample.extractFilename & "_from_" & THIS_HOST & "_to_" & target if testname in toskip: @@ -59,6 +62,8 @@ if host_systems.hasKey(THIS_HOST): var args = @["c", "-o:" & dst] for arg in THIS_HOST.compile_args(target, toolchains_root): args.add(arg) + if testname in @["threading_from_windows-amd64_to_linux-amd64", "threading_from_macosx-amd64_to_linux-amd64"]: + args.add("--passC:-Wno-error=int-conversion -fno-sanitize=undefined") args.add(src.extractFilename) echo "cd " & subdir echo "nim " & args.mapIt("'" & it & "'").join(" ")