Skip to content

Instantly share code, notes, and snippets.

@tonyg
Created November 17, 2017 13:46
Show Gist options
  • Save tonyg/a718584f7cd661be90c9863dd8d73dc7 to your computer and use it in GitHub Desktop.
Save tonyg/a718584f7cd661be90c9863dd8d73dc7 to your computer and use it in GitHub Desktop.
Compile and run a small C program from Racket to determine values of system flags and enums
#lang racket
(define-logger dumpflags)
(define (delete-file/no-exn p)
(with-handlers [(exn:fail:filesystem? void)]
(delete-file p)))
(define (c-eval program-text #:quiet? [quiet? #f])
(define tmp.c (make-temporary-file "racket-c-eval-~a.c" #f))
(define a.out (path-replace-extension tmp.c #""))
(log-dumpflags-debug "c-eval: Program text:\n~a" program-text)
(log-dumpflags-debug "c-eval: source file: ~a" tmp.c)
(log-dumpflags-debug "c-eval: output file: ~a" a.out)
(with-handlers [(exn? (lambda (e)
(delete-file/no-exn tmp.c)
(delete-file/no-exn a.out)
(raise e)))]
(with-output-to-file #:exists 'truncate tmp.c
(lambda () (write-string program-text)))
(system* (find-executable-path "cc") ;; maybe reuse dynext/compile machinery?
"-o" a.out
tmp.c)
(let ((result (void)))
(define output (with-output-to-string
(lambda () (set! result (system* a.out)))))
(values result output))))
(define (c-program-template #:base-includes [base-includes '("stdlib.h" "stdio.h" "stdint.h" "string.h")]
#:includes [extra-includes '()]
#:local-includes [local-includes '()]
main-text
. other-definitions)
(string-append*
(flatten
(list
(for/list [(i (in-list (append base-includes extra-includes)))]
(format "#include <~a>\n" i))
(for/list [(i (in-list local-includes))]
(format "#include \"~a\"\n" i))
(for/list [(d (in-list other-definitions))]
(list d "\n\n"))
"int main(int argc, char *argv[]) {\n"
main-text
"\n}\n"))))
(define (c-query-flags #:includes [includes '()]
#:local-includes [local-includes '()]
. flags)
(match/values (c-eval
(c-program-template #:includes includes #:local-includes local-includes
(list
(for/list [(flag (in-list (flatten flags)))]
(define-values (format-string argument)
(match flag
[(? symbol? s) (values "%d" s)]
[(list (? string? fmt) (? symbol? s)) (values fmt s)]))
(format " printf(\"~a:::~a\\n\", ~a);\n"
argument
format-string
argument))
" return EXIT_SUCCESS;\n")))
[(#f _) #f]
[(#t lines)
(map (match-lambda [(regexp #px"^(.*):::(.*)$" (list _ name value))
(list (string->symbol name)
(string->number value))])
(string-split lines "\n"))]))
(module+ main
(c-query-flags #:includes '("sys/mman.h")
'PROT_EXEC
'PROT_READ
'PROT_WRITE
'PROT_NONE
'MAP_SHARED
'MAP_PRIVATE
'MAP_ANONYMOUS))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment