2016-06-11 15 views
1

Ich spiele mit der Idee des Ladens С/Rust/etc Funktionen über FFI in Racket. Ich würde gerne eine Liste von Funktionsnamen als Strings angeben und sie dann einfach durch eine Hilfsfunktion laden. Hauptproblem ist das Erstellen von Bezeichnern/Wörtern aus einer Zeichenfolge. Zum Beispiel ist es in Rebol sehr einfach:Dynamisch erstellen FFI-Methoden in Racket

foo: "test1" 
set to-word (rejoin [foo "_result_data"]) some 
print test1_result_data 

aber im Racket muss ich Syntax Zeug verwenden. Also habe ich Beispiele wie How do I define functions using Racket macros? und Racket Macro to auto-define functions given a list gefunden. Sie decken eine Menge Wissen, das ich brauche, also habe ich geschrieben nächsten Schnipsel:

#lang racket 
(require (for-syntax racket/syntax ffi/unsafe)) 

(define-for-syntax *method-names* 
    ; Given I have hello, one and two methods in my shared lib 
    (list "hello" 
     "one" 
     "two" 
     )) 

(define-syntax (define-ffi-func stx) 
    (syntax-case stx() 
    [(_) 
    (let ([elem->fn-id 
      (λ (elem-str) 
       (format-id 
       stx "~a" 
       (datum->syntax stx (string->symbol elem-str))))] 
      [rustlib 
       (ffi-lib "/path/to/libffitest.dylib") 
       ] 
      ) 
     (with-syntax 
     ([((method cation) ...) 
      (map 
      (λ (elem) 
       ; I can load C code here for sure :) But not much more 
       ; (define c (get-ffi-obj elem rustlib (_fun -> _int) 
       ; (lambda() 
       ;  (error 'rustlib 
       ;  "installed lib does not provide given method")))) 
       (list (elem->fn-id elem) elem) 
      ) 
      *method-names*)]) 
     #`(begin 
      (define (method) 
       ; I'm curious what should be here 
       1 
      ) 
      ...)))])) 

(define-ffi-func) 
; Actually one, two and hello methods are in scope 
; but surely they all return 1 
(two) 

Aber noch kann ich keine neuen Racket Methoden mit ffi Anrufe verbinden. Ich glaube, ich kann sie nicht in with-syntax Körper passen, aber weitere Syntaxdefinition weiß nichts über externe Module (zB

#`(begin 
    (define (ate) 
     (get-ffi-obj elem rustlib (_fun -> _int)) 
     ) 
    ...)))])) 

wird nicht funktionieren.

Ich glaube, ich bin fehlt etwas zu bindenden Spiel.

?!

Wie kann ich FFI-gebundene Methoden durch eine Liste mit Namen Angabe Vielen Dank im Voraus

Antwort

1

Da Sie bereits Ihre Hauptfrage beantwortet haben, wollte ich nur feststellen, dass es im Allgemeinen nicht sehr Rackety ist, Listen von Strings zu verwenden, um Namen darzustellen. Es ist normalerweise besser, Kennungen zu verwenden. Müssen Sie diese Strings tatsächlich dynamisch berechnen?

Wenn Sie dies nicht tun, dann ist es sehr einfach, ein Makro zu schreiben, um alle FFI-Bindungen eine Liste von Kennungen gegeben zu definieren:

(define-syntax-rule (define-ffi-functions name ...) 
    (begin (define name 
      (get-ffi-obj (quote name) ffi-lib (_fun -> _int))) 
     ...)) 

(define-ffi-functions hello one two) 

mit einer geeigneten Definition von ffi-lib.

+0

Einfach genial! –

0

endete schließlich mit so etwas wie dies oben:

(define-for-syntax *method-names* 
    (list "hello" 
     "one" 
     "two" 
     )) 

(define rustlib (ffi-lib "/path/to/Projects/libffitest.dylib")) 

(define-syntax (define-ffi-func stx) 
    (syntax-case stx() 
    [(_ lib ffi-func) 
    (let ([elem->fn-id 
      (λ (elem-str) 
       (format-id 
       stx "~a" 
       (datum->syntax stx (string->symbol elem-str))))] 
      ) 
     (with-syntax 
     ([((method name) ...) 
      (map 
      (λ (elem) 
       (list (elem->fn-id elem) elem) 
      ) 
      *method-names*)]) 
     #`(begin 
      (define method 
       (ffi-func name lib (_fun -> _int)) 
      ) 
      ...)))])) 

(define-ffi-func rustlib get-ffi-obj) 
(+ (one) (two)) 

Noch muss poliert werden, aber im Allgemeinen ist verständlich.