4 * Symbol merging utility for Windows DLL's.
6 * Portable Windows Library
8 * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
27 * Revision 1.15 2004/06/05 04:55:29 rjongbloed
28 * Removed the unmangled versions of symbols to eliminate problems withthe line length
29 * exceeding MSVC linkers internal limits. Has added benefit of making files half the size.
31 * Revision 1.14 2004/05/22 07:41:32 rjongbloed
32 * Added ability to specify command line override of the "dumpbin" program run
33 * to get library symbols, very useful for debugging.
35 * Revision 1.13 2004/04/09 07:03:23 rjongbloed
36 * Added ability to get the output to DUMPBIN sent to a file.
38 * Revision 1.12 2004/04/03 06:54:32 rjongbloed
39 * Many and various changes to support new Visual C++ 2003
41 * Revision 1.11 2003/10/30 11:27:12 rjongbloed
42 * Fixed ability to specify partial path for -x parameter.
44 * Revision 1.10 2003/02/11 07:00:17 robertj
45 * Added copying def file to a backup version before alteration from read only.
47 * Revision 1.9 2002/06/13 05:51:01 robertj
48 * Added ignore of some inherently private symbols exported by libraru eg debug
49 * line number info and real number constants.
51 * Revision 1.8 2000/12/18 07:31:10 robertj
52 * Fixed minor irritation with DEF file being reordered when symbol added.
54 * Revision 1.7 2000/04/29 05:48:22 robertj
55 * Added error and progress reporting in searching path for external DEF files.
57 * Revision 1.6 2000/04/29 05:01:49 robertj
58 * Added multiple external DEF file capability (-x flag).
59 * Added directory search path argument for external DEF files.
60 * Fixed bug for symbols in external DEF file actively removed from merged DEF file.
61 * Added copyright notice.
66 #include <ptlib/pipechan.h>
69 PDECLARE_CLASS(Symbol
, PCaselessString
)
71 Symbol(const PString
& sym
, const PString
& cpp
, PINDEX ord
= 0, BOOL ext
= FALSE
)
72 : PCaselessString(sym
), unmangled(cpp
) { ordinal
= ord
; external
= ext
; }
74 void SetOrdinal(PINDEX ord
) { ordinal
= ord
; }
75 BOOL
IsExternal() const { return external
; }
77 void PrintOn(ostream
& s
) const
78 { s
<< " " << theArray
<< " @" << ordinal
<< " NONAME\n"; }
86 PSORTED_LIST(SortedSymbolList
, Symbol
);
89 PDECLARE_CLASS(MergeSym
, PProcess
)
95 PCREATE_PROCESS(MergeSym
);
99 : PProcess("Equivalence", "MergeSym", 1, 4, ReleaseCode
, 0)
104 void MergeSym::Main()
106 cout
<< GetName() << " version " << GetVersion(TRUE
)
107 << " on " << GetOSClass() << ' ' << GetOSName()
108 << " by " << GetManufacturer() << endl
;
110 PArgList
& args
= GetArguments();
111 args
.Parse("vsd:x:I:");
113 PFilePath lib_filename
, def_filename
;
115 switch (args
.GetCount()) {
117 def_filename
= args
[1];
118 lib_filename
= args
[0];
122 lib_filename
= def_filename
= args
[0];
123 def_filename
.SetType(".def");
127 PError
<< "usage: MergeSym [ -v ] [ -s ] [ -d dumpbin ] [ -x deffile[.def] ] [-I deffilepath ] libfile[.lib] [ deffile[.def] ]";
128 SetTerminationValue(1);
132 if (lib_filename
.GetType().IsEmpty())
133 lib_filename
.SetType(".lib");
135 if (!PFile::Exists(lib_filename
)) {
136 PError
<< "MergeSym: library file " << lib_filename
<< " does not exist.\n";
137 SetTerminationValue(1);
141 if (def_filename
.GetType().IsEmpty())
142 def_filename
.SetType(".def");
144 SortedSymbolList def_symbols
;
146 if (args
.HasOption('x')) {
147 PStringArray include_path
;
148 if (args
.HasOption('I'))
149 include_path
= args
.GetOptionString('I').Tokenise(';', FALSE
);
150 include_path
.InsertAt(0, new PString());
151 PStringArray file_list
= args
.GetOptionString('x').Lines();
152 for (PINDEX ext_index
= 0; ext_index
< file_list
.GetSize(); ext_index
++) {
153 PString base_ext_filename
= file_list
[ext_index
];
154 PString ext_filename
= base_ext_filename
;
155 if (PFilePath(ext_filename
).GetType().IsEmpty())
156 ext_filename
+= ".def";
158 PINDEX previous_def_symbols_size
= def_symbols
.GetSize();
160 for (PINDEX inc_index
= 0; inc_index
< include_path
.GetSize(); inc_index
++) {
161 PString trial_filename
= PDirectory(include_path
[inc_index
]) + ext_filename
;
162 if (args
.HasOption('v'))
163 cout
<< "\nTrying " << trial_filename
<< " ..." << flush
;
165 if (ext
.Open(trial_filename
, PFile::ReadOnly
)) {
166 if (args
.HasOption('v'))
167 cout
<< "\nReading external symbols from " << ext
.GetFilePath() << " ..." << flush
;
170 PCaselessString line
;
173 prefix
= line
.Find("EXPORTS") == P_MAX_INDEX
;
176 while (isspace(line
[start
]))
179 while (line
[end
] != '\0' && !isspace(line
[end
]))
181 def_symbols
.Append(new Symbol(line(start
, end
-1), "", 0, TRUE
));
182 if (args
.HasOption('v') && def_symbols
.GetSize()%100 == 0)
183 cout
<< '.' << flush
;
189 if (inc_index
>= include_path
.GetSize())
190 PError
<< "MergeSym: external symbol file \"" << base_ext_filename
<< "\" not found.\n";
191 if (args
.HasOption('v'))
192 cout
<< '\n' << (def_symbols
.GetSize() - previous_def_symbols_size
)
193 << " symbols read." << endl
;
197 PStringList def_file_lines
;
198 PINDEX max_ordinal
= 0;
202 if (def
.Open(def_filename
, PFile::ReadOnly
)) {
203 if (args
.HasOption('v'))
204 cout
<< "Reading existing ordinals..." << flush
;
207 PCaselessString line
;
210 def_file_lines
.AppendString(line
);
211 if (line
.Find("EXPORTS") != P_MAX_INDEX
)
216 while (isspace(line
[start
]))
219 while (line
[end
] != '\0' && !isspace(line
[end
]))
221 PINDEX ordpos
= line
.Find('@', end
);
222 if (ordpos
!= P_MAX_INDEX
) {
223 PINDEX ordinal
= line
.Mid(ordpos
+1).AsInteger();
224 if (ordinal
> max_ordinal
)
225 max_ordinal
= ordinal
;
226 PINDEX unmanglepos
= line
.Find(';', ordpos
);
227 if (unmanglepos
!= P_MAX_INDEX
)
229 Symbol
sym(line(start
, end
-1), line
.Mid(unmanglepos
), ordinal
);
230 if (def_symbols
.GetValuesIndex(sym
) == P_MAX_INDEX
)
231 def_symbols
.Append(new Symbol(sym
));
233 if (args
.HasOption('v') && def_symbols
.GetSize()%100 == 0)
234 cout
<< '.' << flush
;
239 if (args
.HasOption('v'))
240 cout
<< '\n' << removed
<< " symbols read." << endl
;
243 def_file_lines
.AppendString("LIBRARY " + def_filename
.GetTitle());
244 def_file_lines
.AppendString("EXPORTS");
247 if (args
.HasOption('v'))
248 cout
<< "Reading library symbols..." << flush
;
249 PINDEX linecount
= 0;
250 SortedSymbolList lib_symbols
;
251 PString dumpbin
= args
.GetOptionString('d', "dumpbin");
252 PPipeChannel
pipe(dumpbin
+ " /symbols '" + lib_filename
+ "'", PPipeChannel::ReadOnly
);
253 if (!pipe
.IsOpen()) {
254 PError
<< "\nMergeSym: could not run \"" << dumpbin
<< "\".\n";
255 SetTerminationValue(2);
260 if (args
.HasOption('s')) {
261 PFilePath sym_filename
= def_filename
;
262 sym_filename
.SetType(".sym");
263 if (!symfile
.Open(sym_filename
, PFile::WriteOnly
))
264 cerr
<< "Could not open symbol file " << sym_filename
<< endl
;
267 while (!pipe
.eof()) {
272 char * namepos
= strchr(line
, '|');
273 if (namepos
!= NULL
) {
275 while (*++namepos
== ' ');
276 if (strstr(line
, " UNDEF ") == NULL
&&
277 strstr(line
, " External ") != NULL
&&
278 strstr(namepos
, "deleting destructor") == NULL
) {
279 int namelen
= strcspn(namepos
, "\r\n\t ");
280 PString
name(namepos
, namelen
);
281 if (strncmp(name
, "??_C@_", 6) != 0 &&
282 strncmp(name
, "__real@", 7) != 0 &&
283 strncmp(name
, "?__LINE__Var@", 13) != 0 &&
284 lib_symbols
.GetValuesIndex(name
) == P_MAX_INDEX
) {
285 const char * unmangled
= strchr(namepos
+namelen
, '(');
286 if (unmangled
== NULL
)
290 char * endunmangle
= strrchr(unmangled
, ')');
291 if (endunmangle
!= NULL
)
294 lib_symbols
.Append(new Symbol(name
, unmangled
));
298 if (args
.HasOption('v') && linecount
%500 == 0)
299 cout
<< '.' << flush
;
303 if (args
.HasOption('v'))
304 cout
<< '\n' << lib_symbols
.GetSize() << " symbols read.\n"
305 "Sorting symbols... " << flush
;
308 for (i
= 0; i
< def_symbols
.GetSize(); i
++) {
309 if (lib_symbols
.GetValuesIndex(def_symbols
[i
]) != P_MAX_INDEX
&&
310 !def_symbols
[i
].IsExternal())
315 for (i
= 0; i
< lib_symbols
.GetSize(); i
++) {
316 if (def_symbols
.GetValuesIndex(lib_symbols
[i
]) == P_MAX_INDEX
) {
317 lib_symbols
[i
].SetOrdinal(++max_ordinal
);
322 if (added
== 0 && removed
== 0)
323 cout
<< "\nNo changes to symbols.\n";
325 if (args
.HasOption('v'))
326 cout
<< "Writing .DEF file..." << flush
;
328 // If file is read/only, set it to read/write
330 if (PFile::GetInfo(def_filename
, info
)) {
331 if ((info
.permissions
&PFileInfo::UserWrite
) == 0) {
332 PFile::SetPermissions(def_filename
, info
.permissions
|PFileInfo::UserWrite
);
333 cout
<< "Setting \"" << def_filename
<< "\" to read/write mode." << flush
;
334 PFile::Copy(def_filename
, def_filename
+".original");
338 if (def
.Open(def_filename
, PFile::WriteOnly
)) {
339 SortedSymbolList merged_symbols
;
340 merged_symbols
.DisallowDeleteObjects();
342 for (i
= 0; i
< def_symbols
.GetSize(); i
++) {
343 if (lib_symbols
.GetValuesIndex(def_symbols
[i
]) != P_MAX_INDEX
&&
344 !def_symbols
[i
].IsExternal()) {
345 merged_symbols
.Append(&def_symbols
[i
]);
347 if (args
.HasOption('v') && i
%100 == 0)
348 cout
<< '.' << flush
;
350 for (i
= 0; i
< lib_symbols
.GetSize(); i
++) {
351 if (def_symbols
.GetValuesIndex(lib_symbols
[i
]) == P_MAX_INDEX
)
352 merged_symbols
.Append(&lib_symbols
[i
]);
353 if (args
.HasOption('v') && i
%100 == 0)
354 cout
<< '.' << flush
;
356 cout
<< "\nSymbols merged: " << added
<< " added, " << removed
<< " removed.\n";
358 for (i
= 0; i
< def_file_lines
.GetSize(); i
++)
359 def
<< def_file_lines
[i
] << '\n';
360 for (i
= 0; i
< merged_symbols
.GetSize(); i
++)
361 def
<< merged_symbols
[i
];
363 if (args
.HasOption('v'))
364 cout
<< merged_symbols
.GetSize() << " symbols written." << endl
;
367 PError
<< "Could not create file " << def_filename
<< ':' << def
.GetErrorText() << endl
;
368 SetTerminationValue(1);