open_toontown_panda3d/dtool/src/interrogate/interrogate_module.cxx

493 lines
14 KiB
C++

/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file interrogate_module.cxx
* @author drose
* @date 2000-08-08
*/
// This program generates a module-level file for interrogate. This is a
// higher level than library, and groups several libraries together.
// Presently, the only thing that goes into the module file is a python table,
// but who knows what the future holds.
#include "interrogate_interface.h"
#include "interrogate_request.h"
#include "load_dso.h"
#include "pystub.h"
#include "pnotify.h"
#include "panda_getopt_long.h"
#include "preprocess_argv.h"
#include "vector_string.h"
#include <algorithm>
Filename output_code_filename;
string module_name;
string library_name;
bool build_c_wrappers = false;
bool build_python_wrappers = false;
bool build_python_native_wrappers = false;
bool track_interpreter = false;
vector_string imports;
// Short command-line options.
static const char *short_options = "";
// Long command-line options.
enum CommandOptions {
CO_oc = 256,
CO_module,
CO_library,
CO_c,
CO_python,
CO_python_native,
CO_track_interpreter,
CO_import,
};
static struct option long_options[] = {
{ "oc", required_argument, NULL, CO_oc },
{ "module", required_argument, NULL, CO_module },
{ "library", required_argument, NULL, CO_library },
{ "c", no_argument, NULL, CO_c },
{ "python", no_argument, NULL, CO_python },
{ "python-native", no_argument, NULL, CO_python_native },
{ "track-interpreter", no_argument, NULL, CO_track_interpreter },
{ "import", required_argument, NULL, CO_import },
{ NULL }
};
/*
static string
upcase_string(const string &str) {
string result;
for (string::const_iterator si = str.begin();
si != str.end();
++si) {
result += toupper(*si);
}
return result;
}
*/
int write_python_table_native(ostream &out) {
out << "\n#include \"dtoolbase.h\"\n"
<< "#include \"interrogate_request.h\"\n\n"
<< "#include \"py_panda.h\"\n\n";
int count = 0;
vector_string libraries;
// out << "extern \"C\" {\n";
// Walk through all of the Python functions.
int num_functions = interrogate_number_of_functions();
int fi;
for (fi = 0; fi < num_functions; fi++) {
FunctionIndex function_index = interrogate_get_function(fi);
// Consider only those that belong in the module we asked for. if
// (interrogate_function_has_module_name(function_index) && module_name ==
// interrogate_function_module_name(function_index)) { if it has a library
// name add it to set of libraries
if (interrogate_function_has_library_name(function_index)) {
string library_name = interrogate_function_library_name(function_index);
if (std::find(libraries.begin(), libraries.end(), library_name) == libraries.end()) {
libraries.push_back(library_name);
}
}
// }
}
for (int ti = 0; ti < interrogate_number_of_types(); ti++) {
TypeIndex thetype = interrogate_get_type(ti);
if (interrogate_type_has_module_name(thetype) && module_name == interrogate_type_module_name(thetype)) {
if (interrogate_type_has_library_name(thetype)) {
string library_name = interrogate_type_library_name(thetype);
if (std::find(libraries.begin(), libraries.end(), library_name) == libraries.end()) {
libraries.push_back(library_name);
}
}
}
}
vector_string::const_iterator ii;
for (ii = libraries.begin(); ii != libraries.end(); ++ii) {
printf("Referencing Library %s\n", (*ii).c_str());
out << "extern LibraryDef " << *ii << "_moddef;\n";
out << "extern void Dtool_" << *ii << "_RegisterTypes();\n";
out << "extern void Dtool_" << *ii << "_ResolveExternals();\n";
out << "extern void Dtool_" << *ii << "_BuildInstants(PyObject *module);\n";
}
out.put('\n');
out << "#if PY_MAJOR_VERSION >= 3 || !defined(NDEBUG)\n"
<< "#ifdef _WIN32\n"
<< "extern \"C\" __declspec(dllexport) PyObject *PyInit_" << library_name << "();\n"
<< "#elif __GNUC__ >= 4\n"
<< "extern \"C\" __attribute__((visibility(\"default\"))) PyObject *PyInit_" << library_name << "();\n"
<< "#else\n"
<< "extern \"C\" PyObject *PyInit_" << library_name << "();\n"
<< "#endif\n"
<< "#endif\n";
out << "#if PY_MAJOR_VERSION < 3 || !defined(NDEBUG)\n"
<< "#ifdef _WIN32\n"
<< "extern \"C\" __declspec(dllexport) void init" << library_name << "();\n"
<< "#elif __GNUC__ >= 4\n"
<< "extern \"C\" __attribute__((visibility(\"default\"))) void init" << library_name << "();\n"
<< "#else\n"
<< "extern \"C\" void init" << library_name << "();\n"
<< "#endif\n"
<< "#endif\n";
out << "\n"
<< "#if PY_MAJOR_VERSION >= 3\n"
<< "static struct PyModuleDef py_" << library_name << "_module = {\n"
<< " PyModuleDef_HEAD_INIT,\n"
<< " \"" << library_name << "\",\n"
<< " NULL,\n"
<< " -1,\n"
<< " NULL,\n"
<< " NULL, NULL, NULL, NULL\n"
<< "};\n"
<< "\n"
<< "PyObject *PyInit_" << library_name << "() {\n";
if (track_interpreter) {
out << " in_interpreter = 1;\n";
}
vector_string::const_iterator si;
for (si = imports.begin(); si != imports.end(); ++si) {
out << " PyImport_Import(PyUnicode_FromString(\"" << *si << "\"));\n";
}
for (ii = libraries.begin(); ii != libraries.end(); ii++) {
out << " Dtool_" << *ii << "_RegisterTypes();\n";
}
for (ii = libraries.begin(); ii != libraries.end(); ii++) {
out << " Dtool_" << *ii << "_ResolveExternals();\n";
}
out << "\n";
out << " LibraryDef *defs[] = {";
for(ii = libraries.begin(); ii != libraries.end(); ii++) {
out << "&" << *ii << "_moddef, ";
}
out << "NULL};\n"
<< "\n"
<< " PyObject *module = Dtool_PyModuleInitHelper(defs, &py_" << library_name << "_module);\n"
<< " if (module != NULL) {\n";
for (ii = libraries.begin(); ii != libraries.end(); ii++) {
out << " Dtool_" << *ii << "_BuildInstants(module);\n";
}
out << " }\n"
<< " return module;\n"
<< "}\n"
<< "\n"
<< "#ifndef NDEBUG\n"
<< "void init" << library_name << "() {\n"
<< " PyErr_SetString(PyExc_ImportError, \"" << module_name << " was "
<< "compiled for Python \" PY_VERSION \", which is incompatible "
<< "with Python 2\");\n"
<< "}\n"
<< "#endif\n"
<< "#else // Python 2 case\n"
<< "\n"
<< "void init" << library_name << "() {\n";
if (track_interpreter) {
out << " in_interpreter = 1;\n";
}
for (si = imports.begin(); si != imports.end(); ++si) {
out << " PyImport_Import(PyUnicode_FromString(\"" << *si << "\"));\n";
}
for (ii = libraries.begin(); ii != libraries.end(); ii++) {
out << " Dtool_" << *ii << "_RegisterTypes();\n";
}
for (ii = libraries.begin(); ii != libraries.end(); ii++) {
out << " Dtool_" << *ii << "_ResolveExternals();\n";
}
out << "\n";
out << " LibraryDef *defs[] = {";
for(ii = libraries.begin(); ii != libraries.end(); ii++) {
out << "&" << *ii << "_moddef, ";
}
out << "NULL};\n"
<< "\n"
<< " PyObject *module = Dtool_PyModuleInitHelper(defs, \"" << module_name << "\");\n"
<< " if (module != NULL) {\n";
for (ii = libraries.begin(); ii != libraries.end(); ii++) {
out << " Dtool_" << *ii << "_BuildInstants(module);\n";
}
out << " }\n"
<< "}\n"
<< "\n"
<< "#ifndef NDEBUG\n"
<< "PyObject *PyInit_" << library_name << "() {\n"
<< " PyErr_SetString(PyExc_ImportError, \"" << module_name << " was "
<< "compiled for Python \" PY_VERSION \", which is incompatible "
<< "with Python 3\");\n"
<< " return (PyObject *)NULL;\n"
<< "}\n"
<< "#endif\n"
<< "#endif\n"
<< "\n";
return count;
}
int write_python_table(ostream &out) {
out << "\n#include \"dtoolbase.h\"\n"
<< "#include \"interrogate_request.h\"\n\n"
<< "#undef _POSIX_C_SOURCE\n"
<< "#include \"Python.h\"\n\n";
int count = 0;
// First, we have to declare extern C prototypes for each of the function
// names.
out << "extern \"C\" {\n";
// Walk through all of the Python functions.
int num_functions = interrogate_number_of_functions();
int fi;
for (fi = 0; fi < num_functions; fi++) {
FunctionIndex function_index = interrogate_get_function(fi);
// Consider only those that belong in the module we asked for.
if (interrogate_function_has_module_name(function_index) &&
module_name == interrogate_function_module_name(function_index)) {
// For each function, get all of the python wrappers.
int num_wrappers =
interrogate_function_number_of_python_wrappers(function_index);
for (int wi = 0; wi < num_wrappers; wi++) {
FunctionWrapperIndex wrapper_index =
interrogate_function_python_wrapper(function_index, wi);
if (interrogate_wrapper_is_callable_by_name(wrapper_index)) {
count++;
const char *wrapper_name =
interrogate_wrapper_name(wrapper_index);
out << " PyObject *" << wrapper_name
<< "(PyObject *self, PyObject *args);\n";
}
}
}
}
out << "}\n\n";
// Now go back through and build the table of function names.
out << "static PyMethodDef python_methods[" << count + 1 << "] = {\n";
// Walk through all of the Python functions.
for (fi = 0; fi < num_functions; fi++) {
FunctionIndex function_index = interrogate_get_function(fi);
// Consider only those that belong in the module we asked for.
if (interrogate_function_has_module_name(function_index) &&
module_name == interrogate_function_module_name(function_index)) {
// For each function, get all of the python wrappers.
int num_wrappers =
interrogate_function_number_of_python_wrappers(function_index);
for (int wi = 0; wi < num_wrappers; wi++) {
FunctionWrapperIndex wrapper_index =
interrogate_function_python_wrapper(function_index, wi);
if (interrogate_wrapper_is_callable_by_name(wrapper_index)) {
const char *wrapper_name =
interrogate_wrapper_name(wrapper_index);
out << " { \""
<< wrapper_name << "\", &"
<< wrapper_name << ", METH_VARARGS },\n";
}
}
}
}
if (library_name.empty()) {
library_name = module_name;
}
out << " { NULL, NULL }\n"
<< "};\n\n"
<< "#if PY_MAJOR_VERSION >= 3\n"
<< "static struct PyModuleDef python_module = {\n"
<< " PyModuleDef_HEAD_INIT,\n"
<< " \"" << library_name << "\",\n"
<< " NULL,\n"
<< " -1,\n"
<< " python_methods,\n"
<< " NULL, NULL, NULL, NULL\n"
<< "};\n\n"
<< "#define INIT_FUNC PyObject *PyInit_" << library_name << "\n"
<< "#else\n"
<< "#define INIT_FUNC void init" << library_name << "\n"
<< "#endif\n\n"
<< "#ifdef _WIN32\n"
<< "extern \"C\" __declspec(dllexport) INIT_FUNC();\n"
<< "#else\n"
<< "extern \"C\" INIT_FUNC();\n"
<< "#endif\n\n"
<< "INIT_FUNC() {\n";
if (track_interpreter) {
out << " in_interpreter = 1;\n";
}
out << "#if PY_MAJOR_VERSION >= 3\n"
<< " return PyModule_Create(&python_module);\n"
<< "#else\n"
<< " Py_InitModule(\"" << library_name << "\", python_methods);\n"
<< "#endif\n"
<< "}\n\n";
return count;
}
int main(int argc, char *argv[]) {
extern char *optarg;
extern int optind;
int flag;
pystub();
preprocess_argv(argc, argv);
flag = getopt_long_only(argc, argv, short_options, long_options, NULL);
while (flag != EOF) {
switch (flag) {
case CO_oc:
output_code_filename = optarg;
break;
case CO_module:
module_name = optarg;
break;
case CO_library:
library_name = optarg;
break;
case CO_c:
build_c_wrappers = true;
break;
case CO_python:
build_python_wrappers = true;
break;
case CO_python_native:
build_python_native_wrappers = true;
break;
case CO_track_interpreter:
track_interpreter = true;
break;
case CO_import:
imports.push_back(optarg);
break;
default:
exit(1);
}
flag = getopt_long_only(argc, argv, short_options, long_options, NULL);
}
argc -= (optind-1);
argv += (optind-1);
if (argc < 2) {
nout
<< "\nUsage:\n"
<< " interrogate-module [opts] libname.in [libname.in ...]\n\n";
exit(1);
}
output_code_filename.set_text();
if (!build_c_wrappers && !build_python_wrappers && !build_python_native_wrappers) {
build_c_wrappers = true;
}
for (int i = 1; i < argc; i++) {
string param = argv[i];
if (param.length() > 3 && param.substr(param.length() - 3) == ".in") {
// If the filename ends in ".in", it's an interrogate database file, not
// a shared library--read it directly.
interrogate_request_database(param.c_str());
} else {
// Otherwise, assume it's a shared library, and try to load it.
Filename pathname = argv[i];
pathname.set_type(Filename::T_dso);
nout << "Loading " << pathname << "\n";
void *dl = load_dso(DSearchPath(), pathname);
if (dl == NULL) {
nout << "Unable to load: " << load_dso_error() << "\n";
exit(1);
}
}
}
// Now output the table.
if (!output_code_filename.empty()) {
pofstream output_code;
if (!output_code_filename.open_write(output_code)) {
nout << "Unable to write to " << output_code_filename << "\n";
} else {
if (build_python_wrappers) {
int count = write_python_table(output_code);
nout << count << " python function wrappers exported.\n";
}
if (build_python_native_wrappers) {
write_python_table_native(output_code);
}
}
}
if (interrogate_error_flag()) {
nout << "Error reading interrogate data.\n";
output_code_filename.unlink();
exit(1);
}
return (0);
}