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 A string to be mixed in that defines all the necessary runtime pyd boilerplate. 39 */ 40 string wrapAll(in LibraryName libraryName, 41 in Modules modules, 42 in PreModuleInitCode preModuleInitCode = PreModuleInitCode(), 43 in PostModuleInitCode postModuleInitCode = PostModuleInitCode()) 44 @safe pure 45 { 46 if(!__ctfe) return null; 47 48 string ret = 49 pydMainMixin(modules, preModuleInitCode, postModuleInitCode) ~ 50 pydInitMixin(libraryName.value); 51 52 version(Have_excel_d) { 53 ret ~= 54 // this is needed because of the excel-d dependency 55 q{ 56 import xlld.wrap.worksheet: WorksheetFunction; 57 extern(C) WorksheetFunction[] getWorksheetFunctions() @safe pure nothrow { return []; } 58 }; 59 } else version(Windows) { 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 120 return exception_catcher(delegate PyObject*() { 121 ensureAttached(); 122 pyd_module_name = "%s"; 123 PydMain(); 124 return pyd_modules[""]; 125 }); 126 } 127 }.format(libraryName, libraryName); 128 } else { 129 return q{ 130 import pyd.exception: exception_catcher; 131 import pyd.thread: ensureAttached; 132 import pyd.def: pyd_module_name; 133 extern(C) export void init%s() { 134 exception_catcher(delegate void() { 135 ensureAttached(); 136 pyd_module_name = "%s"; 137 PydMain(); 138 }); 139 140 } 141 }.format(libraryName, libraryName); 142 } 143 }