123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- (define-module (draft parameters)
- #:use-module (srfi srfi-1)
- #:use-module (ice-9 match))
- ;; IMPORTANT:
- ;; functions will be renamed to more sensible names
- ;; s/p\//parameters-/g
- (define %parameters ; example parameters of a package "zoo"
- '(parameters
- (required ant beaver) ; these are REQUIRED to build the package
- (required-off zebra) ; these are REQUIRED TO BE OFF, useful for forcing errors
- (optional (cat dog) elephant) ; these are optional, cat and dog are default
- (one-of cat flamingo gorilla) ; only one of these is allowed, cat is default
- (one-of none hippo impala) ; only one of these is allowed, none are default
- (special (on flamingo) ; flamingo, if ON, has a special transform
- (off cat hippo)))) ; cat and hippo have one when OFF
- ;; special transforms here refer to parameters that need a special package transform to be run
- ;; for example flamingo could have a generic transform that just adds a dependency feathers,
- ;; but in this particular instance it also needs to add a configuration-flag pink
- (define (p/default p-list)
- (delete-duplicates
- (apply
- append
- (map
- (lambda (ls)
- (case (car ls)
- ((required)
- (cdr ls))
- ((optional)
- (if (list? (cadr ls))
- (cadr ls)
- '()))
- ((one-of)
- (if (not (eq? (cadr ls) 'none))
- (list (cadr ls))
- '()))
- ((special required-off)
- '())
- (else (error "Invalid parameter specification: " (car ls)))))
- (cdr p-list)))))
- (define (p/default-off p-list)
- (delete-duplicates
- (apply
- append
- (map
- (lambda (ls)
- (case (car ls)
- ((required-off)
- (cdr ls))
- ((optional)
- (if (list? (cadr ls))
- (cddr ls)
- (cdr ls)))
- ((one-of)
- (cddr ls))
- ((special required)
- '())
- (else (error "Invalid parameter specification: " (car ls)))))
- (cdr p-list)))))
- (define (p/total p-list)
- (lset-union
- eqv?
- (p/default p-list)
- (p/default-off p-list)))
- (p/default %parameters)
- (p/default-off %parameters)
- (p/total %parameters)
- ;; We need custom boolean operators as they cannot short-circuit
- (define (p-and . args)
- (= 0
- (count (lambda (x) (eqv? #f x))
- args)))
- (define (p-none . args)
- (= 0
- (count (lambda (x) (eqv? #t x))
- args)))
- (define (p-xor . args)
- (= 1
- (count (lambda (x) (eqv? #t x))
- args)))
- (p-and #t #t)
- (define (p/resolve p-spec parameter-list)
- (apply
- p-and
- (let ((p-list (cons 'none parameter-list)))
- (map
- (lambda (ls)
- (apply
- (case (car ls)
- ((required) p-and)
- ((required-off) p-none)
- ((optional) (lambda _ #t))
- ((one-of) p-xor)
- ((special) (lambda _ #t))
- (else (error "Invalid parameter specification: " (car ls))))
- (map
- (lambda (sym)
- (not (not (member sym p-list))))
- (cdr ls))))
- (cdr p-spec)))))
- (p/resolve %parameters (p/default %parameters)) ; sanity check
- ;; Code for getting the OS' parameter specification
- ;; defined "parameter" in the OS record
- ;; use method to get it
- ;; write similar parser for it
- (define %default-os-parameters
- '((on ant cat mouse)
- (off cow horse elephant)))
- (define (p/read-os-parameters) ; dummy method
- %default-os-parameters)
- ;; OS parameters method needs to create (on) and (off)
- ;; regardless of the existence of on/off parameters
- ;; Expected format for OS parameters:
- ;; '((on x y) (off z) (on d e f a) (off u l t))
- ;; run two filters to collect all on/off respectively
- (define (p/os-parameters)
- (let ((user-p (p/read-os-parameters)))
- (list
- (cons 'on
- (apply append
- (map (lambda (ls) (cdr ls))
- (filter (lambda (ls)
- (eqv? (car ls) 'on))
- user-p))))
- (cons 'off
- (apply append
- (map (lambda (ls) (cdr ls))
- (filter (lambda (ls)
- (eqv? (car ls) 'off))
- user-p)))))))
- (define (p/read-os-parameters)
- '((on ant cat) (off cow) (on mouse) (off horse elephant)))
- (p/os-parameters) ; works!
- (define (p/read-os-parameters)
- '((on ant cat mouse))) ; only on parameters
- (p/os-parameters) ; still generates (off)
- ;; should we actually override %base-parameters
- ;; if a in os' (on) is in user's (off)?
- (define (p/os-parameters-overriding)
- (let ((user-p (p/read-os-parameters)))
- (define (recurse-on p off-lst)
- (filter (lambda (x) (not (member x off-lst)))
- p))
- (define (recurse-off p on-lst)
- (filter (lambda (x) (not (member x on-lst)))
- p))
- (define (recurse-over-p p on-lst off-lst)
- (if (null? p)
- (list (cons 'on on-lst)
- (cons 'off off-lst))
- (if (eqv? 'on (caar p))
- (recurse-over-p
- (cdr p)
- (append (recurse-on (cdar p) off-lst)
- on-lst)
- off-lst)
- (recurse-over-p
- (cdr p)
- on-lst
- (append (recurse-on (cdar p) on-lst)
- off-lst)))))
- (recurse-over-p user-p '() '())))
- (define (p/read-os-parameters)
- ;; horse is off in %base-parameters but on in user parameters
- '((on ant cat horse) (off cow) (on mouse) (off horse elephant)))
- (p/os-parameters-overriding) ; works!
- (define (p/get-parameters _) ; dummy method
- %parameters)
- ;; parameters = default + (common os-on available) - (common os-off available)
- (define (p/package-parameters package)
- (let* ((os-on (cdar (p/os-parameters)))
- (os-off (cdadr (p/os-parameters)))
- (p-pkg (p/get-parameters package))
- (all (p/total p-pkg)))
- (lset-difference
- eqv?
- (lset-union
- eqv?
- (p/default p-pkg) ; default parameters
- (lset-intersection
- eqv?
- all ; all available parameters
- os-on)) ; os' on parameters
- (lset-intersection
- eqv?
- all
- os-off)))) ; os' off parameters
- (p/package-parameters %parameters)
- ;; Now, we want to check if the OS configuration resolves
- (define (p/applicable-parameters pkg)
- (let ((user-p (p/package-parameters pkg))
- (pkg-p (p/get-parameters pkg)))
- (if (p/resolve pkg-p user-p) ; if user-p resolve
- user-p ; return user-p
- (and ; XXX: print package name
- (display "User parameters do not resolve. Using default parameters for package")
- (p/default pkg-p))))) ; uses default parameters
- (p/applicable-parameters %parameters)
- (define (p/applicable-parameters-off package)
- (lset-difference
- eqv?
- (p/total package)
- (p/applicable-parameters package)))
- (p/applicable-parameters-off %parameters)
- ;; Functions for checking what parameters require special transforms
- (define (p/special-transforms pkg ps/e ps/d)
- (let* ((p-spec (p/get-parameters pkg))
- (special (last (cdr p-spec)))) ; "special" must be the last list
- (if (eqv? (car special) 'special)
- (filter (lambda (ls) (> (length ls) 1)) ; remove "(on)" and "(off)"
- (map (lambda (ls)
- (if (eqv? (car ls) 'on)
- (cons 'on
- (lset-intersection eqv?
- ps/e
- (cdr ls)))
- (cons 'off
- (lset-intersection eqv?
- ps/d
- (cdr ls)))))
- (cdr special)))
- '())))
- (p/special-transforms %parameters
- (p/applicable-parameters %parameters)
- (p/applicable-parameters-off %parameters))
- ;; Now we will have to modify the package record itself to hold 'special transforms'
- ;; These are transforms that do not match the standard parameter transforms for the build system
- ;; Ex. disabled `tests` is usually done by the without-tests transform
- ;; But maybe a package needs an extra transform to be done for it
- ;; Might also need to look into declaring parameters as _necessarily_ recursive for #2 and #3
- ;; We also need to modify Ludo's parameter record type to accept these instead
- ;; And the new package record needs to take the parameters as a list
- ;; After simple parameters are done, CFLAGS/CXXFLAGS may be implemented as parameters
- ;; For these, letting package-specific rules override OS rules makes more sense
- ;; As parameter syms can be anything, having ex. -ffast-math itself as a sym works
- ;; Implementing these will be otherwise very easy as with-configure-flag can be used
- ;; WISHLIST: Add sublist for CFLAGS (gcc flags)
- ;; 6/4: s/enabled/on/g s/disabled/off/g
- ;; on/off are more succint and nicer
- ;; added 'required-off'; could be useful for packages that cannot be built on systems
- ;; with a particular parameter enabled (ex. x86-only package on ARM system)
- ;; created os-parameters and os-parameters-overriding!
- ;; For finding complexity, there are two possible ways to do it
- ;; This problem is actually what we call a #SAT problem, and it is known to be #P-hard!
- ;; But approximating the answer to them is not as computationally expensive.
- ;; Since the number of parameters per package will not exceed a small number
- ;; it would make more sense to write a simple backtracking-based #SAT solver for the time-being
- ;; and then if required, write a more complicated approximating algorithm.
- ;; Naive approach: recurse over all states of every parameter and make a list of valid combinations
|