mescc.scm 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. ;;; GNU Mes --- Maxwell Equations of Software
  2. ;;; Copyright © 2016,2017,2018,2019,2020 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
  3. ;;;
  4. ;;; This file is part of GNU Mes.
  5. ;;;
  6. ;;; GNU Mes is free software; you can redistribute it and/or modify it
  7. ;;; under the terms of the GNU General Public License as published by
  8. ;;; the Free Software Foundation; either version 3 of the License, or (at
  9. ;;; your option) any later version.
  10. ;;;
  11. ;;; GNU Mes is distributed in the hope that it will be useful, but
  12. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. ;;; GNU General Public License for more details.
  15. ;;;
  16. ;;; You should have received a copy of the GNU General Public License
  17. ;;; along with GNU Mes. If not, see <http://www.gnu.org/licenses/>.
  18. (define-module (mescc mescc)
  19. #:use-module (srfi srfi-1)
  20. #:use-module (srfi srfi-26)
  21. #:use-module (ice-9 pretty-print)
  22. #:use-module (ice-9 getopt-long)
  23. #:use-module (mes mes-0)
  24. #:use-module (mes misc)
  25. #:use-module (mescc info)
  26. #:use-module (mescc armv4 info)
  27. #:use-module (mescc i386 info)
  28. #:use-module (mescc x86_64 info)
  29. #:use-module (mescc preprocess)
  30. #:use-module (mescc compile)
  31. #:use-module (mescc M1)
  32. #:export (count-opt
  33. mescc:preprocess
  34. mescc:get-host
  35. mescc:compile
  36. mescc:assemble
  37. mescc:link
  38. multi-opt))
  39. (define GUILE-with-output-to-file with-output-to-file)
  40. (define (with-output-to-file file-name thunk)
  41. (if (equal? file-name "-") (thunk)
  42. (GUILE-with-output-to-file file-name thunk)))
  43. (define (mescc:preprocess options)
  44. (let* ((pretty-print/write (string->symbol (option-ref options 'write (if guile? "pretty-print" "write"))))
  45. (pretty-print/write (if (eq? pretty-print/write 'pretty-print) pretty-print write))
  46. (files (option-ref options '() '("a.c")))
  47. (input-file-name (car files))
  48. (input-base (basename input-file-name))
  49. (ast-file-name (cond ((and (option-ref options 'preprocess #f)
  50. (option-ref options 'output #f)))
  51. (else (replace-suffix input-base ".E"))))
  52. (dir (dirname input-file-name))
  53. (defines (reverse (filter-map (multi-opt 'define) options)))
  54. (includes (reverse (filter-map (multi-opt 'include) options)))
  55. (includes (cons (option-ref options 'includedir #f) includes))
  56. (includes (cons dir includes))
  57. (prefix (option-ref options 'prefix ""))
  58. (machine (option-ref options 'machine "32"))
  59. (arch (arch-get options))
  60. (defines (append (arch-get-defines options) defines))
  61. (verbose? (count-opt options 'verbose)))
  62. (with-output-to-file ast-file-name
  63. (lambda _ (for-each (cut c->ast prefix defines includes arch pretty-print/write verbose? <>) files)))))
  64. (define (c->ast prefix defines includes arch write verbose? file-name)
  65. (with-input-from-file file-name
  66. (cut write (c99-input->ast #:prefix prefix #:defines defines #:includes includes #:arch arch #:verbose? verbose?))))
  67. (define (mescc:compile options)
  68. (let* ((files (option-ref options '() '("a.c")))
  69. (input-file-name (car files))
  70. (input-base (basename input-file-name))
  71. (M1-file-name (cond ((and (option-ref options 'compile #f)
  72. (option-ref options 'output #f)))
  73. ((string-suffix? ".S" input-file-name) input-file-name)
  74. (else (replace-suffix input-base ".s"))))
  75. (infos (map (cut file->info options <>) files))
  76. (verbose? (count-opt options 'verbose))
  77. (numbered-arch? (option-ref options 'numbered-arch? #f))
  78. (align (filter-map (multi-opt 'align) options))
  79. (align (if (null? align) '(functions) (map string->symbol align)))
  80. (align (if (not numbered-arch?) align
  81. ;; function alignment not supported by MesCC-Tools 0.5.2
  82. (filter (negate (cut eq? <> 'functions)) align))))
  83. (when verbose?
  84. (format (current-error-port) "dumping: ~a\n" M1-file-name))
  85. (with-output-to-file M1-file-name
  86. (cut infos->M1 M1-file-name infos #:align align #:verbose? verbose?))
  87. M1-file-name))
  88. (define (file->info options file-name)
  89. (cond ((.c? file-name) (c->info options file-name))
  90. ((.E? file-name) (E->info options file-name))))
  91. (define (c->info options file-name)
  92. (let* ((dir (dirname file-name))
  93. (defines (reverse (filter-map (multi-opt 'define) options)))
  94. (includes (reverse (filter-map (multi-opt 'include) options)))
  95. (includes (cons (option-ref options 'includedir #f) includes))
  96. (includes (cons dir includes))
  97. (prefix (option-ref options 'prefix ""))
  98. (defines (append (arch-get-defines options) defines))
  99. (arch (arch-get options))
  100. (verbose? (count-opt options 'verbose)))
  101. (with-input-from-file file-name
  102. (cut c99-input->info (arch-get-info options) #:prefix prefix #:defines defines #:includes includes #:arch arch #:verbose? verbose?))))
  103. (define (E->info options file-name)
  104. (let ((ast (with-input-from-file file-name read))
  105. (verbose? (count-opt options 'verbose)))
  106. (c99-ast->info (arch-get-info options) ast #:verbose? verbose?)))
  107. (define (mescc:assemble options)
  108. (let* ((files (option-ref options '() '("a.c")))
  109. (input-file-name (car files))
  110. (input-base (basename input-file-name))
  111. (hex2-file-name (cond ((and (option-ref options 'assemble #f)
  112. (option-ref options 'output #f)))
  113. (else (replace-suffix input-base ".o"))))
  114. (s-files (filter .s? files))
  115. (hex2-files M1->hex2 ) ;; FIXME
  116. (source-files (filter (disjoin .c? .E?) files))
  117. (infos (map (cut file->info options <>) source-files)))
  118. (if (and (pair? s-files) (pair? infos))
  119. (error "mixing source and object not supported:" source-files s-files))
  120. (when (pair? s-files)
  121. (M1->hex2 options s-files))
  122. (when (pair? infos)
  123. (infos->hex2 options hex2-file-name infos))
  124. hex2-file-name))
  125. (define (mescc:link options)
  126. (let* ((files (option-ref options '() '("a.c")))
  127. (source-files (filter (disjoin .c? .E?) files))
  128. (input-file-name (car files))
  129. (hex2-file-name (if (or (string-suffix? ".hex2" input-file-name)
  130. (string-suffix? ".o" input-file-name)) input-file-name
  131. (replace-suffix input-file-name ".o")))
  132. (infos (map (cut file->info options <>) source-files))
  133. (s-files (filter .s? files))
  134. (hex2-files (filter .o? files))
  135. (hex2-files (if (null? s-files) hex2-files
  136. (append hex2-files (list (M1->hex2 options s-files)))))
  137. (hex2-files (if (null? infos) hex2-files
  138. (append hex2-files
  139. (list (infos->hex2 options hex2-file-name infos)))))
  140. (default-libraries (if (or (option-ref options 'nodefaultlibs #f)
  141. (option-ref options 'nostdlib #f))
  142. '()
  143. '("mescc" "c")))
  144. (libraries (filter-map (multi-opt 'library) options))
  145. (libraries (delete-duplicates (append libraries default-libraries)))
  146. (hex2-libraries (map (cut find-library options ".a" <>) libraries))
  147. (hex2-files (append hex2-files hex2-libraries))
  148. (s-files (append s-files (map (cut find-library options ".s" <>) libraries)))
  149. (debug-info? (option-ref options 'debug-info #f))
  150. (s-files (if (string-suffix? ".S" input-file-name) s-files
  151. (cons (replace-suffix input-file-name ".s") s-files)))
  152. (elf-footer (and debug-info?
  153. (or (M1->blood-elf options s-files)
  154. (exit 1)))))
  155. (or (hex2->elf options hex2-files #:elf-footer elf-footer)
  156. (exit 1))))
  157. (define (infos->hex2 options hex2-file-name infos)
  158. (let* ((input-file-name (car (option-ref options '() '("a.c"))))
  159. (M1-file-name (replace-suffix hex2-file-name ".s"))
  160. (options (acons 'compile #t options)) ; ugh
  161. (options (acons 'output hex2-file-name options))
  162. (verbose? (count-opt options 'verbose))
  163. (numbered-arch? (option-ref options 'numbered-arch? #f))
  164. (align (filter-map (multi-opt 'align) options))
  165. (align (if (null? align) '(functions) (map string->symbol align)))
  166. (align (if (not numbered-arch?) align
  167. ;; function alignment not supported by MesCC-Tools 0.5.2
  168. (filter (negate (cut eq? <> 'functions)) align))))
  169. (when verbose?
  170. (format (current-error-port) "dumping: ~a\n" M1-file-name))
  171. (with-output-to-file M1-file-name
  172. (cut infos->M1 M1-file-name infos #:align align))
  173. (or (M1->hex2 options (list M1-file-name))
  174. (exit 1))))
  175. (define (M1->hex2 options M1-files)
  176. (let* ((input-file-name (car (option-ref options '() '("a.c"))))
  177. (input-base (basename input-file-name))
  178. (M1-file-name (car M1-files))
  179. (hex2-file-name (cond ((and (option-ref options 'assemble #f)
  180. (option-ref options 'output #f)))
  181. ((option-ref options 'assemble #f)
  182. (replace-suffix input-base ".o"))
  183. (else (replace-suffix M1-file-name ".o"))))
  184. (verbose? (count-opt options 'verbose))
  185. (M1 (or (getenv "M1") "M1"))
  186. (command `(,M1
  187. "--little-endian"
  188. ,@(arch-get-architecture options)
  189. "-f" ,(arch-find options (arch-get-m1-macros options))
  190. ,@(append-map (cut list "-f" <>) M1-files)
  191. "-o" ,hex2-file-name)))
  192. (when (and verbose? (> verbose? 1))
  193. (format (current-error-port) "~a\n" (string-join command)))
  194. (and (zero? (apply assert-system* command))
  195. hex2-file-name)))
  196. (define* (hex2->elf options hex2-files #:key elf-footer)
  197. (let* ((input-file-name (car (option-ref options '() '("a.c"))))
  198. (elf-file-name (cond ((option-ref options 'output #f))
  199. (else "a.out")))
  200. (verbose? (count-opt options 'verbose))
  201. (hex2 (or (getenv "HEX2") "hex2"))
  202. (base-address (option-ref options 'base-address "0x1000000"))
  203. (machine (arch-get-machine options))
  204. (elf-footer
  205. (or elf-footer
  206. (kernel-find
  207. options
  208. (string-append "elf" machine "-footer-single-main.hex2"))))
  209. (start-files (if (or (option-ref options 'nostartfiles #f)
  210. (option-ref options 'nostdlib #f)) '()
  211. `("-f" ,(arch-find options "crt1.o"))))
  212. (command `(,hex2
  213. "--little-endian"
  214. ,@(arch-get-architecture options)
  215. "--base-address" ,base-address
  216. "-f" ,(kernel-find
  217. options
  218. (string-append "elf" machine "-header.hex2"))
  219. ,@start-files
  220. ,@(append-map (cut list "-f" <>) hex2-files)
  221. "-f" ,elf-footer
  222. "--exec_enable"
  223. "-o" ,elf-file-name)))
  224. (when (and verbose? (> verbose? 1))
  225. (format (current-error-port) "~a\n" (string-join command)))
  226. (and (zero? (apply assert-system* command))
  227. elf-file-name)))
  228. (define (M1->blood-elf options M1-files)
  229. (let* ((M1-file-name (car M1-files))
  230. (M1-blood-elf-footer (string-append M1-file-name ".blood-elf"))
  231. (hex2-file-name (replace-suffix M1-file-name ".o"))
  232. (blood-elf-footer (string-append hex2-file-name ".blood-elf"))
  233. (verbose? (count-opt options 'verbose))
  234. (blood-elf (or (getenv "BLOOD_ELF") "blood-elf"))
  235. (command `(,blood-elf
  236. "-f" ,(arch-find options (arch-get-m1-macros options))
  237. ,@(append-map (cut list "-f" <>) M1-files)
  238. "-o" ,M1-blood-elf-footer)))
  239. (when (and verbose? (> verbose? 1))
  240. (format (current-error-port) "~a\n" (string-join command)))
  241. (and (zero? (apply assert-system* command))
  242. (let* ((options (acons 'compile #t options)) ; ugh
  243. (options (acons 'output blood-elf-footer options)))
  244. (M1->hex2 options (list M1-blood-elf-footer))))))
  245. (define (replace-suffix file-name suffix)
  246. (let* ((parts (string-split file-name #\.))
  247. (base (if (pair? (cdr parts)) (drop-right parts 1) (list file-name)))
  248. (old-suffix (if (pair? (cdr parts)) (last parts) ""))
  249. (program-prefix (cond ((string-prefix? "arm-mes-" old-suffix) ".arm-mes-")
  250. ((string-prefix? "x86-mes-" old-suffix) ".x86-mes-")
  251. ((string-prefix? "x86_64-mes-" old-suffix) ".x86_64-mes-")
  252. (else "."))))
  253. (if (string-null? suffix)
  254. (if (string-null? program-prefix) (string-join base ".")
  255. (string-append (string-drop program-prefix 1) (string-join base ".")))
  256. (string-append (string-join base ".") program-prefix (string-drop suffix 1)))))
  257. (define (find-library options ext o)
  258. (arch-find options (string-append "lib" o ext)))
  259. (define* (arch-find options file-name #:key kernel)
  260. (let* ((srcdest (or (getenv "srcdest") ""))
  261. (srcdir-lib (string-append srcdest "lib"))
  262. (srcdir-mescc-lib (string-append srcdest "mescc-lib"))
  263. (libdir (option-ref options 'libdir "lib"))
  264. (libdir-mescc (string-append
  265. (dirname (option-ref options 'libdir "lib"))
  266. "/mescc-lib"))
  267. (arch (string-append (arch-get options) "-mes"))
  268. (path (append (if (getenv "MES_UNINSTALLED")
  269. (list srcdir-mescc-lib
  270. srcdir-lib
  271. libdir-mescc)
  272. '())
  273. (list libdir)
  274. (or (and=> (getenv "LIBRARY_PATH")
  275. (cut string-split <> #\:)) '())
  276. (filter-map (multi-opt 'library-dir) options)))
  277. (arch-file-name (string-append arch "/" file-name))
  278. (arch-file-name (if kernel (string-append kernel "/" arch-file-name)
  279. arch-file-name))
  280. (verbose? (count-opt options 'verbose)))
  281. (let ((file (search-path path arch-file-name)))
  282. (when (and verbose? (> verbose? 1))
  283. (format (current-error-port) "arch-find=~s\n" arch-file-name)
  284. (format (current-error-port) " path=~s\n" path)
  285. (format (current-error-port) " => ~s\n" file))
  286. (or file
  287. (error (format #f "mescc: file not found: ~s" arch-file-name))))))
  288. (define (kernel-find options file-name)
  289. (let ((kernel (option-ref options 'kernel "linux")))
  290. (or (arch-find options file-name #:kernel kernel)
  291. (arch-find options file-name))))
  292. (define (assert-system* . args)
  293. (let ((status (apply system* args)))
  294. (when (not (zero? status))
  295. (format (current-error-port) "mescc: failed: ~a\n" (string-join args))
  296. (exit (status:exit-val status)))
  297. status))
  298. (define (arch-get options)
  299. (let* ((machine (option-ref options 'machine #f))
  300. (arch (option-ref options 'arch #f)))
  301. (if machine (cond ((member arch '("x86" "x86_64")) (cond ((equal? machine "32") "x86")
  302. ((equal? machine "64") "x86_64")))
  303. ((equal? arch "arm") (cond ((equal? machine "32") "arm")
  304. ((equal? machine "arm") "arm"))))
  305. arch)))
  306. (define (mescc:get-host options)
  307. (let ((cpu (arch-get options))
  308. (kernel (option-ref options 'kernel "linux")))
  309. (string-join (list cpu kernel "mes") "-")))
  310. (define (arch-get-info options)
  311. (let ((arch (arch-get options)))
  312. (cond ((equal? arch "arm") (armv4-info))
  313. ((equal? arch "x86") (x86-info))
  314. ((equal? arch "x86_64") (x86_64-info)))))
  315. (define (arch-get-defines options)
  316. (let* ((arch (arch-get options))
  317. (info (arch-get-info options))
  318. (types (.types info)))
  319. (define (sizeof type)
  320. (type:size (assoc-ref types type)))
  321. (let ((int (sizeof "int"))
  322. (long (sizeof "long"))
  323. (long-long (sizeof "long long")))
  324. (cons (cond ((equal? arch "arm")
  325. "__arm__=1")
  326. ((equal? arch "x86")
  327. "__i386__=1")
  328. ((equal? arch "x86_64")
  329. "__x86_64__=1"))
  330. `(,(string-append "__SIZEOF_INT__=" (number->string int))
  331. ,(string-append "__SIZEOF_LONG__=" (number->string long))
  332. ,@(if (< long-long 8) '() ;C99: long long must be >= 8
  333. '("__SIZEOF_LONG_LONG__=8")))))))
  334. (define (arch-get-machine options)
  335. (let* ((machine (option-ref options 'machine #f))
  336. (arch (option-ref options 'arch #f)))
  337. (or machine
  338. (if (member arch '("x86_64")) "64"
  339. "32"))))
  340. (define (arch-get-m1-macros options)
  341. (let ((arch (arch-get options)))
  342. (cond ((equal? arch "arm") "arm.M1")
  343. ((equal? arch "x86") "x86.M1")
  344. ((equal? arch "x86_64") "x86_64.M1"))))
  345. (define (arch-get-architecture options)
  346. (let* ((arch (arch-get options))
  347. (numbered-arch? (option-ref options 'numbered-arch? #f))
  348. (flag (if numbered-arch? "--Architecture" "--architecture")))
  349. (list flag
  350. (cond ((equal? arch "arm") (if numbered-arch? "40" "armv7l"))
  351. ((equal? arch "x86") (if numbered-arch? "1" "x86"))
  352. ((equal? arch "x86_64") (if numbered-arch? "2" "amd64"))))))
  353. (define (multi-opt option-name) (lambda (o) (and (eq? (car o) option-name) (cdr o))))
  354. (define (count-opt options option-name)
  355. (let ((lst (filter-map (multi-opt option-name) options)))
  356. (and (pair? lst) (length lst))))
  357. (define (.c? o) (or (string-suffix? ".c" o)
  358. (string-suffix? ".M2" o)))
  359. (define (.E? o) (or (string-suffix? ".E" o)
  360. (string-suffix? ".mes-E" o)
  361. (string-suffix? ".arm-mes-E" o)
  362. (string-suffix? ".x86-mes-E" o)
  363. (string-suffix? ".x86_64-mes-E" o)))
  364. (define (.s? o) (or (string-suffix? ".s" o)
  365. (string-suffix? ".S" o)
  366. (string-suffix? ".mes-S" o)
  367. (string-suffix? ".arm-mes-S" o)
  368. (string-suffix? ".x86-mes-S" o)
  369. (string-suffix? ".x86_64-mes-S" o)
  370. (string-suffix? ".M1" o)))
  371. (define (.o? o) (or (string-suffix? ".o" o)
  372. (string-suffix? ".mes-o" o)
  373. (string-suffix? ".arm-mes-o" o)
  374. (string-suffix? ".x86-mes-o" o)
  375. (string-suffix? ".x86_64-mes-o" o)
  376. (string-suffix? ".hex2" o)))