From 74b122d4303d8a8130375480d3379c6f7c789656 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Thu, 14 Feb 2013 14:58:26 +0100 Subject: [PATCH] Implemented the 'Script' type. --- configure.ac | 7 + icinga-app/Makefile.am | 2 +- lib/Makefile.am | 3 +- lib/base/Makefile.am | 1 + lib/base/dynamicobject.cpp | 3 + lib/base/dynamicobject.h | 3 + lib/base/dynamictype.cpp | 3 + lib/base/script.cpp | 20 +- lib/base/script.h | 3 +- lib/base/scriptinterpreter.cpp | 8 +- lib/base/scriptinterpreter.h | 6 +- lib/base/scriptlanguage.cpp | 3 + lib/base/scriptlanguage.h | 18 ++ lib/config/Makefile.am | 1 + lib/icinga/Makefile.am | 1 + lib/python/Makefile.am | 35 +++ lib/python/i2-python.cpp | 22 ++ lib/python/i2-python.h | 44 +++ lib/python/pythoninterpreter.cpp | 56 ++++ lib/python/pythoninterpreter.h | 49 +++ lib/python/pythonlanguage.cpp | 54 ++++ lib/python/pythonlanguage.h | 49 +++ lib/remoting/Makefile.am | 1 + m4/ax_python_embed.m4 | 515 +++++++++++++++++++++++++++++++ 24 files changed, 890 insertions(+), 17 deletions(-) create mode 100644 lib/python/Makefile.am create mode 100644 lib/python/i2-python.cpp create mode 100644 lib/python/i2-python.h create mode 100644 lib/python/pythoninterpreter.cpp create mode 100644 lib/python/pythoninterpreter.h create mode 100644 lib/python/pythonlanguage.cpp create mode 100644 lib/python/pythonlanguage.h create mode 100644 m4/ax_python_embed.m4 diff --git a/configure.ac b/configure.ac index fc0fe88ef..f1bc33f51 100644 --- a/configure.ac +++ b/configure.ac @@ -78,6 +78,12 @@ if test "$ax_cv___attribute__" = "yes"; then CXXFLAGS="$CXXFLAGS -fvisibility=hidden" fi +AX_PYTHON_DEFAULT +AX_PYTHON_ENABLE +AX_PYTHON_VERSION_ENSURE([2.5]) +AX_PYTHON_CSPEC +AX_PYTHON_LSPEC + AC_MSG_CHECKING(whether to enable debugging) AC_ARG_ENABLE(debug, [ --enable-debug=[no/yes] turn on debugging (default=no)],, enable_debug=no) if test "x$enable_debug" = "xyes"; then @@ -121,6 +127,7 @@ lib/Makefile lib/base/Makefile lib/config/Makefile lib/icinga/Makefile +lib/python/Makefile lib/remoting/Makefile test/Makefile third-party/Makefile diff --git a/icinga-app/Makefile.am b/icinga-app/Makefile.am index 4e6baccc7..25a87a6d7 100644 --- a/icinga-app/Makefile.am +++ b/icinga-app/Makefile.am @@ -28,8 +28,8 @@ icinga2_LDADD = \ $(BOOST_PROGRAM_OPTIONS_LIB) \ ${top_builddir}/lib/base/libbase.la \ ${top_builddir}/lib/config/libconfig.la \ - ${top_builddir}/lib/remoting/libremoting.la \ -dlopen ${top_builddir}/lib/icinga/libicinga.la \ + -dlopen ${top_builddir}/lib/python/libpython.la \ -dlopen ${top_builddir}/components/checker/checker.la \ -dlopen ${top_builddir}/components/replication/replication.la \ -dlopen ${top_builddir}/components/compat/compat.la \ diff --git a/lib/Makefile.am b/lib/Makefile.am index 3e680a2eb..442f2058a 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -5,4 +5,5 @@ SUBDIRS = \ base \ config \ remoting \ - icinga + icinga \ + python diff --git a/lib/base/Makefile.am b/lib/base/Makefile.am index ac4d619ff..1f105e1a8 100644 --- a/lib/base/Makefile.am +++ b/lib/base/Makefile.am @@ -26,6 +26,7 @@ libbase_la_SOURCES = \ exception.h \ fifo.cpp \ fifo.h \ + i2-base.cpp \ i2-base.h \ logger.cpp \ logger.h \ diff --git a/lib/base/dynamicobject.cpp b/lib/base/dynamicobject.cpp index b3ad74084..10ae87196 100644 --- a/lib/base/dynamicobject.cpp +++ b/lib/base/dynamicobject.cpp @@ -481,6 +481,9 @@ void DynamicObject::FlushTx(void) BeginTx(); } +void DynamicObject::OnInitCompleted(void) +{ } + void DynamicObject::OnAttributeChanged(const String&, const Value&) { } diff --git a/lib/base/dynamicobject.h b/lib/base/dynamicobject.h index 7260efa6a..8e02d075d 100644 --- a/lib/base/dynamicobject.h +++ b/lib/base/dynamicobject.h @@ -132,6 +132,7 @@ public: static void FlushTx(void); protected: + virtual void OnInitCompleted(void); virtual void OnAttributeChanged(const String& name, const Value& oldValue); private: @@ -148,6 +149,8 @@ private: /* This has to be a set of raw pointers because the DynamicObject * constructor has to be able to insert objects into this list. */ static set m_ModifiedObjects; + + friend class DynamicType; /* for OnInitCompleted. */ }; } diff --git a/lib/base/dynamictype.cpp b/lib/base/dynamictype.cpp index 05efe7b5a..75ec7fae6 100644 --- a/lib/base/dynamictype.cpp +++ b/lib/base/dynamictype.cpp @@ -93,6 +93,9 @@ DynamicObject::Ptr DynamicType::CreateObject(const Dictionary::Ptr& serializedUp /* apply the object's non-config attributes */ obj->ApplyUpdate(serializedUpdate, Attribute_All & ~Attribute_Config); + /* notify the object that it's been fully initialized */ + obj->OnInitCompleted(); + return obj; } diff --git a/lib/base/script.cpp b/lib/base/script.cpp index 23418af47..0bcc5ca77 100644 --- a/lib/base/script.cpp +++ b/lib/base/script.cpp @@ -32,6 +32,11 @@ Script::Script(const Dictionary::Ptr& properties) : DynamicObject(properties) { } +void Script::OnInitCompleted(void) +{ + SpawnInterpreter(); +} + String Script::GetLanguage(void) const { return Get("language"); @@ -44,17 +49,14 @@ String Script::GetCode(void) const void Script::OnAttributeUpdate(const String& name, const Value& oldValue) { - if (name == "code") - Reload(); + if (name == "language" || name == "code") + SpawnInterpreter(); } -void Script::Reload(void) +void Script::SpawnInterpreter(void) { - if (!m_Interpreter) { - ScriptLanguage::Ptr language = ScriptLanguage::GetByName(GetLanguage()); + Logger::Write(LogInformation, "base", "Reloading script '" + GetName() + "'"); - m_Interpreter = language->CreateInterpreter(GetSelf()); - } else { - m_Interpreter->Reload(); - } + ScriptLanguage::Ptr language = ScriptLanguage::GetByName(GetLanguage()); + m_Interpreter = language->CreateInterpreter(GetSelf()); } diff --git a/lib/base/script.h b/lib/base/script.h index 47c300246..daaf288e1 100644 --- a/lib/base/script.h +++ b/lib/base/script.h @@ -42,12 +42,13 @@ public: String GetCode(void) const; protected: + virtual void OnInitCompleted(void); virtual void OnAttributeUpdate(const String& name, const Value& oldValue); private: shared_ptr m_Interpreter; - void Reload(void); + void SpawnInterpreter(void); }; } diff --git a/lib/base/scriptinterpreter.cpp b/lib/base/scriptinterpreter.cpp index 0d2b24b66..787ce6883 100644 --- a/lib/base/scriptinterpreter.cpp +++ b/lib/base/scriptinterpreter.cpp @@ -22,12 +22,12 @@ using namespace icinga; ScriptInterpreter::ScriptInterpreter(const Script::Ptr& script) - : m_Thread(&ScriptInterpreter::ThreadWorkerProc, this, script) + : m_Thread(&ScriptInterpreter::ThreadWorkerProc, this) { m_Thread.detach(); } -void ScriptInterpreter::ThreadWorkerProc(const Script::Ptr& script) +void ScriptInterpreter::ThreadWorkerProc(void) { ScriptCall call; @@ -55,3 +55,7 @@ bool ScriptInterpreter::WaitForCall(ScriptCall *call) return true; } +void ScriptInterpreter::RegisterMethod(const String& name) +{ + // TODO: implement +} diff --git a/lib/base/scriptinterpreter.h b/lib/base/scriptinterpreter.h index 629e99075..1a6dc10ec 100644 --- a/lib/base/scriptinterpreter.h +++ b/lib/base/scriptinterpreter.h @@ -41,8 +41,6 @@ public: typedef shared_ptr Ptr; typedef weak_ptr WeakPtr; - virtual void Reload(void) = 0; - void EnqueueCall(const ScriptCall& call); protected: @@ -52,6 +50,8 @@ protected: bool WaitForCall(ScriptCall *call); + void RegisterMethod(const String& name); + private: boost::mutex m_Mutex; deque m_Calls; @@ -59,7 +59,7 @@ private: boost::thread m_Thread; - void ThreadWorkerProc(const Script::Ptr& script); + void ThreadWorkerProc(void); }; } diff --git a/lib/base/scriptlanguage.cpp b/lib/base/scriptlanguage.cpp index eac9078e4..9c131807b 100644 --- a/lib/base/scriptlanguage.cpp +++ b/lib/base/scriptlanguage.cpp @@ -21,6 +21,9 @@ using namespace icinga; +ScriptLanguage::ScriptLanguage(void) +{ } + void ScriptLanguage::Register(const String& name, const ScriptLanguage::Ptr& language) { GetLanguages()[name] = language; diff --git a/lib/base/scriptlanguage.h b/lib/base/scriptlanguage.h index 7972a0b09..da6e30e53 100644 --- a/lib/base/scriptlanguage.h +++ b/lib/base/scriptlanguage.h @@ -47,6 +47,24 @@ private: static map& GetLanguages(void); }; +/** + * Helper class for registering ScriptLanguage implementation classes. + * + * @ingroup base + */ +class RegisterLanguageHelper +{ +public: + RegisterLanguageHelper(const String& name, const ScriptLanguage::Ptr& language) + { + if (!ScriptLanguage::GetByName(name)) + ScriptLanguage::Register(name, language); + } +}; + +#define REGISTER_SCRIPTLANGUAGE(name, klass) \ + static RegisterLanguageHelper g_RegisterSL_ ## type(name, boost::make_shared()) + } #endif /* SCRIPTLANGUAGE_H */ diff --git a/lib/config/Makefile.am b/lib/config/Makefile.am index 8737d31bd..18ad41c77 100644 --- a/lib/config/Makefile.am +++ b/lib/config/Makefile.am @@ -15,6 +15,7 @@ libconfig_la_SOURCES = \ configcompilercontext.h \ config_lexer.ll \ config_parser.yy \ + i2-config.cpp \ i2-config.h \ configitem.cpp \ configitem.h \ diff --git a/lib/icinga/Makefile.am b/lib/icinga/Makefile.am index 72358dbac..2dff520ab 100644 --- a/lib/icinga/Makefile.am +++ b/lib/icinga/Makefile.am @@ -15,6 +15,7 @@ libicinga_la_SOURCES = \ hostgroup.cpp \ hostgroup.h \ host.h \ + i2-icinga.cpp \ i2-icinga.h \ icingaapplication.cpp \ icingaapplication.h \ diff --git a/lib/python/Makefile.am b/lib/python/Makefile.am new file mode 100644 index 000000000..d314d6968 --- /dev/null +++ b/lib/python/Makefile.am @@ -0,0 +1,35 @@ +## Process this file with automake to produce Makefile.in + +if PYTHON_USE +pkglib_LTLIBRARIES = \ + libpython.la + +libpython_la_SOURCES = \ + i2-python.h \ + pythoninterpreter.cpp \ + pythoninterpreter.h \ + pythonlanguage.cpp \ + pythonlanguage.h + +libpython_la_CPPFLAGS = \ + -DI2_PYTHON_BUILD \ + $(BOOST_CPPFLAGS) \ + @PYTHON_CSPEC@ \ + -I${top_srcdir}/lib/base \ + -I${top_srcdir}/lib/config \ + -I${top_srcdir}/lib/remoting \ + -I${top_srcdir} + +libpython_la_LDFLAGS = \ + $(BOOST_LDFLAGS) \ + @PYTHON_LSPEC@ + -no-undefined \ + @RELEASE_INFO@ \ + @VERSION_INFO@ + +libpython_la_LIBADD = \ + $(BOOST_THREAD_LIB) \ + ${top_builddir}/lib/base/libbase.la \ + ${top_builddir}/lib/config/libconfig.la \ + ${top_builddir}/lib/remoting/libremoting.la +endif diff --git a/lib/python/i2-python.cpp b/lib/python/i2-python.cpp new file mode 100644 index 000000000..405d82046 --- /dev/null +++ b/lib/python/i2-python.cpp @@ -0,0 +1,22 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +/* This file is used by MSVC to generate the pre-compiled hedader. */ + +#include "i2-python.h" diff --git a/lib/python/i2-python.h b/lib/python/i2-python.h new file mode 100644 index 000000000..8b6a68799 --- /dev/null +++ b/lib/python/i2-python.h @@ -0,0 +1,44 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#ifndef I2PYTHON_H +#define I2PYTHON_H + +/** + * @defgroup python Icinga python support + * + * Lets you integrate Python scripts into Icinga. + */ + +#include + +#include +#include +#include + +#ifdef I2_PYTHON_BUILD +# define I2_PYTHON_API I2_EXPORT +#else /* I2_PYTHON_BUILD */ +# define I2_PYTHON_API I2_IMPORT +#endif /* I2_PYTHON_BUILD */ + +#include "pythonlanguage.h" +#include "pythoninterpreter.h" + +#endif /* I2PYTHON_H */ diff --git a/lib/python/pythoninterpreter.cpp b/lib/python/pythoninterpreter.cpp new file mode 100644 index 000000000..b4f0e3fe2 --- /dev/null +++ b/lib/python/pythoninterpreter.cpp @@ -0,0 +1,56 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#include "i2-python.h" + +using namespace icinga; + +PythonInterpreter::PythonInterpreter(const PythonLanguage::Ptr& language, const Script::Ptr& script) + : ScriptInterpreter(script), m_Language(language), m_ThreadState(NULL) +{ + PyEval_AcquireLock(); + + PyInterpreterState *interp = m_Language->GetMainThreadState()->interp; + m_ThreadState = PyThreadState_New(interp); + + PyEval_ReleaseLock(); + + PyEval_AcquireThread(m_ThreadState); + PyRun_SimpleString(script->GetCode().CStr()); + PyEval_ReleaseThread(m_ThreadState); +} + +PythonInterpreter::~PythonInterpreter(void) +{ + PyEval_AcquireLock(); + + PyThreadState_Clear(m_ThreadState); + PyThreadState_Delete(m_ThreadState); + + PyEval_ReleaseLock(); +} + +void PythonInterpreter::ProcessCall(const ScriptCall& call) +{ + PyEval_AcquireThread(m_ThreadState); + PyRun_SimpleString("import antigravity"); + PyEval_ReleaseThread(m_ThreadState); + + call.Task->FinishResult(0); +} diff --git a/lib/python/pythoninterpreter.h b/lib/python/pythoninterpreter.h new file mode 100644 index 000000000..70d19ef88 --- /dev/null +++ b/lib/python/pythoninterpreter.h @@ -0,0 +1,49 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#ifndef PYTHONINTERPRETER_H +#define PYTHONINTERPRETER_H + +namespace icinga +{ + +/** + * A Python script interpreter. + * + * @ingroup base + */ +class I2_PYTHON_API PythonInterpreter : public ScriptInterpreter +{ +public: + typedef shared_ptr Ptr; + typedef weak_ptr WeakPtr; + + PythonInterpreter(const PythonLanguage::Ptr& language, const Script::Ptr& script); + ~PythonInterpreter(void); + +protected: + PythonLanguage::Ptr m_Language; + PyThreadState *m_ThreadState; + + virtual void ProcessCall(const ScriptCall& call); +}; + +} + +#endif /* PYTHONINTERPRETER_H */ diff --git a/lib/python/pythonlanguage.cpp b/lib/python/pythonlanguage.cpp new file mode 100644 index 000000000..5226081e5 --- /dev/null +++ b/lib/python/pythonlanguage.cpp @@ -0,0 +1,54 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#include "i2-python.h" + +using namespace icinga; + +REGISTER_SCRIPTLANGUAGE("Python", PythonLanguage); + +PythonLanguage::PythonLanguage(void) + : ScriptLanguage() +{ + Py_Initialize(); + PyEval_InitThreads(); + + //PySys_SetArgv(argc, argv); + + m_MainThreadState = PyThreadState_Get(); + + PyThreadState_Swap(NULL); + + PyEval_ReleaseLock(); +} + +PythonLanguage::~PythonLanguage(void) +{ + Py_Finalize(); +} + +ScriptInterpreter::Ptr PythonLanguage::CreateInterpreter(const Script::Ptr& script) +{ + return boost::make_shared(GetSelf(), script); +} + +PyThreadState *PythonLanguage::GetMainThreadState(void) const +{ + return m_MainThreadState; +} diff --git a/lib/python/pythonlanguage.h b/lib/python/pythonlanguage.h new file mode 100644 index 000000000..bf0a519eb --- /dev/null +++ b/lib/python/pythonlanguage.h @@ -0,0 +1,49 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#ifndef PYTHONLANGUAGE_H +#define PYTHONLANGUAGE_H + +namespace icinga +{ + +/** + * The Python scripting language. + * + * @ingroup base + */ +class I2_PYTHON_API PythonLanguage : public ScriptLanguage +{ +public: + typedef shared_ptr Ptr; + typedef weak_ptr WeakPtr; + + PythonLanguage(void); + ~PythonLanguage(void); + + virtual ScriptInterpreter::Ptr CreateInterpreter(const Script::Ptr& script); + + PyThreadState *GetMainThreadState(void) const; +private: + PyThreadState *m_MainThreadState; +}; + +} + +#endif /* PYTHONLANGUAGE_H */ diff --git a/lib/remoting/Makefile.am b/lib/remoting/Makefile.am index eee7801c7..372dcca81 100644 --- a/lib/remoting/Makefile.am +++ b/lib/remoting/Makefile.am @@ -9,6 +9,7 @@ libremoting_la_SOURCES = \ endpoint.h \ endpointmanager.cpp \ endpointmanager.h \ + i2-remoting.cpp \ i2-remoting.h \ jsonrpcconnection.cpp \ jsonrpcconnection.h \ diff --git a/m4/ax_python_embed.m4 b/m4/ax_python_embed.m4 new file mode 100644 index 000000000..31f3547ea --- /dev/null +++ b/m4/ax_python_embed.m4 @@ -0,0 +1,515 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_python_embed.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PYTHON_DEFAULT +# AX_PYTHON_ENABLE +# AX_PYTHON_WITH +# AX_PYTHON_PATH +# AX_PYTHON_VERSION_ENSURE( [2.2] ) +# AX_PYTHON_CSPEC +# AX_PYTHON_LSPEC +# +# DESCRIPTION +# +# This file provides autoconf support for those applications that want to +# embed python. It supports all pythons >= 2.2 which is the first official +# release containing distutils. Version 2.2 of python was released +# December 21, 2001. Since it actually executes the python, cross platform +# configuration will probably not work. Also, most of the platforms +# supported are consistent until you look into Mac OS X. The python +# included with it is installed as a framework which is a very different +# environment to set up the normal tools such as gcc and libtool to deal +# with. Therefore, once we establish which python that we are going to +# use, we use its distutils to actually compile and link our modules or +# applications. +# +# At this time, it does NOT support linking with Python statically. It +# does support dynamic linking. +# +# This set of macros help define $PYTHON, $PYTHON_USE, $PYTHON_CSPEC and +# $PYTHON_LSPEC. $PYTHON defines the full executable path for the Python +# being linked to and is used within these macros to determine if that has +# been specified or found. These macros do execute this python version so +# it must be present on the system at configure time. +# +# $PYTHON_USE is an automake variable that defines whether Python support +# should be included or not in your application. $PYTHON_CSPEC is a +# variable that supplies additional CFLAGS for the compilation of the +# application/shared library. $PYTHON_LSPEC is a variable that supplies +# additional LDFLAGS for linking the application/shared library. +# +# The following is an example of how to set up for python usage within +# your application in your configure.in: +# +# AX_PYTHON_DEFAULT( ) +# AX_PYTHON_ENABLE( ) # Optional +# AX_PYTHON_WITH( ) # Optional +# AX_PYTHON_PATH( ) # or AX_PYTHON_INSIST( ) +# # if $PYTHON is not defined, then the following do nothing. +# AX_PYTHON_VERSION_ENSURE( [2.2] ) +# AX_PYTHON_CSPEC +# AX_PYTHON_LSPEC +# +# The AX_PYTHON_DEFAULT sets the $PYTHON_USE to false. Thereby, excluding +# it if it was optional. +# +# The AX_PYTHON_ENABLE looks for the optional configure parameters of +# --enable-python/--disable-python and establishes the $PYTHON and +# $PYTHON_USE variables accordingly. +# +# The AX_PYTHON_WITH looks for the optional configure parameters of +# --with-python/--without-python and establishes the $PYTHON and +# $PYTHON_USE variables accordingly. +# +# The AX_PYTHON_PATH looks for python assuming that none has been +# previously found or defined and issues an error if it does not find it. +# If it does find it, it establishes the $PYTHON and $PYTHON_USE variables +# accordingly. AX_PYTHON_INSIST could be used here instead if you want to +# insist that Python support be included using the --enable-python or +# --with-python checks previously done. +# +# The AX_PYTHON_VERSION_ENSURE issues an error if the Python previously +# found is not of version 2.2 or greater. +# +# Once that these macros have be run, we can use PYTHON_USE within the +# makefile.am file to conditionally add the Python support such as: +# +# Makefile.am example showing optional inclusion of directories: +# +# if PYTHON_USE +# plugins = plugins +# src = src +# else +# plugins = +# src = +# endif +# +# SUBDIRS = . $(plugins) $(src) +# +# Makefile.am example showing optional shared library build: +# +# if PYTHON_USE +# lib_LTLIBRARIES = libElemList.la +# libElemList_la_SOURCES = libElemList.c +# libElemList_la_CFLAGS = @PYTHON_CSPEC@ +# libElemList_la_LDFLAGS = @PYTHON_LSPEC@ +# endif +# +# Makefile.am example showing optional program build: +# +# if PYTHON_USE +# bin_PROGRAMS = runFunc +# runFunc_SOURCES = runFunc.c +# runFunc_CFLAGS = @PYTHON_CSPEC@ +# runFunc_LDFLAGS = @PYTHON_LSPEC@ +# endif +# +# The above compiles the modules only if PYTHON_USE was specified as true. +# Also, the else portion of the if was optional. +# +# LICENSE +# +# Copyright (c) 2008 Robert White +# Copyright (c) 2008 Dustin J. Mitchell +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 8 + +# AX_PYTHON_DEFAULT( ) +# ----------------- +# Sets the default to not include Python support. + +AC_DEFUN([AX_PYTHON_DEFAULT], +[ + ax_python_use=false + AM_CONDITIONAL(PYTHON_USE, test x"$ax_python_use" = x"true") +]) + + + +# AX_PYTHON_ENABLE( [path] ) +# ----------------------------------------------------------------- +# Handles the various --enable-python commands. +# Input: +# $1 is the optional search path for the python executable if needed +# Ouput: +# PYTHON_USE (AM_CONDITIONAL) is true if python executable found +# and --enable-python was requested; otherwise false. +# $PYTHON contains the full executable path to python if PYTHON_ENABLE_USE +# is true. +# +# Example: +# AX_PYTHON_ENABLE( ) +# or +# AX_PYTHON_ENABLE( "/usr/bin" ) + +AC_DEFUN([AX_PYTHON_ENABLE], +[ + AC_ARG_VAR([PYTHON],[Python Executable Path]) + + # unless PYTHON was supplied to us (as a precious variable), + # see if --enable-python[=PythonExecutablePath], --enable-python, + # --disable-python or --enable-python=no was given. + if test -z "$PYTHON" + then + AC_MSG_CHECKING(for --enable-python) + AC_ARG_ENABLE( + python, + AS_HELP_STRING([--enable-python@<:@=PYTHON@:>@], + [absolute path name of Python executable] + ), + [ + if test "$enableval" = "yes" + then + # "yes" was specified, but we don't have a path + # for the executable. + # So, let's searth the PATH Environment Variable. + AC_MSG_RESULT(yes) + AC_PATH_PROG( + [PYTHON], + python, + [], + $1 + ) + if test -z "$PYTHON" + then + AC_MSG_ERROR(no path to python found) + fi + ax_python_use=true + AM_CONDITIONAL(PYTHON_USE, test x"$ax_python_use" = x"true") + AX_PYTHON_PREFIX( ) + elif test "$enableval" = "no" + then + AC_MSG_RESULT(no) + ax_python_use=false + AM_CONDITIONAL(PYTHON_USE, test x"$ax_python_use" = x"true") + else + # $enableval must be the executable path then. + AC_SUBST([PYTHON], ["${enableval}"]) + AC_MSG_RESULT($withval) + ax_python_use=true + AM_CONDITIONAL(PYTHON_USE, test x"$ax_python_use" = x"true") + AX_PYTHON_PREFIX( ) + fi + ], + [ + # --with-python was not specified. + AC_MSG_RESULT(no) + ax_python_use=false + AM_CONDITIONAL(PYTHON_USE, test x"$ax_python_use" = x"true") + ] + ) + fi + +]) + + + +# AX_PYTHON_CSPEC( ) +# ----------------- +# Set up the c compiler options to compile Python +# embedded programs/libraries in $PYTHON_CSPEC if +# $PYTHON has been defined. + +AC_DEFUN([AX_PYTHON_CSPEC], +[ + AC_ARG_VAR( [PYTHON], [Python Executable Path] ) + if test -n "$PYTHON" + then + ax_python_prefix=`${PYTHON} -c "import sys; print sys.prefix"` + if test -z "$ax_python_prefix" + then + AC_MSG_ERROR([Python Prefix is not known]) + fi + ax_python_execprefix=`${PYTHON} -c "import sys; print sys.exec_prefix"` + ax_python_version=`$PYTHON -c "import sys; print sys.version[[:3]]"` + ax_python_includespec="-I${ax_python_prefix}/include/python${ax_python_version}" + if test x"$python_prefix" != x"$python_execprefix"; then + ax_python_execspec="-I${ax_python_execprefix}/include/python${ax_python_version}" + ax_python_includespec="${ax_python_includespec} $ax_python_execspec" + fi + ax_python_ccshared=`${PYTHON} -c "import distutils.sysconfig; print distutils.sysconfig.get_config_var('CFLAGSFORSHARED')"` + ax_python_cspec="${ax_python_ccshared} ${ax_python_includespec}" + AC_SUBST([PYTHON_CSPEC], [${ax_python_cspec}]) + AC_MSG_NOTICE([PYTHON_CSPEC=${ax_python_cspec}]) + fi +]) + + + +# AX_PYTHON_INSIST( ) +# ----------------- +# Look for Python and set the output variable 'PYTHON' +# to 'python' if found, empty otherwise. + +AC_DEFUN([AX_PYTHON_INSIST], +[ + AC_ARG_VAR( [PYTHON], [Python Executable Path] ) + if test -z "$PYTHON" + then + AC_MSG_ERROR([Python Executable not found]) + fi +]) + + + +# AX_PYTHON_LSPEC( ) +# ----------------- +# Set up the linker options to link Python embedded +# programs/libraries in $PYTHON_LSPEC if $PYTHON +# has been defined. + +AC_DEFUN([AX_PYTHON_LSPEC], +[ + AC_ARG_VAR( [PYTHON], [Python Executable Path] ) + if test -n "$PYTHON" + then + AX_PYTHON_RUN([ +import sys +import distutils.sysconfig +strUseFrameWork = "--enable-framework" +dictConfig = distutils.sysconfig.get_config_vars( ) +strConfigArgs = dictConfig.get("CONFIG_ARGS") +strLinkSpec = dictConfig.get('LDFLAGS') +if -1 == strConfigArgs.find(strUseFrameWork): + strLibPL = dictConfig.get("LIBPL") + if strLibPL and (strLibPL != ""): + strLinkSpec += " -L%s" % (strLibPL) + strSys = dictConfig.get("SYSLIBS") + if strSys and (strSys != ""): + strLinkSpec += " %s" % (strSys) + strSHL = dictConfig.get("SHLIBS") + if strSHL and (strSHL != ""): + strLinkSpec += " %s" % (strSHL) + # Construct the Python Library Name. + strTmplte = " -lpython%d.%d" + if (sys.platform == "win32") or (sys.platform == "os2emx"): + strTmplte = " -lpython%d%d" + strWrk = strTmplte % ( (sys.hexversion >> 24), + ((sys.hexversion >> 16) & 0xff)) + strLinkSpec += strWrk +else: + # This is not ideal since it changes the search path + # for Frameworks which could have side-effects on + # other included Frameworks. However, it is necessary + # where someone has installed more than one frameworked + # Python. Frameworks are really only used in MacOSX. + strLibFW = dictConfig.get("PYTHONFRAMEWORKPREFIX") + if strLibFW and (strLibFW != ""): + strLinkSpec += " -F%s" % (strLibFW) +strLinkSpec += " %s" % (dictConfig.get('LINKFORSHARED')) +print strLinkSpec + ]) + AC_SUBST([PYTHON_LSPEC], [${ax_python_output}]) + AC_MSG_NOTICE([PYTHON_LSPEC=${ax_python_output}]) + fi +]) + + + +# AX_PYTHON_PATH( ) +# ----------------- +# Look for Python and set the output variable 'PYTHON' +# to 'python' if found, empty otherwise. + +AC_DEFUN([AX_PYTHON_PATH], +[ + AC_ARG_VAR( [PYTHON], [Python Executable Path] ) + AC_PATH_PROG( PYTHON, python, [], $1 ) + if test -z "$PYTHON" + then + AC_MSG_ERROR([Python Executable not found]) + else + ax_python_use=true + fi + AM_CONDITIONAL(PYTHON_USE, test "$ax_python_use" = "true") +]) + + + +# AX_PYTHON_PREFIX( ) +# ------------------- +# Use the values of $prefix and $exec_prefix for the corresponding +# values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. + +AC_DEFUN([AX_PYTHON_PREFIX], +[ + if test -z "$PYTHON" + then + AC_MSG_ERROR([Python Executable Path is not known]) + fi + ax_python_prefix=`${PYTHON} -c "import sys; print sys.prefix"` + ax_python_execprefix=`${PYTHON} -c "import sys; print sys.exec_prefix"` + AC_SUBST([PYTHON_PREFIX], ["${ax_python_prefix}"]) + AC_SUBST([PYTHON_EXECPREFIX], ["${ax_python_execprefix}"]) +]) + + + +# AX_PYTHON_RUN( PYTHON_PROGRAM ) +# ----------------- +# Run a Python Test Program saving its output +# in ax_python_output and its condition code +# in ax_python_cc. + +AC_DEFUN([AX_PYTHON_RUN], +[ + AC_ARG_VAR( [PYTHON], [Python Executable Path] ) + if test -z "$PYTHON" + then + AC_MSG_ERROR([Python Executable not found]) + else + cat >conftest.py <<_ACEOF +$1 +_ACEOF + ax_python_output=`$PYTHON conftest.py` + ax_python_cc=$? + rm conftest.py + if test -f "conftest.pyc" + then + rm conftest.pyc + fi + fi +]) + + + +# AX_PYTHON_VERSION_CHECK( VERSION, [ACTION-IF-TRUE], [ACTION-IF-FALSE] ) +# ----------------------------------------------------------------------------- +# Run ACTION-IF-TRUE if the Python interpreter has version >= VERSION. +# Run ACTION-IF-FALSE otherwise. +# This test uses sys.hexversion instead of the string equivalant (first +# word of sys.version), in order to cope with versions such as 2.2c1. +# hexversion has been introduced in Python 1.5.2; it's probably not +# worth to support older versions (1.5.1 was released on October 31, 1998). + +AC_DEFUN([AX_PYTHON_VERSION_CHECK], + [ + AC_ARG_VAR( [PYTHON], [Python Executable Path] ) + if test -n "$PYTHON" + then + AC_MSG_CHECKING([whether $PYTHON version >= $1]) + AX_PYTHON_RUN([ +import sys, string +# split strings by '.' and convert to numeric. Append some zeros +# because we need at least 4 digits for the hex conversion. +minver = map(int, string.split('$1', '.')) + [[0, 0, 0]] +minverhex = 0 +for i in xrange(0, 4): minverhex = (minverhex << 8) + minver[[i]] +if sys.hexversion >= minverhex: + sys.exit( 0 ) +else: + sys.exit( 1 ) + ]) + if test $ax_python_cc -eq 0 + then + $2 + m4_ifvaln( + [$3], + [else $3] + ) + fi + fi +]) + + + +# AX_PYTHON_VERSION_ENSURE( VERSION ) +# ----------------- +# Insure that the Python Interpreter Version +# is greater than or equal to the VERSION +# parameter. + +AC_DEFUN([AX_PYTHON_VERSION_ENSURE], +[ + AX_PYTHON_VERSION_CHECK( + [$1], + [AC_MSG_RESULT(yes)], + [AC_MSG_ERROR(too old)] + ) +]) + + + +# AX_PYTHON_WITH( [path] ) +# ----------------------------------------------------------------- +# Handles the various --with-python commands. +# Input: +# $1 is the optional search path for the python executable if needed +# Ouput: +# PYTHON_USE (AM_CONDITIONAL) is true if python executable found +# and --with-python was requested; otherwise false. +# $PYTHON contains the full executable path to python if PYTHON_USE +# is true. +# +# Example: +# AX_PYTHON_WITH( ) +# or +# AX_PYTHON_WITH("/usr/bin") + +AC_DEFUN([AX_PYTHON_WITH], +[ + AC_ARG_VAR([PYTHON],[Python Executable Path]) + + # unless PYTHON was supplied to us (as a precious variable), + # see if --with-python[=PythonExecutablePath], --with-python, + # --without-python or --with-python=no was given. + if test -z "$PYTHON" + then + AC_MSG_CHECKING(for --with-python) + AC_ARG_WITH( + python, + AS_HELP_STRING([--with-python@<:@=PYTHON@:>@], + [absolute path name of Python executable] + ), + [ + if test "$withval" = "yes" + then + # "yes" was specified, but we don't have a path + # for the executable. + # So, let's searth the PATH Environment Variable. + AC_MSG_RESULT(yes) + AC_PATH_PROG( + [PYTHON], + python, + [], + $1 + ) + if test -z "$PYTHON" + then + AC_MSG_ERROR(no path to python found) + fi + ax_python_use=true + AM_CONDITIONAL(PYTHON_USE, test x"$ax_python_use" = x"true") + AX_PYTHON_PREFIX( ) + elif test "$withval" = "no" + then + AC_MSG_RESULT(no) + ax_python_use=false + AM_CONDITIONAL(PYTHON_USE, test x"$ax_python_use" = x"true") + else + # $withval must be the executable path then. + AC_SUBST([PYTHON], ["${withval}"]) + AC_MSG_RESULT($withval) + ax_python_use=true + AM_CONDITIONAL(PYTHON_USE, test x"$ax_python_use" = x"true") + AX_PYTHON_PREFIX( ) + fi + ], + [ + # --with-python was not specified. + AC_MSG_RESULT(no) + ax_python_use=false + AM_CONDITIONAL(PYTHON_USE, test x"$ax_python_use" = x"true") + ] + ) + fi + +]) -- 2.40.0