← Back to team overview

kicad-developers team mailing list archive

[patch 1/1] kicad-python-support.patch Python Binding Start

 

Here is the (final?) version of this patch, for now Kicad with minor 
fixes, next patches will stack on it.

At kicad start time, python scripts are executed in this order:

%KICADDATA%/scripts/kicad_startup.py
%KICADDATA%/plugins/<name>/*.py
%USERDIR%/.kicad.d/scripts/kicad_startup.py
%USERDIR%/.kicad.d/plugins/<name>/*.py
%USERDIR%/.kicad_d/scripts/kicad_startup.py
%USERDIR%/_kicad_d/plugins/<name>/*.py

where

%KICADDATA% stands for the data directory of kicad
%USERDIR% stands for the current user home directory
<name> stands for the current kicad app (namely, kicad, eeschema ...)

The python binding is quite limited yet, there is only one variable set 
'kicadApp' which is the name of the current kicad application.

in a very near future, I'll add an online (English/French) HTML 
documentation file, but since the documentation is not part of the 
source archive, I am wondering where to put it ... can somebody point me 
the right path for it ?

Florian

---
3d-viewer/makefile.gtk | 1
3d-viewer/makefile.include | 2
common/edaappl.cpp | 14 +++
common/makefile.include | 8 +-
common/pyhandler.cpp | 148 ++++++++++++++++++++++++++++++++++++++++++
cvpcb/makefile.include | 2
eeschema/makefile.include | 2
eeschema/plugins/makefile.gtk | 2
gerbview/makefile.include | 2
include/appl_wxstruct.h | 1
include/pyhandler.h | 47 +++++++++++++
kicad/makefile.include | 2
libs.linux | 17 ++++
pcbnew/makefile.include | 2
share/infospgm.cpp | 11 +++
15 files changed, 251 insertions(+), 10 deletions(-)

This patch adds a PyHandler class to handle all python bindings, and 
modify the build system (currently only for linux gtk) to handle python 
2.4 libs

to compile with python you'll first need to have boost.python installed 
on your system (with its dev files) as well as python itself, then edit 
libs.linux
and set KICAD_PYTHON to 1 (or to anything)

then you'll just have to build it

At running time, kcad now looks for a script 'scripts/kicad_startup.py' 
in it's data directory, and 'scripts/.py', where is the app name, then 
run all those scripts.
There is currently nothing exposed from Kicad to Python (more to come)

 --------------080605030407010308020200 Content-Type: text/x-patch;
name="kicad-python-support.patch"
Content-Transfer-Encoding: 8bit
Content-Disposition: inline;
filename="kicad-python-support.patch"

Subject: [patch @num@/@total@] @name@ Python Binding Start

---
3d-viewer/makefile.gtk | 1 
3d-viewer/makefile.include | 2 
common/edaappl.cpp | 14 ++++
common/makefile.include | 8 ++
common/pyhandler.cpp | 134 ++++++++++++++++++++++++++++++++++++++++++
cvpcb/makefile.include | 2 
eeschema/makefile.include | 2 
eeschema/plugins/makefile.gtk | 2 
gerbview/makefile.include | 2 
include/appl_wxstruct.h | 1 
include/pyhandler.h | 43 +++++++++++++
kicad/makefile.include | 2 
libs.linux | 17 ++++-
pcbnew/makefile.include | 2 
share/infospgm.cpp | 11 +++
15 files changed, 233 insertions(+), 10 deletions(-)

This patch adds a PyHandler class to handle all python bindings, and modify the build system (currently only for linux gtk) to handle python 2.4 libs

to compile with python you'll first need to have boost.python installed on your system (with its dev files) as well as python itself, then edit libs.linux
and set KICAD_PYTHON to 1 (or to anything)

then you'll just have to build it 

At running time, kcad now looks for a script 'scripts/kicad_startup.py' in it's data directory, and 'scripts/<name>.py', where <name> is the app name, then run all those scripts.
There is currently nothing exposed from Kicad to Python (more to come)
Index: kicad-dev/libs.linux
===================================================================
--- kicad-dev.orig/libs.linux	2007-04-18 20:54:12.000000000 +0200
+++ kicad-dev/libs.linux	2007-04-18 20:54:26.000000000 +0200
@@ -7,6 +7,8 @@
OBJSUFF = .o
FINAL = 1

+# You must comment or uncommen tthis line to disable/enable python support
+KICAD_PYTHON = 1

# You must comment or uncomment this line for dynamic or static link
# dynamic link is less difficult than static link
@@ -69,11 +71,22 @@
endif


+#ifdef KICAD_PYTHON
+
+PYLIBS= -L/usr/lib
+PYLIBS+= -L /usr/include/python
+PYLIBS+= -lpython2.4
+PYLIBS+= -lboost_python
+EXTRACPPFLAGS+=-I /usr/include/python2.4 -DKICAD_PYTHON -fno-strict-aliasing -ggdb
+
+#endif
+
# attention à l'ordre des libairies
LIBS = -L/usr/local/lib -L/usr/X11R6/lib\
$(EXTRALIBS) $(WXSYSLIB)\
-	$(LIBSTDC)
+	$(LIBSTDC) $(PYLIBS)

LIBS_WITH_GL = -L/usr/local/lib -L/usr/X11R6/lib\
$(EXTRALIBS) $(WXSYSLIB_WITH_GL)\
-	$(LIBSTDC)
+	$(LIBSTDC) $(PYLIBS)
+
Index: kicad-dev/eeschema/plugins/makefile.gtk
===================================================================
--- kicad-dev.orig/eeschema/plugins/makefile.gtk	2007-04-18 20:54:12.000000000 +0200
+++ kicad-dev/eeschema/plugins/makefile.gtk	2007-04-18 20:54:26.000000000 +0200
@@ -16,7 +16,7 @@
all: netlist_form_pads-pcb

netlist_form_pads-pcb: netlist_form_pads-pcb.cpp makefile.gtk
-	gcc -D__UNIX__ -Wall netlist_form_pads-pcb.cpp -o netlist_form_pads-pcb $(LIBSTDC)
+	gcc -D__UNIX__ -Wall netlist_form_pads-pcb.cpp -o netlist_form_pads-pcb $(LIBSTDC) $(CXXFLAGS)

install:
cp -v netlist_form_pads-pcb $(KICAD_BIN)/plugins/
Index: kicad-dev/common/makefile.include
===================================================================
--- kicad-dev.orig/common/makefile.include	2007-04-18 20:54:12.000000000 +0200
+++ kicad-dev/common/makefile.include	2007-04-18 20:54:26.000000000 +0200
@@ -1,4 +1,4 @@
-EXTRACPPFLAGS= -I$(SYSINCLUDE) -I./ -Ibitmaps -I../include
+EXTRACPPFLAGS+= -I$(SYSINCLUDE) -I./ -Ibitmaps -I../include

COMMON = ../include/colors.h

@@ -34,6 +34,10 @@
base_screen.o\
dcsvg.o

+ifdef KICAD_PYTHON
+OBJECTS+= pyhandler.o
+endif
+
gr_basic.o: gr_basic.cpp ../include/gr_basic.h $(DEPEND)

confirm.o: confirm.cpp $(COMMON)
@@ -85,3 +89,5 @@
eda_dde.o: eda_dde.cpp $(COMMON) ../include/eda_dde.h

displlst.o: displlst.cpp $(COMMON)
+
+pyhandler.o: pyhandler.cpp $(COMMON) ../include/pyhandler.h
Index: kicad-dev/3d-viewer/makefile.include
===================================================================
--- kicad-dev.orig/3d-viewer/makefile.include	2007-04-18 20:54:12.000000000 +0200
+++ kicad-dev/3d-viewer/makefile.include	2007-04-18 20:54:26.000000000 +0200
@@ -1,5 +1,5 @@
EXTRALIBS =
-EXTRACPPFLAGS= -I./ -I../include -I../common -I../pcbnew
+EXTRACPPFLAGS+= -I./ -I../include -I../common -I../pcbnew

OBJECTS3D =	3d_frame.o 3d_read_mesh.o 3d_canvas.o trackball.o 3d_aux.o\
3d_draw.o 3d_toolbar.o 3d_class.o
Index: kicad-dev/cvpcb/makefile.include
===================================================================
--- kicad-dev.orig/cvpcb/makefile.include	2007-04-18 20:54:12.000000000 +0200
+++ kicad-dev/cvpcb/makefile.include	2007-04-18 20:54:26.000000000 +0200
@@ -1,7 +1,7 @@
# makefile pour cvpcb (mingw)
OBJSUFF = o

-EXTRACPPFLAGS = -DCVPCB -I./ -I../cvpcb -I../include -Ibitmaps -I../pcbnew -I../3d-viewer
+EXTRACPPFLAGS += -DCVPCB -I./ -I../cvpcb -I../include -Ibitmaps -I../pcbnew -I../3d-viewer
EXTRALIBS = ../common/common.a

LIBVIEWER3D = ../3d-viewer/3d-viewer.a
Index: kicad-dev/eeschema/makefile.include
===================================================================
--- kicad-dev.orig/eeschema/makefile.include	2007-04-18 20:54:12.000000000 +0200
+++ kicad-dev/eeschema/makefile.include	2007-04-18 20:54:26.000000000 +0200
@@ -3,7 +3,7 @@
FINAL = 1

EESCHEMA_FLAGS= -DEESCHEMA
-EXTRACPPFLAGS=$(KICAD_FLAGS) $(EESCHEMA_FLAGS) -I./ -Ibitmaps -I../include -I../eeschema
+EXTRACPPFLAGS+=$(KICAD_FLAGS) $(EESCHEMA_FLAGS) -I./ -Ibitmaps -I../include -I../eeschema
EXTRALIBS = ../common/common.a

# DEPEND = program.h general.h
Index: kicad-dev/gerbview/makefile.include
===================================================================
--- kicad-dev.orig/gerbview/makefile.include	2007-04-18 20:54:12.000000000 +0200
+++ kicad-dev/gerbview/makefile.include	2007-04-18 20:54:26.000000000 +0200
@@ -1,5 +1,5 @@
EXTRALIBS = ../common/common.a
-EXTRACPPFLAGS= -DGERBVIEW -DPCBNEW -I./ -I../gerbview -I../include\
+EXTRACPPFLAGS+= -DGERBVIEW -DPCBNEW -I./ -I../gerbview -I../include\
-I../share -I../pcbnew -I../3d-viewer

#COMMON = pcbnew.h struct.h
Index: kicad-dev/kicad/makefile.include
===================================================================
--- kicad-dev.orig/kicad/makefile.include	2007-04-18 20:54:12.000000000 +0200
+++ kicad-dev/kicad/makefile.include	2007-04-18 20:54:26.000000000 +0200
@@ -1,5 +1,5 @@
EXTRALIBS = ../common/common.a
-EXTRACPPFLAGS= -DKICAD -I./ -Ibitmaps -I../include -I../kicad -I../share
+EXTRACPPFLAGS+= -DKICAD -I./ -Ibitmaps -I../include -I../kicad -I../share

DEPEND =

Index: kicad-dev/pcbnew/makefile.include
===================================================================
--- kicad-dev.orig/pcbnew/makefile.include	2007-04-18 20:54:12.000000000 +0200
+++ kicad-dev/pcbnew/makefile.include	2007-04-18 20:54:26.000000000 +0200
@@ -1,5 +1,5 @@
EXTRALIBS = ../common/common.a
-EXTRACPPFLAGS= -DPCBNEW -I./ -Ibitmaps -I../include -I../share -I../pcbnew -I../3d-viewer
+EXTRACPPFLAGS+= -DPCBNEW -I./ -Ibitmaps -I../include -I../share -I../pcbnew -I../3d-viewer

#COMMON = pcbnew.h struct.h class_pad.h class_module.h class_text_mod.h \
#	class_edge_mod.h class_equipot.h
Index: kicad-dev/common/pyhandler.cpp
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ kicad-dev/common/pyhandler.cpp	2007-04-18 21:03:19.000000000 +0200
@@ -0,0 +1,134 @@
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+// for all others, include the necessary headers (this file is usually all you
+// need because it includes almost all "standard" wxWindows headers
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+#include <wx/dir.h>
+
+#include <pyhandler.h>
+#include <iostream>
+
+#include "fctsys.h"
+#include "common.h"
+
+using namespace boost::python;
+
+PyHandler* PyHandler::m_instance = NULL;
+
+PyHandler * PyHandler::GetInstance()
+/* Singleton implementation */
+{
+	if ( !PyHandler::m_instance )
+	{
+	PyHandler::m_instance = new PyHandler();
+	}
+	return PyHandler::m_instance;
+}
+
+PyHandler::PyHandler()
+/* Init the Python env */
+{
+	Py_Initialize();
+}
+
+PyHandler::~PyHandler()
+/* Closes the Python env */
+{
+	Py_Finalize();
+}
+
+void PyHandler::RunScripts()
+/* Run application startup scripts */
+{
+	// SYSTEMWIDE :
+
+	wxString dataPath = ReturnKicadDatasPath();
+
+	// check if we can have a kicad_startup.py around ?
+	wxString script = dataPath + wxString::FromAscii( "scripts/kicad_startup.py" );
+
+	// First find scripts/<name>.py and run it if found :
+
+	script = wxString::FromAscii( "scripts/" ) + m_appName + wxString::FromAscii(".py");
+	if ( wxFileExists( dataPath + script ) ) RunScript( script );
+
+	// Now lets see if we can find a suitable plugin directory (plugin/<name>) somewhere
+
+	wxString pluginDir = wxString::FromAscii( "plugins/" ) + m_appName;
+	if ( wxDirExists( dataPath + pluginDir ) )
+	{
+	// We do have a systemwide plugin dir, let's find files in it
+	wxArrayString pluginList;
+	wxDir::GetAllFiles( pluginDir, &pluginList, wxString::FromAscii("*.py") );
+
+	for ( unsigned int i = 0; i < pluginList.Count() ; i++ )
+	{
+	RunScript( pluginList[i] );
+	}
+
+	}
+
+	// We did read all systemwide scripts, let's have a look at user's ones
+
+
+	// USER Scripts
+
+}
+
+bool PyHandler::RunScript( const wxString & name )
+/* Run the script specified by 'name' */
+{
+ object module(( handle<>(borrowed(PyImport_AddModule("__main__")))));
+ object ns = module.attr( "__dict__" );
+
+ FILE * file = fopen( name.fn_str(), "r" );
+
+ if ( !file )
+ {
+ // do something
+ std::cout << "Unable to Load " << name.fn_str() << "\n";
+ return false;
+ }
+
+	try
+	{
+ handle<> ignored( ( PyRun_File( file, name.fn_str(), Py_file_input, ns.ptr(), ns.ptr() ) ) );
+	}
+	catch ( error_already_set )
+	{
+	PyErr_Print(); // should be printed into an error message ...
+	fclose( file );
+	return false;
+	}
+
+	fclose( file );
+	return true;
+}
+
+void PyHandler::SetAppName( const wxString & name )
+/* Set the application name in the python scope */
+{
+	m_appName = name;
+ object module(( handle<>(borrowed(PyImport_AddModule("__main__")))));
+ object ns = module.attr( "__dict__" );
+	try {
+	ns["kicadApp"] = std::string( name.ToAscii() );
+	}
+	catch (error_already_set)
+	{
+	PyErr_Print();
+	}
+}
+
+const char * PyHandler::GetVersion()
+{
+	return Py_GetVersion();
+}
+// vim: set tabstop=4 :
Index: kicad-dev/include/pyhandler.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ kicad-dev/include/pyhandler.h	2007-04-18 20:54:26.000000000 +0200
@@ -0,0 +1,43 @@
+	/****************************/
+	/*	pyhandler.h	*/
+	/****************************/
+
+#ifndef PYHANDLER_H
+#define PYHANDLER_H
+
+#include <boost/python.hpp>
+#include <Python.h>
+
+#include <wx/string.h>
+
+class PyHandler
+{
+
+	private:
+	static PyHandler * m_instance;
+
+	protected:
+	PyHandler();
+
+	wxString m_appName;
+
+	public:
+	static PyHandler * GetInstance();
+
+	~PyHandler();
+
+	void SetAppName( const wxString & name );
+
+	void RunScripts();
+	bool RunScript( const wxString & name );
+
+	void AddModule( void (* initfunc)(void) );
+
+	const char * GetVersion();
+};
+
+
+#define KICAD_PY_BIND_MODULE( mod ) PyHandler::GetInstance()->AddModule( init#mod )
+
+// vim: set tabstop=4 :
+#endif
Index: kicad-dev/share/infospgm.cpp
===================================================================
--- kicad-dev.orig/share/infospgm.cpp	2007-04-18 20:54:12.000000000 +0200
+++ kicad-dev/share/infospgm.cpp	2007-04-18 20:54:26.000000000 +0200
@@ -7,6 +7,10 @@
#include "gr_basic.h"
#include "common.h"

