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"
|