parameter-parser.scm 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. (define-module (draft parameters)
  2. #:use-module (srfi srfi-1)
  3. #:use-module (ice-9 match))
  4. ;; IMPORTANT:
  5. ;; functions will be renamed to more sensible names
  6. ;; s/p\//parameters-/g
  7. (define %parameters ; example parameters of a package "zoo"
  8. '(parameters
  9. (required ant beaver) ; these are REQUIRED to build the package
  10. (required-off zebra) ; these are REQUIRED TO BE OFF, useful for forcing errors
  11. (optional (cat dog) elephant) ; these are optional, cat and dog are default
  12. (one-of cat flamingo gorilla) ; only one of these is allowed, cat is default
  13. (one-of none hippo impala) ; only one of these is allowed, none are default
  14. (special (on flamingo) ; flamingo, if ON, has a special transform
  15. (off cat hippo)))) ; cat and hippo have one when OFF
  16. ;; special transforms here refer to parameters that need a special package transform to be run
  17. ;; for example flamingo could have a generic transform that just adds a dependency feathers,
  18. ;; but in this particular instance it also needs to add a configuration-flag pink
  19. (define (p/default p-list)
  20. (delete-duplicates
  21. (apply
  22. append
  23. (map
  24. (lambda (ls)
  25. (case (car ls)
  26. ((required)
  27. (cdr ls))
  28. ((optional)
  29. (if (list? (cadr ls))
  30. (cadr ls)
  31. '()))
  32. ((one-of)
  33. (if (not (eq? (cadr ls) 'none))
  34. (list (cadr ls))
  35. '()))
  36. ((special required-off)
  37. '())
  38. (else (error "Invalid parameter specification: " (car ls)))))
  39. (cdr p-list)))))
  40. (define (p/default-off p-list)
  41. (delete-duplicates
  42. (apply
  43. append
  44. (map
  45. (lambda (ls)
  46. (case (car ls)
  47. ((required-off)
  48. (cdr ls))
  49. ((optional)
  50. (if (list? (cadr ls))
  51. (cddr ls)
  52. (cdr ls)))
  53. ((one-of)
  54. (cddr ls))
  55. ((special required)
  56. '())
  57. (else (error "Invalid parameter specification: " (car ls)))))
  58. (cdr p-list)))))
  59. (define (p/total p-list)
  60. (lset-union
  61. eqv?
  62. (p/default p-list)
  63. (p/default-off p-list)))
  64. (p/default %parameters)
  65. (p/default-off %parameters)
  66. (p/total %parameters)
  67. ;; We need custom boolean operators as they cannot short-circuit
  68. (define (p-and . args)
  69. (= 0
  70. (count (lambda (x) (eqv? #f x))
  71. args)))
  72. (define (p-none . args)
  73. (= 0
  74. (count (lambda (x) (eqv? #t x))
  75. args)))
  76. (define (p-xor . args)
  77. (= 1
  78. (count (lambda (x) (eqv? #t x))
  79. args)))
  80. (p-and #t #t)
  81. (define (p/resolve p-spec parameter-list)
  82. (apply
  83. p-and
  84. (let ((p-list (cons 'none parameter-list)))
  85. (map
  86. (lambda (ls)
  87. (apply
  88. (case (car ls)
  89. ((required) p-and)
  90. ((required-off) p-none)
  91. ((optional) (lambda _ #t))
  92. ((one-of) p-xor)
  93. ((special) (lambda _ #t))
  94. (else (error "Invalid parameter specification: " (car ls))))
  95. (map
  96. (lambda (sym)
  97. (not (not (member sym p-list))))
  98. (cdr ls))))
  99. (cdr p-spec)))))
  100. (p/resolve %parameters (p/default %parameters)) ; sanity check
  101. ;; Code for getting the OS' parameter specification
  102. ;; defined "parameter" in the OS record
  103. ;; use method to get it
  104. ;; write similar parser for it
  105. (define %default-os-parameters
  106. '((on ant cat mouse)
  107. (off cow horse elephant)))
  108. (define (p/read-os-parameters) ; dummy method
  109. %default-os-parameters)
  110. ;; OS parameters method needs to create (on) and (off)
  111. ;; regardless of the existence of on/off parameters
  112. ;; Expected format for OS parameters:
  113. ;; '((on x y) (off z) (on d e f a) (off u l t))
  114. ;; run two filters to collect all on/off respectively
  115. (define (p/os-parameters)
  116. (let ((user-p (p/read-os-parameters)))
  117. (list
  118. (cons 'on
  119. (apply append
  120. (map (lambda (ls) (cdr ls))
  121. (filter (lambda (ls)
  122. (eqv? (car ls) 'on))
  123. user-p))))
  124. (cons 'off
  125. (apply append
  126. (map (lambda (ls) (cdr ls))
  127. (filter (lambda (ls)
  128. (eqv? (car ls) 'off))
  129. user-p)))))))
  130. (define (p/read-os-parameters)
  131. '((on ant cat) (off cow) (on mouse) (off horse elephant)))
  132. (p/os-parameters) ; works!
  133. (define (p/read-os-parameters)
  134. '((on ant cat mouse))) ; only on parameters
  135. (p/os-parameters) ; still generates (off)
  136. ;; should we actually override %base-parameters
  137. ;; if a in os' (on) is in user's (off)?
  138. (define (p/os-parameters-overriding)
  139. (let ((user-p (p/read-os-parameters)))
  140. (define (recurse-on p off-lst)
  141. (filter (lambda (x) (not (member x off-lst)))
  142. p))
  143. (define (recurse-off p on-lst)
  144. (filter (lambda (x) (not (member x on-lst)))
  145. p))
  146. (define (recurse-over-p p on-lst off-lst)
  147. (if (null? p)
  148. (list (cons 'on on-lst)
  149. (cons 'off off-lst))
  150. (if (eqv? 'on (caar p))
  151. (recurse-over-p
  152. (cdr p)
  153. (append (recurse-on (cdar p) off-lst)
  154. on-lst)
  155. off-lst)
  156. (recurse-over-p
  157. (cdr p)
  158. on-lst
  159. (append (recurse-on (cdar p) on-lst)
  160. off-lst)))))
  161. (recurse-over-p user-p '() '())))
  162. (define (p/read-os-parameters)
  163. ;; horse is off in %base-parameters but on in user parameters
  164. '((on ant cat horse) (off cow) (on mouse) (off horse elephant)))
  165. (p/os-parameters-overriding) ; works!
  166. (define (p/get-parameters _) ; dummy method
  167. %parameters)
  168. ;; parameters = default + (common os-on available) - (common os-off available)
  169. (define (p/package-parameters package)
  170. (let* ((os-on (cdar (p/os-parameters)))
  171. (os-off (cdadr (p/os-parameters)))
  172. (p-pkg (p/get-parameters package))
  173. (all (p/total p-pkg)))
  174. (lset-difference
  175. eqv?
  176. (lset-union
  177. eqv?
  178. (p/default p-pkg) ; default parameters
  179. (lset-intersection
  180. eqv?
  181. all ; all available parameters
  182. os-on)) ; os' on parameters
  183. (lset-intersection
  184. eqv?
  185. all
  186. os-off)))) ; os' off parameters
  187. (p/package-parameters %parameters)
  188. ;; Now, we want to check if the OS configuration resolves
  189. (define (p/applicable-parameters pkg)
  190. (let ((user-p (p/package-parameters pkg))
  191. (pkg-p (p/get-parameters pkg)))
  192. (if (p/resolve pkg-p user-p) ; if user-p resolve
  193. user-p ; return user-p
  194. (and ; XXX: print package name
  195. (display "User parameters do not resolve. Using default parameters for package")
  196. (p/default pkg-p))))) ; uses default parameters
  197. (p/applicable-parameters %parameters)
  198. (define (p/applicable-parameters-off package)
  199. (lset-difference
  200. eqv?
  201. (p/total package)
  202. (p/applicable-parameters package)))
  203. (p/applicable-parameters-off %parameters)
  204. ;; Functions for checking what parameters require special transforms
  205. (define (p/special-transforms pkg ps/e ps/d)
  206. (let* ((p-spec (p/get-parameters pkg))
  207. (special (last (cdr p-spec)))) ; "special" must be the last list
  208. (if (eqv? (car special) 'special)
  209. (filter (lambda (ls) (> (length ls) 1)) ; remove "(on)" and "(off)"
  210. (map (lambda (ls)
  211. (if (eqv? (car ls) 'on)
  212. (cons 'on
  213. (lset-intersection eqv?
  214. ps/e
  215. (cdr ls)))
  216. (cons 'off
  217. (lset-intersection eqv?
  218. ps/d
  219. (cdr ls)))))
  220. (cdr special)))
  221. '())))
  222. (p/special-transforms %parameters
  223. (p/applicable-parameters %parameters)
  224. (p/applicable-parameters-off %parameters))
  225. ;; Now we will have to modify the package record itself to hold 'special transforms'
  226. ;; These are transforms that do not match the standard parameter transforms for the build system
  227. ;; Ex. disabled `tests` is usually done by the without-tests transform
  228. ;; But maybe a package needs an extra transform to be done for it
  229. ;; Might also need to look into declaring parameters as _necessarily_ recursive for #2 and #3
  230. ;; We also need to modify Ludo's parameter record type to accept these instead
  231. ;; And the new package record needs to take the parameters as a list
  232. ;; After simple parameters are done, CFLAGS/CXXFLAGS may be implemented as parameters
  233. ;; For these, letting package-specific rules override OS rules makes more sense
  234. ;; As parameter syms can be anything, having ex. -ffast-math itself as a sym works
  235. ;; Implementing these will be otherwise very easy as with-configure-flag can be used
  236. ;; WISHLIST: Add sublist for CFLAGS (gcc flags)
  237. ;; 6/4: s/enabled/on/g s/disabled/off/g
  238. ;; on/off are more succint and nicer
  239. ;; added 'required-off'; could be useful for packages that cannot be built on systems
  240. ;; with a particular parameter enabled (ex. x86-only package on ARM system)
  241. ;; created os-parameters and os-parameters-overriding!
  242. ;; For finding complexity, there are two possible ways to do it
  243. ;; This problem is actually what we call a #SAT problem, and it is known to be #P-hard!
  244. ;; But approximating the answer to them is not as computationally expensive.
  245. ;; Since the number of parameters per package will not exceed a small number
  246. ;; it would make more sense to write a simple backtracking-based #SAT solver for the time-being
  247. ;; and then if required, write a more complicated approximating algorithm.
  248. ;; Naive approach: recurse over all states of every parameter and make a list of valid combinations