##// END OF EJS Templates
exewrapper: report name of failed DLL in error message...
Adrian Buehlmann -
r26662:d215def5 default
parent child Browse files
Show More
@@ -1,164 +1,164
1 /*
1 /*
2 exewrapper.c - wrapper for calling a python script on Windows
2 exewrapper.c - wrapper for calling a python script on Windows
3
3
4 Copyright 2012 Adrian Buehlmann <adrian@cadifra.com> and others
4 Copyright 2012 Adrian Buehlmann <adrian@cadifra.com> and others
5
5
6 This software may be used and distributed according to the terms of the
6 This software may be used and distributed according to the terms of the
7 GNU General Public License version 2 or any later version.
7 GNU General Public License version 2 or any later version.
8 */
8 */
9
9
10 #include <stdio.h>
10 #include <stdio.h>
11 #include <windows.h>
11 #include <windows.h>
12
12
13 #include "hgpythonlib.h"
13 #include "hgpythonlib.h"
14
14
15 #ifdef __GNUC__
15 #ifdef __GNUC__
16 int strcat_s(char *d, size_t n, const char *s)
16 int strcat_s(char *d, size_t n, const char *s)
17 {
17 {
18 return !strncat(d, s, n);
18 return !strncat(d, s, n);
19 }
19 }
20 int strcpy_s(char *d, size_t n, const char *s)
20 int strcpy_s(char *d, size_t n, const char *s)
21 {
21 {
22 return !strncpy(d, s, n);
22 return !strncpy(d, s, n);
23 }
23 }
24 #endif
24 #endif
25
25
26
26
27 static char pyscript[MAX_PATH + 10];
27 static char pyscript[MAX_PATH + 10];
28 static char pyhome[MAX_PATH + 10];
28 static char pyhome[MAX_PATH + 10];
29 static char envpyhome[MAX_PATH + 10];
29 static char envpyhome[MAX_PATH + 10];
30 static char pydllfile[MAX_PATH + 10];
30 static char pydllfile[MAX_PATH + 10];
31
31
32 int main(int argc, char *argv[])
32 int main(int argc, char *argv[])
33 {
33 {
34 char *p;
34 char *p;
35 int ret;
35 int ret;
36 int i;
36 int i;
37 int n;
37 int n;
38 char **pyargv;
38 char **pyargv;
39 WIN32_FIND_DATA fdata;
39 WIN32_FIND_DATA fdata;
40 HANDLE hfind;
40 HANDLE hfind;
41 const char *err;
41 const char *err;
42 HMODULE pydll;
42 HMODULE pydll;
43 void (__cdecl *Py_SetPythonHome)(char *home);
43 void (__cdecl *Py_SetPythonHome)(char *home);
44 int (__cdecl *Py_Main)(int argc, char *argv[]);
44 int (__cdecl *Py_Main)(int argc, char *argv[]);
45
45
46 if (GetModuleFileName(NULL, pyscript, sizeof(pyscript)) == 0)
46 if (GetModuleFileName(NULL, pyscript, sizeof(pyscript)) == 0)
47 {
47 {
48 err = "GetModuleFileName failed";
48 err = "GetModuleFileName failed";
49 goto bail;
49 goto bail;
50 }
50 }
51
51
52 p = strrchr(pyscript, '.');
52 p = strrchr(pyscript, '.');
53 if (p == NULL) {
53 if (p == NULL) {
54 err = "malformed module filename";
54 err = "malformed module filename";
55 goto bail;
55 goto bail;
56 }
56 }
57 *p = 0; /* cut trailing ".exe" */
57 *p = 0; /* cut trailing ".exe" */
58 strcpy_s(pyhome, sizeof(pyhome), pyscript);
58 strcpy_s(pyhome, sizeof(pyhome), pyscript);
59
59
60 hfind = FindFirstFile(pyscript, &fdata);
60 hfind = FindFirstFile(pyscript, &fdata);
61 if (hfind != INVALID_HANDLE_VALUE) {
61 if (hfind != INVALID_HANDLE_VALUE) {
62 /* pyscript exists, close handle */
62 /* pyscript exists, close handle */
63 FindClose(hfind);
63 FindClose(hfind);
64 } else {
64 } else {
65 /* file pyscript isn't there, take <pyscript>exe.py */
65 /* file pyscript isn't there, take <pyscript>exe.py */
66 strcat_s(pyscript, sizeof(pyscript), "exe.py");
66 strcat_s(pyscript, sizeof(pyscript), "exe.py");
67 }
67 }
68
68
69 pydll = NULL;
69 pydll = NULL;
70 if (GetEnvironmentVariable("PYTHONHOME", envpyhome,
70 if (GetEnvironmentVariable("PYTHONHOME", envpyhome,
71 sizeof(envpyhome)) == 0)
71 sizeof(envpyhome)) == 0)
72 {
72 {
73 /* environment var PYTHONHOME is not set */
73 /* environment var PYTHONHOME is not set */
74
74
75 p = strrchr(pyhome, '\\');
75 p = strrchr(pyhome, '\\');
76 if (p == NULL) {
76 if (p == NULL) {
77 err = "can't find backslash in module filename";
77 err = "can't find backslash in module filename";
78 goto bail;
78 goto bail;
79 }
79 }
80 *p = 0; /* cut at directory */
80 *p = 0; /* cut at directory */
81
81
82 /* check for private Python of HackableMercurial */
82 /* check for private Python of HackableMercurial */
83 strcat_s(pyhome, sizeof(pyhome), "\\hg-python");
83 strcat_s(pyhome, sizeof(pyhome), "\\hg-python");
84
84
85 hfind = FindFirstFile(pyhome, &fdata);
85 hfind = FindFirstFile(pyhome, &fdata);
86 if (hfind != INVALID_HANDLE_VALUE) {
86 if (hfind != INVALID_HANDLE_VALUE) {
87 /* path pyhome exists, let's use it */
87 /* path pyhome exists, let's use it */
88 FindClose(hfind);
88 FindClose(hfind);
89 strcpy_s(pydllfile, sizeof(pydllfile), pyhome);
89 strcpy_s(pydllfile, sizeof(pydllfile), pyhome);
90 strcat_s(pydllfile, sizeof(pydllfile), "\\" HGPYTHONLIB);
90 strcat_s(pydllfile, sizeof(pydllfile), "\\" HGPYTHONLIB);
91 pydll = LoadLibrary(pydllfile);
91 pydll = LoadLibrary(pydllfile);
92 if (pydll == NULL) {
92 if (pydll == NULL) {
93 err = "failed to load private Python DLL";
93 err = "failed to load private Python DLL";
94 goto bail;
94 goto bail;
95 }
95 }
96 Py_SetPythonHome = (void*)GetProcAddress(pydll,
96 Py_SetPythonHome = (void*)GetProcAddress(pydll,
97 "Py_SetPythonHome");
97 "Py_SetPythonHome");
98 if (Py_SetPythonHome == NULL) {
98 if (Py_SetPythonHome == NULL) {
99 err = "failed to get Py_SetPythonHome";
99 err = "failed to get Py_SetPythonHome";
100 goto bail;
100 goto bail;
101 }
101 }
102 Py_SetPythonHome(pyhome);
102 Py_SetPythonHome(pyhome);
103 }
103 }
104 }
104 }
105
105
106 if (pydll == NULL) {
106 if (pydll == NULL) {
107 pydll = LoadLibrary(HGPYTHONLIB);
107 pydll = LoadLibrary(HGPYTHONLIB);
108 if (pydll == NULL) {
108 if (pydll == NULL) {
109 err = "failed to load Python DLL";
109 err = "failed to load Python DLL " HGPYTHONLIB ".dll";
110 goto bail;
110 goto bail;
111 }
111 }
112 }
112 }
113
113
114 Py_Main = (void*)GetProcAddress(pydll, "Py_Main");
114 Py_Main = (void*)GetProcAddress(pydll, "Py_Main");
115 if (Py_Main == NULL) {
115 if (Py_Main == NULL) {
116 err = "failed to get Py_Main";
116 err = "failed to get Py_Main";
117 goto bail;
117 goto bail;
118 }
118 }
119
119
120 /*
120 /*
121 Only add the pyscript to the args, if it's not already there. It may
121 Only add the pyscript to the args, if it's not already there. It may
122 already be there, if the script spawned a child process of itself, in
122 already be there, if the script spawned a child process of itself, in
123 the same way as it got called, that is, with the pyscript already in
123 the same way as it got called, that is, with the pyscript already in
124 place. So we optionally accept the pyscript as the first argument
124 place. So we optionally accept the pyscript as the first argument
125 (argv[1]), letting our exe taking the role of the python interpreter.
125 (argv[1]), letting our exe taking the role of the python interpreter.
126 */
126 */
127 if (argc >= 2 && strcmp(argv[1], pyscript) == 0) {
127 if (argc >= 2 && strcmp(argv[1], pyscript) == 0) {
128 /*
128 /*
129 pyscript is already in the args, so there is no need to copy
129 pyscript is already in the args, so there is no need to copy
130 the args and we can directly call the python interpreter with
130 the args and we can directly call the python interpreter with
131 the original args.
131 the original args.
132 */
132 */
133 return Py_Main(argc, argv);
133 return Py_Main(argc, argv);
134 }
134 }
135
135
136 /*
136 /*
137 Start assembling the args for the Python interpreter call. We put the
137 Start assembling the args for the Python interpreter call. We put the
138 name of our exe (argv[0]) in the position where the python.exe
138 name of our exe (argv[0]) in the position where the python.exe
139 canonically is, and insert the pyscript next.
139 canonically is, and insert the pyscript next.
140 */
140 */
141 pyargv = malloc((argc + 5) * sizeof(char*));
141 pyargv = malloc((argc + 5) * sizeof(char*));
142 if (pyargv == NULL) {
142 if (pyargv == NULL) {
143 err = "not enough memory";
143 err = "not enough memory";
144 goto bail;
144 goto bail;
145 }
145 }
146 n = 0;
146 n = 0;
147 pyargv[n++] = argv[0];
147 pyargv[n++] = argv[0];
148 pyargv[n++] = pyscript;
148 pyargv[n++] = pyscript;
149
149
150 /* copy remaining args from the command line */
150 /* copy remaining args from the command line */
151 for (i = 1; i < argc; i++)
151 for (i = 1; i < argc; i++)
152 pyargv[n++] = argv[i];
152 pyargv[n++] = argv[i];
153 /* argv[argc] is guaranteed to be NULL, so we forward that guarantee */
153 /* argv[argc] is guaranteed to be NULL, so we forward that guarantee */
154 pyargv[n] = NULL;
154 pyargv[n] = NULL;
155
155
156 ret = Py_Main(n, pyargv); /* The Python interpreter call */
156 ret = Py_Main(n, pyargv); /* The Python interpreter call */
157
157
158 free(pyargv);
158 free(pyargv);
159 return ret;
159 return ret;
160
160
161 bail:
161 bail:
162 fprintf(stderr, "abort: %s\n", err);
162 fprintf(stderr, "abort: %s\n", err);
163 return 255;
163 return 255;
164 }
164 }
General Comments 0
You need to be logged in to leave comments. Login now