Removed the unmangled versions of symbols to eliminate problems withthe line length
[pwlib.git] / tools / MergeSym / MergeSym.cxx
blob96c067f4f902b89692f1855b77747f56e92850f3
1 /*
2 * MergeSym.cxx
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
18 * under the License.
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
26 * $Log$
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.
65 #include <ptlib.h>
66 #include <ptlib/pipechan.h>
69 PDECLARE_CLASS(Symbol, PCaselessString)
70 public:
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"; }
80 private:
81 PString unmangled;
82 PINDEX ordinal;
83 BOOL external;
86 PSORTED_LIST(SortedSymbolList, Symbol);
89 PDECLARE_CLASS(MergeSym, PProcess)
90 public:
91 MergeSym();
92 void Main();
95 PCREATE_PROCESS(MergeSym);
98 MergeSym::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()) {
116 case 2 :
117 def_filename = args[1];
118 lib_filename = args[0];
119 break;
121 case 1 :
122 lib_filename = def_filename = args[0];
123 def_filename.SetType(".def");
124 break;
126 default :
127 PError << "usage: MergeSym [ -v ] [ -s ] [ -d dumpbin ] [ -x deffile[.def] ] [-I deffilepath ] libfile[.lib] [ deffile[.def] ]";
128 SetTerminationValue(1);
129 return;
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);
138 return;
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;
164 PTextFile ext;
165 if (ext.Open(trial_filename, PFile::ReadOnly)) {
166 if (args.HasOption('v'))
167 cout << "\nReading external symbols from " << ext.GetFilePath() << " ..." << flush;
168 BOOL prefix = TRUE;
169 while (!ext.eof()) {
170 PCaselessString line;
171 ext >> line;
172 if (prefix)
173 prefix = line.Find("EXPORTS") == P_MAX_INDEX;
174 else {
175 PINDEX start = 0;
176 while (isspace(line[start]))
177 start++;
178 PINDEX end = start;
179 while (line[end] != '\0' && !isspace(line[end]))
180 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;
186 break;
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;
199 PINDEX removed = 0;
201 PTextFile def;
202 if (def.Open(def_filename, PFile::ReadOnly)) {
203 if (args.HasOption('v'))
204 cout << "Reading existing ordinals..." << flush;
205 BOOL prefix = TRUE;
206 while (!def.eof()) {
207 PCaselessString line;
208 def >> line;
209 if (prefix) {
210 def_file_lines.AppendString(line);
211 if (line.Find("EXPORTS") != P_MAX_INDEX)
212 prefix = FALSE;
214 else {
215 PINDEX start = 0;
216 while (isspace(line[start]))
217 start++;
218 PINDEX end = start;
219 while (line[end] != '\0' && !isspace(line[end]))
220 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)
228 unmanglepos++;
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));
232 removed++;
233 if (args.HasOption('v') && def_symbols.GetSize()%100 == 0)
234 cout << '.' << flush;
238 def.Close();
239 if (args.HasOption('v'))
240 cout << '\n' << removed << " symbols read." << endl;
242 else {
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);
256 return;
259 PTextFile symfile;
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()) {
268 PString line;
269 pipe >> line;
270 symfile << line;
272 char * namepos = strchr(line, '|');
273 if (namepos != NULL) {
274 *namepos = '\0';
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)
287 unmangled = name;
288 else {
289 unmangled++;
290 char * endunmangle = strrchr(unmangled, ')');
291 if (endunmangle != NULL)
292 *endunmangle = '\0';
294 lib_symbols.Append(new Symbol(name, unmangled));
298 if (args.HasOption('v') && linecount%500 == 0)
299 cout << '.' << flush;
300 linecount++;
303 if (args.HasOption('v'))
304 cout << '\n' << lib_symbols.GetSize() << " symbols read.\n"
305 "Sorting symbols... " << flush;
307 PINDEX i;
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())
311 removed--;
314 PINDEX added = 0;
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);
318 added++;
322 if (added == 0 && removed == 0)
323 cout << "\nNo changes to symbols.\n";
324 else {
325 if (args.HasOption('v'))
326 cout << "Writing .DEF file..." << flush;
328 // If file is read/only, set it to read/write
329 PFileInfo info;
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;
366 else {
367 PError << "Could not create file " << def_filename << ':' << def.GetErrorText() << endl;
368 SetTerminationValue(1);
374 // End MergeSym.cxx