## Turning a sysroot into compiler flags. ## ## Nim's OpenSSL binding is the one place a static build needs more than paths: ## `-d:ssl` makes Nim dlopen libssl at runtime, which a static binary cannot do, ## and OpenSSL 3 dropped a symbol Nim still references. Both fixes are emitted ## here rather than left as folklore in someone's shell history. import std/[os, strutils] import ./sysroot type Toolchain* = enum tcNim = "nim", tcCc = "cc", tcPkgConfig = "pkg-config" proc includeDir*(root: string): string = root / "usr" / "include" proc libDir*(root: string): string = root / "usr" / "lib" proc hasLib(root, name: string): bool = fileExists(libDir(root) / ("lib" & name & ".a")) proc nimFlags*(root: string, libs: openArray[string] = [], opensslCompat = true): seq[string] = result = @["--passC:-I" & includeDir(root), "--passL:-L" & libDir(root), "--passL:-static"] if hasLib(root, "ssl") and hasLib(root, "crypto"): # Stop Nim dlopen'ing OpenSSL, and link the archives instead. result.add "--dynlibOverride:ssl" result.add "--dynlibOverride:crypto" result.add "--passL:" & libDir(root) / "libssl.a" result.add "--passL:" & libDir(root) / "libcrypto.a" if opensslCompat: # Removed in OpenSSL 3.0; Nim's wrapper still names it. result.add "--passC:-DSSL_get_peer_certificate=SSL_get1_peer_certificate" for lib in libs: result.add "--passL:-l" & lib proc ccFlags*(root: string, libs: openArray[string] = []): seq[string] = result = @["-I" & includeDir(root), "-L" & libDir(root), "-static"] for lib in libs: result.add "-l" & lib proc pkgConfigEnv*(root: string): seq[string] = @["PKG_CONFIG_SYSROOT_DIR=" & root, "PKG_CONFIG_LIBDIR=" & libDir(root) / "pkgconfig"] proc nimCfg*(root, cc: string, libs: openArray[string] = []): string = ## A nim.cfg fragment: cross-compiler plus every flag from `nimFlags`. result = "# Generated by muslkit — static musl build against " & root & "\n# Regenerate with: muslkit nimcfg --root " & root & "\n" if cc.len > 0: result.add "--cc:clang\n" result.add "--clang.exe:\"" & cc & "\"\n" result.add "--clang.linkerexe:\"" & cc & "\"\n" for f in nimFlags(root, libs): result.add f & "\n" const zigccTemplate* = """#!/bin/sh # Generated by muslkit: zig as a musl cross-compiler. exec zig cc -target @TARGET@ "$@" """ proc zigccScript*(target: string): string = zigccTemplate.replace("@TARGET@", target) proc writeZigCc*(path, target: string) = writeFile(path, zigccScript(target)) setFilePermissions(path, {fpUserRead, fpUserWrite, fpUserExec, fpGroupRead, fpGroupExec, fpOthersRead, fpOthersExec}) proc describe*(root: string): string = let libs = staticLibs(root) if libs.len == 0: return "no static libraries in " & root result = $libs.len & " static libraries in " & libDir(root) & ":\n" for l in libs: result.add " " & l.extractFilename & " (" & $(getFileSize(l) div 1024) & " KiB)\n"