2015-05-07 4 views
8

पहले जब कोड-बेस सी ++ में था, तो मेरे पास सी ++ रैपर फाइलें थीं जो कोड बेस से लिंक होंगी और मैं swig (सी ++ 11 समर्थन के लिए संस्करण 3) चलाने के लिए चलाऊंगा लक्षित भाषा के लिए इंटरफ़ेस फ़ाइलें (पायथन, जावास्क्रिप्ट, सी #, आदि)। फिर निश्चित रूप से इन सभी फ़ाइलों और पुस्तकालयों को एक साझा ऑब्जेक्ट में संकलित करें और इसे आवश्यक भाषाओं से लिया गया है। अब कोड बेस जंग में बदल दिया जा रहा है। तो काम करने के लिए स्विग के लिए मेरे पास निम्न है:अन्य भाषाओं से जंग का उपयोग कैसे करें

  1. मुख्य जंग कोड फ़ाइल एक आरएलआईबी में संकलित।
  2. जंग कोड रैपर फ़ाइल जो मुख्य कोड बेस में कॉल करती है लेकिन no_mangle और externFFI के लिए वाक्यविन्यास का उपयोग करती है और एक staticlib में संकलित करता है।
  3. एक सी फ़ाइल जो जंग रस्सी को बुलाती है और इसकी प्रतिकृति है।

अब मैं सी फाइल पर swig का उपयोग करें, लक्षित भाषा के लिए इंटरफ़ेस फ़ाइल मिलता है, लक्षित भाषा से एक साझा वस्तु में सभी फाइलों (दो कदम और तीन) और बड़ा घूँट इंटरफ़ेस फ़ाइल) गठबंधन और कॉल ।

तो:

  1. दृष्टिकोण ठीक है?

  2. मुझे काम करने के लिए नि: शुल्क कार्य मिल सकते हैं। हालांकि मैं काम करने के लिए सदस्य कार्य (विधियों) को कैसे प्राप्त करने के बारे में उलझन में हूं। सी ++ में सदस्य कार्यों का पहला पैरामीटर अंतर्निहित this पॉइंटर है। इसलिए मैं void* सी इंटरफ़ेस के लिए कक्षा या संरचना को संभाल सकता हूं जो इसे स्टोर करना चाहता था (जैसे फ़ायरफ़ॉक्स के लिए jsctypes) और फिर इसे reinterpret_cast को कंक्रीट/वास्तविक प्रकार में प्राप्त करने और फिर से प्राप्त करने पर उस पर सदस्य समारोह। मैं जंग के साथ यह कैसे करूँ?

जैसे,

pub struct A { id: SomeType, } 
impl A { 
    pub fn some_funct_0(&mut self) {} 
    pub fn some_funct_1(&self) {} 
} 

impl SomeTrait for A { 
    fn some_trait_funct(&mut self) {} 
} 

तो मैं कैसे लक्ष्य भाषाओं से (अप्रबंधित और ढेर मुझे लगता है पर होना चाहिए?) A की एक वस्तु पर इन सदस्य कार्यों का उपयोग करते हैं (पायथन, सी के लिए, आदि) या यहां तक ​​कि बस एक सी इंटरफेस?

+0

विधि परिभाषाओं में, 'स्वयं' स्वयं के लिए 'स्वयं', स्वयं 'और स्वयं' के लिए चीनी है: स्वयं और स्वयं के लिए 'स्वयं' और 'mut mut' : और म्यूट Self'। निश्चित रूप से, 'स्वयं' कीवर्ड * अभी भी जंग में विशेष है, लेकिन 'ए :: some_trait_funct' और' ए :: some_funct_0' अभी भी उनके पहले पैरामीटर के प्रकार के रूप में 'और mut A' के साथ कार्य करता है। –

+0

आप एक कंपाइलर-प्लगइन के माध्यम से अपनी खुद की विशेषता बनाने का प्रयास कर सकते हैं, जो स्वचालित रूप से 'no_mangle' डालता है, उस फ़ंक्शन के लिए एक सी-हेडर फ़ाइल बनाता है और उस पर स्विग चलाता है। –

उत्तर

3

ठीक है, विधियां केवल नियमित कार्य हैं, और क्रिस ने कहा, self तर्क Self प्रकार के साथ अंतर्निहित कनेक्शन है।

#[repr(C)] 
pub struct A { id: u32, } 

#[no_mangle] 
pub extern fn new_a(id: u32) -> A { 
    A { id: id } 
} 

impl A { 
    #[no_mangle] 
    pub extern fn some_funct(&self) { 
     println!("Called some_funct: {}", self.id); 
    } 
} 

trait SomeTrait { 
    extern fn some_trait_funct(&self); 
} 

impl SomeTrait for A { 
    #[no_mangle] 
    extern fn some_trait_funct(&self) { 
     println!("Called some_trait_funct: {}", self.id); 
    } 
} 

