ยป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#include <mach-o/dyld.h>
32n/a
33n/a
34n/aextern char** environ;
35n/a
36n/a/*
37n/a * Locate the python framework by looking for the
38n/a * library that contains Py_Initialize.
39n/a *
40n/a * In a regular framework the structure is:
41n/a *
42n/a * Python.framework/Versions/2.7
43n/a * /Python
44n/a * /Resources/Python.app/Contents/MacOS/Python
45n/a *
46n/a * In a virtualenv style structure the expected
47n/a * structure is:
48n/a *
49n/a * ROOT
50n/a * /bin/pythonw
51n/a * /.Python <- the dylib
52n/a * /.Resources/Python.app/Contents/MacOS/Python
53n/a *
54n/a * NOTE: virtualenv's are not an officially supported
55n/a * feature, support for that structure is provided as
56n/a * a convenience.
57n/a */
58n/astatic char* get_python_path(void)
59n/a{
60n/a size_t len;
61n/a Dl_info info;
62n/a char* end;
63n/a char* g_path;
64n/a
65n/a if (dladdr(Py_Initialize, &info) == 0) {
66n/a return NULL;
67n/a }
68n/a
69n/a len = strlen(info.dli_fname);
70n/a
71n/a g_path = malloc(len+60);
72n/a if (g_path == NULL) {
73n/a return NULL;
74n/a }
75n/a
76n/a strcpy(g_path, info.dli_fname);
77n/a end = g_path + len - 1;
78n/a while (end != g_path && *end != '/') {
79n/a end --;
80n/a }
81n/a end++;
82n/a if (*end == '.') {
83n/a end++;
84n/a }
85n/a strcpy(end, "Resources/Python.app/Contents/MacOS/" PYTHONFRAMEWORK);
86n/a
87n/a return g_path;
88n/a}
89n/a
90n/a#ifdef HAVE_SPAWN_H
91n/astatic void
92n/asetup_spawnattr(posix_spawnattr_t* spawnattr)
93n/a{
94n/a size_t ocount;
95n/a size_t count;
96n/a cpu_type_t cpu_types[1];
97n/a short flags = 0;
98n/a#ifdef __LP64__
99n/a int ch;
100n/a#endif
101n/a
102n/a if ((errno = posix_spawnattr_init(spawnattr)) != 0) {
103n/a err(2, "posix_spawnattr_int");
104n/a /* NOTREACHTED */
105n/a }
106n/a
107n/a count = 1;
108n/a
109n/a /* Run the real python executable using the same architecture as this
110n/a * executable, this allows users to control the architecture using
111n/a * "arch -ppc python"
112n/a */
113n/a
114n/a#if defined(__ppc64__)
115n/a cpu_types[0] = CPU_TYPE_POWERPC64;
116n/a
117n/a#elif defined(__x86_64__)
118n/a cpu_types[0] = CPU_TYPE_X86_64;
119n/a
120n/a#elif defined(__ppc__)
121n/a cpu_types[0] = CPU_TYPE_POWERPC;
122n/a#elif defined(__i386__)
123n/a cpu_types[0] = CPU_TYPE_X86;
124n/a#else
125n/a# error "Unknown CPU"
126n/a#endif
127n/a
128n/a if (posix_spawnattr_setbinpref_np(spawnattr, count,
129n/a cpu_types, &ocount) == -1) {
130n/a err(1, "posix_spawnattr_setbinpref");
131n/a /* NOTREACHTED */
132n/a }
133n/a if (count != ocount) {
134n/a fprintf(stderr, "posix_spawnattr_setbinpref failed to copy\n");
135n/a exit(1);
136n/a /* NOTREACHTED */
137n/a }
138n/a
139n/a
140n/a /*
141n/a * Set flag that causes posix_spawn to behave like execv
142n/a */
143n/a flags |= POSIX_SPAWN_SETEXEC;
144n/a if ((errno = posix_spawnattr_setflags(spawnattr, flags)) != 0) {
145n/a err(1, "posix_spawnattr_setflags");
146n/a /* NOTREACHTED */
147n/a }
148n/a}
149n/a#endif
150n/a
151n/aint
152n/amain(int argc, char **argv) {
153n/a char* exec_path = get_python_path();
154n/a static char path[PATH_MAX * 2];
155n/a static char real_path[PATH_MAX * 2];
156n/a int status;
157n/a uint32_t size = PATH_MAX * 2;
158n/a
159n/a /* Set the original executable path in the environment. */
160n/a status = _NSGetExecutablePath(path, &size);
161n/a if (status == 0) {
162n/a /*
163n/a * Note: don't call 'realpath', that will
164n/a * erase symlink information, and that
165n/a * breaks "pyvenv --symlink"
166n/a *
167n/a * It is nice to have the directory name
168n/a * as a cleaned up absolute path though,
169n/a * therefore call realpath on dirname(path)
170n/a */
171n/a char* slash = strrchr(path, '/');
172n/a if (slash) {
173n/a char replaced;
174n/a replaced = slash[1];
175n/a slash[1] = 0;
176n/a if (realpath(path, real_path) == NULL) {
177n/a err(1, "realpath: %s", path);
178n/a }
179n/a slash[1] = replaced;
180n/a if (strlcat(real_path, slash, sizeof(real_path)) > sizeof(real_path)) {
181n/a errno = EINVAL;
182n/a err(1, "realpath: %s", path);
183n/a }
184n/a
185n/a } else {
186n/a if (realpath(".", real_path) == NULL) {
187n/a err(1, "realpath: %s", path);
188n/a }
189n/a if (strlcat(real_path, "/", sizeof(real_path)) > sizeof(real_path)) {
190n/a errno = EINVAL;
191n/a err(1, "realpath: %s", path);
192n/a }
193n/a if (strlcat(real_path, path, sizeof(real_path)) > sizeof(real_path)) {
194n/a errno = EINVAL;
195n/a err(1, "realpath: %s", path);
196n/a }
197n/a }
198n/a
199n/a setenv("__PYVENV_LAUNCHER__", real_path, 1);
200n/a }
201n/a
202n/a /*
203n/a * Let argv[0] refer to the new interpreter. This is needed to
204n/a * get the effect we want on OSX 10.5 or earlier. That is, without
205n/a * changing argv[0] the real interpreter won't have access to
206n/a * the Window Server.
207n/a */
208n/a argv[0] = exec_path;
209n/a
210n/a#ifdef HAVE_SPAWN_H
211n/a /* We're weak-linking to posix-spawnv to ensure that
212n/a * an executable build on 10.5 can work on 10.4.
213n/a */
214n/a if (posix_spawn != NULL) {
215n/a posix_spawnattr_t spawnattr = NULL;
216n/a
217n/a setup_spawnattr(&spawnattr);
218n/a posix_spawn(NULL, exec_path, NULL,
219n/a &spawnattr, argv, environ);
220n/a err(1, "posix_spawn: %s", exec_path);
221n/a }
222n/a#endif
223n/a execve(exec_path, argv, environ);
224n/a err(1, "execve: %s", argv[0]);
225n/a /* NOTREACHED */
226n/a}