Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

interrogate.cxx

Go to the documentation of this file.
00001 // Filename: interrogate.cxx
00002 // Created by:  drose (31Jul00)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "interrogate.h"
00020 #include "interrogateBuilder.h"
00021 
00022 #include <interrogateDatabase.h>
00023 #include <cppGlobals.h>
00024 #include <notify.h>
00025 #include <time.h>
00026 
00027 // If our system getopt() doesn't come with getopt_long_only(), then use
00028 // the GNU flavor that we've got in tool for this purpose.
00029 #ifndef HAVE_GETOPT_LONG_ONLY
00030 #include <gnu_getopt.h>
00031 #else
00032 #include <getopt.h>
00033 #endif
00034 
00035 CPPParser parser;
00036 
00037 Filename output_code_filename;
00038 Filename output_data_filename;
00039 string output_data_basename;
00040 bool output_module_specific = false;
00041 bool output_function_pointers = false;
00042 bool output_function_names = false;
00043 bool convert_strings = false;
00044 bool manage_reference_counts = false;
00045 bool watch_asserts = false;
00046 bool true_wrapper_names = false;
00047 bool build_c_wrappers = false;
00048 bool build_python_wrappers = false;
00049 bool build_python_obj_wrappers = false;
00050 bool track_interpreter = false;
00051 bool save_unique_names = false;
00052 bool no_database = false;
00053 bool generate_spam = false;
00054 bool left_inheritance_requires_upcast = false;
00055 CPPVisibility min_vis = V_published;
00056 string library_name;
00057 string module_name;
00058 
00059 // Short command-line options.
00060 static const char *short_options = "I:S:D:F:vh";
00061 
00062 // Long command-line options.
00063 enum CommandOptions {
00064   CO_oc = 256,
00065   CO_od,
00066   CO_module,
00067   CO_library,
00068   CO_do_module,
00069   CO_fptrs,
00070   CO_fnames,
00071   CO_string,
00072   CO_refcount,
00073   CO_assert,
00074   CO_true_names,
00075   CO_c,
00076   CO_python,
00077   CO_python_obj,
00078   CO_track_interpreter,
00079   CO_unique_names,
00080   CO_nodb,
00081   CO_longlong,
00082   CO_promiscuous,
00083   CO_spam,
00084   CO_help,
00085 };
00086 
00087 static struct option long_options[] = {
00088   { "oc", required_argument, NULL, CO_oc },
00089   { "od", required_argument, NULL, CO_od },
00090   { "module", required_argument, NULL, CO_module },
00091   { "library", required_argument, NULL, CO_library },
00092   { "do-module", no_argument, NULL, CO_do_module },
00093   { "fptrs", no_argument, NULL, CO_fptrs },
00094   { "fnames", no_argument, NULL, CO_fnames },
00095   { "string", no_argument, NULL, CO_string },
00096   { "refcount", no_argument, NULL, CO_refcount },
00097   { "assert", no_argument, NULL, CO_assert },
00098   { "true-names", no_argument, NULL, CO_true_names },
00099   { "c", no_argument, NULL, CO_c },
00100   { "python", no_argument, NULL, CO_python },
00101   { "python-obj", no_argument, NULL, CO_python_obj },
00102   { "track-interpreter", no_argument, NULL, CO_track_interpreter },
00103   { "unique-names", no_argument, NULL, CO_unique_names },
00104   { "nodb", no_argument, NULL, CO_nodb },
00105   { "longlong", required_argument, NULL, CO_longlong },
00106   { "promiscuous", no_argument, NULL, CO_promiscuous },
00107   { "spam", no_argument, NULL, CO_spam },
00108   { "help", no_argument, NULL, CO_help },
00109   { NULL }
00110 };
00111 
00112 void
00113 show_usage() {
00114   cerr
00115     << "\nUsage:\n"
00116     << "  interrogate [opts] file.C [file.C ...]\n"
00117     << "  interrogate -h\n\n";
00118 }
00119 
00120 void show_help() {
00121   show_usage();
00122   cerr
00123     << "Interrogate is a program to parse a body of C++ code and build up a table\n"
00124     << "of classes, methods, functions, and symbols found, for the purposes of\n"
00125     << "calling into the codebase via a non-C++ scripting language like Scheme,\n"
00126     << "Smalltalk, or Python.\n\n"
00127 
00128     << "In addition to identifying all the classes and their relationships,\n"
00129     << "interrogate will generate a wrapper function for each callable function.\n"
00130     << "The wrapper functions will be callable directly from the scripting language,\n"
00131     << "with no understanding of C++ necessary; these wrapper functions will in turn\n"
00132     << "call the actual C++ functions or methods.\n\n"
00133 
00134     << "Most exportable features of C++ are supported, including templates, default\n"
00135     << "parameters, and function overloading.\n\n"
00136 
00137     << "Options:\n\n"
00138 
00139     << "  -oc output.C\n"
00140     << "        Specify the name of the file to which generated code will be written.\n"
00141     << "        This includes all of the function wrappers, as well as those tables\n"
00142     << "        which must be compiled into the library.\n\n"
00143 
00144     << "  -od output.in\n"
00145     << "        Specify the name of the file to which the non-compiled data tables\n"
00146     << "        will be written.  This file describes the relationships between\n"
00147     << "        all the types and the functions, and associates the function wrappers\n"
00148     << "        above with this data.  This file will be opened and read at runtime\n"
00149     << "        when the scripting language first calls some interrogate query\n"
00150     << "        function.\n\n"
00151 
00152     << "  -module module_name\n"
00153     << "        Defines the name of the module this data is associated with.  This\n"
00154     << "        is strictly a code-organizational tool.  Conceptually, a module is\n"
00155     << "        the highest level of grouping for interrogate data; a module may\n"
00156     << "        contain several libraries.  If this is omitted, no module name is\n"
00157     << "        specified.\n\n"
00158 
00159     << "        Sometimes, depending on the type of wrappers being generated, there\n"
00160     << "        may be additional code that needs to be generated on the module\n"
00161     << "        level, above that which was already generated at the library level.\n"
00162     << "        Python, for instance, generates the table of python-callable function\n"
00163     << "        wrappers at the module level.  Use the program interrogate-module\n"
00164     << "        to generate the appropriate code at the module level.\n\n"
00165 
00166     << "  -library library_name\n"
00167     << "        Defines the name of the library this data is associated with.  This\n"
00168     << "        is another code-organizational tool.  Typically, there will be one\n"
00169     << "        invocation of interrogate for each library, and there will be\n"
00170     << "        multiple libraries per module.  If this is omitted, no library name\n"
00171     << "        is specified.\n\n"
00172 
00173     << "  -do-module\n"
00174     << "        Generate whatever module-level code should be generated immediately,\n"
00175     << "        rather than waiting for a special interrogate-module pass.\n"
00176     << "        This, of course, prohibits grouping several libraries together\n"
00177     << "        into a single module.\n\n"
00178 
00179     << "  -fptrs\n"
00180     << "        Make void* pointers to the function wrappers directly available.  A\n"
00181     << "        scripting language will be able to call the interrogate functions\n"
00182     << "        directly by pointer.\n\n"
00183 
00184     << "  -fnames\n"
00185     << "        Make the names of the function wrappers public symbols so that the\n"
00186     << "        scripting language will be able to call the interrogate functions\n"
00187     << "        by name.\n\n"
00188 
00189     << "  Either or both of -fptrs and/or -fnames may be specified.  If both are\n"
00190     << "  omitted, the default is -fnames.\n\n"
00191 
00192     << "  -string\n"
00193     << "        Treat char* and basic_string<char> as special cases, and map\n"
00194     << "        parameters of these types to type atomic string.  The scripting\n"
00195     << "        language will see only functions that receive and return strings,\n"
00196     << "        not pointers to character or structures of basic_string<char>.\n"
00197     << "        If C calling convention wrappers are being generated, the atomic\n"
00198     << "        string type means type char*.  In any other calling convention, the\n"
00199     << "        atomic string type is whatever the native string type is.\n\n"
00200 
00201     << "  -refcount\n"
00202     << "        Treat classes that inherit from a class called ReferenceCount as a\n"
00203     << "        special case.  Any wrapper function that returns a pointer to\n"
00204     << "        one of these classes will automatically increment the reference\n"
00205     << "        count by calling ref() on the object first, and any destructors\n"
00206     << "        that are generated will call unref_delete() on the object instead of\n"
00207     << "        simply delete.\n\n"
00208     << "        Furthermore, parameters of type PointerTo<N> or ConstPointerTo<N>\n"
00209     << "        will automatically be mapped to N * and const N *, respectively.\n\n"
00210 
00211     << "  -assert\n"
00212     << "        Generate code in each wrapper that will check the state of the assert\n"
00213     << "        flag and trigger an exception in the scripting language when a\n"
00214     << "        C++ assertion fails.  Presently, this only has meaning to the Python\n"
00215     << "        wrappers.\n\n"
00216 
00217     << "  -true-names\n"
00218     << "        Use the actual name of the function being wrapped as the name of\n"
00219     << "        the generated wrapper function, instead of an ugly hash name.\n"
00220     << "        This means the wrapper functions may be called directly using a\n"
00221     << "        meaningful name (especially if -fnames is also given), but it\n"
00222     << "        also means that C++ function overloading (including default values\n"
00223     << "        for parameters) cannot be used, as it will lead to multiple wrapper\n"
00224     << "        functions with the same name.\n\n"
00225 
00226     << "  -c\n"
00227     << "        Generate function wrappers using the C calling convention.  Any\n"
00228     << "        scripting language that can call a C function should be able to\n"
00229     << "        make advantage of the interrogate database.\n\n"
00230     << "  -python\n"
00231     << "        Generate function wrappers using the Python calling convention.\n"
00232     << "        The shared library will be directly loadable as a Python module\n"
00233     << "        (especially if the module definitions are made available either by\n"
00234     << "        running interrogate-module later, or by specifying -do-module on\n"
00235     << "        the command line now).  However, C++ objects and methods will be\n"
00236     << "        converted into an object handle and a list of independent Python\n"
00237     << "        functions.\n\n"
00238     << "  -python-obj\n"
00239     << "        Generate Python function wrappers that convert C++ objects to true\n"
00240     << "        python objects, with all methods converted to Python methods.  This\n"
00241     << "        is currently experimental.\n\n"
00242 
00243     << "  Any combination of -c, -python, or -python-obj may be specified.  If all\n"
00244     << "  are omitted, the default is -c.\n\n"
00245 
00246     << "  -track-interpreter\n"
00247     << "        Generate code within each wrapper function to adjust the global\n"
00248     << "        variable \"in_interpreter\" to indicated whether code is running\n"
00249     << "        within the Panda C++ environment or within the high-level language.\n"
00250 
00251     << "  -unique-names\n"
00252     << "        Compile a table into the library (i.e. generate code into the -oc\n"
00253     << "        file) that defines a lookup of each function wrapper by its unique\n"
00254     << "        name.  This makes it possible to consistently identify function\n"
00255     << "        wrappers between sessions, at the cost of having this additional\n"
00256     << "        table in memory.\n\n"
00257 
00258     << "  -nodb\n"
00259     << "        Do not build a full interrogate database, but just generate function\n"
00260     << "        wrappers.  It is assumed that the user will know how to call the\n"
00261     << "        function wrappers already, from some external source.  This is most\n"
00262     << "        useful in conjunction with -true-names.\n\n"
00263 
00264     << "  -longlong typename\n"
00265     << "        Specify the name of the 64-bit integer type for the current compiler.\n"
00266     << "        By default, this is \"long long\".\n\n"
00267 
00268     << "  -promiscuous\n"
00269     << "        Export *all* public symbols, functions, and classes seen, even those\n"
00270     << "        not explicitly marked to be published.\n\n"
00271 
00272     << "  -spam\n"
00273     << "        Generate wrapper functions that report each invocation to Notify.\n"
00274     << "        This can sometimes be useful for tracking down bugs.\n\n";
00275 }
00276 
00277 // handle commandline -D options
00278 static void
00279 predefine_macro(CPPParser& parser, const string& option) {
00280   string macro_name, macro_def;
00281 
00282   size_t eq = option.find('=');
00283   if (eq != string::npos) {
00284     macro_name = option.substr(0, eq);
00285     macro_def = option.substr(eq + 1);
00286   } else {
00287     macro_name = option;
00288   }
00289 
00290   CPPManifest *macro = new CPPManifest(macro_name + " " + macro_def);
00291   parser._manifests[macro->_name] = macro;
00292 }
00293 
00294 int
00295 main(int argc, char *argv[]) {
00296   string command_line;
00297   int i;
00298   for (i = 0; i < argc; i++) {
00299     command_line += string(argv[i]) + " ";
00300   }
00301 
00302   extern char *optarg;
00303   extern int optind;
00304   int flag;
00305 
00306   flag = getopt_long_only(argc, argv, short_options, long_options, NULL);
00307   while (flag != EOF) {
00308     switch (flag) {
00309     case 'I':
00310       parser._include_path.append_directory(optarg);
00311       break;
00312 
00313     case 'S':
00314       parser._system_include_path.append_directory(optarg);
00315       break;
00316 
00317     case 'D':
00318       predefine_macro(parser, optarg);
00319       break;
00320 
00321     case 'F':
00322       // This is just a compile directive which we ignore.
00323       break;
00324 
00325     case 'v':
00326       parser.set_verbose(parser.get_verbose() + 1);
00327       break;
00328 
00329     case CO_oc:
00330       output_code_filename = optarg;
00331       break;
00332 
00333     case CO_od:
00334       output_data_filename = optarg;
00335       break;
00336 
00337     case CO_module:
00338       module_name = optarg;
00339       break;
00340 
00341     case CO_library:
00342       library_name = optarg;
00343       break;
00344 
00345     case CO_do_module:
00346       output_module_specific = true;
00347       break;
00348 
00349     case CO_fptrs:
00350       output_function_pointers = true;
00351       break;
00352 
00353     case CO_fnames:
00354       output_function_names = true;
00355       break;
00356 
00357     case CO_string:
00358       convert_strings = true;
00359       break;
00360 
00361     case CO_refcount:
00362       manage_reference_counts = true;
00363       break;
00364 
00365     case CO_assert:
00366       watch_asserts = true;
00367       break;
00368 
00369     case CO_true_names:
00370       true_wrapper_names = true;
00371       break;
00372 
00373     case CO_c:
00374       build_c_wrappers = true;
00375       break;
00376 
00377     case CO_python:
00378       build_python_wrappers = true;
00379       break;
00380 
00381     case CO_python_obj:
00382       build_python_obj_wrappers = true;
00383       break;
00384 
00385     case CO_track_interpreter:
00386       track_interpreter = true;
00387       break;
00388 
00389     case CO_unique_names:
00390       save_unique_names = true;
00391       break;
00392 
00393     case CO_nodb:
00394       no_database = true;
00395       break;
00396 
00397     case CO_longlong:
00398       cpp_longlong_keyword = optarg;
00399       break;
00400 
00401     case CO_promiscuous:
00402       min_vis = V_public;
00403       break;
00404 
00405     case CO_spam:
00406       generate_spam = true;
00407       break;
00408 
00409     case 'h':
00410     case CO_help:
00411       show_help();
00412       exit(0);
00413 
00414     default:
00415       exit(1);
00416     }
00417     flag = getopt_long_only(argc, argv, short_options, long_options, NULL);
00418   }
00419 
00420   argc -= (optind-1);
00421   argv += (optind-1);
00422 
00423   if (argc < 2) {
00424     show_usage();
00425     exit(1);
00426   }
00427 
00428   output_code_filename.set_text();
00429   output_data_filename.set_text();
00430   output_data_basename = output_data_filename.get_basename();
00431 
00432   if (output_function_names && true_wrapper_names) {
00433     cerr
00434       << "Cannot simultaneously export function names and report\n"
00435       << "true wrapper names--wrapper names will clash with the\n"
00436       << "wrapped functions!\n";
00437     exit(1);
00438   }
00439 
00440   if (!build_c_wrappers && !build_python_wrappers && 
00441       !build_python_obj_wrappers) {
00442     build_c_wrappers = true;
00443   }
00444 
00445   // Get all of the .h files.
00446   for (i = 1; i < argc; ++i) {
00447     if (!parser.parse_file(argv[i])) {
00448       cerr << "Error parsing file: '" << argv[i] << "'\n";
00449       exit(1);
00450     }
00451     builder.add_source_file(argv[i]);
00452   }
00453 
00454   // Now that we've parsed all the source code, change the way things
00455   // are output from now on so we can compile our generated code using
00456   // VC++.  Sheesh.
00457   cppparser_output_class_keyword = false;
00458 
00459 
00460   // Now look for the .N files.
00461   for (i = 1; i < argc; ++i) {
00462     Filename nfilename = argv[i];
00463     nfilename.set_extension("N");
00464     nfilename.set_text();
00465     ifstream nfile;
00466     if (nfilename.open_read(nfile)) {
00467       builder.read_command_file(nfile);
00468     }
00469   }
00470 
00471 
00472   builder.build();
00473 
00474   // Make up a file identifier.  This is just some bogus number that
00475   // should be the same in both the compiled-in code and in the
00476   // database, so we can check synchronicity at load time.
00477   int file_identifier = time((time_t *)NULL);
00478   InterrogateModuleDef *def = builder.make_module_def(file_identifier);
00479 
00480   // Now output all of the wrapper functions.
00481   if (!output_code_filename.empty()) {
00482     ofstream output_code;
00483     output_code_filename.open_write(output_code);
00484 
00485     output_code
00486       << "/*\n"
00487       << " * This file generated by:\n"
00488       << " * " << command_line << "\n"
00489       << " *\n"
00490       << " */\n\n";
00491 
00492     if (output_code.fail()) {
00493       nout << "Unable to write to " << output_code_filename << "\n";
00494     } else {
00495       builder.write_code(output_code, def);
00496     }
00497   }
00498 
00499   // And now output the bulk of the database.
00500   if (!output_data_filename.empty()) {
00501     ofstream output_data;
00502     output_data_filename.open_write(output_data);
00503 
00504     if (output_data.fail()) {
00505       nout << "Unable to write to " << output_data_filename << "\n";
00506     } else {
00507       InterrogateDatabase::get_ptr()->write(output_data, def);
00508     }
00509   }
00510 
00511   return (0);
00512 }

Generated on Fri Apr 18 01:33:47 2003 for DTool by doxygen1.3