ध्यान दें कि मैं extern जोड़ा बुला सम्मेलन और #[no_mangle] बदलने के लिए struct पर नाम mangling और #[repr(C)] से बचने के लिए: अपने उदाहरण (थोड़ा संशोधित) सी कोड से कार्यों का उपयोग कर सरल होना चाहिए के साथ। उत्तरार्द्ध आवश्यक नहीं है यदि आपका कोड संरचना के Box ईएस बनाता है और उन्हें सी को कच्चे पॉइंटर्स के रूप में पास कर देता है। मुझे यकीन नहीं है, हालांकि, #[no_mangle] एक से अधिक विशेषता कार्यान्वयनकर्ता होने पर विशेषता विधियों को प्रभावित कर सकता है - यदि दोनों के पास #[no_mangle] है, तो किसी प्रकार का नाम संघर्ष होना चाहिए।

अब इस प्रकार के और सी से अपने कार्यों का उपयोग कर आसान है:

#include <stdint.h> 

struct A { 
    uint32_t id; 
}; 

extern struct A new_a(uint32_t id); 
extern void some_funct(const struct A *self); 
extern void some_trait_funct(const struct A *self); 

int main() { 
    struct A a = new_a(123); 
    some_funct(&a); 
    some_trait_funct(&a); 
} 

इस कार्यक्रम को संकलित करता है और काम करता है:

% rustc --crate-type=staticlib test.rs 
multirust: a new version of 'nightly' is available. run `multirust update nightly` to install it 
note: link against the following native artifacts when linking against this static library 
note: the order and any duplication can be significant on some platforms, and so may need to be preserved 
note: library: System 
note: library: pthread 
note: library: c 
note: library: m 
% gcc -o test_use test_use.c libtest.a -lSystem -lpthread -lc -lm 
% ./test_use 
Called some_funct: 123 
Called some_trait_funct: 123 

हैं तरीकों &mut self स्वीकार किए जाते हैं:

#[no_mangle] 
extern fn some_funct_mut(&mut self) { ... } 

तुम करोगी const को छोड़ने की आवश्यकता है:

extern void some_funct_mut(struct A *self); 

हैं तरीकों self स्वीकार किए जाते हैं:

#[no_mangle] 
extern fn some_funct_value(self) { ... } 

आप मान द्वारा संरचना में उत्तीर्ण होना होगा:, यदि आप एक अपारदर्शी सूचक के माध्यम से संरचना का उपयोग

extern void some_funct_value(struct A self); 

हालांकि यह लेने कार्यों बुला मूल्य से मुश्किल हो सकती है क्योंकि सी को संरचना के सटीक आकार को जानना है। ऐसा नहीं है कि ओपेक पॉइंटर्स के साथ यह आम है, मुझे विश्वास है।

बैकएंड जंग कोड कि rlib का संकलन किया जाता है:

+0

नोट: जब आप मूल्य से संरचना वापस करते हैं, तो वापसी मूल्य शून्य हो जाता है और वास्तविक वापसी मूल्य को फ़ंक्शन के पहले तर्क (एक अतिरिक्त सूचक) 'बाहरी शून्य बम (Bla * sret, Bla * , int32_t वैल); 'जंग का' पब बाहरी एफएन बम (और स्वयं, वैल: i32) -> Bla' का प्रकार है। कम से कम यह एलवीएम में दिखता है: http://is.gd/1VDMKd –

+0

@ker, क्या यह बाहरी कार्यों को भी प्रभावित करता है? यह अजीब बात है, हालांकि मैं 'बाहरी' कार्यों को सी में बिल्कुल काम करता है। वैसे भी, यह अनुकूलन केवल बड़े structs (पॉइंटर आकार से बड़ा, मुझे विश्वास है) के लिए आग लग रहा है, क्योंकि ऊपर दिया गया प्रोग्राम सही तरीके से काम करता है। –

+0

आह देर से होने के लिए खेद है .. कुछ दिनों के लिए दूर था। आपने मेरे प्रश्न का उत्तर दिया और मैं इसे सही उत्तर के रूप में स्वीकार कर रहा हूं लेकिन मुझे पता चला कि मैं ऐसा करने में सक्षम नहीं हूं क्योंकि इसे वास्तविक बैकएंड कोडबेस को '# [repr (सी)] आदि के साथ संशोधित करने की आवश्यकता है। इसलिए मैं इसके बजाय एक जंग-रैपर लिख रहा हूं जो इन structs के लिए हैंडल का खुलासा करेगा और उन्हें सी के लिए 'शून्य *' के रूप में देगा। जब सी एक समारोह को कॉल करना चाहता है तो यह इस पीठ को पार करेगा, जंग रैपर 'retinterpret_cast'' ('ट्रांसम्यूट') होगा और मेम को बुलाओ फ़ंक्शन इत्यादि। मैं जल्द ही आपको और दूसरों के लिए टिप्पणी करने के लिए यहां पोस्ट करूंगा। – ustulation

