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