|
| 1 | +Adding NumPy to your iOS project |
| 2 | +================================ |
| 3 | + |
| 4 | +1. Build NumPy. You can either build NumPy specficially:: |
| 5 | + |
| 6 | + make <name of package> |
| 7 | + |
| 8 | + or build all supported binary packages:: |
| 9 | + |
| 10 | + make app_packages |
| 11 | + |
| 12 | + This will produce: |
| 13 | + |
| 14 | + * a folder named `dist/app_packages`, containing the python code required by |
| 15 | + the package |
| 16 | + |
| 17 | + * a folder for each supported mobile platform (iOS, tvOS and watchOS) |
| 18 | + containing the static fat binary libraries needed to support the Python |
| 19 | + code. |
| 20 | + |
| 21 | +2. Copy the contents of `dist/app_packages` into your project's `site_packages` |
| 22 | + or `app_packages` directory. This will make the Python library available to |
| 23 | + your project. |
| 24 | + |
| 25 | +3. Copy the static binary libraries in the platform directory (e.g., the contents |
| 26 | + of `dist/iOS`) into your project and add them as static libraries in your |
| 27 | + project. The location where you copy the files doesn't matter - they just need |
| 28 | + to be part of the project. If you're using a BeeWare template, we'd suggest |
| 29 | + putting them in the Support folder. |
| 30 | + |
| 31 | +4. Add the following function definition to the file that configures your |
| 32 | + Python environment (if you're using a BeeWare template, this will be |
| 33 | + the ``main.m`` file; in other projects, it's whichever file contains |
| 34 | + the code that invokes ``Py_Initialize()`` and ``PyEval_InitThreads()``:: |
| 35 | + |
| 36 | + void numpy_importer() { |
| 37 | + PyRun_SimpleString( |
| 38 | + "import sys, importlib\n" \ |
| 39 | + "class NumpyImporter(object):\n" \ |
| 40 | + " def find_module(self, fullname, mpath=None):\n" \ |
| 41 | + " if fullname in (" \ |
| 42 | + " 'numpy.core.multiarray', " \ |
| 43 | + " 'numpy.core.umath', " \ |
| 44 | + " 'numpy.fft.fftpack_lite', " \ |
| 45 | + " 'numpy.linalg._umath_linalg', " \ |
| 46 | + " 'numpy.linalg.lapack_lite', " \ |
| 47 | + " 'numpy.random.mtrand', " \ |
| 48 | + " ):\n" \ |
| 49 | + " return self\n" \ |
| 50 | + " return\n" \ |
| 51 | + " def load_module(self, fullname):\n" \ |
| 52 | + " f = '__' + fullname.replace('.', '_')\n" \ |
| 53 | + " mod = sys.modules.get(f)\n" \ |
| 54 | + " if mod is None:\n" \ |
| 55 | + " mod = importlib.__import__(f)\n" \ |
| 56 | + " sys.modules[fullname] = mod\n" \ |
| 57 | + " return mod\n" \ |
| 58 | + " return mod\n" \ |
| 59 | + "sys.meta_path.append(NumpyImporter())" |
| 60 | + ); |
| 61 | + } |
| 62 | + |
| 63 | +5. Add the following external function declarations to the file that |
| 64 | + configures your Python enviroment:: |
| 65 | + |
| 66 | + extern PyMODINIT_FUNC PyInit_multiarray(void); |
| 67 | + extern PyMODINIT_FUNC PyInit_umath(void); |
| 68 | + extern PyMODINIT_FUNC PyInit_fftpack_lite(void); |
| 69 | + extern PyMODINIT_FUNC PyInit__umath_linalg(void); |
| 70 | + extern PyMODINIT_FUNC PyInit_lapack_lite(void); |
| 71 | + extern PyMODINIT_FUNC PyInit_mtrand(void); |
| 72 | + |
| 73 | +6. Add the following function calls *before* invoking ``Py_Initialize()``:: |
| 74 | + |
| 75 | + PyImport_AppendInittab("__numpy_core_multiarray", &PyInit_multiarray); |
| 76 | + PyImport_AppendInittab("__numpy_core_umath", &PyInit_umath); |
| 77 | + PyImport_AppendInittab("__numpy_fft_fftpack_lite", &PyInit_fftpack_lite); |
| 78 | + PyImport_AppendInittab("__numpy_linalg__umath_linalg", &PyInit__umath_linalg); |
| 79 | + PyImport_AppendInittab("__numpy_linalg_lapack_lite", &PyInit_lapack_lite); |
| 80 | + PyImport_AppendInittab("__numpy_random_mtrand", &PyInit_mtrand); |
| 81 | + |
| 82 | +7. Install the numpy importer, by invoking ``numpy_importer()`` *after* |
| 83 | + invoking `PyEval_InitThreads()`, but before you run any Python scripts. |
| 84 | + |
| 85 | + |
| 86 | +If you've followed these instructions, and you're using a BeeWare project |
| 87 | +template, your ``iOS/<project name>/main.m`` file (in the Supporting Files |
| 88 | +folder in the Xcode project) will look something like this:: |
| 89 | + |
| 90 | + // |
| 91 | + // main.m |
| 92 | + // A main module for starting Python projects under iOS. |
| 93 | + // |
| 94 | + |
| 95 | + #import <Foundation/Foundation.h> |
| 96 | + #import <UIKit/UIKit.h> |
| 97 | + #include <Python.h> |
| 98 | + #include <dlfcn.h> |
| 99 | + |
| 100 | + |
| 101 | + void numpy_importer() { |
| 102 | + PyRun_SimpleString( |
| 103 | + "import sys, importlib\n" \ |
| 104 | + ... |
| 105 | + "sys.meta_path.append(NumpyImporter())" |
| 106 | + ); |
| 107 | + } |
| 108 | + |
| 109 | + |
| 110 | + extern PyMODINIT_FUNC PyInit_multiarray(void); |
| 111 | + extern PyMODINIT_FUNC PyInit_umath(void); |
| 112 | + extern PyMODINIT_FUNC PyInit_fftpack_lite(void); |
| 113 | + extern PyMODINIT_FUNC PyInit__umath_linalg(void); |
| 114 | + extern PyMODINIT_FUNC PyInit_lapack_lite(void); |
| 115 | + extern PyMODINIT_FUNC PyInit_mtrand(void); |
| 116 | + |
| 117 | + |
| 118 | + int main(int argc, char *argv[]) { |
| 119 | + int ret = 0; |
| 120 | + unsigned int i; |
| 121 | + NSString *tmp_path; |
| 122 | + NSString *python_home; |
| 123 | + NSString *python_path; |
| 124 | + wchar_t *wpython_home; |
| 125 | + const char* main_script; |
| 126 | + wchar_t** python_argv; |
| 127 | + |
| 128 | + @autoreleasepool { |
| 129 | + ... |
| 130 | + |
| 131 | + // iOS provides a specific directory for temp files. |
| 132 | + tmp_path = [NSString stringWithFormat:@"TMP=%@/tmp", resourcePath, nil]; |
| 133 | + putenv((char *)[tmp_path UTF8String]); |
| 134 | + |
| 135 | + PyImport_AppendInittab("__numpy_core_multiarray", &PyInit_multiarray); |
| 136 | + PyImport_AppendInittab("__numpy_core_umath", &PyInit_umath); |
| 137 | + PyImport_AppendInittab("__numpy_fft_fftpack_lite", &PyInit_fftpack_lite); |
| 138 | + PyImport_AppendInittab("__numpy_linalg__umath_linalg", &PyInit__umath_linalg); |
| 139 | + PyImport_AppendInittab("__numpy_linalg_lapack_lite", &PyInit_lapack_lite); |
| 140 | + PyImport_AppendInittab("__numpy_random_mtrand", &PyInit_mtrand); |
| 141 | + |
| 142 | + NSLog(@"Initializing Python runtime"); |
| 143 | + Py_Initialize(); |
| 144 | + |
| 145 | + ... |
| 146 | + |
| 147 | + // If other modules are using threads, we need to initialize them. |
| 148 | + PyEval_InitThreads(); |
| 149 | + |
| 150 | + numpy_importer(); |
| 151 | + |
| 152 | + // Start the main.py script |
| 153 | + NSLog(@"Running %s", main_script); |
| 154 | + |
| 155 | + ... |
| 156 | + } |
| 157 | + |
| 158 | + exit(ret); |
| 159 | + return ret; |
| 160 | + } |
0 commit comments