262 lines
7.5 KiB
Racket
262 lines
7.5 KiB
Racket
#lang racket/base
|
|
|
|
(require racket
|
|
racket/splicing
|
|
racket/stxparam
|
|
(for-syntax racket/base
|
|
racket/stxparam
|
|
syntax/parse)
|
|
"private/commands.rkt"
|
|
"private/engine.rkt"
|
|
git-cli
|
|
package-zipper
|
|
net/sendurl
|
|
racket/string)
|
|
|
|
(provide makefile
|
|
target
|
|
deps
|
|
phony
|
|
default-target
|
|
make
|
|
current-makefile-prefix
|
|
makefile-prefixes
|
|
makefile-targets
|
|
makefile-target-exists?
|
|
makefile-target-procedure
|
|
refresh-makefile
|
|
run
|
|
raco
|
|
rm-f
|
|
rm-rf
|
|
cleanup
|
|
list-dir/files
|
|
list-files
|
|
list-dirs
|
|
$target
|
|
$deps
|
|
$<
|
|
(all-from-out git-cli)
|
|
(all-from-out package-zipper)
|
|
(all-from-out net/sendurl)
|
|
(all-from-out racket/string))
|
|
|
|
(define loaded-makefile #f)
|
|
|
|
(define (remember-makefile! path)
|
|
(when path
|
|
(set! loaded-makefile path))
|
|
(void))
|
|
|
|
(define (refresh-makefile)
|
|
(unless loaded-makefile
|
|
(error 'refresh-makefile "no makefile definition has been evaluated"))
|
|
|
|
(define source loaded-makefile)
|
|
(define directory (or (path-only source) (current-directory)))
|
|
(define refresh-source
|
|
(make-temporary-file "racket-makefile-refresh~a.rkt" #f directory))
|
|
|
|
(copy-file source refresh-source #t)
|
|
(reset-makefiles!)
|
|
|
|
(dynamic-wind
|
|
void
|
|
(λ ()
|
|
(dynamic-require refresh-source #f))
|
|
(λ ()
|
|
(set! loaded-makefile source)
|
|
(delete-file refresh-source)))
|
|
(void))
|
|
|
|
(define (make . names)
|
|
(apply make-targets! names))
|
|
|
|
(define-syntax $target
|
|
(syntax-id-rules ()
|
|
[$target
|
|
(or (current-target)
|
|
(error '$target "$target is only available while a target procedure is running"))]))
|
|
|
|
(define-syntax $deps
|
|
(syntax-id-rules ()
|
|
[$deps
|
|
(or (current-dependencies)
|
|
(error '$deps "$deps is only available while a target procedure is running"))]))
|
|
|
|
(define-syntax $<
|
|
(syntax-id-rules ()
|
|
[$<
|
|
(or (current-first-dependency)
|
|
(error '$< "$< is only available while a target procedure with dependencies is running"))]))
|
|
|
|
(define-syntax-parameter makefile-prefix
|
|
(λ (stx)
|
|
(raise-syntax-error 'racket-makefile "only valid inside makefile" stx)))
|
|
|
|
(begin-for-syntax
|
|
(define (makefile-prefix-expression stx)
|
|
(define transformer (syntax-parameter-value #'makefile-prefix))
|
|
(transformer stx))
|
|
|
|
(define (makefile-prefix-datum stx)
|
|
(define expression (makefile-prefix-expression stx))
|
|
(syntax-parse expression
|
|
[((~datum quote) value)
|
|
(syntax-e #'value)]
|
|
[_
|
|
(raise-syntax-error
|
|
'makefile
|
|
"makefile prefix must be a quoted symbol or string"
|
|
stx)]))
|
|
|
|
(define (static-name-datum stx)
|
|
(syntax-parse stx
|
|
[((~datum quote) value)
|
|
(define datum (syntax-e #'value))
|
|
(unless (or (symbol? datum) (string? datum) (path? datum))
|
|
(raise-syntax-error
|
|
'target
|
|
"quoted target name must be a symbol, string, or path"
|
|
stx))
|
|
datum]
|
|
[_ #f]))
|
|
|
|
(define (procedure-identifier context prefix target)
|
|
(define name
|
|
(string->symbol
|
|
(format "makefile-target-~a-~a" prefix target)))
|
|
(datum->syntax context name context context))
|
|
|
|
(define (dynamic-target-expression prefix-expression name dependencies body)
|
|
#`(let* ([target-name #,name]
|
|
[target-procedure
|
|
(procedure-rename
|
|
(λ ()
|
|
(call-target-procedure
|
|
#,prefix-expression
|
|
target-name
|
|
(λ ()
|
|
#,@body
|
|
(void))))
|
|
(string->symbol
|
|
(format "makefile-target-~a-~a"
|
|
#,prefix-expression
|
|
target-name)))])
|
|
(register-target!
|
|
#,prefix-expression
|
|
target-name
|
|
(list #,@dependencies)
|
|
target-procedure)
|
|
(void))))
|
|
|
|
(define-syntax (target stx)
|
|
(syntax-parse stx
|
|
#:datum-literals (deps)
|
|
[(_ name (deps dependency ...) body ...)
|
|
(define prefix-expression (makefile-prefix-expression stx))
|
|
(define prefix-datum (makefile-prefix-datum stx))
|
|
(define static-name (static-name-datum #'name))
|
|
(define dependencies (syntax->list #'(dependency ...)))
|
|
(define body-list (syntax->list #'(body ...)))
|
|
|
|
(if (and static-name
|
|
(not (eq? (syntax-local-context) 'expression)))
|
|
(let ([proc-id
|
|
(procedure-identifier stx prefix-datum static-name)])
|
|
#`(begin
|
|
(define (#,proc-id)
|
|
(call-target-procedure
|
|
#,prefix-expression
|
|
name
|
|
(λ ()
|
|
body ...
|
|
(void))))
|
|
(register-target!
|
|
#,prefix-expression
|
|
name
|
|
(list dependency ...)
|
|
#,proc-id)))
|
|
(dynamic-target-expression
|
|
prefix-expression
|
|
#'name
|
|
dependencies
|
|
body-list))]
|
|
|
|
[(_ name body ...)
|
|
(define prefix-expression (makefile-prefix-expression stx))
|
|
(define prefix-datum (makefile-prefix-datum stx))
|
|
(define static-name (static-name-datum #'name))
|
|
(define body-list (syntax->list #'(body ...)))
|
|
|
|
(if (and static-name
|
|
(not (eq? (syntax-local-context) 'expression)))
|
|
(let ([proc-id
|
|
(procedure-identifier stx prefix-datum static-name)])
|
|
#`(begin
|
|
(define (#,proc-id)
|
|
(call-target-procedure
|
|
#,prefix-expression
|
|
name
|
|
(λ ()
|
|
body ...
|
|
(void))))
|
|
(register-target!
|
|
#,prefix-expression
|
|
name
|
|
'()
|
|
#,proc-id)))
|
|
(dynamic-target-expression
|
|
prefix-expression
|
|
#'name
|
|
'()
|
|
body-list))]))
|
|
|
|
(define-syntax (deps stx)
|
|
(raise-syntax-error 'deps "only valid as the dependency clause of target" stx))
|
|
|
|
(define-syntax (phony stx)
|
|
(syntax-parse stx
|
|
[(_ name ...)
|
|
(define prefix-expression (makefile-prefix-expression stx))
|
|
#`(mark-phony! #,prefix-expression name ...)]))
|
|
|
|
(define-syntax (default-target stx)
|
|
(syntax-parse stx
|
|
[(_ name)
|
|
(define prefix-expression (makefile-prefix-expression stx))
|
|
#`(set-default-target! #,prefix-expression name)]))
|
|
|
|
(define-syntax (makefile stx)
|
|
(syntax-parse stx
|
|
[(_ ((~datum quote) prefix) form ...)
|
|
(define prefix-datum (syntax-e #'prefix))
|
|
(unless (or (symbol? prefix-datum) (string? prefix-datum))
|
|
(raise-syntax-error
|
|
'makefile
|
|
"prefix must be a quoted symbol or string"
|
|
#'prefix))
|
|
|
|
(define prefix-expression #`(quote #,prefix-datum))
|
|
(define source (syntax-source stx))
|
|
(define remember-source
|
|
(if (path? source)
|
|
#`(remember-makefile! (string->path #,(path->string source)))
|
|
#'(void)))
|
|
|
|
(with-syntax ([prefix-expression prefix-expression])
|
|
#`(begin
|
|
#,remember-source
|
|
(begin-makefile! prefix-expression)
|
|
(splicing-syntax-parameterize
|
|
([makefile-prefix (λ (stx) #'prefix-expression)])
|
|
form ...)
|
|
(current-makefile-prefix prefix-expression)
|
|
(void)))]
|
|
|
|
[(_ prefix form ...)
|
|
(raise-syntax-error
|
|
'makefile
|
|
"prefix must be explicit, for example (makefile 'stuff ...)"
|
|
#'prefix)]))
|