Issue #7654: enable additional bytes/bytearray tests. Patch by Florent Xicluna.
[python.git] / Mac / Tools / pythonw.c
blobd7a86f26432e2d98c6e3b91ff7c4724e847b665b
1 /*
2 * This wrapper program executes a python executable hidden inside an
3 * application bundle inside the Python framework. This is needed to run
4 * GUI code: some GUI API's don't work unless the program is inside an
5 * application bundle.
7 * This program uses posix_spawn rather than plain execv because we need
8 * slightly more control over how the "real" interpreter is executed.
9 */
10 #include <unistd.h>
11 #include <spawn.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <errno.h>
15 #include <err.h>
16 #include <dlfcn.h>
17 #include <stdlib.h>
18 #include <Python.h>
21 extern char** environ;
24 * Locate the python framework by looking for the
25 * library that contains Py_Initialize.
27 * In a regular framework the structure is:
29 * Python.framework/Versions/2.7
30 * /Python
31 * /Resources/Python.app/Contents/MacOS/Python
33 * In a virtualenv style structure the expected
34 * structure is:
36 * ROOT
37 * /bin/pythonw
38 * /.Python <- the dylib
39 * /.Resources/Python.app/Contents/MacOS/Python
41 * NOTE: virtualenv's are not an officially supported
42 * feature, support for that structure is provided as
43 * a convenience.
45 static char* get_python_path(void)
47 size_t len;
48 Dl_info info;
49 char* end;
50 char* g_path;
52 if (dladdr(Py_Initialize, &info) == 0) {
53 return NULL;
56 len = strlen(info.dli_fname);
58 g_path = malloc(len+60);
59 if (g_path == NULL) {
60 return NULL;
63 strcpy(g_path, info.dli_fname);
64 end = g_path + len - 1;
65 while (end != g_path && *end != '/') {
66 end --;
68 end++;
69 if (end[1] == '.') {
70 end++;
72 strcpy(end, "Resources/Python.app/Contents/MacOS/Python");
74 return g_path;
77 static void
78 setup_spawnattr(posix_spawnattr_t* spawnattr)
80 size_t ocount;
81 size_t count;
82 cpu_type_t cpu_types[1];
83 short flags = 0;
84 #ifdef __LP64__
85 int ch;
86 #endif
88 if ((errno = posix_spawnattr_init(spawnattr)) != 0) {
89 err(2, "posix_spawnattr_int");
90 /* NOTREACHTED */
93 count = 1;
95 /* Run the real python executable using the same architure as this
96 * executable, this allows users to controle the architecture using
97 * "arch -ppc python"
100 #if defined(__ppc64__)
101 cpu_types[0] = CPU_TYPE_POWERPC64;
103 #elif defined(__x86_64__)
104 cpu_types[0] = CPU_TYPE_X86_64;
106 #elif defined(__ppc__)
107 cpu_types[0] = CPU_TYPE_POWERPC;
108 #elif defined(__i386__)
109 cpu_types[0] = CPU_TYPE_X86;
110 #else
111 # error "Unknown CPU"
112 #endif
114 if (posix_spawnattr_setbinpref_np(spawnattr, count,
115 cpu_types, &ocount) == -1) {
116 err(1, "posix_spawnattr_setbinpref");
117 /* NOTREACHTED */
119 if (count != ocount) {
120 fprintf(stderr, "posix_spawnattr_setbinpref failed to copy\n");
121 exit(1);
122 /* NOTREACHTED */
127 * Set flag that causes posix_spawn to behave like execv
129 flags |= POSIX_SPAWN_SETEXEC;
130 if ((errno = posix_spawnattr_setflags(spawnattr, flags)) != 0) {
131 err(1, "posix_spawnattr_setflags");
132 /* NOTREACHTED */
136 int
137 main(int argc, char **argv) {
138 posix_spawnattr_t spawnattr = NULL;
139 char* exec_path = get_python_path();
142 setup_spawnattr(&spawnattr);
143 posix_spawn(NULL, exec_path, NULL,
144 &spawnattr, argv, environ);
145 err(1, "posix_spawn: %s", argv[0]);
146 /* NOTREACHED */