I am trying to use GLib to spawn a python script process from within a C program. I can easily do this when the Python script has been compiled into an executable via PyInstaller by using:
// Set the python executable string based on the OS
gchar* python_executable;
#ifdef __MSYS__
python_executable = "../gtk_simple_plot/dist/plot/plot.exe";
g_print("Using MSYS2\n");
#else
python_executable = "../gtk_simple_plot/dist/plot/./plot";
g_print("Not Using MSYS2\n");
#endif
// Create argv for the python executable
gchar* argv[] = {python_executable, NULL};
GPid transition_pid;
GError* err = NULL;
int stdoutFD;
int stderrFD;
// Spawn the python program to plot
g_spawn_async_with_pipes (NULL, // Inherit parent's working directory
argv, // argv from above
NULL, // Don't set any additional environment variables
G_SPAWN_DO_NOT_REAP_CHILD, // Default spawn settings
NULL, // No setup function prior to executing
NULL, // No data passed to setup function
&transition_pid, // Store child pid
NULL, // No standard input file descriptor
&stdoutFD, // Standard output file descriptor
&stderrFD, // Standard error file descriptor
&err); // Store error
if (err != NULL)
{
g_error ("Spawning child failed: %s", err->message);
return;
}
However, I am running into some issues which I believe are coming from PyInstaller, so I want to just spawn the Python script, rather than the executable. The issue I am having stems from not being aware of what to pass to argv[]
. The GLib page on spawning processes states that the g_spawn
family of functions act like a cross-platform fork()
and exec()
:
https://developer.gnome.org/glib/stable/glib-Spawning-Processes.html
I found this Stack Overflow link that states what is necessary for argv[]
using an execlp()
to spawn a Python script from a C program:
How to execute a Python program from C in Linux
There, the accepted answer states that the arguments should be as follows:
execlp("python3", "python3", "name_of_script.py", (char*)0);
// ^ program to find
// ^ name to set in argv[0]
// ^ script name to put in argv[1] so script is run
However, I have tried the following and none of them work:
(1) gchar* argv[] = {"python3 ../gtk_simple_plot/plot.py", NULL};
(2) gchar* argv[] = {"python3", "../gtk_simple_plot/plot.py", NULL};
(3) gchar* argv[] = {"python3", "../gtk_simple_plot/plot.py", (char*)0};
(4) gchar* argv[] = {"python3", "python3", "../gtk_simple_plot/plot.py", (char*)0};
All resulting in the same error:
Spawning child failed: Failed to execute child process (No such file or directory)
Clearly I am overlooking something (probably simple). Any assistance would be greatly appreciated.
The solution is using:
gchar* argv[] = {"python3", "../gtk_simple_plot/plot.py", NULL};
with the addition of G_SPAWN_SEARCH_PATH
in the default spawn settings, such that the g_spawn call now looks like this:
// Spawn the python program to plot
spawn_success =
g_spawn_async_with_pipes (NULL, // Inherit parent's working directory
argv, // argv from above
NULL, // Don't set any additional environment variables
G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, // Default spawn settings
NULL, // No setup function prior to executing
NULL, // No data passed to setup function
&transition_pid, // Store child pid
NULL, // No standard input file descriptor
&stdoutFD, // Standard output file descriptor
&stderrFD, // Standard error file descriptor
&err); // Store error
This flag specifies that argv[0]
need not be an absolute path, it will be looked for in the user's PATH
.