mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-30 16:58:40 -04:00
one_process support. Some issues.
This commit is contained in:
parent
034a977c3d
commit
4388b853e5
@ -2185,10 +2185,12 @@ class Packager:
|
||||
# This is the main program that drives the runtime Python. It
|
||||
# is responsible for loading _vfsimporter.pyd, and then
|
||||
# importing direct.p3d.AppRunner, to start an application
|
||||
# running. Note that the .exe extension is automatically
|
||||
# replaced with the platform-specific extension appropriate
|
||||
# for an executable.
|
||||
# running. The program comes in two parts: an executable, and
|
||||
# an associated dynamic library. Note that the .exe and .dll
|
||||
# extensions are automatically replaced with the appropriate
|
||||
# platform-specific extensions.
|
||||
self.do_file('p3dpython.exe')
|
||||
self.do_file('libp3dpython.dll')
|
||||
|
||||
def do_freeze(self, filename, compileToExe = False):
|
||||
""" Freezes all of the current Python code into either an
|
||||
|
@ -18,6 +18,7 @@
|
||||
find_root_dir.cxx find_root_dir.h \
|
||||
get_tinyxml.h \
|
||||
binaryXml.cxx binaryXml.h \
|
||||
fhandle.h \
|
||||
handleStream.cxx handleStream.h handleStream.I \
|
||||
handleStreamBuf.cxx handleStreamBuf.h handleStreamBuf.I \
|
||||
mkdir_complete.cxx mkdir_complete.h \
|
||||
@ -51,7 +52,8 @@
|
||||
p3dUndefinedObject.h \
|
||||
p3dWinSplashWindow.h p3dWinSplashWindow.I \
|
||||
p3dX11SplashWindow.h \
|
||||
p3dWindowParams.h p3dWindowParams.I
|
||||
p3dWindowParams.h p3dWindowParams.I \
|
||||
run_p3dpython.h
|
||||
|
||||
#define INCLUDED_SOURCES \
|
||||
p3d_plugin.cxx \
|
||||
@ -91,7 +93,7 @@
|
||||
|
||||
#end lib_target
|
||||
|
||||
#begin bin_target
|
||||
#begin lib_target
|
||||
#define BUILD_TARGET $[HAVE_PYTHON]
|
||||
#define USE_PACKAGES tinyxml python
|
||||
#define TARGET p3dpython
|
||||
@ -105,19 +107,31 @@
|
||||
|
||||
#define SOURCES \
|
||||
binaryXml.cxx binaryXml.h \
|
||||
fhandle.h \
|
||||
handleStream.cxx handleStream.h handleStream.I \
|
||||
handleStreamBuf.cxx handleStreamBuf.h handleStreamBuf.I \
|
||||
p3d_lock.h p3d_plugin.h \
|
||||
p3d_plugin_config.h \
|
||||
p3dCInstance.cxx \
|
||||
p3dCInstance.h p3dCInstance.I \
|
||||
p3dPythonRun.cxx p3dPythonRun.h p3dPythonRun.I
|
||||
p3dPythonRun.cxx p3dPythonRun.h p3dPythonRun.I \
|
||||
run_p3dpython.h
|
||||
|
||||
#define WIN_SYS_LIBS user32.lib
|
||||
|
||||
// If you have to link with a static Python library, define it here.
|
||||
#define EXTRA_LIBS $[EXTRA_P3DPYTHON_LIBS]
|
||||
|
||||
#end lib_target
|
||||
|
||||
#begin bin_target
|
||||
#define BUILD_TARGET $[HAVE_PYTHON]
|
||||
#define TARGET p3dpython
|
||||
|
||||
#define SOURCES \
|
||||
fhandle.h \
|
||||
p3dPythonMain.cxx \
|
||||
run_p3dpython.h
|
||||
#end bin_target
|
||||
|
||||
#begin static_lib_target
|
||||
|
29
direct/src/plugin/fhandle.h
Normal file
29
direct/src/plugin/fhandle.h
Normal file
@ -0,0 +1,29 @@
|
||||
// Filename: fhandle.h
|
||||
// Created by: drose (29Aug09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef FHANDLE_H
|
||||
#define FHANDLE_H
|
||||
|
||||
// This header file simply defines the FHandle type, which is used to
|
||||
// pass around a handle to an open file object.
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
typedef HANDLE FHandle;
|
||||
#else
|
||||
// On POSIX, we use a file descriptor as a "handle".
|
||||
typedef int FHandle;
|
||||
#endif
|
||||
|
||||
#endif
|
@ -15,14 +15,7 @@
|
||||
#ifndef HANDLESTREAMBUF_H
|
||||
#define HANDLESTREAMBUF_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
typedef HANDLE FHandle;
|
||||
#else
|
||||
// On POSIX, we use a file descriptor as a "handle".
|
||||
typedef int FHandle;
|
||||
#endif
|
||||
|
||||
#include "fhandle.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
@ -29,28 +29,27 @@ P3DPythonRun *P3DPythonRun::_global_ptr = NULL;
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DPythonRun::
|
||||
P3DPythonRun(int argc, char *argv[]) {
|
||||
P3DPythonRun(const char *program_name, const char *archive_file,
|
||||
FHandle input, FHandle output) {
|
||||
_read_thread_continue = false;
|
||||
_program_continue = true;
|
||||
_session_terminated = false;
|
||||
INIT_LOCK(_commands_lock);
|
||||
INIT_THREAD(_read_thread);
|
||||
|
||||
_session_id = 0;
|
||||
_next_sent_id = 0;
|
||||
|
||||
if (argc >= 1) {
|
||||
_program_name = argv[0];
|
||||
if (program_name != NULL) {
|
||||
_program_name = program_name;
|
||||
}
|
||||
if (argc >= 2) {
|
||||
_archive_file = Filename::from_os_specific(argv[1]);
|
||||
}
|
||||
if (_archive_file.empty()) {
|
||||
nout << "No archive filename specified on command line.\n";
|
||||
exit(1);
|
||||
if (archive_file != NULL) {
|
||||
_archive_file = Filename::from_os_specific(archive_file);
|
||||
}
|
||||
|
||||
_py_argc = 1;
|
||||
_py_argv = (char **)malloc(2 * sizeof(char *));
|
||||
|
||||
_py_argv[0] = (char *)_program_name.c_str();
|
||||
_py_argv[1] = NULL;
|
||||
|
||||
@ -66,28 +65,15 @@ P3DPythonRun(int argc, char *argv[]) {
|
||||
|
||||
// Initialize Python. It appears to be important to do this before
|
||||
// we open the pipe streams and spawn the thread, below.
|
||||
PyEval_InitThreads();
|
||||
Py_SetProgramName((char *)_program_name.c_str());
|
||||
Py_Initialize();
|
||||
PySys_SetArgv(_py_argc, _py_argv);
|
||||
|
||||
// Open the pipe streams with the input and output handles from the
|
||||
// parent.
|
||||
#ifdef _WIN32
|
||||
HANDLE read = GetStdHandle(STD_INPUT_HANDLE);
|
||||
HANDLE write = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (!SetStdHandle(STD_INPUT_HANDLE, INVALID_HANDLE_VALUE)) {
|
||||
nout << "unable to reset input handle\n";
|
||||
}
|
||||
if (!SetStdHandle(STD_OUTPUT_HANDLE, INVALID_HANDLE_VALUE)) {
|
||||
nout << "unable to reset input handle\n";
|
||||
}
|
||||
|
||||
_pipe_read.open_read(read);
|
||||
_pipe_write.open_write(write);
|
||||
#else
|
||||
_pipe_read.open_read(STDIN_FILENO);
|
||||
_pipe_write.open_write(STDOUT_FILENO);
|
||||
#endif // _WIN32
|
||||
_pipe_read.open_read(input);
|
||||
_pipe_write.open_write(output);
|
||||
|
||||
if (!_pipe_read) {
|
||||
nout << "unable to open read pipe\n";
|
||||
@ -125,7 +111,6 @@ run_python() {
|
||||
// "_d", so that the Panda DLL preloader can import the correct
|
||||
// filenames.
|
||||
PyRun_SimpleString("import sys; sys.dll_suffix = '_d'");
|
||||
|
||||
#endif
|
||||
|
||||
// We'll need libpandaexpress to be imported before we can load
|
||||
@ -696,6 +681,9 @@ check_comm() {
|
||||
_commands.pop_front();
|
||||
RELEASE_LOCK(_commands_lock);
|
||||
handle_command(doc);
|
||||
if (_session_terminated) {
|
||||
return;
|
||||
}
|
||||
ACQUIRE_LOCK(_commands_lock);
|
||||
}
|
||||
RELEASE_LOCK(_commands_lock);
|
||||
@ -704,6 +692,7 @@ check_comm() {
|
||||
// The low-level thread detected an error, for instance pipe
|
||||
// closed. We should exit gracefully.
|
||||
terminate_session();
|
||||
return;
|
||||
}
|
||||
|
||||
// Sleep to yield the timeslice, but only if we're not running in
|
||||
@ -758,6 +747,9 @@ wait_script_response(int response_id) {
|
||||
_commands.erase(ci);
|
||||
RELEASE_LOCK(_commands_lock);
|
||||
handle_command(doc);
|
||||
if (_session_terminated) {
|
||||
return NULL;
|
||||
}
|
||||
ACQUIRE_LOCK(_commands_lock);
|
||||
break;
|
||||
}
|
||||
@ -791,6 +783,7 @@ wait_script_response(int response_id) {
|
||||
|
||||
if (!_program_continue) {
|
||||
terminate_session();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
@ -839,6 +832,9 @@ py_request_func(PyObject *args) {
|
||||
}
|
||||
|
||||
TiXmlDocument *doc = wait_script_response(response_id);
|
||||
if (_session_terminated) {
|
||||
return Py_BuildValue("");
|
||||
}
|
||||
assert(doc != NULL);
|
||||
TiXmlElement *xcommand = doc->FirstChildElement("command");
|
||||
assert(xcommand != NULL);
|
||||
@ -1230,10 +1226,7 @@ terminate_session() {
|
||||
}
|
||||
Py_DECREF(result);
|
||||
|
||||
// The task manager is cleaned up. Let's exit immediately here,
|
||||
// rather than returning all the way up. This just makes it easier
|
||||
// when we call terminate_session() from a deeply-nested loop.
|
||||
exit(0);
|
||||
_session_terminated = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -1561,16 +1554,18 @@ rt_thread_run() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: main
|
||||
// Description: Starts the program running.
|
||||
// Function: run_p3dpython
|
||||
// Description: This externally-visible function is the main entry
|
||||
// point to this DLL, and it starts the whole thing
|
||||
// running. Returns true on success, false on failure.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int
|
||||
main(int argc, char *argv[]) {
|
||||
P3DPythonRun::_global_ptr = new P3DPythonRun(argc, argv);
|
||||
|
||||
if (!P3DPythonRun::_global_ptr->run_python()) {
|
||||
nout << "Couldn't initialize Python.\n";
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
bool
|
||||
run_p3dpython(const char *program_name, const char *archive_file,
|
||||
FHandle input, FHandle output) {
|
||||
P3DPythonRun::_global_ptr =
|
||||
new P3DPythonRun(program_name, archive_file, input, output);
|
||||
bool result = P3DPythonRun::_global_ptr->run_python();
|
||||
delete P3DPythonRun::_global_ptr;
|
||||
P3DPythonRun::_global_ptr = NULL;
|
||||
return result;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "run_p3dpython.h"
|
||||
#include "p3d_lock.h"
|
||||
#include "handleStream.h"
|
||||
#include "p3dCInstance.h"
|
||||
@ -65,7 +66,8 @@ using namespace std;
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class P3DPythonRun {
|
||||
public:
|
||||
P3DPythonRun(int argc, char *argv[]);
|
||||
P3DPythonRun(const char *program_name, const char *archive_file,
|
||||
FHandle input, FHandle output);
|
||||
~P3DPythonRun();
|
||||
|
||||
bool run_python();
|
||||
@ -153,6 +155,7 @@ private:
|
||||
|
||||
bool _read_thread_continue;
|
||||
bool _program_continue;
|
||||
bool _session_terminated;
|
||||
THREAD _read_thread;
|
||||
|
||||
public:
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "p3dConcreteStruct.h"
|
||||
#include "binaryXml.h"
|
||||
#include "mkdir_complete.h"
|
||||
#include "run_p3dpython.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
@ -34,6 +35,7 @@
|
||||
#include <sys/wait.h>
|
||||
#include <sys/select.h>
|
||||
#include <signal.h>
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -53,6 +55,7 @@ P3DSession(P3DInstance *inst) {
|
||||
_python_version = inst->get_python_version();
|
||||
|
||||
_start_dir = inst_mgr->get_root_dir() + "/start";
|
||||
_p3dpython_one_process = false;
|
||||
_p3dpython_started = false;
|
||||
_p3dpython_running = false;
|
||||
|
||||
@ -100,67 +103,86 @@ shutdown() {
|
||||
|
||||
static const int max_wait_ms = 2000;
|
||||
|
||||
if (_p3dpython_one_process) {
|
||||
// Since it's running in a thread, we can't reliably force-kill
|
||||
// it. So, just wait.
|
||||
nout << "Waiting for Python thread to exit\n";
|
||||
JOIN_THREAD(_p3dpython_thread);
|
||||
nout << "Done waiting.\n";
|
||||
_p3dpython_one_process = false;
|
||||
|
||||
} else {
|
||||
// Python's running in a sub-process, the preferred way. In
|
||||
// this case, we can wait a brief amount of time before it
|
||||
// closes itself; but if it doesn't, we can safely force-kill
|
||||
// it.
|
||||
|
||||
#ifdef _WIN32
|
||||
// Now give the process a chance to terminate itself cleanly.
|
||||
if (WaitForSingleObject(_p3dpython_handle, max_wait_ms) == WAIT_TIMEOUT) {
|
||||
// It didn't shut down cleanly, so kill it the hard way.
|
||||
nout << "Force-killing python process.\n";
|
||||
TerminateProcess(_p3dpython_handle, 2);
|
||||
}
|
||||
|
||||
CloseHandle(_p3dpython_handle);
|
||||
#else // _WIN32
|
||||
|
||||
// Wait for a certain amount of time for the process to stop by
|
||||
// itself.
|
||||
struct timeval start;
|
||||
gettimeofday(&start, NULL);
|
||||
int start_ms = start.tv_sec * 1000 + start.tv_usec / 1000;
|
||||
|
||||
int status;
|
||||
pid_t result = waitpid(_p3dpython_pid, &status, WNOHANG);
|
||||
while (result != _p3dpython_pid) {
|
||||
if (result == -1) {
|
||||
perror("waitpid");
|
||||
break;
|
||||
}
|
||||
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
int now_ms = now.tv_sec * 1000 + now.tv_usec / 1000;
|
||||
int elapsed = now_ms - start_ms;
|
||||
|
||||
if (elapsed > max_wait_ms) {
|
||||
// Tired of waiting. Kill the process.
|
||||
nout << "Force-killing python process, pid " << _p3dpython_pid
|
||||
<< "\n";
|
||||
kill(_p3dpython_pid, SIGKILL);
|
||||
start_ms = now_ms;
|
||||
// Wait for a certain amount of time for the process to stop by
|
||||
// itself.
|
||||
if (WaitForSingleObject(_p3dpython_handle, max_wait_ms) == WAIT_TIMEOUT) {
|
||||
// It didn't shut down cleanly, so kill it the hard way.
|
||||
nout << "Force-killing python process.\n";
|
||||
TerminateProcess(_p3dpython_handle, 2);
|
||||
}
|
||||
|
||||
// Yield the timeslice and wait some more.
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 1;
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
result = waitpid(_p3dpython_pid, &status, WNOHANG);
|
||||
}
|
||||
|
||||
nout << "Python process has successfully stopped.\n";
|
||||
if (WIFEXITED(status)) {
|
||||
nout << " exited normally, status = "
|
||||
<< WEXITSTATUS(status) << "\n";
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
nout << " signalled by " << WTERMSIG(status) << ", core = "
|
||||
<< WCOREDUMP(status) << "\n";
|
||||
} else if (WIFSTOPPED(status)) {
|
||||
nout << " stopped by " << WSTOPSIG(status) << "\n";
|
||||
}
|
||||
CloseHandle(_p3dpython_handle);
|
||||
|
||||
#else // _WIN32
|
||||
// Wait for a certain amount of time for the process to stop by
|
||||
// itself.
|
||||
struct timeval start;
|
||||
gettimeofday(&start, NULL);
|
||||
int start_ms = start.tv_sec * 1000 + start.tv_usec / 1000;
|
||||
|
||||
int status;
|
||||
pid_t result = waitpid(_p3dpython_pid, &status, WNOHANG);
|
||||
while (result != _p3dpython_pid) {
|
||||
if (result == -1) {
|
||||
perror("waitpid");
|
||||
break;
|
||||
}
|
||||
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
int now_ms = now.tv_sec * 1000 + now.tv_usec / 1000;
|
||||
int elapsed = now_ms - start_ms;
|
||||
|
||||
if (elapsed > max_wait_ms) {
|
||||
// Tired of waiting. Kill the process.
|
||||
nout << "Force-killing python process, pid " << _p3dpython_pid
|
||||
<< "\n";
|
||||
kill(_p3dpython_pid, SIGKILL);
|
||||
start_ms = now_ms;
|
||||
}
|
||||
|
||||
// Yield the timeslice and wait some more.
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 1;
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
result = waitpid(_p3dpython_pid, &status, WNOHANG);
|
||||
}
|
||||
|
||||
nout << "Python process has successfully stopped.\n";
|
||||
if (WIFEXITED(status)) {
|
||||
nout << " exited normally, status = "
|
||||
<< WEXITSTATUS(status) << "\n";
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
nout << " signalled by " << WTERMSIG(status) << ", core = "
|
||||
<< WCOREDUMP(status) << "\n";
|
||||
} else if (WIFSTOPPED(status)) {
|
||||
nout << " stopped by " << WSTOPSIG(status) << "\n";
|
||||
}
|
||||
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
_p3dpython_running = false;
|
||||
_p3dpython_started = false;
|
||||
|
||||
// Close the pipe now.
|
||||
_pipe_read.close();
|
||||
}
|
||||
|
||||
// If there are any leftover commands in the queue (presumably
|
||||
@ -657,10 +679,9 @@ start_p3dpython(P3DInstance *inst) {
|
||||
// Change the current directory to the standard start directory, but
|
||||
// only if the runtime environment told us the original current
|
||||
// directory isn't meaningful.
|
||||
string start_dir;
|
||||
if (!inst_mgr->get_keep_cwd()) {
|
||||
start_dir = _start_dir;
|
||||
mkdir_complete(start_dir, nout);
|
||||
_use_start_dir = !inst_mgr->get_keep_cwd();
|
||||
if (_use_start_dir) {
|
||||
mkdir_complete(_start_dir, nout);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
@ -725,16 +746,30 @@ start_p3dpython(P3DInstance *inst) {
|
||||
<< "PRC_PATH set to: " << prc_path << "\n";
|
||||
}
|
||||
|
||||
string p3dpython = P3D_PLUGIN_P3DPYTHON;
|
||||
if (p3dpython.empty()) {
|
||||
p3dpython = _python_root_dir + "/p3dpython";
|
||||
// Get the name of the executable and dynamic library to run.
|
||||
// Ideally, we'll run the executable successfully, in a sub-process;
|
||||
// this will in turn load and run the dynamic library. If that
|
||||
// fails for some reason, we can fall back to loading and running
|
||||
// the library directly.
|
||||
_p3dpython_exe = _python_root_dir + "/p3dpython";
|
||||
#ifdef _WIN32
|
||||
p3dpython += ".exe";
|
||||
_p3dpython_exe += ".exe";
|
||||
#endif
|
||||
|
||||
_p3dpython_dll = P3D_PLUGIN_P3DPYTHON;
|
||||
if (_p3dpython_dll.empty()) {
|
||||
_p3dpython_dll = _python_root_dir + "/libp3dpython";
|
||||
#ifdef _WIN32
|
||||
_p3dpython_dll += ".dll";
|
||||
#elif defined(__APPLE__)
|
||||
_p3dpython_dll += ".dylib";
|
||||
#else
|
||||
_p3dpython_dll += ".so";
|
||||
#endif
|
||||
}
|
||||
|
||||
// Populate the new process' environment.
|
||||
string env;
|
||||
_env = string();
|
||||
|
||||
// These are the enviroment variables we forward from the current
|
||||
// environment, if they are set.
|
||||
@ -748,41 +783,41 @@ start_p3dpython(P3DInstance *inst) {
|
||||
for (int ki = 0; keep[ki] != NULL; ++ki) {
|
||||
char *value = getenv(keep[ki]);
|
||||
if (value != NULL) {
|
||||
env += keep[ki];
|
||||
env += "=";
|
||||
env += value;
|
||||
env += '\0';
|
||||
_env += keep[ki];
|
||||
_env += "=";
|
||||
_env += value;
|
||||
_env += '\0';
|
||||
}
|
||||
}
|
||||
|
||||
// Define some new environment variables.
|
||||
env += "PATH=";
|
||||
env += search_path;
|
||||
env += '\0';
|
||||
_env += "PATH=";
|
||||
_env += search_path;
|
||||
_env += '\0';
|
||||
|
||||
env += "LD_LIBRARY_PATH=";
|
||||
env += search_path;
|
||||
env += '\0';
|
||||
_env += "LD_LIBRARY_PATH=";
|
||||
_env += search_path;
|
||||
_env += '\0';
|
||||
|
||||
env += "DYLD_LIBRARY_PATH=";
|
||||
env += search_path;
|
||||
env += '\0';
|
||||
_env += "DYLD_LIBRARY_PATH=";
|
||||
_env += search_path;
|
||||
_env += '\0';
|
||||
|
||||
env += "PYTHONPATH=";
|
||||
env += python_path;
|
||||
env += '\0';
|
||||
_env += "PYTHONPATH=";
|
||||
_env += python_path;
|
||||
_env += '\0';
|
||||
|
||||
env += "PYTHONHOME=";
|
||||
env += _python_root_dir;
|
||||
env += '\0';
|
||||
_env += "PYTHONHOME=";
|
||||
_env += _python_root_dir;
|
||||
_env += '\0';
|
||||
|
||||
env += "PRC_PATH=";
|
||||
env += prc_path;
|
||||
env += '\0';
|
||||
_env += "PRC_PATH=";
|
||||
_env += prc_path;
|
||||
_env += '\0';
|
||||
|
||||
env += "PANDA_PRC_PATH=";
|
||||
env += prc_path;
|
||||
env += '\0';
|
||||
_env += "PANDA_PRC_PATH=";
|
||||
_env += prc_path;
|
||||
_env += '\0';
|
||||
|
||||
// Define each package's root directory in an environment variable
|
||||
// named after the package, for the convenience of the packages in
|
||||
@ -793,11 +828,11 @@ start_p3dpython(P3DInstance *inst) {
|
||||
for (string::const_iterator si = package_name.begin();
|
||||
si != package_name.end();
|
||||
++si) {
|
||||
env += toupper(*si);
|
||||
_env += toupper(*si);
|
||||
}
|
||||
env += string("_ROOT=");
|
||||
env += package->get_package_dir();
|
||||
env += '\0';
|
||||
_env += string("_ROOT=");
|
||||
_env += package->get_package_dir();
|
||||
_env += '\0';
|
||||
}
|
||||
|
||||
// Get the log filename from the p3d_info.xml file.
|
||||
@ -809,6 +844,7 @@ start_p3dpython(P3DInstance *inst) {
|
||||
}
|
||||
|
||||
bool console_output = (inst->get_fparams().lookup_token_int("console_output") != 0);
|
||||
bool one_process = (inst->get_fparams().lookup_token_int("one_process") != 0);
|
||||
|
||||
#ifdef P3D_PLUGIN_LOG_BASENAME3
|
||||
if (log_basename.empty()) {
|
||||
@ -840,24 +876,82 @@ start_p3dpython(P3DInstance *inst) {
|
||||
_log_pathname += ".log";
|
||||
}
|
||||
|
||||
string archive_file = inst->_panda3d->get_archive_file_pathname();
|
||||
|
||||
nout << "Attempting to start python from " << p3dpython << "\n";
|
||||
// Create the pipes for communication.
|
||||
#ifdef _WIN32
|
||||
_p3dpython_handle = win_create_process
|
||||
(p3dpython, archive_file, start_dir, env, _log_pathname,
|
||||
_pipe_read, _pipe_write);
|
||||
bool started_p3dpython = (_p3dpython_handle != INVALID_HANDLE_VALUE);
|
||||
// Create a bi-directional pipe to communicate with the sub-process.
|
||||
HANDLE r_to, w_to, r_from, w_from;
|
||||
|
||||
// Create the pipe to the process.
|
||||
if (!CreatePipe(&r_to, &w_to, NULL, 0)) {
|
||||
nout << "failed to create pipe\n";
|
||||
} else {
|
||||
// Make sure the right end of the pipe is inheritable.
|
||||
SetHandleInformation(r_to, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
|
||||
SetHandleInformation(w_to, HANDLE_FLAG_INHERIT, 0);
|
||||
}
|
||||
|
||||
// Create the pipe from the process.
|
||||
if (!CreatePipe(&r_from, &w_from, NULL, 0)) {
|
||||
nout << "failed to create pipe\n";
|
||||
} else {
|
||||
// Make sure the right end of the pipe is inheritable.
|
||||
SetHandleInformation(w_from, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
|
||||
SetHandleInformation(r_from, HANDLE_FLAG_INHERIT, 0);
|
||||
}
|
||||
|
||||
_output = w_from;
|
||||
_input = r_to;
|
||||
_pipe_read.open_read(r_from);
|
||||
_pipe_write.open_write(w_to);
|
||||
|
||||
#else
|
||||
_p3dpython_pid = posix_create_process
|
||||
(p3dpython, archive_file, start_dir, env, _log_pathname,
|
||||
_pipe_read, _pipe_write);
|
||||
bool started_p3dpython = (_p3dpython_pid > 0);
|
||||
// Create a bi-directional pipe to communicate with the sub-process.
|
||||
int to_fd[2];
|
||||
if (pipe(to_fd) < 0) {
|
||||
perror("failed to create pipe");
|
||||
}
|
||||
int from_fd[2];
|
||||
if (pipe(from_fd) < 0) {
|
||||
perror("failed to create pipe");
|
||||
}
|
||||
|
||||
_input = to_fd[0];
|
||||
_output = from_fd[1];
|
||||
_pipe_read.open_read(from_fd[0]);
|
||||
_pipe_write.open_write(to_fd[1]);
|
||||
#endif // _WIN32
|
||||
|
||||
// Get the filename to the Panda3D multifile. We need to pass this
|
||||
// to p3dpython.
|
||||
_mf_filename = inst->_panda3d->get_archive_file_pathname();
|
||||
|
||||
bool started_p3dpython;
|
||||
if (one_process) {
|
||||
nout << "one_process is set; running Python within parent process.\n";
|
||||
started_p3dpython = false;
|
||||
} else {
|
||||
nout << "Attempting to start python from " << _p3dpython_exe
|
||||
<< " and " << _p3dpython_dll << "\n";
|
||||
#ifdef _WIN32
|
||||
_p3dpython_handle = win_create_process();
|
||||
started_p3dpython = (_p3dpython_handle != INVALID_HANDLE_VALUE);
|
||||
#else
|
||||
_p3dpython_pid = posix_create_process();
|
||||
started_p3dpython = (_p3dpython_pid > 0);
|
||||
#endif
|
||||
if (!started_p3dpython) {
|
||||
nout << "Failed to create process.\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (!started_p3dpython) {
|
||||
nout << "Failed to create process.\n";
|
||||
return;
|
||||
// Well, we couldn't run python in a sub-process, for some reason.
|
||||
// Fall back to running it in a sub-thread within the same
|
||||
// process. This isn't nearly as good, but I guess it's better
|
||||
// than nothing.
|
||||
INIT_THREAD(_p3dpython_thread);
|
||||
SPAWN_THREAD(_p3dpython_thread, p3dpython_thread_run, this);
|
||||
_p3dpython_one_process = true;
|
||||
}
|
||||
_p3dpython_started = true;
|
||||
_p3dpython_running = true;
|
||||
@ -1019,60 +1113,37 @@ rt_terminate() {
|
||||
#ifdef _WIN32
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DSession::win_create_process
|
||||
// Access: Private, Static
|
||||
// Description: Creates a sub-process to run the named program
|
||||
// executable, with the indicated environment string.
|
||||
// Standard error is logged to log_pathname, if that
|
||||
// string is nonempty.
|
||||
// Access: Private
|
||||
// Description: Creates a sub-process to run _p3dpython_exe, with
|
||||
// the appropriate command-line arguments, and the
|
||||
// environment string defined in _env. Standard error
|
||||
// is logged to _log_pathname, if that string is
|
||||
// nonempty.
|
||||
//
|
||||
// Opens the two HandleStreams as the read and write
|
||||
// pipes to the child process's standard output and
|
||||
// standard input, respectively.
|
||||
// Opens the two HandleStreams _pipe_read and
|
||||
// _pipe_write as the read and write pipes to the child
|
||||
// process's standard output and standard input,
|
||||
// respectively.
|
||||
//
|
||||
// Returns the handle to the created process on success,
|
||||
// or INVALID_HANDLE_VALUE on falure.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
HANDLE P3DSession::
|
||||
win_create_process(const string &program, const string &archive_file,
|
||||
const string &start_dir,
|
||||
const string &env, const string &log_pathname,
|
||||
HandleStream &pipe_read, HandleStream &pipe_write) {
|
||||
|
||||
// Create a bi-directional pipe to communicate with the sub-process.
|
||||
HANDLE r_to, w_to, r_from, w_from;
|
||||
|
||||
// Create the pipe to the process.
|
||||
if (!CreatePipe(&r_to, &w_to, NULL, 0)) {
|
||||
nout << "failed to create pipe\n";
|
||||
} else {
|
||||
// Make sure the right end of the pipe is inheritable.
|
||||
SetHandleInformation(r_to, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
|
||||
SetHandleInformation(w_to, HANDLE_FLAG_INHERIT, 0);
|
||||
}
|
||||
|
||||
// Create the pipe from the process.
|
||||
if (!CreatePipe(&r_from, &w_from, NULL, 0)) {
|
||||
nout << "failed to create pipe\n";
|
||||
} else {
|
||||
// Make sure the right end of the pipe is inheritable.
|
||||
SetHandleInformation(w_from, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
|
||||
SetHandleInformation(r_from, HANDLE_FLAG_INHERIT, 0);
|
||||
}
|
||||
|
||||
win_create_process() {
|
||||
HANDLE error_handle = GetStdHandle(STD_ERROR_HANDLE);
|
||||
bool got_log_pathname = !log_pathname.empty();
|
||||
bool got_log_pathname = !_log_pathname.empty();
|
||||
if (got_log_pathname) {
|
||||
// Open the named file for output and redirect the child's stderr
|
||||
// into it.
|
||||
HANDLE handle = CreateFile
|
||||
(log_pathname.c_str(), GENERIC_WRITE,
|
||||
(_log_pathname.c_str(), GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL, CREATE_ALWAYS, 0, NULL);
|
||||
if (handle != INVALID_HANDLE_VALUE) {
|
||||
error_handle = handle;
|
||||
SetHandleInformation(error_handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
|
||||
} else {
|
||||
nout << "Unable to open " << log_pathname << "\n";
|
||||
nout << "Unable to open " << _log_pathname << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
@ -1085,8 +1156,8 @@ win_create_process(const string &program, const string &archive_file,
|
||||
ZeroMemory(&startup_info, sizeof(STARTUPINFO));
|
||||
startup_info.cb = sizeof(startup_info);
|
||||
startup_info.hStdError = error_handle;
|
||||
startup_info.hStdOutput = w_from;
|
||||
startup_info.hStdInput = r_to;
|
||||
startup_info.hStdOutput = _output;
|
||||
startup_info.hStdInput = _input;
|
||||
startup_info.dwFlags |= STARTF_USESTDHANDLES;
|
||||
|
||||
// Make sure the "python" console window is hidden.
|
||||
@ -1096,15 +1167,18 @@ win_create_process(const string &program, const string &archive_file,
|
||||
// If the start directory is empty, meaning not to change the
|
||||
// current directory, then pass NULL in to CreateProcess().
|
||||
const char *start_dir_cstr = NULL;
|
||||
if (!start_dir.empty()) {
|
||||
start_dir_cstr = start_dir.c_str();
|
||||
if (_use_start_dir) {
|
||||
start_dir_cstr = _start_dir.c_str();
|
||||
}
|
||||
|
||||
// Construct the command-line string, containing the quoted
|
||||
// command-line arguments.
|
||||
ostringstream stream;
|
||||
stream << "\"" << program << "\" \"" << archive_file << "\"";
|
||||
stream << "\"" << _p3dpython_exe << "\" \"" << _p3dpython_dll
|
||||
<< "\" \"" << _mf_filename << "\"";
|
||||
|
||||
// I'm not sure why CreateProcess wants a non-const char pointer for
|
||||
// the command-line argument, but I'm not taking chances. It gets a
|
||||
// its command-line string, but I'm not taking chances. It gets a
|
||||
// non-const char array that it can modify.
|
||||
string command_line_str = stream.str();
|
||||
char *command_line = new char[command_line_str.size() + 1];
|
||||
@ -1112,29 +1186,26 @@ win_create_process(const string &program, const string &archive_file,
|
||||
|
||||
PROCESS_INFORMATION process_info;
|
||||
BOOL result = CreateProcess
|
||||
(program.c_str(), command_line, NULL, NULL, TRUE, 0,
|
||||
(void *)env.c_str(), start_dir_cstr,
|
||||
(_p3dpython_exe.c_str(), command_line, NULL, NULL, TRUE, 0,
|
||||
(void *)_env.c_str(), _start_dir_cstr,
|
||||
&startup_info, &process_info);
|
||||
bool started_program = (result != 0);
|
||||
|
||||
delete[] command_line;
|
||||
|
||||
// Close the pipe handles that are now owned by the child.
|
||||
CloseHandle(w_from);
|
||||
CloseHandle(r_to);
|
||||
CloseHandle(_output);
|
||||
CloseHandle(_input);
|
||||
if (got_log_pathname) {
|
||||
CloseHandle(error_handle);
|
||||
}
|
||||
|
||||
if (!started_program) {
|
||||
CloseHandle(r_from);
|
||||
CloseHandle(w_to);
|
||||
_pipe_read.close();
|
||||
_pipe_write.close();
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
pipe_read.open_read(r_from);
|
||||
pipe_write.open_write(w_to);
|
||||
|
||||
CloseHandle(process_info.hThread);
|
||||
return process_info.hProcess;
|
||||
}
|
||||
@ -1144,54 +1215,40 @@ win_create_process(const string &program, const string &archive_file,
|
||||
#ifndef _WIN32
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DSession::posix_create_process
|
||||
// Access: Private, Static
|
||||
// Description: Creates a sub-process to run the named program
|
||||
// executable, with the indicated environment string.
|
||||
// Access: Private
|
||||
// Description: Creates a sub-process to run _p3dpython_exe, with
|
||||
// the appropriate command-line arguments, and the
|
||||
// environment string defined in _env. Standard error
|
||||
// is logged to _log_pathname, if that string is
|
||||
// nonempty.
|
||||
//
|
||||
// Opens the two HandleStreams as the read and write
|
||||
// pipes to the child process's standard output and
|
||||
// standard input, respectively. Returns true on
|
||||
// success, false on failure.
|
||||
// Opens the two HandleStreams _pipe_read and
|
||||
// _pipe_write as the read and write pipes to the child
|
||||
// process's standard output and standard input,
|
||||
// respectively.
|
||||
//
|
||||
// Returns the pid of the created process on success, or
|
||||
// -1 on falure.
|
||||
// Returns the handle to the created process on success,
|
||||
// or INVALID_HANDLE_VALUE on falure.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int P3DSession::
|
||||
posix_create_process(const string &program, const string &archive_file,
|
||||
const string &start_dir,
|
||||
const string &env, const string &log_pathname,
|
||||
HandleStream &pipe_read, HandleStream &pipe_write) {
|
||||
// Create a bi-directional pipe to communicate with the sub-process.
|
||||
int to_fd[2];
|
||||
if (pipe(to_fd) < 0) {
|
||||
perror("failed to create pipe");
|
||||
}
|
||||
int from_fd[2];
|
||||
if (pipe(from_fd) < 0) {
|
||||
perror("failed to create pipe");
|
||||
}
|
||||
|
||||
posix_create_process() {
|
||||
// Fork and exec.
|
||||
pid_t child = fork();
|
||||
if (child < 0) {
|
||||
close(to_fd[0]);
|
||||
close(to_fd[1]);
|
||||
close(from_fd[0]);
|
||||
close(from_fd[1]);
|
||||
perror("fork");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (child == 0) {
|
||||
// Here we are in the child process.
|
||||
bool got_log_pathname = !log_pathname.empty();
|
||||
bool got_log_pathname = !_log_pathname.empty();
|
||||
if (got_log_pathname) {
|
||||
// Open the named file for output and redirect the child's stderr
|
||||
// into it.
|
||||
int logfile_fd = open(log_pathname.c_str(),
|
||||
int logfile_fd = open(_log_pathname.c_str(),
|
||||
O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||
if (logfile_fd < 0) {
|
||||
nout << "Unable to open " << log_pathname << "\n";
|
||||
nout << "Unable to open " << _log_pathname << "\n";
|
||||
} else {
|
||||
dup2(logfile_fd, STDERR_FILENO);
|
||||
close(logfile_fd);
|
||||
@ -1200,41 +1257,108 @@ posix_create_process(const string &program, const string &archive_file,
|
||||
|
||||
// Set the appropriate ends of the bi-directional pipe as the
|
||||
// standard input and standard output of the child process.
|
||||
dup2(to_fd[0], STDIN_FILENO);
|
||||
dup2(from_fd[1], STDOUT_FILENO);
|
||||
close(to_fd[1]);
|
||||
close(from_fd[0]);
|
||||
dup2(_input, STDIN_FILENO);
|
||||
dup2(_output, STDOUT_FILENO);
|
||||
_pipe_read.close();
|
||||
_pipe_write.close();
|
||||
|
||||
if (!start_dir.empty()) {
|
||||
if (chdir(start_dir.c_str()) < 0) {
|
||||
nout << "Could not chdir to " << start_dir << "\n";
|
||||
_exit(1);
|
||||
if (_use_start_dir) {
|
||||
if (chdir(_start_dir.c_str()) < 0) {
|
||||
nout << "Could not chdir to " << _start_dir << "\n";
|
||||
// This is a warning, not an error. We don't actually care
|
||||
// that much about the starting directory.
|
||||
}
|
||||
}
|
||||
|
||||
// build up an array of char strings for the environment.
|
||||
vector<const char *> ptrs;
|
||||
size_t p = 0;
|
||||
size_t zero = env.find('\0', p);
|
||||
size_t zero = _env.find('\0', p);
|
||||
while (zero != string::npos) {
|
||||
ptrs.push_back(env.data() + p);
|
||||
ptrs.push_back(_env.data() + p);
|
||||
p = zero + 1;
|
||||
zero = env.find('\0', p);
|
||||
zero = _env.find('\0', p);
|
||||
}
|
||||
ptrs.push_back((char *)NULL);
|
||||
|
||||
execle(program.c_str(),
|
||||
program.c_str(), archive_file.c_str(), (char *)0,
|
||||
|
||||
execle(_p3dpython_exe.c_str(),
|
||||
_p3dpython_exe.c_str(), _p3dpython_dll.c_str(), _mf_filename.c_str(), (char *)0,
|
||||
&ptrs[0]);
|
||||
nout << "Failed to exec " << program << "\n";
|
||||
nout << "Failed to exec " << _p3dpython_exe << "\n";
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
pipe_read.open_read(from_fd[0]);
|
||||
pipe_write.open_write(to_fd[1]);
|
||||
close(to_fd[0]);
|
||||
close(from_fd[1]);
|
||||
close(_input);
|
||||
close(_output);
|
||||
|
||||
return child;
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DSession::p3dpython_thread_run
|
||||
// Access: Private
|
||||
// Description: This method is called in a sub-thread to fire up
|
||||
// p3dpython within this same process, but only if the
|
||||
// above attempt to create a sub-process failed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DSession::
|
||||
p3dpython_thread_run() {
|
||||
nout << "running p3dpython_thread_run()\n";
|
||||
|
||||
// Set the environment. Hopefully this won't be too destructive to
|
||||
// the current process, and hopefully these changes will be read
|
||||
// properly by Python.
|
||||
size_t p = 0;
|
||||
size_t zero = _env.find('\0', p);
|
||||
while (zero != string::npos) {
|
||||
const char *start = _env.data() + p;
|
||||
const char *equals = strchr(start, '=');
|
||||
if (equals != NULL) {
|
||||
string variable(start, equals - start);
|
||||
#ifdef _WIN32
|
||||
_putenv_s(variable.c_str(), equals + 1);
|
||||
#else
|
||||
setenv(variable.c_str(), equals + 1, true);
|
||||
#endif // _WIN32
|
||||
}
|
||||
p = zero + 1;
|
||||
zero = _env.find('\0', p);
|
||||
}
|
||||
|
||||
// Now load the library.
|
||||
#ifdef _WIN32
|
||||
SetErrorMode(0);
|
||||
HMODULE module = LoadLibrary(_p3dpython_dll.c_str());
|
||||
if (module == NULL) {
|
||||
// Couldn't load the DLL.
|
||||
nout << "Couldn't load " << _p3dpython_dll << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
#define get_func GetProcAddress
|
||||
|
||||
#else // _WIN32
|
||||
// Posix case.
|
||||
void *module = dlopen(_p3dpython_dll.c_str(), RTLD_GLOBAL);
|
||||
if (module == NULL) {
|
||||
// Couldn't load the .so.
|
||||
nout << "Couldn't load " << _p3dpython_dll << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
#define get_func dlsym
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
run_p3dpython_func *run_p3dpython = (run_p3dpython_func *)get_func(module, "run_p3dpython");
|
||||
if (run_p3dpython == NULL) {
|
||||
nout << "Couldn't find run_p3dpython\n";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!run_p3dpython(_p3dpython_dll.c_str(), _mf_filename.c_str(),
|
||||
_input, _output)) {
|
||||
nout << "Failure on startup.\n";
|
||||
}
|
||||
}
|
||||
|
@ -75,19 +75,16 @@ private:
|
||||
void rt_handle_request(TiXmlDocument *doc);
|
||||
|
||||
#ifdef _WIN32
|
||||
static HANDLE
|
||||
win_create_process(const string &program, const string &archive_file,
|
||||
const string &start_dir,
|
||||
const string &env, const string &output_filename,
|
||||
HandleStream &pipe_read, HandleStream &pipe_write);
|
||||
HANDLE win_create_process();
|
||||
#else
|
||||
static int
|
||||
posix_create_process(const string &program, const string &archive_file,
|
||||
const string &start_dir,
|
||||
const string &env, const string &output_filename,
|
||||
HandleStream &pipe_read, HandleStream &pipe_write);
|
||||
int posix_create_process();
|
||||
#endif
|
||||
|
||||
// In case we can't get a separate process, we'll run p3dpython in a
|
||||
// sub-thread.
|
||||
THREAD_CALLBACK_DECLARATION(P3DSession, p3dpython_thread_run);
|
||||
void p3dpython_thread_run();
|
||||
|
||||
private:
|
||||
int _session_id;
|
||||
string _session_key;
|
||||
@ -95,6 +92,15 @@ private:
|
||||
string _log_pathname;
|
||||
string _python_root_dir;
|
||||
string _start_dir;
|
||||
bool _use_start_dir;
|
||||
|
||||
// This information is passed to create_process(), or to
|
||||
// p3dpython_thread_run().
|
||||
string _p3dpython_exe;
|
||||
string _p3dpython_dll;
|
||||
string _mf_filename;
|
||||
string _env;
|
||||
FHandle _input, _output;
|
||||
|
||||
typedef map<int, P3DInstance *> Instances;
|
||||
Instances _instances;
|
||||
@ -114,12 +120,21 @@ private:
|
||||
|
||||
P3DPackage *_panda3d;
|
||||
|
||||
// Members for communicating with the p3dpython child process.
|
||||
// If this is true, then CreateProcess() or fork() failed (or we had
|
||||
// one_process set true in the tokens), and we're forced to run
|
||||
// p3dpython in a sub-thread within the same process, rather than in
|
||||
// a separate process. This means we can't have multiple sessions
|
||||
// running simultaneously, because Python don't play that way.
|
||||
bool _p3dpython_one_process;
|
||||
|
||||
// Members for communicating with the p3dpython child process (or
|
||||
// thread, as the case may be).
|
||||
#ifdef _WIN32
|
||||
HANDLE _p3dpython_handle;
|
||||
#else
|
||||
int _p3dpython_pid;
|
||||
#endif
|
||||
THREAD _p3dpython_thread;
|
||||
bool _p3dpython_started;
|
||||
bool _p3dpython_running;
|
||||
|
||||
|
37
direct/src/plugin/run_p3dpython.h
Normal file
37
direct/src/plugin/run_p3dpython.h
Normal file
@ -0,0 +1,37 @@
|
||||
// Filename: run_p3dpython.h
|
||||
// Created by: drose (29Aug09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef RUN_P3DPYTHON_H
|
||||
#define RUN_P3DPYTHON_H
|
||||
|
||||
// This header file defines the prototype for run_p3dpython(), the
|
||||
// main entry point to this DLL.
|
||||
|
||||
#include "fhandle.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define EXPCL_P3DPYTHON __declspec(dllexport)
|
||||
#else
|
||||
#define EXPCL_P3DPYTHON
|
||||
#endif
|
||||
|
||||
typedef bool run_p3dpython_func(const char *program_name, const char *archive_file,
|
||||
FHandle input, FHandle output);
|
||||
|
||||
EXPCL_P3DPYTHON extern "C" bool
|
||||
run_p3dpython(const char *program_name, const char *archive_file,
|
||||
FHandle input, FHandle output);
|
||||
|
||||
#endif
|
||||
|
@ -12,7 +12,7 @@
|
||||
prc:c dtoolutil:c dtoolbase:c dtool:m \
|
||||
interrogatedb:c dconfig:c dtoolconfig:m \
|
||||
express:c downloader:c pandaexpress:m \
|
||||
pystub
|
||||
$[if $[WINDOWS_PLATFORM],pystub,]
|
||||
|
||||
#define OSX_SYS_FRAMEWORKS Foundation AppKit Carbon
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user