1 /** 2 Necessary boilerplate for pyd. 3 4 To wrap all functions/return/parameter types and struct/class definitions from 5 a list of modules, write this in a "main" module and generate mylib.{so,dll}: 6 7 ------ 8 mixin wrapAll(LibraryName("mylib"), Modules("module1", "module2", ...)); 9 ------ 10 */ 11 module autowrap.python.boilerplate; 12 13 14 public import autowrap.types: LibraryName, PreModuleInitCode, PostModuleInitCode; 15 import autowrap.reflection : Modules; 16 17 18 /** 19 Returns a string to mixin that implements the necessary boilerplate 20 to create a Python library containing one Python module 21 wrapping all relevant D code and data structures. 22 */ 23 string wrapDlang( 24 LibraryName libraryName, 25 Modules modules, 26 PreModuleInitCode preModuleInitCode = PreModuleInitCode(), 27 PostModuleInitCode postModuleInitCode = PostModuleInitCode()) 28 () 29 { 30 return __ctfe 31 ? wrapAll(libraryName, modules, preModuleInitCode, postModuleInitCode) 32 : null; 33 } 34 35 36 /** 37 A string to be mixed in that defines all the necessary runtime pyd boilerplate. 38 */ 39 string wrapAll(in LibraryName libraryName, 40 in Modules modules, 41 in PreModuleInitCode preModuleInitCode = PreModuleInitCode(), 42 in PostModuleInitCode postModuleInitCode = PostModuleInitCode()) 43 @safe pure 44 { 45 if(!__ctfe) return null; 46 47 string ret = 48 pydMainMixin(modules, preModuleInitCode, postModuleInitCode) ~ 49 pydInitMixin(libraryName.value); 50 51 version(Have_excel_d) { 52 ret ~= 53 // this is needed because of the excel-d dependency 54 q{ 55 import xlld.wrap.worksheet: WorksheetFunction; 56 extern(C) WorksheetFunction[] getWorksheetFunctions() @safe pure nothrow { return []; } 57 }; 58 } else version(Windows) { 59 import autowrap.common : dllMainMixinStr; 60 ret ~= dllMainMixinStr; 61 } 62 63 return ret; 64 } 65 66 /** 67 A string to be mixed in that defines PydMain, automatically registering all 68 functions and structs in the passed in modules. 69 */ 70 string pydMainMixin(in Modules modules, 71 in PreModuleInitCode preModuleInitCode = PreModuleInitCode(), 72 in PostModuleInitCode postModuleInitCode = PostModuleInitCode()) 73 @safe pure 74 { 75 import std.format: format; 76 import std.algorithm: map; 77 import std.array: join; 78 79 if(!__ctfe) return null; 80 81 const modulesList = modules.value.map!(a => a.toString).join(", "); 82 83 return q{ 84 extern(C) void PydMain() { 85 import std.typecons: Yes, No; 86 import pyd.pyd: module_init; 87 import autowrap.python.wrap: wrapAllFunctions, wrapAllAggregates; 88 89 // this must go before module_init 90 wrapAllFunctions!(%s); 91 92 %s 93 94 module_init; 95 96 // this must go after module_init 97 wrapAllAggregates!(%s); 98 99 %s 100 } 101 }.format(modulesList, preModuleInitCode.value, modulesList, postModuleInitCode.value); 102 } 103 104 /** 105 A string to be mixed in that defines the PyInit function for a library. 106 */ 107 string pydInitMixin(in string libraryName) @safe pure { 108 import std.format: format; 109 110 if(!__ctfe) return null; 111 112 version(Python_3_0_Or_Later) { 113 return q{ 114 import deimos.python.object: PyObject; 115 extern(C) export PyObject* PyInit_%s() { 116 import pyd.def: pyd_module_name, pyd_modules; 117 import pyd.exception: exception_catcher; 118 import pyd.thread: ensureAttached; 119 import core.runtime: rt_init; 120 121 rt_init; 122 123 return exception_catcher(delegate PyObject*() { 124 ensureAttached(); 125 pyd_module_name = "%s"; 126 PydMain(); 127 return pyd_modules[""]; 128 }); 129 } 130 }.format(libraryName, libraryName); 131 } else { 132 return q{ 133 extern(C) export void init%s() { 134 import pyd.exception: exception_catcher; 135 import pyd.thread: ensureAttached; 136 import pyd.def: pyd_module_name; 137 import core.runtime: rt_init; 138 139 rt_init; 140 141 exception_catcher(delegate void() { 142 ensureAttached(); 143 pyd_module_name = "%s"; 144 PydMain(); 145 }); 146 147 } 148 }.format(libraryName, libraryName); 149 } 150 }