5

ठीक है, जैसा कि मैंने स्वीकार कर लिया जवाब है कि मैं उस दृष्टिकोण का उपयोग नहीं कर सकता है में टिप्पणी की, मैं इस पर टिप्पणी करने के लिए अन्य के लिए कुछ इस तरह कर रही है समाप्त हो गया

pub trait TestTrait { 
    fn trait_func(&mut self) -> i32; 
} 

pub struct TestStruct { 
    value: i32, 
} 

impl TestStruct { 
    pub fn new(value: i32) -> TestStruct { 
     TestStruct { 
      value: value, 
     } 
    } 

    pub fn decrement(&mut self, delta: i32) { 
     self.value -= delta; 
    } 
} 

impl TestTrait for TestStruct { 
    fn trait_func(&mut self) -> i32 { 
     self.value += 3; 
     self.value 
    } 
} 

इस पर जंग-आवरण है कि ऊपर rlib से जोड़ता है और staticlib में संकलित (यानी, .a लिनक्स आदि में।):

#[no_mangle] 
pub extern fn free_function_wrapper(value: i32) -> i32 { 
    rustlib::free_function(value) 
} 

#[no_mangle] 
pub extern fn new_test_struct_wrapper(value: i32) -> *mut libc::c_void { 
    let obj = rustlib::TestStruct::new(value); 
    unsafe { 
     let raw_ptr = libc::malloc(mem::size_of::<rustlib::TestStruct>() as libc::size_t) as *mut rustlib::TestStruct; 

     ptr::write(&mut *raw_ptr, obj); 
     raw_ptr as *mut libc::c_void 
    } 
} 

#[no_mangle] 
pub extern fn test_struct_decrement_wrapper(raw_ptr: *mut libc::c_void, delta: i32) { 
    unsafe { 
     mem::transmute::<*mut libc::c_void, &mut rustlib::TestStruct>(raw_ptr).decrement(delta); 
    } 
} 

#[no_mangle] 
pub extern fn test_struct_trait_function_wrapper(raw_ptr: *mut libc::c_void) -> i32 { 
    unsafe { 
     mem::transmute::<*mut libc::c_void, &mut rustlib::TestStruct>(raw_ptr).trait_func() 
    } 
} 

सी-आवरण (api.h & api.c) है कि इसके बाद के संस्करण staticlib से जोड़ता है और एक साझा वस्तु में संकलित यदि आवश्यक:

extern int32_t free_function_wrapper(int32_t value); 

extern void* new_test_struct_wrapper(int32_t value); 
extern void test_struct_decrement_wrapper(void* ptr, int32_t delta); 
extern int32_t test_struct_trait_function_wrapper(void* ptr); 

int32_t free_function(int32_t value) { 
    return free_function_wrapper(value); 
} 

void* new_test_struct(int32_t value) { 
    return new_test_struct_wrapper(value); 
} 

void test_struct_decrement(void* ptr, int32_t value) { 
    test_struct_decrement_wrapper(ptr, value); 
} 

int32_t test_struct_trait_function(void* ptr) { 
    return test_struct_trait_function_wrapper(ptr); 
} 

अब बस सी फ़ाइल पर SWIG चलाने (मैं सिर्फ .c फ़ाइल पोस्ट किया है - आप लक्ष्य भाषा के लिए .h पर एसडब्ल्यूआईजी चलाएगा), interface_wrap.c जेनरेट (डिफ़ॉल्ट नाम) प्राप्त करें और इन स्रोत कोड लिंक को संकलित करें, उन्हें staticlib के विरुद्ध साझा-ऑब्जेक्ट प्राप्त करने के लिए संकलित करें।

जैसे, अजगर के लिए:

swig -python interface.i 
gcc -std=c99 -c -fPIC -Wall -Werror -O2 api.c interface_wrap.c -I/usr/include/python2.7 
gcc -shared -o _port_sample.so api.o interface_wrap.o -L./ -lrust_wrapper 

अब बस अजगर और पूरी बात से फोन काम करता है:

$ python 
Python 2.7.6 (default, Mar 22 2014, 22:59:56) 
[GCC 4.8.2] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import port_sample 
>>> handle = port_sample.new_test_struct(36) 
>>> port_sample.test_struct_decrement(handle, 12) 
>>> value = port_sample.test_struct_trait_function(handle) 
>>> print value 
27 
>>> exit() 

मैं किसी को इस उपयोगी पाता है और/या सुधार आदि मैं 'कर सकते हैं सुझाव आशा मुझे यह भी काम मिल रहा है और मेरे जीथब रेपो के लिए प्रतिबद्ध है: https://github.com/ustulation/rust-ffi/tree/master/python-swig-rust

संबंधित मुद्दे