Skip to content

Commit 980a6b3

Browse files
committed
Add to C++ and Debug sections.
1 parent 55095f9 commit 980a6b3

File tree

6 files changed

+141
-5
lines changed

6 files changed

+141
-5
lines changed

doc/sphinx/source/cpp_and_numpy.rst

+97
Original file line numberDiff line numberDiff line change
@@ -188,3 +188,100 @@ Supposing you have laid out your source code in the following fashion::
188188
This is a hybrid of the above and typical for CPython C++ extensions where ``module.c`` contains the CPython code that allows Python to access the pure C++ code.
189189

190190
The code in ``class.h`` and ``class.cpp`` is unchanged and the code in ``module.c`` is essentially the same as that of a CPython module as described above where ``import_array()`` is called from within the ``PyInit_<module>`` function.
191+
192+
193+
How These Macros Work Together
194+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
195+
196+
The two macros ``PY_ARRAY_UNIQUE_SYMBOL`` and ``NO_IMPORT_ARRAY`` work together as follows:
197+
198+
+-----------------------------------+-------------------------------+-------------------------------+
199+
| | | |
200+
+-----------------------------------+-------------------------------+-------------------------------+
201+
| | ``PY_ARRAY_UNIQUE_SYMBOL`` | ``PY_ARRAY_UNIQUE_SYMBOL`` |
202+
| | NOT defined | defined as <NAME> |
203+
+-----------------------------------+-------------------------------+-------------------------------+
204+
| | C API is declared as: | C API is declared as: |
205+
| ``NO_IMPORT_ARRAY`` not defined | ``static void **PyArray_API`` | ``void **<NAME>`` |
206+
| | Which makes it only available | so can be seen by other |
207+
| | to that translation unit. | translation units. |
208+
+-----------------------------------+-------------------------------+-------------------------------+
209+
| | C API is declared as: | C API is declared as: |
210+
| ``NO_IMPORT_ARRAY`` defined | ``extern void **PyArray_API`` | ``extern void **<NAME>`` |
211+
| | so is available from another | so is available from another |
212+
| | translation unit. | translation unit. |
213+
+-----------------------------------+-------------------------------+-------------------------------+
214+
215+
216+
Adding a Search Path to a Virtual Environment
217+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
218+
219+
If you are linking to the system Python this may not have numpy installed, here is a way to cope with that. Create a virtual environment from the system python and install numpy:
220+
221+
.. code-block:: bash
222+
223+
python -m venv <PATH_TO_VIRTUAL_ENVIRONMENT>
224+
pip install numpy
225+
226+
Then in your C++ entry point add this function that manipulates ``sys.path``:
227+
228+
.. code-block:: cpp
229+
230+
/** Takes a path and adds it to sys.paths by calling PyRun_SimpleString.
231+
* This does rather laborious C string concatenation so that it will work in
232+
* a primitive C environment.
233+
*
234+
* Returns 0 on success, non-zero on failure.
235+
*/
236+
int add_path_to_sys_module(const char *path) {
237+
int ret = 0;
238+
const char *prefix = "import sys\nsys.path.append(\"";
239+
const char *suffix = "\")\n";
240+
char *command = (char*)malloc(strlen(prefix)
241+
+ strlen(path)
242+
+ strlen(suffix)
243+
+ 1);
244+
if (! command) {
245+
return -1;
246+
}
247+
strcpy(command, prefix);
248+
strcat(command, path);
249+
strcat(command, suffix);
250+
ret = PyRun_SimpleString(command);
251+
#ifdef DEBUG
252+
printf("Calling PyRun_SimpleString() with:\n");
253+
printf("%s", command);
254+
printf("PyRun_SimpleString() returned: %d\n", ret);
255+
fflush(stdout);
256+
#endif
257+
free(command);
258+
return ret;
259+
}
260+
261+
``main()`` now calls this with the path to the virtual environment ``site-packages``:
262+
263+
.. code-block:: cpp
264+
265+
int main(int argc, const char * argv[]) {
266+
wchar_t *program = Py_DecodeLocale(argv[0], NULL);
267+
if (program == NULL) {
268+
fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
269+
exit(1);
270+
}
271+
// Initialise the interpreter.
272+
Py_SetProgramName(program); /* optional but recommended */
273+
Py_Initialize();
274+
const char *multiarray_path = "<PATH_TO_VIRTUAL_ENVIRONMENT_SITE_PACKAGES>";
275+
add_path_to_sys_module(multiarray_path);
276+
import_array();
277+
if (PyErr_Occurred()) {
278+
std::cerr << "Failed to import numpy Python module(s)." << std::endl;
279+
return -1;
280+
}
281+
assert(PyArray_API);
282+
// Your code here...
283+
}
284+
285+
286+
287+

doc/sphinx/source/debugging/debug_in_ide.rst

+27
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,33 @@ And you should get something like this:
356356

