ยปCore Development>Code coverage>Mac/Tools/pythonw.c

Python code coverage for Mac/Tools/pythonw.c

#countcontent
1n/a/*
2n/a * This wrapper program executes a python executable hidden inside an
3n/a * application bundle inside the Python framework. This is needed to run
4n/a * GUI code: some GUI API's don't work unless the program is inside an
5n/a * application bundle.
6n/a *
7n/a * This program uses posix_spawn rather than plain execv because we need
8n/a * slightly more control over how the "real" interpreter is executed.
9n/a *
10n/a * On OSX 10.4 (and earlier) this falls back to using exec because the
11n/a * posix_spawnv functions aren't available there.
12n/a */
13n/a
14n/a#pragma weak_import posix_spawnattr_init
15n/a#pragma weak_import posix_spawnattr_setbinpref_np
16n/a#pragma weak_import posix_spawnattr_setflags
17n/a#pragma weak_import posix_spawn
18n/a
19n/a#include <Python.h>
20n/a#include <unistd.h>
21n/a#ifdef HAVE_SPAWN_H
22n/a#include <spawn.h>
23n/a#endif
24n/a#include <stdio.h>
25n/a#include <string.h>
26n/a#include <errno.h>
27n/a#include <err.h>
28n/a#include <dlfcn.h>
29n/a#include <stdlib.h>
30n/a#include <Python.h>
31n/a
32n/a
33n/aextern char** environ;
34n/a
35n/a/*
36n/a * Locate the python framework by looking for the
37n/a * library that contains Py_Initialize.
38n/a *
39n/a * In a regular framework the structure is:
40n/a *
41n/a * Python.framework/Versions/2.7
42n/a * /Python
43n/a * /Resources/Python.app/Contents/MacOS/Python
44n/a *
45n/a * In a virtualenv style structure the expected
46n/a * structure is:
47n/a *
48n/a * ROOT
49n/a * /bin/pythonw
50n/a * /.Python <- the dylib
51n/a * /.Resources/Python.app/Contents/MacOS/Python
52n/a *
53n/a * NOTE: virtualenv's are not an officially supported
54n/a * feature, support for that structure is provided as
55n/a * a convenience.
56n/a */
57n/astatic char* get_python_path(void)
58n/a{
59n/a size_t len;
60n/a Dl_info info;
61n/a char* end;
62n/a char* g_path;
63n/a
64n/a if (dladdr(Py_Initialize, &info) == 0) {
65n/a return NULL;
66n/a }
67n/a
68n/a len = strlen(info.dli_fname);
69n/a
70n/a g_path = malloc(len+60);
71n/a if (g_path == NULL) {
72n/a return NULL;
73n/a }
74n/a
75n/a strcpy(g_path, info.dli_fname);
76n/a end = g_path + len - 1;
77n/a while (end != g_path && *end != '/') {
78n/a end --;
79n/a }
80n/a end++;
81n/a if (*end == '.') {
82n/a end++;
83n/a }
84n/a strcpy(end, "Resources/Python.app/Contents/MacOS/" PYTHONFRAMEWORK);
85n/a
86n/a return g_path;
87n/a}
88n/a
89n/a#ifdef HAVE_SPAWN_H
90n/astatic void
91n/asetup_spawnattr(posix_spawnattr_t* spawnattr)
92n/a{
93n/a size_t ocount;
94n/a size_t count;
95n/a cpu_type_t cpu_types[1];
96n/a short flags = 0;
97n/a#ifdef __LP64__
98n/a int ch;
99n/a#endif
100n/a
101n/a if ((errno = posix_spawnattr_init(spawnattr)) != 0) {
102n/a err(2, "posix_spawnattr_int");
103n/a /* NOTREACHTED */
104n/a }
105n/a
106n/a count = 1;
107n/a
108n/a /* Run the real python executable using the same architure as this
109n/a * executable, this allows users to controle the architecture using
110n/a * "arch -ppc python"
111n/a */
112n/a
113n/a#if defined(__ppc64__)
114n/a cpu_types[0] = CPU_TYPE_POWERPC64;
115n/a
116n/a#elif defined(__x86_64__)
117n/a cpu_types[0] = CPU_TYPE_X86_64;
118n/a
119n/a#elif defined(__ppc__)
120n/a cpu_types[0] = CPU_TYPE_POWERPC;
121n/a#elif defined(__i386__)
122n/a cpu_types[0] = CPU_TYPE_X86;
123n/a#else
124n/a# error "Unknown CPU"
125n/a#endif
126n/a
127n/a if (posix_spawnattr_setbinpref_np(spawnattr, count,
128n/a cpu_types, &ocount) == -1) {
129n/a err(1, "posix_spawnattr_setbinpref");
130n/a /* NOTREACHTED */
131n/a }
132n/a if (count != ocount) {
133n/a fprintf(stderr, "posix_spawnattr_setbinpref failed to copy\n");
134n/a exit(1);
135n/a /* NOTREACHTED */
136n/a }
137n/a
138n/a
139n/a /*
140n/a * Set flag that causes posix_spawn to behave like execv
141n/a */
142n/a flags |= POSIX_SPAWN_SETEXEC;
143n/a if ((errno = posix_spawnattr_setflags(spawnattr, flags)) != 0) {
144n/a err(1, "posix_spawnattr_setflags");
145n/a /* NOTREACHTED */
146n/a }
147n/a}
148n/a#endif
149n/a
150n/aint
151n/amain(int argc, char **argv) {
152n/a char* exec_path = get_python_path();
153n/a
154n/a /*
155n/a * Let argv[0] refer to the new interpreter. This is needed to
156n/a * get the effect we want on OSX 10.5 or earlier. That is, without
157n/a * changing argv[0] the real interpreter won't have access to
158n/a * the Window Server.
159n/a */
160n/a argv[0] = exec_path;
161n/a
162n/a#ifdef HAVE_SPAWN_H
163n/a /* We're weak-linking to posix-spawnv to ensure that
164n/a * an executable build on 10.5 can work on 10.4.
165n/a */
166n/a if (posix_spawn != NULL) {
167n/a posix_spawnattr_t spawnattr = NULL;
168n/a
169n/a setup_spawnattr(&spawnattr);
170n/a posix_spawn(NULL, exec_path, NULL,
171n/a &spawnattr, argv, environ);
172n/a err(1, "posix_spawn: %s", exec_path);
173n/a }
174n/a#endif
175n/a execve(exec_path, argv, environ);
176n/a err(1, "execve: %s", argv[0]);
177n/a /* NOTREACHED */
178n/a}