Is there any example about writing Python extension with FBC?

General FreeBASIC programming questions.
Cretin Ho
Posts: 182
Joined: Feb 04, 2021 13:01

Is there any example about writing Python extension with FBC?

Post by Cretin Ho »

I wanted to try writing a toy extension for Python in FBC. The point is just to prove it's possible or not. If no one ever think about it then my work will be much more difficult :)
Cretin Ho
Posts: 182
Joined: Feb 04, 2021 13:01

Re: Is there any example about writing Python extension with FBC?

Post by Cretin Ho »

I will try writing a toy PHP extension using FBC, too. I hope I could do it and showcase here. No promise, though.
oyster
Posts: 274
Joined: Oct 11, 2005 10:46

Re: Is there any example about writing Python extension with FBC?

Post by oyster »

you can write DLL and call the functions in DLL via, for example, ctypes
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: Is there any example about writing Python extension with FBC?

Post by caseih »

I looked into translating the python.h file a few years ago. Has a ton of macros in it that made translation difficult. But someone more patient and experienced than I could no doubt do it. FB could be a great language for making python extensions. Python might be a great scripting language to embed in FB apps also. Whether you're making extensions for python or embedding python in your FB app the API is the same.
marcov
Posts: 3455
Joined: Jun 16, 2005 9:45
Location: Netherlands
Contact:

Re: Is there any example about writing Python extension with FBC?

Post by marcov »

Are there such solutions for python 3 already ? Most dlls I saw seem to be python 2.
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: Is there any example about writing Python extension with FBC?

Post by caseih »

