`generate-mapped-static-ffi` produces empty mapping
Given the following program...
#lang racket/base
(require dynamic-ffi/unsafe)
(define vulkan-sdk (bytes->string/utf-8
(environment-variables-ref (current-environment-variables)
#"VULKAN_SDK")))
(define (vulkan-path . args)
(apply build-path vulkan-sdk args))
(define lib-path (vulkan-path "lib/libvulkan"))
(define header-path (vulkan-path "include/vulkan/vulkan.h"))
(module+ main
(generate-mapped-static-ffi "vulkan"
"dffi-vulkan.rkt"
lib-path
header-path))
I get this output. I was expecting ffi-obj-map to be non-empty.
#lang racket/base
(require ffi/unsafe)
(provide (except-out
(all-defined-out)
ffi-obj-map))
(define vulkan-ffi-lib (ffi-lib "/home/sage/vulkan/1.1.121.1/x86_64/lib/libvulkan"))
(define vulkan-headers (list "/home/sage/vulkan/1.1.121.1/x86_64/include/vulkan/vulkan.h"))
(define (warn-undefined-symbol sym)
(lambda ()
(fprintf (current-error-port)
"warning: vulkan does not contain symbol ~a" sym)))
(define ffi-obj-map
(make-hash
(list )))
(define vulkan
(case-lambda
[() ffi-obj-map]
[(sym)
(let ([obj (hash-ref ffi-obj-map sym)])
(if (procedure? obj) (obj) obj))]
[(sym . args)
(let ([obj (hash-ref ffi-obj-map sym)])
(apply obj args))]))
The dynamic ffi does not parse header files recursively. This is because it would also parse out and create many unneeded ffi-objects for all dependencies, such as libc etc. Are there are nested headers for different subsystems you can include in place of the top level vulcan.h?
I know this is an unfortunate limitation, because many large libraries provide a single top level header. The only other recommendation I have is to perhaps define wrapper functions using define-inline-ffi.
I would also like to find a better solution to this issue. If you have any ideas, please let me know.
@dbenoit17 Ah, ok. That makes sense. Vulkan makes heavy use of include guards for per-platform support, but I see some ways to work with this. Thank you.
I would also like to find a better solution to this issue. If you have any ideas, please let me know.
Yeah, I don't think this has an ideal solution. I was spitballing things like telling dynamic-ffi what specific symbols I would expect, but that had its own problems.
The only general solution I see is difficult: A public Racket interface to the clang AST through your plugin, plus a way to "direct" dynamic-ffi to recurse to only programmer-specified headers. I imagine that's a ways off.
It is actually pretty trivial to have clang recurse and provide all of the metadata. In reality, clang does recurse through the nested headers, but only reports top-level headers to racket to avoid the overhead of generating the objects. There is already a keword arg buried somewhere in the dynamic-ffi library to turn on all nested declarations.
I think you are on to something with your suggestion to direct the library to include programmer-defined headers. We could probably have the public interfaces of the library take an optional lambda to be used as a filter predicate. Thanks for the idea, I will implement that.
Thanks for the idea, I will implement that.
That's great news, thank you! I'll be happy to verify once it is complete.