nandi/nimstaticpublic Fork 0
5feb05094be9eb20a8a0588b44117d22c7dc3cac
Commits
Clone
git clone https://git.rickub.com/nandi/nimstatic.git
git clone ssh://git@rickub.com/nandi/nimstatic.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

muslkit: musl static libraries from Alpine, without Alpine 5feb050 · on 5feb05094be9eb20a8a0588b44117d22c7dc3cac · nandi · 20h ago
flags.nim · 78 lines · 3.0 KBNim Blame HistoryRaw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
## 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"