Of course. Python ships with the DLL by default (it's required for the interpreter to function), and the .h files are an optional install in the standard installer. Both the DLL and the .h files are required to build the python interpreter (well technically the source builds the DLL first, then the interpreter binary). So yes, they are current and widely available.

EDIT. I just looked at my python install on Windows 10. the include directory has 99 files in it. Would be quite a project to get that all converted to FB. Probably not all of those files would be needed to do some things.

I agree the simplest way to use FB code from Python is to make a DLL or shared library and used ctypes to marshal parameters and types, and run the FB code directly. Could wrap the calls in Python code to make it more python friendly, and that would be easier and just as fast as trying to make Python objects from FB code using the API.
angros47
Posts: 2321
Joined: Jun 21, 2005 19:04

Re: Is there any example about writing Python extension with FBC?

Post by angros47 »

I personally managed to use OpenB3D (that is written in C++, but exports functions in the C calling convention) in Python using a simple header file

https://www.syntaxbomb.com/index.php/topic,8314.0.html

The same approach can be used for a library written in FreeBasic, if the functions are declared as cdecl
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: Is there any example about writing Python extension with FBC?

Post by D.J.Peters »

A python DLL wrapper isn't a real python module or extension !

You can use any language that can create C compatble dynamic libs for a python extension or module !

I don't use python but here some code as starting point.

Joshy

file "python.bi"

Code: Select all

#pragma once

' NOTE: python is case sensitive and the API interface of v3.x differs a little from v2.x

#define PYTHON_API_VERSION 1013 ' !!! this is defined by python-2.7.13  !!!

#define PYTHON_LIB "python27"  ' "python23" should work also

#ifndef NULL
 #define NULL cptr(any ptr,0)
#endif 

' unsigned 32/64-bit
#ifndef size_t
 #define size_t uinteger   
#endif 

' signed 32/64-bit
type Py_ssize_t as integer 
const as Py_ssize_t Py_INVALID_SIZE = -1

#if defined( __FB_64BIT__ ) and (not defined(__FB_WIN32__))
	type clong as integer
	type culong as uinteger
#else
	type clong as long
	type culong as ulong
#endif

type _typeobject as any

extern "C" lib PYTHON_LIB

' Nothing is actually declared to be a PyObject, but every pointer to a Python object can be cast to a PyObject*.
' This is inheritance built by hand.
' Similarly every pointer to a variable-size Python object can, in addition, be cast to PyVarObject*.
type PyObject
  as Py_ssize_t      ob_refcnt
  as _typeobject ptr ob_type
end type  

type PyVarObject
  as Py_ssize_t  ptr ob_refcnt
  as _typeobject ptr ob_type
  as Py_ssize_t      ob_size
end type



extern _Py_NoneStruct As PyObject 

#define Py_None @_Py_NoneStruct

#define Py_REFCNT(ob)  (cptr(PyObject ptr,(ob))->ob_refcnt)
#define Py_TYPE(ob)    (cptr(PyObject ptr,(ob))->ob_type)
#define Py_SIZE(ob)    (cptr(PyVarObject ptr,(ob))->ob_size)

type PyCFunction as function (self as PyObject ptr, args as PyObject ptr) as PyObject ptr

'Flag passed to newmethodobject
#define METH_OLDARGS  &H0000
#define METH_VARARGS  &H0001
#define METH_KEYWORDS &H0002
' METH_NOARGS and METH_O must not be combined with the flags above.
#define METH_NOARGS   &H0004
#define METH_O        &H0008

type PyMethodDef
  as const zstring ptr ml_name  ' The name of the built-in function/method
  as PyCFunction       ml_meth  ' The C function that implements it 
  as long              ml_flags ' Combination of METH_xxx flags, which mostly describe the args expected by the C func
  as const zstring ptr ml_doc   ' The __doc__ attribute, or NULL 
end type

declare function Py_InitModule4(sName   as const zstring ptr, _
                                methods as PyMethodDef   ptr, _
                                sDoc    as const zstring ptr = NULL, _
                                self    as PyObject      ptr = NULL     , _
                                apiver  as long              = PYTHON_API_VERSION) as PyObject ptr



declare function PyArg_ParseTuple(args as PyObject ptr, aFormat as const zstring ptr, ...) as long

' PyInt
declare function PyInt_FromString(as zstring ptr, as zstring ptr ptr, as long) as PyObject ptr 
declare function PyInt_FromLong(as clong) as PyObject ptr
declare function PyInt_FromSize_t(as size_t) as PyObject ptr
declare function PyInt_FromSsize_t(as Py_ssize_t) as PyObject ptr
declare function PyInt_AsLong(as PyObject ptr) as clong
declare function PyInt_AsSsize_t(as PyObject ptr) as Py_ssize_t
declare function _PyInt_AsInt(as PyObject ptr) as long
declare function PyInt_AsUnsignedLongMask(as PyObject ptr) as PyObject ptr

' PyLong
declare function PyLong_FromString(as zstring ptr, as zstring ptr ptr, as long) as PyObject ptr
declare function PyLong_FromLong(as clong) as PyObject ptr
declare function PyLong_FromUnsignedLong(as culong) as PyObject ptr
declare function PyLong_FromDouble(as double) as PyObject ptr
declare function PyLong_FromSize_t(as size_t) as PyObject ptr
declare function PyLong_FromSsize_t(as Py_ssize_t) as PyObject ptr
declare function PyLong_AsLong(as PyObject ptr) as clong
declare function PyLong_AsLongAndOverflow(as PyObject ptr, as long ptr) as clong
declare function PyLong_AsUnsignedLong(as PyObject ptr) as culong
declare function PyLong_AsUnsignedLongMask(as PyObject ptr) as culong
declare function PyLong_AsSsize_t(as PyObject ptr) as Py_ssize_t
declare function _PyLong_AsInt(as PyObject ptr) as long
declare function PyLong_GetInfo() as PyObject ptr

' PyFloat
declare function PyFloat_FromDouble(as double) as PyObject ptr
declare function PyFloat_AsDouble(as PyObject ptr) as double

end extern
file "MyModule.bas"

Code: Select all

' file "MyModule.bas"
' fbc -dll MyModule.bas -x MyModule.pyd

#include "python.bi"

extern "C"

function exportBeep (self as PyObject ptr, args as PyObject ptr) as PyObject ptr
  beep
  return Py_None ' no return value !
end function

function exportAdd (self as PyObject ptr, args as PyObject ptr) as PyObject ptr
  dim as long  argA,argB
  PyArg_ParseTuple(args,"ii",@argA,@argB)
  dim as clong result = argA + argB
  return PyInt_FromLong(result)
end function

' allocate one more NULL item the last ! e.g. (0)=beep,(1)=add (2)=NULL
dim shared as PyMethodDef methods(2)

' export the init
sub initMyModule() export
  methods(0).ml_name  = @"beep"
  methods(0).ml_meth  = @exportBeep
  methods(0).ml_flags = METH_NOARGS
  methods(0).ml_doc   = @"Test calling beep."
  
  methods(1).ml_name  = @"add"
  methods(1).ml_meth  = @exportAdd
  methods(1).ml_flags = METH_VARARGS
  methods(1).ml_doc   = @"Test of adding int numbers."
  
  ' last methods(2) is the NULL terminator
    
  Py_InitModule4("MyModule",@methods(0))
end sub

end extern
Last edited by D.J.Peters on May 22, 2021 22:08, edited 1 time in total.
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: Is there any example about writing Python extension with FBC?

Post by caseih »

D.J.Peters wrote:A python DLL wrapper isn't a real python module or extension !
Sure it is. The only difference is that if you're missing the dll, one would fail at runtime, whereas the C API method would fail at compile time if something was wrong, which might or might not be important.

Everything in your MyModule example can be done in a pure python file where the methods that you defined in your FB example would be defined in pure python and then use ctypes to call the cdecl non-python functions to do the actual work. The result is the same, and the way you call it from other python code is the same.
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: Is there any example about writing Python extension with FBC?

Post by D.J.Peters »

wrapping a dll or extend the language isn't the same thing !

For sure my mini example isn't a real language module but it shows how the API interface works with FreeBASIC !

By the way if you are a python expert why do not posted a simple solution for the user Cretin Ho ?

Joshy
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: Is there any example about writing Python extension with FBC?

Post by D.J.Peters »

fbc -dll MyModule.bas -x MyModule.pyd

Code: Select all

python.exe -
>>> import MyModule
>>> MyModule.beep()
>>>
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: Is there any example about writing Python extension with FBC?

Post by caseih »

I agree it's not the same thing techincally, but it has the same effect in the end for many types of FB DLLs or programs. That's what I meant. And given how easy ctypes makes it to load and use C symbols from DLLS, with a standard FB-generated DLL, I think ctypes might win in a variety of circumstances. I am neither an FB or Python expert, although I've had some experience with both. And I have used the Python API before and it's a bit cumbersome I admit but if you need to wrap some kind of object system, it might be more appropriate than ctypes.
TJF
Posts: 3809
Joined: Dec 06, 2009 22:27
Location: N47°, E15°
Contact:

Re: Is there any example about writing Python extension with FBC?

Post by TJF »

Cretin Ho wrote:I wanted to try writing a toy extension for Python in FBC. The point is just to prove it's possible or not. If no one ever think about it then my work will be much more difficult :)
libpruio is a library (hardware driver) written in FreeBASIC and PASM assembler code. Beside FB it also ships with bindings/examples for C and Python. The Python CTypes binding gets auto-created by an fbdoc plugin (external emitter) called py_ctypes from the FBC .bi files. Find details at

https://github.com/DTJF/libpruio
marcov
Posts: 3455
Joined: Jun 16, 2005 9:45
Location: Netherlands
Contact:

Re: Is there any example about writing Python extension with FBC?

Post by marcov »

caseih wrote:I agree it's not the same thing techincally, but it has the same effect in the end for many types of FB DLLs or programs. That's what I meant. And given how easy ctypes makes it to load and use C symbols from DLLS, with a standard FB-generated DLL, I think ctypes might win in a variety of circumstances. I am neither an FB or Python expert, although I've had some experience with both. And I have used the Python API before and it's a bit cumbersome I admit but if you need to wrap some kind of object system, it might be more appropriate than ctypes.
I was more thinking about the other way around. Native program with embedded python scripting rather than python mainprogram calling native code in dlls. i used a python26.dll but afaik Python 2.6 is dated (I'm no expert, I only add it when forced)
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: Is there any example about writing Python extension with FBC?

Post by caseih »

Yes for sure if you want to embed python in an FB program you need to use the C API. And if you provide shims between FB objects and Python, you can manipulate your FB objects, variables, call functions, etc, from python scripts in the embedded interpreter. Very similar to embedding Lua, or even Javascript. This is used to good effect in some large programs such as FreeCAD and QGIS. My experience embedding Python in a C app is limited to just one instance and it was pretty simplistic but worked well.
Post Reply