bintools/checklib/main.cpp
changeset 0 044383f39525
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bintools/checklib/main.cpp	Tue Oct 27 16:36:35 2009 +0000
@@ -0,0 +1,173 @@
+// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Entry point for the checklib utility.
+// 
+//
+
+#include "library/library.h" // For handling libraries of Unix "ar" format.
+#include "object/object.h"   // For handling (parts of) ELF and COFF object files.
+
+#include <string>
+#include <sstream>
+#include <iostream>
+#include <stdexcept>
+
+
+const char SELF_NAME[] = "checklib";
+
+// Describes what kind of library it is.
+enum libkind_t
+{
+    STDCPP, // Library should be compatible with Symbian C++.
+    SYMCPP  // Library should be compatible with standard C++ (Open Environment).
+};
+
+// Describes what kind of objects are in the library: ELF or COFF.
+typedef Object_factory::objkind_t objkind_t;
+
+void _usage_and_exit(int exit_code=EXIT_FAILURE);
+void _error_and_exit(const std::string&, int exit_code=EXIT_FAILURE);
+
+// These are the ::operator new symbols we are worried about.
+const char* NEW_NAMES[2][4] = {
+    {"_Znwj", "_Znaj", "_ZnwjRKSt9nothrow_t", "_ZnajRKSt9nothrow_t"}, // ELF
+    {"??2@YAPAXI@Z", "??_U@YAPAXI@Z", "??2@YAPAXIABUnothrow_t@std@@@Z", "??_U@YAPAXIABUnothrow_t@std@@@Z"} // COFF
+};
+
+// Checks whether the object files in the given library references any of the
+// ::operator new functions.
+bool _lib_ref_new(const Library&, objkind_t);
+
+
+int main(int argc, const char* argv[])
+{
+    // Do we have any standard module for handling the command-line interface? If
+    // not, see if we can start using getopt or Boost. 
+
+    if (argc < 4)
+    {
+        _usage_and_exit();
+    }
+
+    // Command-line options.
+    libkind_t opt_libkind;
+    objkind_t opt_objkind;
+
+    if ( std::strcmp(argv[1], "stdc++") == 0 )
+    {
+        opt_libkind = STDCPP;
+    }
+    else if ( std::strcmp(argv[1], "symc++") == 0 )
+    {
+        opt_libkind = SYMCPP;
+    }
+    else
+    {
+        _usage_and_exit();
+    }
+
+    if ( std::strcmp(argv[2], "--elf") == 0 )
+    {
+        opt_objkind = Object_factory::ELF;
+    }
+    else if ( std::strcmp(argv[2], "--coff") == 0 )
+    {
+        opt_objkind = Object_factory::COFF;
+    }
+    else
+    {
+        _usage_and_exit();
+    }
+
+    try
+    {
+        // Check each library that was given on the command-line.
+        for (int i = 3; i < argc; i++)
+        {
+            Library lib( argv[i] ); // May throw std::runtime_error.
+
+            // If the library has the tag, we know that it was built to be OE
+            // compatible, and vice versa.
+            bool lib_is_tagged = lib.contains_symbol("____symbian_stdcpp_mmviii");
+
+            // Handle the two only possible error cases:
+
+            if ( opt_libkind == STDCPP && !lib_is_tagged && _lib_ref_new(lib, opt_objkind) )
+            {
+                std::ostringstream err_msg;
+                err_msg << "library " << argv[i] <<  " is incompatible with standard C++";
+
+                _error_and_exit(err_msg.str());
+            }
+            else if ( opt_libkind == SYMCPP && lib_is_tagged && _lib_ref_new(lib, opt_objkind) )
+            {
+                std::ostringstream err_msg;
+                err_msg << "library " << argv[i] <<  " is incompatible with Symbian C++";
+
+                _error_and_exit(err_msg.str());
+            }
+        }
+    }
+    catch (std::runtime_error& e)
+    {
+        _error_and_exit( e.what() );
+    }
+
+    return 0;
+}
+
+void _error_and_exit(const std::string& a_msg, int a_exit_code)
+{
+    std::cerr << SELF_NAME << ": error: " << a_msg << "." << std::endl;
+    std::exit(a_exit_code);
+}
+
+void _usage_and_exit(int a_exit_code)
+{
+    using std::cout;
+    using std::endl;
+
+    cout << "usage: " << SELF_NAME << " stdc++ --elf|--coff <lib_list>\n"
+         << "       " << SELF_NAME << " symc++ --elf|--coff <lib_list>" << endl;
+
+    std::exit(a_exit_code);
+}
+
+bool _lib_ref_new(const Library& a_lib, objkind_t a_objkind)
+{
+    typedef std::vector< std::pair<const char*, const char*> > T;
+
+    const T* objects_p = a_lib.get_objects();
+
+    T::const_iterator p = objects_p->begin();
+    T::const_iterator end_p = objects_p->end();
+
+    // Iterate over all the objects ...
+    for (; p != end_p; ++p)
+    {
+        std::auto_ptr<Object> obj_p = Object_factory::create(a_objkind, p->first, p->second);
+
+        // ... And check for references to any ::operator new function.
+        for (unsigned i = 0; i < sizeof(NEW_NAMES[a_objkind]) / sizeof(NEW_NAMES[a_objkind][0]); i++)
+        {
+            if ( obj_p->is_undef(NEW_NAMES[a_objkind][i]) )
+            {
+                return 1;
+            }
+        }
+    }
+
+    return 0;
+}
+