357357
The full code for this is in *src/debugging/XcodeExample/PythonSubclassList/*.
358358

359+
360+
--------------------------------------------
361+
Using a Debug Version of Python C with Xcode
362+
--------------------------------------------
363+
364+
To get Xcode to use a debug version of Python first build Python from source assumed here to be ``<SOURCE_DIR>`` with, as a minimum, ``--with-pydebug``. This example is using Python 3.6:
365+
366+
.. code-block:: console
367+
368+
cd <SOURCE_DIR>
369+
mkdir debug-framework
370+
cd debug-framework/
371+
../configure --with-pydebug --without-pymalloc --with-valgrind --enable-framework
372+
make
373+
374+
Then in Xcode select the project and "Add files to ..." and add:
375+
376+
* ``<SOURCE_DIR>/debug-framework/Python.framework/Versions/3.6/Python``
377+
* ``<SOURCE_DIR>/debug-framework/libpython3.6d.a``
378+
379+
In "Build Settings":
380+
381+
* add ``/Library/Frameworks/Python.framework/Versions/3.6/include/python3.6m/`` to "Header Search Paths". Alternatively add both ``<SOURCE_DIR>/Include`` *and* ``<SOURCE_DIR>/debug-framework`` to "Header Search Paths", the latter is needed for ``pyconfig.h``.
382+
* add ``<SOURCE_DIR>/debug-framework`` to "Library Search Paths".
383+
384+
Now you should be able to step into the CPython code.
385+
359386
--------------------------------------------
360387
Debugging Python C Extensions in Eclipse
361388
--------------------------------------------
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>IDEDidComputeMac32BitWarning</key>
6+
<true/>
7+
</dict>
8+
</plist>

src/debugging/XcodeExample/PythonSubclassList/PythonSubclassList.xcodeproj/xcuserdata/paulross.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist

+9-5
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
continueAfterRunningActions = "No"
2525
symbolName = "ScList_append"
2626
moduleName = "PythonSubclassList"
27+
usesParentBreakpointCondition = "Yes"
2728
urlString = "file:///Users/paulross/Documents/workspace/PythonExtensionPatterns/src/debugging/XcodeExample/PythonSubclassList/PythonSubclassList/SubclassList.c"
2829
timestampString = "486418359.147248"
2930
startingColumnNumber = "9223372036854775807"
@@ -38,6 +39,7 @@
3839
continueAfterRunningActions = "No"
3940
symbolName = "ScList_append"
4041
moduleName = "ScList.so"
42+
usesParentBreakpointCondition = "Yes"
4143
urlString = "file:///Users/paulross/Documents/workspace/PythonExtensionPatterns/src/debugging/XcodeExample/PythonSubclassList/PythonSubclassList/SubclassList.c"
4244
timestampString = "486418359.297105"
4345
startingColumnNumber = "9223372036854775807"
@@ -61,31 +63,33 @@
6163
endingColumnNumber = "9223372036854775807"
6264
startingLineNumber = "49"
6365
endingLineNumber = "49"
64-
landmarkName = "call_super_pyname()"
65-
landmarkType = "7">
66+
landmarkName = "call_super_pyname"
67+
landmarkType = "9">
6668
<Locations>
6769
<Location
6870
shouldBeEnabled = "Yes"
6971
ignoreCount = "0"
7072
continueAfterRunningActions = "No"
7173
symbolName = "call_super_pyname"
7274
moduleName = "PythonSubclassList"
75+
usesParentBreakpointCondition = "Yes"
7376
urlString = "file:///Users/paulross/Documents/workspace/PythonExtensionPatterns/src/debugging/XcodeExample/PythonSubclassList/PythonSubclassList/py_call_super.c"
74-
timestampString = "487278611.130096"
77+
timestampString = "564676032.821329"
7578
startingColumnNumber = "9223372036854775807"
7679
endingColumnNumber = "9223372036854775807"
7780
startingLineNumber = "49"
7881
endingLineNumber = "49"
79-
offsetFromSymbolStart = "444">
82+
offsetFromSymbolStart = "405">
8083
</Location>
8184
<Location
8285
shouldBeEnabled = "Yes"
8386
ignoreCount = "0"
8487
continueAfterRunningActions = "No"
8588
symbolName = "call_super_pyname"
8689
moduleName = "ScList.so"
90+
usesParentBreakpointCondition = "Yes"
8791
urlString = "file:///Users/paulross/Documents/workspace/PythonExtensionPatterns/src/debugging/XcodeExample/PythonSubclassList/PythonSubclassList/py_call_super.c"
88-
timestampString = "487278611.358352"
92+
timestampString = "564676034.091737"
8993
startingColumnNumber = "9223372036854775807"
9094
endingColumnNumber = "9223372036854775807"
9195
startingLineNumber = "49"

0 commit comments

Comments
 (0)