00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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
00028
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
00060 static const char *short_options = "I:S:D:F:vh";
00061
00062
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
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
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
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
00455
00456
00457 cppparser_output_class_keyword = false;
00458
00459
00460
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
00475
00476
00477 int file_identifier = time((time_t *)NULL);
00478 InterrogateModuleDef *def = builder.make_module_def(file_identifier);
00479
00480
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
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 }