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: 15 Modules, LibraryName, PreModuleInitCode, PostModuleInitCode, RootNamespace; 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 RootNamespace _ = RootNamespace(), // ignored in this backend 27 PreModuleInitCode preModuleInitCode = PreModuleInitCode(), 28 PostModuleInitCode postModuleInitCode = PostModuleInitCode()) 29 () 30 { 31 return __ctfe 32 ? wrapAll(libraryName, modules, preModuleInitCode, postModuleInitCode) 33 : null; 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 import autowrap.common : dllMainMixinStr; 61 ret ~= dllMainMixinStr; 62 } 63 64 return ret; 65 } 66 67 /** 68 A string to be mixed in that defines PydMain, automatically registering all 69 functions and structs in the passed in modules. 70 */ 71 string pydMainMixin(in Modules modules, 72 in PreModuleInitCode preModuleInitCode = PreModuleInitCode(), 73 in PostModuleInitCode postModuleInitCode = PostModuleInitCode()) 74 @safe pure 75 { 76 import std.format: format; 77 import std.algorithm: map; 78 import std.array: join; 79 80 if(!__ctfe) return null; 81 82 const modulesList = modules.value.map!(a => a.toString).join(", "); 83 84 return q{ 85 extern(C) void PydMain() { 86 import std.typecons: Yes, No; 87 import pyd.pyd: module_init; 88 import autowrap.python.wrap: wrapAllFunctions, wrapAllAggregates; 89 90 // this must go before module_init 91 wrapAllFunctions!(%s); 92 93 %s 94 95 module_init; 96 97 // this must go after module_init 98 wrapAllAggregates!(%s); 99 100 %s 101 } 102 }.format(modulesList, preModuleInitCode.value, modulesList, postModuleInitCode.value); 103 } 104 105 /** 106 A string to be mixed in that defines the PyInit function for a library. 107 */ 108 string pydInitMixin(in string libraryName) @safe pure { 109 import std.format: format; 110 111 if(!__ctfe) return null; 112 113 version(Python_3_0_Or_Later) { 114 return q{ 115 import deimos.python.object: PyObject; 116 extern(C) export PyObject* PyInit_%s() { 117 import pyd.def: pyd_module_name, pyd_modules; 118 import pyd.exception: exception_catcher; 119 import pyd.thread: ensureAttached; 120 import core.runtime: rt_init; 121 122 rt_init; 123 124 return exception_catcher(delegate PyObject*() { 125 ensureAttached(); 126 pyd_module_name = "%s"; 127 PydMain(); 128 return pyd_modules[""]; 129 }); 130 } 131 }.format(libraryName, libraryName); 132 } else { 133 return q{ 134 extern(C) export void init%s() { 135 import pyd.exception: exception_catcher; 136 import pyd.thread: ensureAttached; 137 import pyd.def: pyd_module_name; 138 import core.runtime: rt_init; 139 140 rt_init; 141 142 exception_catcher(delegate void() { 143 ensureAttached(); 144 pyd_module_name = "%s"; 145 PydMain(); 146 }); 147 148 } 149 }.format(libraryName, libraryName); 150 } 151 }