I have a .cpp (called trial.cpp) file as follows:
#include "trial.hpp"
int main()
{
cout << "hello";
return 0;
}
My header file (trial.hpp) is:
#include <iostream>
using namespace std;
I have a .i file (trial.i) as follows:
%module trial
%{
#include "trial.hpp"
%}
%include trial.hpp
I have used SWIG in the following manner in cmd to generate .pyd, .py, .o and .cxx files:
swig -c++ -python trial.i
g++ -c trial_wrap.cxx -I C:\Users.....Python\Python37\include
g++ -shared trial_wrap.o -o _trial.pyd -L
C:\Users.....\Python\Python37\libs -l
python37
The files are generated successfully
However when I open Python command prompt and run this:
from trial import *
main()
I get an error saying
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'main' is not defined
How can I resolve this issue?
Moreover, if I'm using another function name (say fn1()) instead of main(), I get the following error in the third command:
g++ -shared trial_wrap.o -o _trial.pyd -L
C:\Users.....\Python\Python37\libs -l python37
The error is:
undefined reference to fn1()
I'd like to use fn1() instead of main()
How can I solve this issue?
Fixed it!
Used these three statements instead:
swig -c++ -python trial.i
g++ -c trial_wrap.cxx trial.cpp -I C:\Users\ngoyal\AppData\Local\Programs\Python\Python37\include
g++ -shared -o _trial.pyd trial.o trial_wrap.o -L C:\Users\ngoyal\AppData\Local\Programs\Python\Python37\libs -l python37
Also had to change main() to a non reserved function name and gave the function definition in the header file.
Related
This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Embedding Python: undefined reference to `_imp__Py_Initialize'
(2 answers)
Closed 1 year ago.
I'm having trouble importing Python.h to a C program.
I have 4 files, hellofunc.c, hellomake.c, hellomake.h and Makefile.
The hellomake.h, Python.h and all related Python files are in a include folder.
And the rest is in the program folder.
├───include
│ ├───cpython
│ └───internal
├───lib
└───program
The code of hellofunc.c file is:
#include <stdio.h>
#include <hellomake.h>
void myPrintHelloMake(void) {
printf("Hello makefiles!\n");
return;
}
The code of hellomake.h is:
void myPrintHelloMake(void);
The code of hellomake.c is:
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <windows.h>
#include <Python.h>
#include <hellomake.h>
int main() {
// call a function in another file
myPrintHelloMake();
Py_Initialize();
PyRun_SimpleString("print('Hello World from Embedded Python!!!')");
Py_Finalize();
return(0);
}
The code of Makefile is:
IDIR =../include
CC=gcc
CFLAGS=-I$(IDIR)
ODIR=obj
LDIR =../lib
LIBS=-lm
_DEPS = hellomake.h
DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))
_OBJ = hellomake.o hellofunc.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
$(ODIR)/%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
hellomake: $(_OBJ)
$(CC) -o $# $^ $(CFLAGS) $(LIBS)
.PHONY: clean
clean:
rm -f *.o *~ core $(INCDIR)/*~
The error that I got is:
gcc -o hellomake hellomake.o hellofunc.o -I../include -lm
hellomake.o:hellomake.c:(.text+0x14): undefined reference to `_imp__Py_Initialize'
hellomake.o:hellomake.c:(.text+0x2a): undefined reference to `_imp__PyRun_SimpleStringFlags'
hellomake.o:hellomake.c:(.text+0x31): undefined reference to `_imp__Py_Finalize'
collect2.exe: error: ld returned 1 exit status
make: *** [Makefile:56: hellomake] Error 1
Have a simple module written in c:
#include <stdio.h>
#include "apr_hash.h"
#include "ap_config.h"
#include "ap_provider.h"
#include "httpd.h"
#include "http_core.h"
#include "http_config.h"
#include "http_log.h"
#include "http_protocol.h"
#include "http_request.h"
#define PY_SSIZE_T_CLEAN
#include <Python.h>
static int example_handler(request_rec *r) {
if (!r->handler || strcmp(r->handler, "example-handler")){
return (DECLINED);
}
PyObject* py_io = PyImport_ImportModule("io");
Py_DECREF(py_io);
ap_set_content_type(r, "text/html");
ap_rprintf(r, "Filename: %s", r->filename);
return OK;
}
static void register_hooks(apr_pool_t *pool) {
ap_hook_handler(example_handler, NULL, NULL, APR_HOOK_LAST);
}
module AP_MODULE_DECLARE_DATA mod_example = {
STANDARD20_MODULE_STUFF, NULL, NULL, NULL, NULL, NULL, register_hooks
};
And compile without apxs:
# Compile
gcc -D LINUX -D AMD64 \
$($(apxs -q APR_CONFIG) --cflags --includes) \
$(python3-config --cflags --includes) \
-fPIC -DSHARED_MODULE \
-I$(apxs -q INCLUDEDIR) $(apxs -q CFLAGS) \
-c mod_example.c;
# Link shared library
gcc -D LINUX -D AMD64 \
$($(apxs -q APR_CONFIG) --link-ld) \
$(python3-config --ldflags) \
-shared -o mod_example.so mod_example.o;
The compilation is success without errors or warnings:
$ file build/mod_example.so
build/mod_example.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=10f64f7e7c6d0ec9301e07cb61fe5d0249653704, with debug_info, not stripped
But when upload to a vm machine with apache2 installed and enable module and restart apache, says:
apache2: Syntax error on line 146 of /etc/apache2/apache2.conf: Syntax error on line 1 of /etc/apache2/mods-enabled/mod_example.load: Cannot load /usr/lib/apache2/modules/mod_example.so into server: /usr/lib/apache2/modules/mod_example.so: undefined symbol: PyImport_ImportModule
The function is documented here: https://docs.python.org/3/c-api/import.html
Why is the python function declared in python.h compiled correctly but not declared on the server?, have same python and apache version (dev headers included) in host machine (ubuntu-desktop 20.04 lts) and vm machine (ubuntu server 20.04 lts):
$ python3 --version
Python 3.8.5
$ gcc --version
gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0 ...
$ find /usr/include -name "apr-*" | grep -o apr.*
apr-1.0
Expanding my comments into a proper answer:
The problem is that neither the module nor httpd is linked with the Python runtime library, which for you would probably be some version of libpython3.8.so. That has no negative impact on compilation proper, and presumably the linker accepts it on account of the object being built being a shared library, not a program. apxs may also be providing link flags that contribute.
If python3-config is behaving correctly in your build environment then it is emitting the appropriate -L and -l flags already, but link behavior is sensitive to the order of command-line arguments. In particular, you should designate supporting libraries after the objects that require them. Thus, you could get the libraries named at an appropriate point either by moving $(python3-config --ldflags) to the end of the link command or by appending $(python3-config --libs) to that command. It is not a problem for support libraries to be designated multiple times.
I am not sure what conventional practice is in the Python extension world, if even there is a convention. python3-config splits things up strangely, to my eye: inasmuch as it has separate options --ldflags and --libs, I find it a bit surprising that the output requested by the first is a superset of that requested by the second. To my mind, the --ldflags ought to give the linker flags, if any, that go before all object names on the command line, and the --libs should give the libraries that come after. But it looks like those can be used as if their output were according to my expectations, even though that of --ldflags appears not to be:
gcc -D LINUX -D AMD64 \
$($(apxs -q APR_CONFIG) --link-ld) \
$(python3-config --ldflags) \
-shared -o mod_example.so mod_example.o \
$(python3-config --libs)
I am trying to build a hello world C++ Python extension using boost-python.
I got the following source code from https://www.mantidproject.org/Boost_Python_Introduction:
// test.cpp
#include <iostream>
#include <boost/python.hpp>
void sayHello()
{
std::cout << "Hello, Python!\n";
}
BOOST_PYTHON_MODULE(test) // Name here must match the name of the final shared library, i.e. mantid.dll or mantid.so
{
boost::python::def("sayHello", &sayHello);
}
However, when I try to compile using the following command:
g++ -fPIC -I/usr/include/python3.6m test.cpp -c
g++ -shared test.o -o test.so -I/usr/include/python3.6m -I/lib64/libboost_python3
This command compiles successfully the code and creates a library file test.so.
However, when I try to import the module in python3, I get the following error:
ImportError: /home/yt/C++/test.so: undefined symbol: _ZNK5boost6python7objects21py_function_impl_base9max_arityEv
The link Import Error on boost python hello program seems to suggest the command
I used above would solve the problem by adding -I/usr/include/python3.6m and -I/lib64/libboost_python3, but it does not.
What am I doing wrong?
Thanks!
OS: Fedora 29 x86_64
Thanks guys!
The problem was the linker command. The correct one is:
g++ -fPIC -I/usr/include/python3.6m test.cpp -c
g++ -L /lib64 -shared test.o -o test.so -lpython3.6m -lboost_python3
Now it works on Fedora 29
Is there a good way to embed both a Python2 and a Python3 interpreter into a C program and then running either one or the other with the decision occurring at runtime?
Here's an example attempt:
Makefile:
all: main
main: main.c librun_in_py2.so librun_in_py3.so
g++ main.c -lrun_in_py2 -lrun_in_py3 -L. -Wl,-rpath -Wl,$$ORIGIN -o main
librun_in_py2.so: run_in_py2.c
g++ $$(python2.7-config --cflags --ldflags) -shared -fPIC $< -o $#
librun_in_py3.so: run_in_py3.c
g++ $$(python3.4-config --cflags --ldflags) -shared -fPIC $< -o $#
clean:
#-rm main *.so
main.c
void run_in_py2(const char* const str);
void run_in_py3(const char* const str);
static const char str2[] = "from time import time,ctime\n"
"import sys\n"
"print sys.version_info\n"
"print 'Today is',ctime(time())\n";
static const char str3[] = "from time import time,ctime\n"
"import sys\n"
"print(sys.version_info)\n"
"print('Today is', ctime(time()))\n";
int main(int argc, char* [])
{
if (argc == 2)
run_in_py2(str2);
else
run_in_py3(str3);
}
run_in_py2.c
#include <Python.h>
void run_in_py2(const char* const str)
{
Py_Initialize();
PyRun_SimpleString(str);
Py_Finalize();
}
run_in_py3.c:
#include <Python.h>
void run_in_py3(const char* const str)
{
Py_Initialize();
PyRun_SimpleString(str);
Py_Finalize();
}
Because of the order of library linking the result is always the same:
$ ./main
sys.version_info(major=2, minor=7, micro=9, releaselevel='final', serial=0)
('Today is', 'Thu Jun 4 10:59:29 2015')
Since the names are the same it looks like the linker resolves everything with the Python 2 interpreter. Is there some way to isolate the names or to encourage the linker to be lazier in resolving them? If possible, it'd be ideal to get the linker to confirm that all names can be resolved and but put off symbol resolution until the appropriate linker can be chosen.
A highly related question asks about running two independent embedded interpreters at the same time:
Multiple independent embedded Python Interpreters on multiple operating system threads invoked from C/C++ program
The suggestion there is to use two separate processes but I suspect there's a simpler answer to this question.
The reason behind the question is that I thought I understood from a conversation with someone way back when that there was a program that did this. And now I'm just curious about how it would be done.
I'm trying to embedding some Python code into C; It's the first time I do a thing like that.
Here is the simple code of my first attempt copied by a guide on internet:
#include <Python.h>
void exec_pycode(const char* code)
{
Py_Initialize();
PyRun_SimpleString(code);
Py_Finalize();
}
int main(int argc, char **argv) {
exec_pycode(argv[1]);
return 0;
}
So I've installed python3.4-dev package.
Then for having info for the linker I typed:
pkg-config --cflags --libs python3
Then I tried to compile my code:
gcc -std=c99 -o main -I /usr/local/include/python3.4m -L /usr/local/lib -lpython3.4m main.c
(according the command before)
but this is the result:
/tmp/ccJFmdcr.o: in function "exec_pycode":
main.c:(.text+0xd): reference undefined to "Py_Initialize"
main.c:(.text+0x1e): reference undefined to "PyRun_SimpleStringFlags"
main.c:(.text+0x23): reference undefined to "Py_Finalize"
collect2: error: ld returned 1 exit status
It would seem that there is a problem with linking phase, but I can't understend where is the problem seeing that i've passed to the linker the exact paths of the header and of the library. How can I solve that problem?
Try reordering your compilation command, such that all linking options are specified after your C source files:
gcc -std=c99 -o main -I /usr/local/include/python3.4m main.c \
-L /usr/local/lib -lpython3.4m