125 lines
5.7 KiB
Text
125 lines
5.7 KiB
Text
|
|
(define-library (zilch lang go)
|
||
|
|
(import
|
||
|
|
(scheme base) (scheme write) (scheme process-context) (scheme lazy)
|
||
|
|
(chicken file) (chicken format)
|
||
|
|
(zilch magic) (zilch file) (zilch zexpr)
|
||
|
|
(zilch nix drv) (zilch nix path) (zilch nixpkgs)
|
||
|
|
(json)
|
||
|
|
(chicken base) (chicken format) (chicken foreign)
|
||
|
|
(srfi-4)
|
||
|
|
(zilch lang go core))
|
||
|
|
|
||
|
|
(export
|
||
|
|
make-go-package go-package?
|
||
|
|
go-package-name go-package-import-path
|
||
|
|
go-package-api go-package-code go-package-dependencies
|
||
|
|
|
||
|
|
go-dependency-closure
|
||
|
|
go-package-compile go-package-link)
|
||
|
|
|
||
|
|
|
||
|
|
(begin
|
||
|
|
;; A go package consists of a few separate `++(zilch magic)++` store paths.
|
||
|
|
;; The `++name++` is the package name as compiled, and `++import-path++` is a nicer
|
||
|
|
;; package name for "main" packages. The `++go-package-api++` is a store path consisting
|
||
|
|
;; of a `++.a++` containing the output of the compiler's `++__.PKGDEF++` only, which
|
||
|
|
;; contains the exported types and functions, along with a slight amount of LTO and
|
||
|
|
;; inlining metadata. the `++go-package-code++` store path contains the actual assembly
|
||
|
|
;; of the package.
|
||
|
|
(define-record-type <go-package>
|
||
|
|
(make-go-package name import-path api code dependencies)
|
||
|
|
go-package?
|
||
|
|
(name go-package-name)
|
||
|
|
(import-path go-package-import-path)
|
||
|
|
(api go-package-api)
|
||
|
|
(code go-package-code)
|
||
|
|
(dependencies go-package-dependencies))
|
||
|
|
|
||
|
|
(define-record-printer (<go-package> pkg out)
|
||
|
|
(fprintf out "#<go-package ~A api: ~S code: ~S deps: ~S>"
|
||
|
|
(if (string=? (go-package-import-path pkg) (go-package-name pkg))
|
||
|
|
(go-package-name pkg)
|
||
|
|
(string-append (go-package-name pkg) " (" (go-package-import-path pkg) ")"))
|
||
|
|
(go-package-api pkg)
|
||
|
|
(go-package-code pkg)
|
||
|
|
(map go-package-name (go-package-dependencies pkg))))
|
||
|
|
|
||
|
|
;; Recursively walk over the dependencies of a `++go-package++`, prepending to the `++vals++` list.
|
||
|
|
(define (go-dependency-closure package vals)
|
||
|
|
(unless (member package vals)
|
||
|
|
(set! vals (cons package vals))
|
||
|
|
(for-each
|
||
|
|
(lambda (pkg)
|
||
|
|
(set! vals (go-dependency-closure pkg vals)))
|
||
|
|
(go-package-dependencies package)))
|
||
|
|
vals)
|
||
|
|
|
||
|
|
;; `(go-package-compile name deps source-files)`
|
||
|
|
;; or `(go-package-compile name path deps source-files assembly-files assembly-includes embed-filenames embed-patterns)`
|
||
|
|
;; Build a Zilch-defined Go package of one store path as source code, and a list of dependencies.
|
||
|
|
(define go-package-compile
|
||
|
|
(case-lambda
|
||
|
|
((name deps source-files) (go-package-compile name name deps source-files '() '() '() '()))
|
||
|
|
((name path deps source-files assembly-files assembly-includes embed-filenames embed-patterns)
|
||
|
|
(define api-importcfg
|
||
|
|
(zfile #~,(build-importcfg #$(map (lambda (pkg) (cons (go-package-import-path pkg) (go-package-api pkg))) deps) '())))
|
||
|
|
|
||
|
|
(define api-embedcfg
|
||
|
|
(zfile #~,(build-embedcfg #$embed-patterns #$embed-filenames)))
|
||
|
|
|
||
|
|
(define symabis #f)
|
||
|
|
(unless assembly-files (set! assembly-files '()))
|
||
|
|
|
||
|
|
(define path-or-name (if (string=? name "main") name path))
|
||
|
|
|
||
|
|
(define assembly-includes-dir
|
||
|
|
(if (list? assembly-includes)
|
||
|
|
(zdir (map (lambda (pair) (cons (car pair) (zsymlink (cdr pair)))) assembly-includes))
|
||
|
|
assembly-includes))
|
||
|
|
|
||
|
|
(unless (eq? assembly-files '())
|
||
|
|
(set! symabis (go-generate-symabi path-or-name assembly-includes-dir #~,(map cdr #$assembly-files))))
|
||
|
|
|
||
|
|
(define compiled-go
|
||
|
|
(go-compile #f path-or-name api-importcfg symabis api-embedcfg source-files))
|
||
|
|
|
||
|
|
(define merged-asmhdr
|
||
|
|
(zdir "go_asm.h" (zsymlink (cdr (assoc "asmhdr" compiled-go)))))
|
||
|
|
|
||
|
|
;; ISSUE: this needs the source dir for assembly imports reasons (filter out .h files?)
|
||
|
|
(define compiled-assembly
|
||
|
|
(map
|
||
|
|
(lambda (f) (go-compile-assembly path-or-name assembly-includes-dir merged-asmhdr (list f)))
|
||
|
|
assembly-files))
|
||
|
|
|
||
|
|
; Assembly code doesn't have an API, so use the Go code's API only.
|
||
|
|
(define go-api (cdr (assoc "api" compiled-go)))
|
||
|
|
|
||
|
|
; Make a list of the "code" output from the Go with the compiled assembly files.
|
||
|
|
; NOTE: .go has to be compiled in one go; but .s is compiled one file at a time.
|
||
|
|
(define all-code (cons (cdr (assoc "code" compiled-go)) compiled-assembly))
|
||
|
|
|
||
|
|
; (printf " -> (store-path-for-ca-drv* meow meow ~S ~S meow)\n" all-code (env-for-goarch))
|
||
|
|
; Use `go tool pack` to merge the code together.
|
||
|
|
(define merged-code
|
||
|
|
(if (length assembly-files)
|
||
|
|
(cdar (store-path-for-ca-drv*
|
||
|
|
(string-append "go-" (rewrite-package-name path) "-code") "x86_64-linux"
|
||
|
|
#~(,(string-append #$go-toolchain "/bin/go") "tool" "pack" "c" ,(make-placeholder "code") . #$all-code)
|
||
|
|
(env-for-goarch)
|
||
|
|
'("code")))
|
||
|
|
(cdr (assoc "code" compiled-go))))
|
||
|
|
|
||
|
|
; (printf " -> (make-go-package ~S ~S ~S ~S ~S)\n" name path (cdr (assoc "api" compiled-go)) merged-code deps)
|
||
|
|
(make-go-package name path (cdr (assoc "api" compiled-go)) merged-code deps))))
|
||
|
|
|
||
|
|
;; Link a `++go-package++` into a binary that can be (statically) executed.
|
||
|
|
(define (go-package-link pkg)
|
||
|
|
(define code-importcfg
|
||
|
|
(zfile #~,(build-importcfg #$(map (lambda (pkg) (cons (go-package-import-path pkg) (go-package-code pkg))) (go-dependency-closure pkg '())) '())))
|
||
|
|
|
||
|
|
(cdar (store-path-for-ca-drv* (rewrite-package-name (go-package-import-path pkg)) "x86_64-linux"
|
||
|
|
#~(,(string-append #$go-toolchain "/bin/go") "tool" "link" "-buildid" ,(string-append "zilch out=" (make-placeholder "out")) "-importcfg" #$code-importcfg "-o" ,(make-placeholder "out") #$(go-package-code pkg)) (env-for-goarch) '("out"))))))
|
||
|
|
|
||
|
|
|