10
10
// source files extracted from MinGW-w64:
11
11
// https://sourceforge.net/projects/mingw-w64/files/mingw-w64/mingw-w64-release/mingw-w64-v6.0.0.tar.bz2
12
12
//
13
- // assumes VC tools cl, lib and ml installed and found through path
13
+ // assumes dmd & VC tools cl, lib, link and ml installed and found through path
14
14
// and configured to the appropriate architecture
15
15
//
16
16
@@ -87,23 +87,23 @@ void sanitizeDef(string defFile)
87
87
{
88
88
patchLines(defFile, defFile, (line)
89
89
{
90
+ if (line.length == 0 || line[0 ] == ' ;' )
91
+ return line;
92
+
90
93
if (line == " LIBRARY vcruntime140_app" )
91
94
return ` LIBRARY "vcruntime140.dll"` ;
92
95
93
96
// The MinGW-w64 .def files specify weak external symbols as 'alias == realName'.
94
- if (line.length > 1 && line[0 ] != ' ;' )
97
+ const i = line.indexOf(" ==" );
98
+ if (i > 0 )
95
99
{
96
- const i = line.indexOf(" == " );
97
- if (i > 0 )
100
+ const weakName = strip(line[0 .. i]);
101
+ const realName = strip(line[i+ 2 .. $]);
102
+
103
+ if (weakName.indexOf(' ' ) < 0 && realName.indexOf(' ' ) < 0 )
98
104
{
99
- const weakName = line[0 .. i];
100
- const realName = line[i+ 4 .. $];
101
-
102
- if (weakName.indexOf(' ' ) < 0 && realName.indexOf(' ' ) < 0 )
103
- {
104
- weakSymbols[weakName] = realName;
105
- return " ;" ~ line;
106
- }
105
+ weakSymbols[weakName] = realName;
106
+ return " ;" ~ line;
107
107
}
108
108
}
109
109
@@ -118,7 +118,11 @@ void sanitizeDef(string defFile)
118
118
119
119
// Don't export function 'atexit'; we have our own in msvc_atexit.c.
120
120
if (line == " atexit" )
121
- return " " ;
121
+ return " ;atexit" ;
122
+
123
+ // An apparent bug in lib32/shell32.def (there's 'ExtractIconW@12' too).
124
+ if (line == " ExtractIconW@" )
125
+ return " ;ExtractIconW@" ;
122
126
123
127
return line;
124
128
});
@@ -156,6 +160,12 @@ void copyDefs(string inDir, string outDir)
156
160
157
161
void def2implib (string defFile)
158
162
{
163
+ if (! x64)
164
+ {
165
+ if (defWithStdcallMangling2implib(defFile))
166
+ return ;
167
+ }
168
+
159
169
const libFile = setExtension(defFile, " .lib" );
160
170
const arch = x64 ? " X64" : " X86" ;
161
171
runShell(` lib /MACHINE:` ~ arch ~ ` "/DEF:` ~ defFile ~ ` " "/OUT:` ~ libFile ~ ` "` );
@@ -182,6 +192,118 @@ string quote(string arg)
182
192
return ` "` ~ arg ~ ` "` ;
183
193
}
184
194
195
+ /**
196
+ * x86: the WinAPI symbol names in the .def files are stdcall-mangled
197
+ * (trailing `@<N>`). These mangled names are required in the import
198
+ * library, but the names of the DLL exports don't feature the stdcall
199
+ * suffix.
200
+ * `lib /DEF` doesn't support the required renaming functionality, so
201
+ * we have to go through compiling a D file with the symbols and
202
+ * building a DLL with renamed exports to get the appropriate import
203
+ * library.
204
+ */
205
+ bool defWithStdcallMangling2implib (string defFile)
206
+ {
207
+ import std.regex : ctRegex, matchFirst;
208
+
209
+ string [] functions;
210
+ string [] fields;
211
+ bool hasRenamedStdcall = false ;
212
+
213
+ patchLines(defFile, defFile, (line)
214
+ {
215
+ if (line.length == 0 || line[0 ] == ' ;' ||
216
+ line.startsWith(" LIBRARY " ) || line.startsWith(" EXPORTS" ))
217
+ return line;
218
+
219
+ if (line.endsWith(" DATA" ))
220
+ {
221
+ fields ~= line[0 .. $- 5 ];
222
+ return line;
223
+ }
224
+
225
+ // include fastcall mangle (like stdcall, with additional leading '@')
226
+ enum re = ctRegex! r " ^@?([a-zA-Z0-9_]+)(@[0-9]+)" ;
227
+ if (const m = matchFirst(line, re))
228
+ {
229
+ string lineSuffix = line[m[0 ].length .. $];
230
+ if (lineSuffix.startsWith(m[2 ])) // e.g., 'JetAddColumnA@28@28'
231
+ {
232
+ /**
233
+ * Actually not to be renamed, symbol is exported in mangled form.
234
+ * Treat it like 'JetAddColumnA@28' though, because some libraries
235
+ * export the same function as both 'JetAddColumnA' and 'JetAddColumnA@28',
236
+ * and I don't know how to replicate that with our approach.
237
+ */
238
+ lineSuffix = lineSuffix[m[2 ].length .. $];
239
+ }
240
+
241
+ assert (! lineSuffix.startsWith(" =" )); // renamings not supported
242
+
243
+ hasRenamedStdcall = true ;
244
+ functions ~= m[1 ];
245
+ // keep the line suffix (e.g., ' @100' => ordinal 100)
246
+ return m[0 ] ~ " =" ~ m[1 ] ~ lineSuffix;
247
+ }
248
+
249
+ const firstSpaceIndex = line.indexOf(' ' );
250
+ const strippedLine = firstSpaceIndex < 0 ? line : line[0 .. firstSpaceIndex];
251
+ const equalsIndex = strippedLine.indexOf(' =' );
252
+ const functionName = equalsIndex > 0 ? strippedLine[equalsIndex+ 1 .. $] : strippedLine;
253
+ functions ~= functionName;
254
+ return line;
255
+ });
256
+
257
+ if (! hasRenamedStdcall)
258
+ return false ;
259
+
260
+ string src = " module dummy;\n " ;
261
+ alias Emitter = string delegate ();
262
+ void emitOnce (ref bool [string ] emittedSymbols, string symbolName, Emitter emitter)
263
+ {
264
+ if (symbolName ! in emittedSymbols)
265
+ {
266
+ src ~= emitter() ~ " \n " ;
267
+ emittedSymbols[symbolName] = true ;
268
+ }
269
+ }
270
+
271
+ bool [string ] emittedFunctions;
272
+ foreach (i, name; functions)
273
+ {
274
+ emitOnce(emittedFunctions, name, ()
275
+ {
276
+ const linkage = name[0 ] == ' ?' ? " C++" : " C" ;
277
+ return ` pragma(mangle, "%s") extern(%s) void func%d() {}` .format(name, linkage, i);
278
+ });
279
+ }
280
+
281
+ bool [string ] emittedFields;
282
+ foreach (i, name; fields)
283
+ {
284
+ emitOnce(emittedFields, name, ()
285
+ {
286
+ const linkage = name[0 ] == ' _' ? " C" : " C++" ;
287
+ return ` pragma(mangle, "%s") extern(%s) __gshared int field%d;` .format(name, linkage, i);
288
+ });
289
+ }
290
+
291
+ const dFile = setExtension(defFile, " .d" );
292
+ const objFile = setExtension(defFile, " .obj" );
293
+ const dllFile = setExtension(defFile, " .dll" );
294
+
295
+ std.file.write (dFile, src);
296
+ runShell(` dmd -c -betterC -m32mscoff "-of=` ~ objFile ~ ` " ` ~ quote(dFile));
297
+ runShell(" link /NOD /NOENTRY /DLL " ~ quote(objFile) ~ ` "/OUT:` ~ dllFile ~ ` " "/DEF:` ~ defFile ~ ` "` );
298
+
299
+ std.file.remove (dFile);
300
+ std.file.remove (objFile);
301
+ std.file.remove (dllFile);
302
+ std.file.remove (setExtension(dllFile, " .exp" ));
303
+
304
+ return true ;
305
+ }
306
+
185
307
void c2lib (string outDir, string cFile)
186
308
{
187
309
const obj = buildPath(outDir, baseName(cFile).setExtension(" .obj" ));
0 commit comments