+#ifdef KICAD_PYTHON
+#include <pyhandler.h>
+#endif
+
// Import:
extern wxString g_Main_Title;

@@ -47,6 +51,13 @@
#else
Msg << wxT(" - Ansi version");
#endif
+
+#ifdef KICAD_PYTHON
+	Msg << wxT("\n");
+	Msg << wxT( "python : " );
+	Msg << wxString::FromAscii( PyHandler::GetInstance()->GetVersion() );
+#endif
+
Msg << wxT("\n\n") << _("Author:");
Msg << wxT("JP CHARRAS\n\n") << _("Based on wxWidgets ");
Msg << wxMAJOR_VERSION << wxT(".") <<
Index: kicad-dev/3d-viewer/makefile.gtk
===================================================================
--- kicad-dev.orig/3d-viewer/makefile.gtk	2007-04-18 20:54:12.000000000 +0200
+++ kicad-dev/3d-viewer/makefile.gtk	2007-04-18 20:54:26.000000000 +0200
@@ -17,6 +17,7 @@

include makefile.include

+CPPFLAGS+= $(EXTRACPPFLAGS)

$(TARGET).a: $(OBJECTS3D) makefile.gtk makefile.include
rm -f $@
Index: kicad-dev/common/edaappl.cpp
===================================================================
--- kicad-dev.orig/common/edaappl.cpp	2007-04-18 20:54:12.000000000 +0200
+++ kicad-dev/common/edaappl.cpp	2007-04-18 20:54:26.000000000 +0200
@@ -8,6 +8,10 @@
#define EDA_BASE
#define COMMON_GLOBL

+#ifdef KICAD_PYTHON
+#include <pyhandler.h>
+#endif
+
#include "fctsys.h"
#include <wx/image.h>
#include "wx/html/htmlwin.h"
@@ -166,6 +170,7 @@
if ( atof("0,1") ) g_FloatSeparator = ','; // Nombres flottants = 0,1
else g_FloatSeparator = '.';

+	PyHandler::GetInstance()->SetAppName( name );
}


@@ -590,3 +595,12 @@
}


+int WinEDA_App::OnRun(void)
+/* Run init scripts */
+{
+	#ifdef KICAD_PYTHON
+	PyHandler::GetInstance()->RunScripts();
+	#endif
+	return wxApp::OnRun();
+}
+
Index: kicad-dev/include/appl_wxstruct.h
===================================================================
--- kicad-dev.orig/include/appl_wxstruct.h	2007-04-18 20:54:12.000000000 +0200
+++ kicad-dev/include/appl_wxstruct.h	2007-04-18 20:54:26.000000000 +0200
@@ -63,6 +63,7 @@
WinEDA_App(void);
~WinEDA_App(void);
bool OnInit(void);
+	int OnRun(void);

bool SetBinDir(void);
void InitEDA_Appl(const wxString & name);
 --------------080605030407010308020200--