0

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.

Leigh K
  • 561
  • 6
  • 20

1 Answers1

0

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.

Leigh K
  • 561
  • 6
  • 20