diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..ff90f39 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "cmake"] + path = cmake/backbone + url = git@git.backbone.ws:cmake/backbone.git diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..609258d --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Kolan Sh diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..edd42c5 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,21 @@ +PROJECT (GObjectPlugin C) + +CMAKE_MINIMUM_REQUIRED (VERSION 2.8) + +SET (PROJECT_LOWERCASE_NAME "gobject-plugin") +SET (PROJECT_DESCRIPTION "Host/Plugin Interfaces for GObject Based Applications/Libraries.") + +SET (MAJOR 0) +SET (MINOR 1) +SET (PATCH 0) + +LIST (APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/backbone) + +ADD_SUBDIRECTORY (src) +ADD_SUBDIRECTORY (po) +ADD_SUBDIRECTORY (pkg-config) +ADD_SUBDIRECTORY (test) +ADD_SUBDIRECTORY (cpack) + +# enable testing +ENABLE_TESTING () diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/COPYING @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..3e899a5 --- /dev/null +++ b/INSTALL @@ -0,0 +1,84 @@ + Requirements + ------------ + + Build-Time Dependencies + +Vala: https://wiki.gnome.org/Projects/Vala +Gee: https://wiki.gnome.org/Projects/Libgee +CMake: http://www.cmake.org +NSIS (W32): http://nsis.sourceforge.net + + Run-Time Dependencies + +Gee: https://wiki.gnome.org/Projects/Libgee + + Operation Systems + + * GNU/Linux (Gentoo, Debian, etc.) + * MS Windows (Windows 5.1 aka XP) + * BSD-based (FreeBSD, OpenBSD, NetBSD, Mac OS X) + +If you need support of one more OS, be free in writing of patches and sending +pull-requests to the mainstream. + + + Compilation + ----------- + + Compilation under GNU/Linux + +$ mkdir build-gcc && cd build-gcc +$ cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr +$ make -j$((`getconf _NPROCESSORS_ONLN`+1)) + + Compilation under MS Windows + +$ mkdir build-mingw && cd build-mingw +$ cmake -G "MSYS Makefiles" .. -DCMAKE_BUILD_TYPE=Release +$ make -j$((NUMBER_OF_PROCESSORS + 1)) + + Compilation under BSD-based Systems. + +TODO: add description here. + + + Packing/Installation + -------------------- + + Packing/Installation under GNU/Linux + +$ cpack +Install using System Package Manager. + + Packing/Installation under MS Windows + +$ cpack +Install using generated by NSIS executable. + + Packing/Installation under BSD-based + +$ cpack +Install using System Package Manager. + + + Testing + ------- + + Testing under GNU/Linux + +$ ctest -j$((`getconf _NPROCESSORS_ONLN`+1)) + +Automated tests for memory leaks: +$ ctest -j$((NUMBER_OF_PROCESSORS + 1)) -D NightlyMemCheck && grep definitely Testing/Temporary/LastDynamicAnalysis_*.log + + Testing under MS Windows + +$ ctest -j$((NUMBER_OF_PROCESSORS + 1)) +Automated tests for memory leaks are not available as far as Valgrind not +present on this platform. + + Testing under BSD-based + +$ ctest +Automated tests for memory leaks are not available as far as Valgrind not +present on this platform. diff --git a/MAINTAINERS b/MAINTAINERS new file mode 100644 index 0000000..f2b408a --- /dev/null +++ b/MAINTAINERS @@ -0,0 +1,2 @@ +Kolan Sh +email: backbone@backbone.ws diff --git a/cmake/backbone b/cmake/backbone new file mode 160000 index 0000000..a3bf0ee --- /dev/null +++ b/cmake/backbone @@ -0,0 +1 @@ +Subproject commit a3bf0ee0e7f0c514ab3c9d6c37d2c386579465a6 diff --git a/cpack/CMakeLists.txt b/cpack/CMakeLists.txt new file mode 100644 index 0000000..5580fc0 --- /dev/null +++ b/cpack/CMakeLists.txt @@ -0,0 +1,10 @@ +SET (CONTACT "backbone@backbone.ws") +SET (DEBIAN_DEPENDENCIES "valac (>= 0.24), libglib2.0-bin (>= 2.33)") +SET (DEBIAN_SECTION "Libraries") +SET (REDHAT_DEPENDENCIES "vala >= 0.24, glib >= 2.33") +SET (REDHAT_SECTION "Applications/Text") +SET (LICENSE "LGPLv3+") +SET (WIN32_UNINSTALL_NAME "GobjPlug") # <= 8 symbols for the name + +LIST (APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) +INCLUDE (CPackCommon) diff --git a/pkg-config/CMakeLists.txt b/pkg-config/CMakeLists.txt new file mode 100644 index 0000000..dd5c19d --- /dev/null +++ b/pkg-config/CMakeLists.txt @@ -0,0 +1,23 @@ +# configure pkg-config file +IF (WIN32) + SET (PkgConfigPrefix "") +ELSE () + SET (PkgConfigPrefix ${CMAKE_INSTALL_PREFIX}) +ENDIF () +SET (PkgConfigExecPrefix "\${prefix}") +SET (PkgConfigLibDir "\${exec_prefix}/lib") +SET (PkgConfigIncludeDir "\${prefix}/include") + +SET (PkgConfigName "${CMAKE_PROJECT_NAME}") +SET (PkgConfigDescription "${PROJECT_DESCRIPTION}") +SET (PkgConfigVersion "${MAJOR}.${MINOR}.${PATCH}") +SET (PkgConfigLibs "-L\${libdir}") +SET (PkgConfigLibs "${PkgConfigLibs} -l${PROJECT_LOWERCASE_NAME}-iface-${MAJOR}") +SET (PkgConfigLibs "${PkgConfigLibs} -l${PROJECT_LOWERCASE_NAME}-loader-${MAJOR}") +SET (PkgConfigLibsPrivate "") +SET (PkgConfigCflags "") + +CONFIGURE_FILE ( + "${CMAKE_CURRENT_SOURCE_DIR}/pkg-config.pc.in" + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_LOWERCASE_NAME}-${MAJOR}.pc" +) diff --git a/pkg-config/pkg-config.pc.in b/pkg-config/pkg-config.pc.in new file mode 100644 index 0000000..ad5264d --- /dev/null +++ b/pkg-config/pkg-config.pc.in @@ -0,0 +1,11 @@ +prefix=@PkgConfigPrefix@ +exec_prefix=@PkgConfigExecPrefix@ +libdir=@PkgConfigLibDir@ +includedir=@PkgConfigIncludeDir@ + +Name: @PkgConfigName@ +Description: @PkgConfigDescription@ +Version: @PkgConfigVersion@ +Libs: @PkgConfigLibs@ +Libs.private: @PkgConfigLibsPrivate@ +Cflags: @PkgConfigCflags@ diff --git a/po/CMakeLists.txt b/po/CMakeLists.txt new file mode 100644 index 0000000..946851e --- /dev/null +++ b/po/CMakeLists.txt @@ -0,0 +1,41 @@ +SET (GETTEXT_PACKAGE "${PROJECT_LOWERCASE_NAME_ABI}") +ADD_DEFINITIONS (-DGETTEXT_PACKAGE="${GETTEXT_PACKAGE}") + +IF (WIN32) + SET (LOCALEDIR "") +ELSE () + SET (LOCALEDIR "${CMAKE_INSTALL_PREFIX}/share/locale") +ENDIF () + +SET (CUSTOM_LOCALEDIR "" CACHE STRING "Directory to install l10n files into") + +IF (NOT CUSTOM_LOCALEDIR STREQUAL "") + SET (LOCALEDIR "${CUSTOM_LOCALEDIR}") + MESSAGE(STATUS "Using LOCALEDIR=${LOCALEDIR}") +ENDIF () + +ADD_DEFINITIONS (-DLOCALEDIR="${LOCALEDIR}") +SET (LOCALE_INSTALL_DIR "share/locale") +LIST (APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) +INCLUDE (MacroOptionalAddSubdirectory) +FIND_PACKAGE (Gettext REQUIRED) + +MACRO_OPTIONAL_ADD_SUBDIRECTORY (langs) + +# configure a header file for Gettext +SET (VERSION ${MAJOR}.${MINOR}.${PATCH}) +SET (PROJECT_LOWERCASE_NAME_ABI "${PROJECT_LOWERCASE_NAME}-${MAJOR}") + +STRING (TOUPPER "${CMAKE_PROJECT_NAME}" GettextUniqueHeader) +SET (GettextPackageNameAbi "${PROJECT_LOWERCASE_NAME_ABI}") +CONFIGURE_FILE ( + "gettext-config.h.in" + "${PROJECT_BINARY_DIR}/po/gettext-config.h" + ) + +IF (NOT GETTEXT_MSGMERGE_EXECUTABLE) + MESSAGE (FATAL_ERROR "Please install msgmerge binary") +ENDIF (NOT GETTEXT_MSGMERGE_EXECUTABLE) +IF (NOT GETTEXT_MSGFMT_EXECUTABLE) + MESSAGE(FATAL_ERROR "Please install msgmerge binary") +ENDIF (NOT GETTEXT_MSGFMT_EXECUTABLE) diff --git a/po/gettext-config.h.in b/po/gettext-config.h.in new file mode 100644 index 0000000..7dd3e38 --- /dev/null +++ b/po/gettext-config.h.in @@ -0,0 +1,11 @@ +#ifndef @GettextUniqueHeader@_H +#define @GettextUniqueHeader@_H + +#define GETTEXT_PACKAGE "@GettextPackageNameAbi@" +#include + +#ifdef WIN32 +#define _(String) dgettext (GETTEXT_PACKAGE, String) +#endif + +#endif // @GettextUniqueHeader@_H diff --git a/po/langs/CMakeLists.txt b/po/langs/CMakeLists.txt new file mode 100644 index 0000000..33bcd87 --- /dev/null +++ b/po/langs/CMakeLists.txt @@ -0,0 +1,2 @@ +ADD_SUBDIRECTORY (ru) +# ADD_SUBDIRECTORY (de) diff --git a/po/langs/ru/CMakeLists.txt b/po/langs/ru/CMakeLists.txt new file mode 100644 index 0000000..3c6832c --- /dev/null +++ b/po/langs/ru/CMakeLists.txt @@ -0,0 +1,2 @@ +FILE (GLOB _po_files *.po) +GETTEXT_PROCESS_PO_FILES (ru ALL INSTALL_DESTINATION ${LOCALE_INSTALL_DIR} PO_FILES ${_po_files} ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..2979b1a --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,5 @@ +INCLUDE_DIRECTORIES (${CMAKE_BINARY_DIR}/po) + +ADD_SUBDIRECTORY (host-iface) +ADD_SUBDIRECTORY (plugin-iface) +ADD_SUBDIRECTORY (loader) diff --git a/src/host-iface/CMakeLists.txt b/src/host-iface/CMakeLists.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/library_constructor.c b/src/library_constructor.c new file mode 100644 index 0000000..86f9298 --- /dev/null +++ b/src/library_constructor.c @@ -0,0 +1,35 @@ +#if defined(_WIN32) || defined(_WIN64) +#include +#endif + +#include "gettext-config.h" + +#if defined(_WIN32) || defined(_WIN64) +BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) +#elif defined(linux) || defined(UNIX) || defined(__unix__) +void __attribute__ ((constructor)) load_library (void) +#endif +{ +#if defined(_WIN32) || defined(_WIN64) + gchar dllPath[FILENAME_MAX], + *dllDir, + *localePath; + + GetModuleFileName (hInstance, dllPath, FILENAME_MAX); + dllDir = g_path_get_dirname (dllPath); + localePath = g_build_filename (dllDir, "../share/locale", NULL); + g_free (dllDir); + bindtextdomain (GETTEXT_PACKAGE, localePath); + g_free (localePath); +#endif + +#if (!GLIB_CHECK_VERSION (2, 36, 0)) + g_type_init (); +#endif + +#if defined(_WIN32) || defined(_WIN64) + (void) dwReason; // avoid + (void) lpReserved; // warngings + return TRUE; +#endif +} diff --git a/src/loader/CMakeLists.txt b/src/loader/CMakeLists.txt new file mode 100644 index 0000000..ce15a24 --- /dev/null +++ b/src/loader/CMakeLists.txt @@ -0,0 +1,9 @@ +SET (LibName ${PROJECT_LOWERCASE_NAME}-loader) +FILE (GLOB_RECURSE LibSources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} PluginLoader.vala) +SET (LibPackages gee-0.8 gmodule-2.0 gio-2.0) +SET (LibCustomVapis ${CMAKE_BINARY_DIR}/src/plugin-iface/${PROJECT_LOWERCASE_NAME}-iface-${MAJOR}.vapi) +SET (LibExtraSources ${PROJECT_SOURCE_DIR}/src/library_constructor.c) +SET (LibInstall ON) +SET (LibLinkLibs ${PROJECT_LOWERCASE_NAME}-iface) +INCLUDE_DIRECTORIES ("${CMAKE_BINARY_DIR}/src/plugin-iface") +INCLUDE (ValaLibCommonRules) diff --git a/src/loader/PluginLoader.vala b/src/loader/PluginLoader.vala new file mode 100644 index 0000000..8894b6e --- /dev/null +++ b/src/loader/PluginLoader.vala @@ -0,0 +1,133 @@ +/** + * GObject Models. + */ +namespace GObject { + + /** + * Modules/Plugins. + */ + namespace Plugins { + + /** + * Module. + */ + public class Module : TypeModule { + [CCode (has_target = false)] + private delegate Type PluginInitFunc (TypeModule module); + + private GLib.Module module = null; + + private string path = null; + + private Type type; + + /** + * Creates a new Module by specific path. + * + * @param path path to the module. + */ + public Module (string path) { + this.path = path; + } + + /** + * Loads the module. + */ + public override bool load () { + module = GLib.Module.open (path, GLib.ModuleFlags.BIND_LAZY); + if (null == module) { + message ("Module '%s' not found", path); + return false; + } + + void * plugin_init = null; + if (! module.symbol ("plugin_init", out plugin_init)) { + message ("No such symbol: plugin_init in module " + path); + return false; + } + + type = ((PluginInitFunc) plugin_init) (this); + + return true; + } + + /** + * Unloads the module. + */ + public override void unload () { + module = null; + } + + /** + * Gets Plugin Type. + */ + public Type get_plugin_type () { + return type; + } + + /** + * Creates Plugin instance from the module. + */ + public Plugin create_instance () { + return Object.new (type) as Plugin; + } + } + + /** + * Loads modules in the 2-depth directory tree path. + * + * @param dir_path path to the 2-depth directory tree. + * @param modules where to save list of modules. + * + * @return are the modules loaded correctly or not. + */ + public bool load_modules (string dir_path, ref Gee.ArrayList? modules) { + + modules = new Gee.ArrayList (); + + try { + var libPath = File.new_for_path (dir_path); + var dir_enumerator = libPath.enumerate_children ("standard::*", + FileQueryInfoFlags.NOFOLLOW_SYMLINKS, null); + FileInfo dir_info = null; + while ((dir_info = dir_enumerator.next_file (null)) != null ) { + if (dir_info.get_file_type () == FileType.DIRECTORY) { + File subdir = libPath.resolve_relative_path (dir_info.get_name ()); + var lib_enumerator = subdir.enumerate_children (FileAttribute.STANDARD_NAME, 0, null); + FileInfo file_info = null; + while ((file_info = lib_enumerator.next_file (null)) != null) { + if (Regex.match_simple ("^.*\\.(so|dll)$", file_info.get_name ())) { + var path = Path.build_path (Path.DIR_SEPARATOR_S, dir_path, dir_info.get_name ()); + var module = new Module (GLib.Module.build_path (path, file_info.get_name ())); + if (module.load ()) + modules.add (module); + } + } + } + } + } catch (Error e) { + message (e.message); + return false; + } + + modules.sort ((a, b) => { + var a_name = a.get_plugin_type ().name (); + var b_name = b.get_plugin_type ().name (); + if (a_name < b_name) return -1; + if (a_name > b_name) return 1; + return 0; + }); + + return true; + } + + /** + * Unloads modules. + * + * @param modules list of modules. + */ + public void unload_modules (Gee.ArrayList modules) { + modules.foreach ((a) => {a.unload (); return true;}); + } + } +} diff --git a/src/plugin-iface/CMakeLists.txt b/src/plugin-iface/CMakeLists.txt new file mode 100644 index 0000000..da0f6a1 --- /dev/null +++ b/src/plugin-iface/CMakeLists.txt @@ -0,0 +1,6 @@ +SET (LibName ${PROJECT_LOWERCASE_NAME}-iface) +FILE (GLOB_RECURSE LibSources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} PluginInterface.vala) +SET (LibPackages gee-0.8 gmodule-2.0 gio-2.0) +SET (LibExtraSources ${PROJECT_SOURCE_DIR}/src/library_constructor.c) +SET (LibInstall ON) +INCLUDE (ValaLibCommonRules) diff --git a/src/plugin-iface/PluginInterface.vala b/src/plugin-iface/PluginInterface.vala new file mode 100644 index 0000000..a79e2d2 --- /dev/null +++ b/src/plugin-iface/PluginInterface.vala @@ -0,0 +1,23 @@ +/** + * GObject Models. + */ +namespace GObject { + + /** + * Modules/Plugins. + */ + namespace Plugins { + + /** + * Plugin interface. + */ + public interface IPlugabble : Object { + } + + /** + * Abstract Plugin. + */ + public abstract class Plugin : Object, IPlugabble { + } + } +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..b4961e1 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,5 @@ +ADD_SUBDIRECTORY (loader_test-iface) +ADD_SUBDIRECTORY (plugins) +ADD_SUBDIRECTORY (loader_test) + +INCLUDE (CTest) diff --git a/test/loader_test-iface/CMakeLists.txt b/test/loader_test-iface/CMakeLists.txt new file mode 100644 index 0000000..7d1e8a3 --- /dev/null +++ b/test/loader_test-iface/CMakeLists.txt @@ -0,0 +1,6 @@ +SET (LibName loader_test-iface) +FILE (GLOB_RECURSE LibSources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} LoaderTestInterface.vala) +SET (LibCustomVapis ${CMAKE_BINARY_DIR}/src/plugin-iface/${PROJECT_LOWERCASE_NAME}-iface-${MAJOR}.vapi) +SET (LibLinkLibs gobject-plugin-iface) +INCLUDE_DIRECTORIES ("${CMAKE_BINARY_DIR}/src/plugin-iface") +INCLUDE (ValaLibCommonRules) diff --git a/test/loader_test-iface/LoaderTestInterface.vala b/test/loader_test-iface/LoaderTestInterface.vala new file mode 100644 index 0000000..f11129b --- /dev/null +++ b/test/loader_test-iface/LoaderTestInterface.vala @@ -0,0 +1,24 @@ +using GObject.Plugins; + +/** + * Abstract plugin of type A. + */ +public abstract class PluginTypeA: Plugin { + + /** + * Any virtual method for PluginTypeA. + */ + [CCode (has_target = false)] + public virtual void method_a () { } +} + +/** + * Abstract plugin of type B. + */ +public abstract class PluginTypeB : Plugin { + + /** + * Any virtual method for PluginTypeB. + */ + public virtual string method_b () { return ""; } +} diff --git a/test/loader_test/CMakeLists.txt b/test/loader_test/CMakeLists.txt new file mode 100644 index 0000000..b1287f7 --- /dev/null +++ b/test/loader_test/CMakeLists.txt @@ -0,0 +1,39 @@ +SET (BinName loader_test) +FILE (GLOB_RECURSE BinSources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} LoaderTest.vala) +SET (BinPackages gee-0.8 gio-2.0) +SET (BinCustomVapis ${CMAKE_BINARY_DIR}/src/loader/${PROJECT_LOWERCASE_NAME}-loader-${MAJOR}.vapi + ${CMAKE_BINARY_DIR}/src/plugin-iface/${PROJECT_LOWERCASE_NAME}-iface-${MAJOR}.vapi + ${CMAKE_BINARY_DIR}/test/loader_test-iface/loader_test-iface-${MAJOR}.vapi +) +SET (BinLinkLibs ${PROJECT_LOWERCASE_NAME}-loader ${PROJECT_LOWERCASE_NAME}-iface loader_test-iface +) +INCLUDE_DIRECTORIES ("${CMAKE_BINARY_DIR}/src/loader" "${CMAKE_BINARY_DIR}/src/plugin-iface" +"${CMAKE_BINARY_DIR}/test/loader_test-iface") +INCLUDE (ValaBinCommonRules) + +# Plugin Loading Test +MACRO (plugin_loading_test testname regexp) + ADD_TEST (loader_test-${testname} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/loader_test) + SET_TESTS_PROPERTIES (loader_test-${testname} + PROPERTIES PASS_REGULAR_EXPRESSION ${regexp} + FAIL_REGULAR_EXPRESSION "CRITICAL;WARNING") +ENDMACRO (plugin_loading_test) + +# Testing Plugin:[de]init() and Library unload() +plugin_loading_test (SimpleLoaderTest +"Plugin Type Name = TypeA1 +Plugin Type Name = TypeA2 +Plugin Type Name = TypeB1 +Plugin Type Name = TypeB2 +TypeA1 init +TypeA1.method_a \\\\(\\\\) called +TypeA1 deinit +TypeB1 init +TypeB1.method_b \\\\(\\\\) called +TypeB1 returned string +TypeB1 deinit" +) +SET_TESTS_PROPERTIES(loader_test-SimpleLoaderTest PROPERTIES ENVIRONMENT "LANG=en") + +# enable testing +ENABLE_TESTING () diff --git a/test/loader_test/LoaderTest.vala b/test/loader_test/LoaderTest.vala new file mode 100644 index 0000000..8cda1e7 --- /dev/null +++ b/test/loader_test/LoaderTest.vala @@ -0,0 +1,42 @@ +using GObject.Plugins; + +static Gee.ArrayList type_a_modules = null; +static Gee.ArrayList type_b_modules = null; + +int main (string [] args) { + + GObject.Plugins.load_modules ( + Path.build_path (Path.DIR_SEPARATOR_S, File.new_for_path ( + args[0]).get_parent ().get_parent ().get_path (), "test/plugins/typeA"), + ref type_a_modules + ); + + GObject.Plugins.load_modules ( + Path.build_path (Path.DIR_SEPARATOR_S, File.new_for_path ( + args[0]).get_parent ().get_parent ().get_path (), "test/plugins/typeB"), + ref type_b_modules + ); + + // Show Modules List + foreach (var m in type_a_modules) { + stdout.printf ("Plugin Type Name = " + m.get_plugin_type ().name () + "\n"); + } + foreach (var m in type_b_modules) { + stdout.printf ("Plugin Type Name = " + m.get_plugin_type ().name () + "\n"); + } + + // Create a new Plugin Instance by Object.new () method + var a = type_a_modules[0].create_instance () as PluginTypeA; + a.method_a (); + a = null; // free last instance, plugin unload + + // Create a new Plugin Instance by Plugin Type + var b = GLib.Object.new (Type.from_name (type_b_modules[0].get_plugin_type ().name ())) as PluginTypeB; + stdout.puts (b.method_b () + "\n"); + b = null; // free last instance, plugin unload + + GObject.Plugins.unload_modules (type_a_modules); + GObject.Plugins.unload_modules (type_b_modules); + + return 0; +} diff --git a/test/plugins/CMakeLists.txt b/test/plugins/CMakeLists.txt new file mode 100644 index 0000000..85b3f80 --- /dev/null +++ b/test/plugins/CMakeLists.txt @@ -0,0 +1,2 @@ +ADD_SUBDIRECTORY (typeA) +ADD_SUBDIRECTORY (typeB) diff --git a/test/plugins/typeA/CMakeLists.txt b/test/plugins/typeA/CMakeLists.txt new file mode 100644 index 0000000..7db2386 --- /dev/null +++ b/test/plugins/typeA/CMakeLists.txt @@ -0,0 +1,2 @@ +ADD_SUBDIRECTORY (typeA1) +ADD_SUBDIRECTORY (typeA2) diff --git a/test/plugins/typeA/typeA1/CMakeLists.txt b/test/plugins/typeA/typeA1/CMakeLists.txt new file mode 100644 index 0000000..8d93ab9 --- /dev/null +++ b/test/plugins/typeA/typeA1/CMakeLists.txt @@ -0,0 +1,12 @@ +SET (PluginName type_a1) +FILE (GLOB_RECURSE PluginSources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} TypeA1.vala) +SET (PluginCustomVapis + ${CMAKE_BINARY_DIR}/src/plugin-iface/${PROJECT_LOWERCASE_NAME}-iface-${MAJOR}.vapi + ${CMAKE_BINARY_DIR}/test/loader_test-iface/loader_test-iface-${MAJOR}.vapi +) +SET (PluginLinkLibs gobject-plugin-iface loader_test-iface) +INCLUDE_DIRECTORIES ("${CMAKE_BINARY_DIR}/src/plugin-iface") +INCLUDE_DIRECTORIES ("${CMAKE_BINARY_DIR}/test/loader_test-iface") +INCLUDE (ValaPluginCommonRules) + +#INSTALL (TARGETS ${PluginName} DESTINATION lib/${PROJECT_LOWERCASE_NAME}-${MAJOR}/plugins/${PluginName}) diff --git a/test/plugins/typeA/typeA1/TypeA1.vala b/test/plugins/typeA/typeA1/TypeA1.vala new file mode 100644 index 0000000..a625d94 --- /dev/null +++ b/test/plugins/typeA/typeA1/TypeA1.vala @@ -0,0 +1,33 @@ +using GObject.Plugins; + +/** + * Plugin of type A1. + */ +public class TypeA1 : PluginTypeA { + + /** + * Constructs a new ``TypeA1``. + */ + construct { + stdout.puts ("TypeA1 init\n"); + } + + /** + * Destroys the ``TypeA1``. + */ + ~Test () { + stdout.puts ("TypeA1 deinit\n"); + } + + /** + * Any virtual method for PluginTypeA. + */ + public override void method_a () { + stdout.puts ("TypeA1.method_a () called\n"); + } +} + +[ModuleInit] +Type plugin_init (GLib.TypeModule type_module) { + return typeof (TypeA1); +} diff --git a/test/plugins/typeA/typeA2/CMakeLists.txt b/test/plugins/typeA/typeA2/CMakeLists.txt new file mode 100644 index 0000000..11681d0 --- /dev/null +++ b/test/plugins/typeA/typeA2/CMakeLists.txt @@ -0,0 +1,12 @@ +SET (PluginName type_a2) +FILE (GLOB_RECURSE PluginSources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} TypeA2.vala) +SET (PluginCustomVapis + ${CMAKE_BINARY_DIR}/src/plugin-iface/${PROJECT_LOWERCASE_NAME}-iface-${MAJOR}.vapi + ${CMAKE_BINARY_DIR}/test/loader_test-iface/loader_test-iface-${MAJOR}.vapi +) +SET (PluginLinkLibs gobject-plugin-iface loader_test-iface) +INCLUDE_DIRECTORIES ("${CMAKE_BINARY_DIR}/src/plugin-iface") +INCLUDE_DIRECTORIES ("${CMAKE_BINARY_DIR}/test/loader_test-iface") +INCLUDE (ValaPluginCommonRules) + +#INSTALL (TARGETS ${PluginName} DESTINATION lib/${PROJECT_LOWERCASE_NAME}-${MAJOR}/plugins/${PluginName}) diff --git a/test/plugins/typeA/typeA2/TypeA2.vala b/test/plugins/typeA/typeA2/TypeA2.vala new file mode 100644 index 0000000..4f3d335 --- /dev/null +++ b/test/plugins/typeA/typeA2/TypeA2.vala @@ -0,0 +1,33 @@ +using GObject.Plugins; + +/** + * Plugin of type A2. + */ +public class TypeA2 : PluginTypeA { + + /** + * Constructs a new ``TypeA2``. + */ + construct { + stdout.puts ("TypeA2 init\n"); + } + + /** + * Destroys the ``TypeA2``. + */ + ~Test () { + stdout.puts ("TypeA2 deinit\n"); + } + + /** + * Any virtual method for PluginTypeA. + */ + public override void method_a () { + stdout.puts ("TypeA2.method_a () called\n"); + } +} + +[ModuleInit] +Type plugin_init (GLib.TypeModule type_module) { + return typeof (TypeA2); +} diff --git a/test/plugins/typeB/CMakeLists.txt b/test/plugins/typeB/CMakeLists.txt new file mode 100644 index 0000000..d8c45d5 --- /dev/null +++ b/test/plugins/typeB/CMakeLists.txt @@ -0,0 +1,2 @@ +ADD_SUBDIRECTORY (typeB1) +ADD_SUBDIRECTORY (typeB2) diff --git a/test/plugins/typeB/typeB1/CMakeLists.txt b/test/plugins/typeB/typeB1/CMakeLists.txt new file mode 100644 index 0000000..ab7393a --- /dev/null +++ b/test/plugins/typeB/typeB1/CMakeLists.txt @@ -0,0 +1,12 @@ +SET (PluginName type_b1) +FILE (GLOB_RECURSE PluginSources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} TypeB1.vala) +SET (PluginCustomVapis + ${CMAKE_BINARY_DIR}/src/plugin-iface/${PROJECT_LOWERCASE_NAME}-iface-${MAJOR}.vapi + ${CMAKE_BINARY_DIR}/test/loader_test-iface/loader_test-iface-${MAJOR}.vapi +) +SET (PluginLinkLibs gobject-plugin-iface loader_test-iface) +INCLUDE_DIRECTORIES ("${CMAKE_BINARY_DIR}/src/plugin-iface") +INCLUDE_DIRECTORIES ("${CMAKE_BINARY_DIR}/test/loader_test-iface") +INCLUDE (ValaPluginCommonRules) + +#INSTALL (TARGETS ${PluginName} DESTINATION lib/${PROJECT_LOWERCASE_NAME}-${MAJOR}/plugins/${PluginName}) diff --git a/test/plugins/typeB/typeB1/TypeB1.vala b/test/plugins/typeB/typeB1/TypeB1.vala new file mode 100644 index 0000000..e0e488a --- /dev/null +++ b/test/plugins/typeB/typeB1/TypeB1.vala @@ -0,0 +1,34 @@ +using GObject.Plugins; + +/** + * Plugin of type B1. + */ +public class TypeB1 : PluginTypeB { + + /** + * Constructs a new ``TypeB1``. + */ + construct { + stdout.puts ("TypeB1 init\n"); + } + + /** + * Destroys the ``TypeB1``. + */ + ~Test () { + stdout.puts ("TypeB1 deinit\n"); + } + + /** + * Any virtual method for PluginTypeB. + */ + public override string method_b () { + stdout.puts ("TypeB1.method_b () called\n"); + return "TypeB1 returned string"; + } +} + +[ModuleInit] +Type plugin_init (GLib.TypeModule type_module) { + return typeof (TypeB1); +} diff --git a/test/plugins/typeB/typeB2/CMakeLists.txt b/test/plugins/typeB/typeB2/CMakeLists.txt new file mode 100644 index 0000000..2b74e06 --- /dev/null +++ b/test/plugins/typeB/typeB2/CMakeLists.txt @@ -0,0 +1,12 @@ +SET (PluginName type_b2) +FILE (GLOB_RECURSE PluginSources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} TypeB2.vala) +SET (PluginCustomVapis + ${CMAKE_BINARY_DIR}/src/plugin-iface/${PROJECT_LOWERCASE_NAME}-iface-${MAJOR}.vapi + ${CMAKE_BINARY_DIR}/test/loader_test-iface/loader_test-iface-${MAJOR}.vapi +) +SET (PluginLinkLibs gobject-plugin-iface loader_test-iface) +INCLUDE_DIRECTORIES ("${CMAKE_BINARY_DIR}/src/plugin-iface") +INCLUDE_DIRECTORIES ("${CMAKE_BINARY_DIR}/test/loader_test-iface") +INCLUDE (ValaPluginCommonRules) + +#INSTALL (TARGETS ${PluginName} DESTINATION lib/${PROJECT_LOWERCASE_NAME}-${MAJOR}/plugins/${PluginName}) diff --git a/test/plugins/typeB/typeB2/TypeB2.vala b/test/plugins/typeB/typeB2/TypeB2.vala new file mode 100644 index 0000000..9478a1c --- /dev/null +++ b/test/plugins/typeB/typeB2/TypeB2.vala @@ -0,0 +1,34 @@ +using GObject.Plugins; + +/** + * Plugin of type B2. + */ +public class TypeB2 : PluginTypeB { + + /** + * Constructs a new ``TypeB2``. + */ + construct { + stdout.puts ("TypeB2 init\n"); + } + + /** + * Destroys the ``TypeB2``. + */ + ~Test () { + stdout.puts ("TypeB2 deinit\n"); + } + + /** + * Any virtual method for PluginTypeB. + */ + public override string method_b () { + stdout.puts ("TypeB2.method_b () called\n"); + return "TypeB2 returned string"; + } +} + +[ModuleInit] +Type plugin_init (GLib.TypeModule type_module) { + return typeof (TypeB2); +} diff --git a/util/update-po.sh b/util/update-po.sh new file mode 100755 index 0000000..adac908 --- /dev/null +++ b/util/update-po.sh @@ -0,0 +1,50 @@ +#!/bin/sh + +## +# settings +## +PO_DIR_NAME=po +EXE_PATH="`readlink -f $0`" +PRJ_PATH="${EXE_PATH%/*/*}" +C_FILELIST="${PRJ_PATH}/src/*.vala" +UI_FILELIST="${PRJ_PATH}/ui/*.glade" +SOURCE_POT=source.pot +GLADE_POT=glade.pot + +## +# code +## +PROJECT_LOWERCASE_NAME=`grep '\' "$PRJ_PATH"/CMakeLists.txt | sed 's~.*"\(.*\)".*~\1~'` +MAJOR=`grep '\' "$PRJ_PATH"/CMakeLists.txt | sed 's~.*\([0-9]\+\).*~\1~'` +PROJECT_LOWERCASE_NAME_ABI="$PROJECT_LOWERCASE_NAME-$MAJOR" + +xgettext --language=C --escape --package-name=$PROJECT_LOWERCASE_NAME_ABI --default-domain=$PROJECT_LOWERCASE_NAME_ABI --add-comments=/// \ + -k_ -kQ_ -kC_ -kN_ -kNC_ -kg_dgettext -kg_dcgettext \ + -kg_dngettext -kg_dpgettext -kg_dpgettext2 -kg_strip_context -F -n -o \ + $PRJ_PATH/$PO_DIR_NAME/$SOURCE_POT $C_FILELIST + +xgettext --language=C --escape --package-name=$PROJECT_LOWERCASE_NAME_ABI --default-domain=$PROJECT_LOWERCASE_NAME_ABI --add-comments=/// \ + -k_ -kQ_ -kC_ -kN_ -kNC_ -kg_dgettext -kg_dcgettext \ + -kg_dngettext -kg_dpgettext -kg_dpgettext2 -kg_strip_context -F -n -o \ + $PRJ_PATH/$PO_DIR_NAME/$GLADE_POT $C_FILELIST + +msgcat -o $PRJ_PATH/$PO_DIR_NAME/$PROJECT.pot --use-first $PRJ_PATH/$PO_DIR_NAME/$SOURCE_POT $PRJ_PATH/$PO_DIR_NAME/$GLADE_POT + +rm $PRJ_PATH/$PO_DIR_NAME/$SOURCE_POT +rm $PRJ_PATH/$PO_DIR_NAME/$GLADE_POT + +[ 0 != $? ] && echo "xgettext failed ;-(" && exit 1 +[ ! -e $PRJ_PATH/$PO_DIR_NAME/$PROJECT.pot ] && echo "No strings found ;-(" && exit 1 + +for d in $PRJ_PATH/$PO_DIR_NAME/*; do + [ ! -d $d ] && continue + + if [ -e $d/$PROJECT.po ]; then + echo "Merging '${d##*/}' locale" && msgmerge -F -U $d/$PROJECT.po $PRJ_PATH/$PO_DIR_NAME/$PROJECT.pot + [ 0 != $? ] && echo "msgmerge failed ;(" && exit 1 + else + echo "Creating '${d##*/}' locale" && msginit -l ${d##*/} -o $d/$PROJECT.po -i $PRJ_PATH/$PO_DIR_NAME/$PROJECT.pot + [ 0 != $? ] && echo "msginit failed ;(" && exit 1 + fi + +done diff --git a/util/valadoc.sh b/util/valadoc.sh new file mode 100755 index 0000000..911f164 --- /dev/null +++ b/util/valadoc.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +## +# settings +## +BROWSER=firefox + +## +# code +## +EXE_PATH="`readlink -f $0`" +PRJ_PATH="${EXE_PATH%/*/*}" +PROJECT_LOWERCASE_NAME=`grep '\' "$PRJ_PATH"/CMakeLists.txt | sed 's~.*"\(.*\)".*~\1~'` + +OUT_PATH="$PRJ_PATH/doc/html/$PROJECT_LOWERCASE_NAME" +OUT_INTERNAL_PATH="$PRJ_PATH/doc/html/$PROJECT_LOWERCASE_NAME-internals" + +VALA_BASEDIR=`grep -v '\.\.' "$PRJ_PATH"/valadoc_env | grep '^BASEDIR=[-+A-Za-z0-9. ]\+$' | cut -d= -f2` +VALA_PKGS=`grep -v '\.\.' "$PRJ_PATH"/valadoc_env | grep '^PKGS=[-+A-Za-z0-9. ]\+$' | cut -d= -f2 | sed 's~\(^\| \)~ --pkg=~g; s~^ ~~'` + +echo "Generating documentation..." +rm -rf "$OUT_PATH" +echo VALA_BASEDIR=$VALA_BASEDIR +echo VALA_PKGS=$VALA_PKGS +valadoc --no-protected -o "$OUT_PATH" -b "$PRJ_PATH/$VALA_BASEDIR" `find "$PRJ_PATH/$VALA_BASEDIR" -name "*.vapi" -or -name "*.vala"` $VALA_PKGS +$BROWSER "$OUT_PATH"/$PROJECT_LOWERCASE_NAME/index.htm &>/dev/null + +#echo "Generating internal documentation..." +#rm -rf "$OUT_INTERNAL_PATH" +#valadoc -o "$OUT_INTERNAL_PATH" -b "$PRJ_PATH/$VALA_BASEDIR" `find "$PRJ_PATH/$VALA_BASEDIR" -name "*.vapi" -or -name "*.vala"` $VALA_PKGS --internal + +#$BROWSER "$OUT_INTERNAL_PATH"/$PROJECT_LOWERCASE_NAME-internals/index.htm &>/dev/null diff --git a/valadoc_env b/valadoc_env new file mode 100644 index 0000000..8ec487c --- /dev/null +++ b/valadoc_env @@ -0,0 +1,2 @@ +BASEDIR=src +PKGS=gee-0.8 gmodule-2.0 gio-2.0