/* * MergeSym.cxx * * Symbol merging utility for Windows DLL's. * * Portable Windows Library * * Copyright (c) 1993-1998 Equivalence Pty. Ltd. * * The contents of this file are subject to the Mozilla Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Original Code is Portable Windows Library. * * The Initial Developer of the Original Code is Equivalence Pty. Ltd. * * Contributor(s): ______________________________________. * * $Log: MergeSym.cxx,v $ * Revision 1.16 2005/04/20 07:02:11 csoutheren * Changed handle "," in include paths * * Revision 1.15 2004/06/05 04:55:29 rjongbloed * Removed the unmangled versions of symbols to eliminate problems withthe line length * exceeding MSVC linkers internal limits. Has added benefit of making files half the size. * * Revision 1.14 2004/05/22 07:41:32 rjongbloed * Added ability to specify command line override of the "dumpbin" program run * to get library symbols, very useful for debugging. * * Revision 1.13 2004/04/09 07:03:23 rjongbloed * Added ability to get the output to DUMPBIN sent to a file. * * Revision 1.12 2004/04/03 06:54:32 rjongbloed * Many and various changes to support new Visual C++ 2003 * * Revision 1.11 2003/10/30 11:27:12 rjongbloed * Fixed ability to specify partial path for -x parameter. * * Revision 1.10 2003/02/11 07:00:17 robertj * Added copying def file to a backup version before alteration from read only. * * Revision 1.9 2002/06/13 05:51:01 robertj * Added ignore of some inherently private symbols exported by libraru eg debug * line number info and real number constants. * * Revision 1.8 2000/12/18 07:31:10 robertj * Fixed minor irritation with DEF file being reordered when symbol added. * * Revision 1.7 2000/04/29 05:48:22 robertj * Added error and progress reporting in searching path for external DEF files. * * Revision 1.6 2000/04/29 05:01:49 robertj * Added multiple external DEF file capability (-x flag). * Added directory search path argument for external DEF files. * Fixed bug for symbols in external DEF file actively removed from merged DEF file. * Added copyright notice. * */ #include #include PDECLARE_CLASS(Symbol, PCaselessString) public: Symbol(const PString & sym, const PString & cpp, PINDEX ord = 0, BOOL ext = FALSE) : PCaselessString(sym), unmangled(cpp) { ordinal = ord; external = ext; } void SetOrdinal(PINDEX ord) { ordinal = ord; } BOOL IsExternal() const { return external; } void PrintOn(ostream & s) const { s << " " << theArray << " @" << ordinal << " NONAME\n"; } private: PString unmangled; PINDEX ordinal; BOOL external; }; PSORTED_LIST(SortedSymbolList, Symbol); PDECLARE_CLASS(MergeSym, PProcess) public: MergeSym(); void Main(); }; PCREATE_PROCESS(MergeSym); MergeSym::MergeSym() : PProcess("Equivalence", "MergeSym", 1, 4, ReleaseCode, 0) { } void MergeSym::Main() { cout << GetName() << " version " << GetVersion(TRUE) << " on " << GetOSClass() << ' ' << GetOSName() << " by " << GetManufacturer() << endl; PArgList & args = GetArguments(); args.Parse("vsd:x:I:"); PFilePath lib_filename, def_filename; switch (args.GetCount()) { case 2 : def_filename = args[1]; lib_filename = args[0]; break; case 1 : lib_filename = def_filename = args[0]; def_filename.SetType(".def"); break; default : PError << "usage: MergeSym [ -v ] [ -s ] [ -d dumpbin ] [ -x deffile[.def] ] [-I deffilepath ] libfile[.lib] [ deffile[.def] ]"; SetTerminationValue(1); return; } if (lib_filename.GetType().IsEmpty()) lib_filename.SetType(".lib"); if (!PFile::Exists(lib_filename)) { PError << "MergeSym: library file " << lib_filename << " does not exist.\n"; SetTerminationValue(1); return; } if (def_filename.GetType().IsEmpty()) def_filename.SetType(".def"); SortedSymbolList def_symbols; if (args.HasOption('x')) { PStringArray include_path; if (args.HasOption('I')) { PString includes = args.GetOptionString('I'); if (includes.Find(';') == P_MAX_INDEX) include_path = includes.Tokenise(',', FALSE); else include_path = includes.Tokenise(';', FALSE); } include_path.InsertAt(0, new PString()); PStringArray file_list = args.GetOptionString('x').Lines(); for (PINDEX ext_index = 0; ext_index < file_list.GetSize(); ext_index++) { PString base_ext_filename = file_list[ext_index]; PString ext_filename = base_ext_filename; if (PFilePath(ext_filename).GetType().IsEmpty()) ext_filename += ".def"; PINDEX previous_def_symbols_size = def_symbols.GetSize(); for (PINDEX inc_index = 0; inc_index < include_path.GetSize(); inc_index++) { PString trial_filename = PDirectory(include_path[inc_index]) + ext_filename; if (args.HasOption('v')) cout << "\nTrying " << trial_filename << " ..." << flush; PTextFile ext; if (ext.Open(trial_filename, PFile::ReadOnly)) { if (args.HasOption('v')) cout << "\nReading external symbols from " << ext.GetFilePath() << " ..." << flush; BOOL prefix = TRUE; while (!ext.eof()) { PCaselessString line; ext >> line; if (prefix) prefix = line.Find("EXPORTS") == P_MAX_INDEX; else { PINDEX start = 0; while (isspace(line[start])) start++; PINDEX end = start; while (line[end] != '\0' && !isspace(line[end])) end++; def_symbols.Append(new Symbol(line(start, end-1), "", 0, TRUE)); if (args.HasOption('v') && def_symbols.GetSize()%100 == 0) cout << '.' << flush; } } break; } } if (inc_index >= include_path.GetSize()) PError << "MergeSym: external symbol file \"" << base_ext_filename << "\" not found.\n"; if (args.HasOption('v')) cout << '\n' << (def_symbols.GetSize() - previous_def_symbols_size) << " symbols read." << endl; } } PStringList def_file_lines; PINDEX max_ordinal = 0; PINDEX removed = 0; PTextFile def; if (def.Open(def_filename, PFile::ReadOnly)) { if (args.HasOption('v')) cout << "Reading existing ordinals..." << flush; BOOL prefix = TRUE; while (!def.eof()) { PCaselessString line; def >> line; if (prefix) { def_file_lines.AppendString(line); if (line.Find("EXPORTS") != P_MAX_INDEX) prefix = FALSE; } else { PINDEX start = 0; while (isspace(line[start])) start++; PINDEX end = start; while (line[end] != '\0' && !isspace(line[end])) end++; PINDEX ordpos = line.Find('@', end); if (ordpos != P_MAX_INDEX) { PINDEX ordinal = line.Mid(ordpos+1).AsInteger(); if (ordinal > max_ordinal) max_ordinal = ordinal; PINDEX unmanglepos = line.Find(';', ordpos); if (unmanglepos != P_MAX_INDEX) unmanglepos++; Symbol sym(line(start, end-1), line.Mid(unmanglepos), ordinal); if (def_symbols.GetValuesIndex(sym) == P_MAX_INDEX) def_symbols.Append(new Symbol(sym)); removed++; if (args.HasOption('v') && def_symbols.GetSize()%100 == 0) cout << '.' << flush; } } } def.Close(); if (args.HasOption('v')) cout << '\n' << removed << " symbols read." << endl; } else { def_file_lines.AppendString("LIBRARY " + def_filename.GetTitle()); def_file_lines.AppendString("EXPORTS"); } if (args.HasOption('v')) cout << "Reading library symbols..." << flush; PINDEX linecount = 0; SortedSymbolList lib_symbols; PString dumpbin = args.GetOptionString('d', "dumpbin"); PPipeChannel pipe(dumpbin + " /symbols '" + lib_filename + "'", PPipeChannel::ReadOnly); if (!pipe.IsOpen()) { PError << "\nMergeSym: could not run \"" << dumpbin << "\".\n"; SetTerminationValue(2); return; } PTextFile symfile; if (args.HasOption('s')) { PFilePath sym_filename = def_filename; sym_filename.SetType(".sym"); if (!symfile.Open(sym_filename, PFile::WriteOnly)) cerr << "Could not open symbol file " << sym_filename << endl; } while (!pipe.eof()) { PString line; pipe >> line; symfile << line; char * namepos = strchr(line, '|'); if (namepos != NULL) { *namepos = '\0'; while (*++namepos == ' '); if (strstr(line, " UNDEF ") == NULL && strstr(line, " External ") != NULL && strstr(namepos, "deleting destructor") == NULL) { int namelen = strcspn(namepos, "\r\n\t "); PString name(namepos, namelen); if (strncmp(name, "??_C@_", 6) != 0 && strncmp(name, "__real@", 7) != 0 && strncmp(name, "?__LINE__Var@", 13) != 0 && lib_symbols.GetValuesIndex(name) == P_MAX_INDEX) { const char * unmangled = strchr(namepos+namelen, '('); if (unmangled == NULL) unmangled = name; else { unmangled++; char * endunmangle = strrchr(unmangled, ')'); if (endunmangle != NULL) *endunmangle = '\0'; } lib_symbols.Append(new Symbol(name, unmangled)); } } } if (args.HasOption('v') && linecount%500 == 0) cout << '.' << flush; linecount++; } if (args.HasOption('v')) cout << '\n' << lib_symbols.GetSize() << " symbols read.\n" "Sorting symbols... " << flush; PINDEX i; for (i = 0; i < def_symbols.GetSize(); i++) { if (lib_symbols.GetValuesIndex(def_symbols[i]) != P_MAX_INDEX && !def_symbols[i].IsExternal()) removed--; } PINDEX added = 0; for (i = 0; i < lib_symbols.GetSize(); i++) { if (def_symbols.GetValuesIndex(lib_symbols[i]) == P_MAX_INDEX) { lib_symbols[i].SetOrdinal(++max_ordinal); added++; } } if (added == 0 && removed == 0) cout << "\nNo changes to symbols.\n"; else { if (args.HasOption('v')) cout << "Writing .DEF file..." << flush; // If file is read/only, set it to read/write PFileInfo info; if (PFile::GetInfo(def_filename, info)) { if ((info.permissions&PFileInfo::UserWrite) == 0) { PFile::SetPermissions(def_filename, info.permissions|PFileInfo::UserWrite); cout << "Setting \"" << def_filename << "\" to read/write mode." << flush; PFile::Copy(def_filename, def_filename+".original"); } } if (def.Open(def_filename, PFile::WriteOnly)) { SortedSymbolList merged_symbols; merged_symbols.DisallowDeleteObjects(); for (i = 0; i < def_symbols.GetSize(); i++) { if (lib_symbols.GetValuesIndex(def_symbols[i]) != P_MAX_INDEX && !def_symbols[i].IsExternal()) { merged_symbols.Append(&def_symbols[i]); } if (args.HasOption('v') && i%100 == 0) cout << '.' << flush; } for (i = 0; i < lib_symbols.GetSize(); i++) { if (def_symbols.GetValuesIndex(lib_symbols[i]) == P_MAX_INDEX) merged_symbols.Append(&lib_symbols[i]); if (args.HasOption('v') && i%100 == 0) cout << '.' << flush; } cout << "\nSymbols merged: " << added << " added, " << removed << " removed.\n"; for (i = 0; i < def_file_lines.GetSize(); i++) def << def_file_lines[i] << '\n'; for (i = 0; i < merged_symbols.GetSize(); i++) def << merged_symbols[i]; if (args.HasOption('v')) cout << merged_symbols.GetSize() << " symbols written." << endl; } else { PError << "Could not create file " << def_filename << ':' << def.GetErrorText() << endl; SetTerminationValue(1); } } } // End MergeSym.cxx