I need to execute some python and C at the same time. I tried using Python.h:
#include <Python.h>
int python_program(char* cwd)
{
char* python_file_path;
FILE* fd;
int run;
python_file_path = malloc(sizeof(char) * (strlen(cwd) + strlen("src/query.py") + 1));
strcpy(python_file_path, cwd);
strcat(python_file_path, "src/query.py");
fd = fopen(python_file_path, "r");
Py_Initialize();
run = PyRun_AnyFile(fd, "query.py"); //this part is where the bug occur i think
Py_Finalize();
free(python_file_path);
}
int main(int argc, char *argv[])
{
char cwd_buffer[64];
getcwd(cwd_buffer, sizeof(cwd_buffer));
python_program(cwd_buffer);
return 0;
}
...but there's an error with segmentation fault.
26057 segmentation fault (core dumped) ../spotify-viewer-cli
I isolated the Python.h part and it's the problem. So how can I execute the python file in my C program?
Golden rule: error handling is not an option but a hard requirement in programming (pointed out by answers and comments).
Failing to include it might work for a while, but almost certainly will come back and bite in the ass at a later time, and it will do it so hard that someone (unfortunately, often not the same person who wrote the faulty code) will spend much more time (than writing it in the 1st place) fixing subtle errors (or crashes).
Also, reading the documentation for the used functions, might save precious time too, avoiding all kinds of errors generated by passing to them arguments based on some false assumptions.
Same case here (Undefined Behavior):
[Man7]: getcwd(3) doesn't end the path with a separator (/)
Computed script path doesn't exist
fopen fails (returns NULL)
I created a MCVE ([SO]: How to create a Minimal, Reproducible Example (reprex (mcve))), and also added some printf statements useful to identify the culprit (the preferred option would be to go step by step using a debugger (e.g.: [SourceWare]: GDB: The GNU Project Debugger)).
dir00/code00.py
#!/usr/bin/env python
import os
import sys
def main(*argv):
print(f"From Python - file: {os.path.abspath(__file__)}")
if __name__ == "__main__":
print(
"Python {:s} {:03d}bit on {:s}\n".format(
" ".join(elem.strip() for elem in sys.version.split("\n")),
64 if sys.maxsize > 0x100000000 else 32,
sys.platform,
)
)
rc = main(*sys.argv[1:])
#print("\nDone.\n")
#sys.exit(rc)
main00.c:
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <Python.h>
#define PY_SCRIPT "code00.py"
#define FULL_PY_SCRIPT "dir00/" PY_SCRIPT
int runPyFile(const char *wd)
{
char *script;
FILE *fp;
int res;
script = malloc(sizeof(char) * (strlen(wd) + strlen(FULL_PY_SCRIPT) + 2));
if (!script) {
printf("malloc error: %d\n", errno);
return -1;
}
strcpy(script, wd);
strcat(script, "/"); // @TODO - cfati
strcat(script, FULL_PY_SCRIPT);
printf("script path: %s\n", script);
if (access(script, F_OK)) { // Extra check
printf("Script doesn't exist\n");
return -2;
}
fp = fopen(script, "r");
if (!fp) {
printf("fopen error: %d\n", errno);
free(script);
return -3;
}
free(script);
Py_Initialize();
res = PyRun_SimpleFile(fp, PY_SCRIPT); // Call this function directly (skip PyRun_AnyFile layer)
if (res) {
printf("PyRun_SimpleFile error\n");
}
Py_Finalize();
fclose(fp);
return res;
}
int main(int argc, char *argv[])
{
char cwd[PATH_MAX];
if (!getcwd(cwd, sizeof(cwd))) {
printf("getcwd error: %d\n", errno);
return -1;
}
printf("cwd (check its end): %s\n", cwd);
int res = runPyFile(cwd);
if (res) {
// Some extra handling (or exit function if it's more complex)
} else {
printf("Script ran fine\n");
}
printf("\nDone.\n\n");
return res;
}
Output:
[cfati@cfati-5510-0:/mnt/e/Work/Dev/StackExchange/StackOverflow/q079208182]> ~/sopr.sh ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ### [064bit prompt]> tree . +-- dir00 ¦ +-- code00.py +-- main00.c 1 directory, 2 files [064bit prompt]> [064bit prompt]> PY_VER="3.11" [064bit prompt]> gcc -fPIC -I/usr/include/python${PY_VER} -o test${PY_VER} -L/usr/lib/$(uname -m)-linux-gnu main00.c -lpython${PY_VER} [064bit prompt]> ls dir00 main00.c test3.11 [064bit prompt]> [064bit prompt]> ./test${PY_VER} cwd (check its end): /mnt/e/Work/Dev/StackExchange/StackOverflow/q079208182 script path: /mnt/e/Work/Dev/StackExchange/StackOverflow/q079208182/dir00/code00.py Python 3.11.3 (main, Apr 5 2023, 14:15:06) [GCC 9.4.0] 064bit on linux From Python - file: /mnt/e/Work/Dev/StackExchange/StackOverflow/q079208182/code00.py Script ran fine Done.