Dynamic loadable backends: repackage libsyncevolution to enable dynamic loadable backends

Install head files to a standard path, the remaining dependencies are
synthesis and boost
client-test is portable when ENABLE_MODULES is defined, no longer link to
backends libraries.

Add --enable-developer-mode, in which mode the backend scan path will be
under current build directory for development purposes.
This commit is contained in:
Chen Congwu 2009-09-02 11:13:10 +08:00 committed by Patrick Ohly
parent 0579e1d0d2
commit 35ee636619
37 changed files with 445 additions and 362 deletions

View File

@ -29,11 +29,16 @@ For doing development work the recommended configure line is:
configure CFLAGS="-g -Wall -Werror -Wno-unknown-pragmas" \
CXXFLAGS="-g -Wall -Werror -Wno-unknown-pragmas" \
--enable-unit-tests \
--enable-libcurl
--enable-libcurl \
--enable-developer-mode
Enabling libcurl explicitly ensures that it gets built even when not
the default.
Backend libraries are dynamically scannned and loaded into syncevolution, the
library path defaults to $prefix/syncevolution/backends. When developer-mode is
enabled, it will scan libraries in current build directory instead.
-Wno-unknown-pragmas is required to avoid warnings triggered by
'#pragma }', a trick to preserve indention after 'extern "C" {' in
/usr/include/evolution-data-server-1.12/libical/

View File

@ -70,6 +70,17 @@ if test "$enable_evolution_compatibility" == "yes"; then
AC_DEFINE(EVOLUTION_COMPATIBILITY, 1, [avoid hard dependency on Evolution shared objects])
fi
dnl --enable-developer-mode
if test "$enable_developer_mode" == "yes"; then
backendsearchdir=backends/
else
backendsearchdir='$(libdir)'/syncevolution/backends/
fi
backenddir='$(libdir)'/syncevolution/backends/
AC_SUBST(backenddir)
AC_SUBST(backendsearchdir)
dnl This string is sent as part of the SyncML DevInf (device
dnl information) structure to the server. All SyncEvolution platforms
dnl use "SyncEvolution" as HTTP user agent and "Mod" (model), so the
@ -81,7 +92,7 @@ AC_CHECK_HEADERS(stdarg.h valgrind/valgrind.h execinfo.h)
AC_DEFINE(SYNTHESIS, 1, "using Synthesis engine")
AC_CONFIG_FILES(Makefile src/dbus/interfaces/Makefile src/dbus/Makefile src/Makefile src/core/Makefile src/gtk-ui/Makefile po/Makefile.in test/Makefile src/dbus/syncevo-dbus.pc)
AC_CONFIG_FILES(Makefile src/dbus/interfaces/Makefile src/dbus/Makefile src/Makefile src/syncevo/Makefile src/syncevo/syncevolution.pc src/gtk-ui/Makefile po/Makefile.in test/Makefile src/dbus/syncevo-dbus.pc)
AC_OUTPUT
echo

View File

@ -69,6 +69,11 @@ AC_ARG_ENABLE(evolution-compatibility,
[build executables which only call Evolution via dlopen/dlsym: this avoids all hard dependencies on EDS shared objects, but might lead to crashes when their ABI changes]),
enable_evolution_compatibility="$enableval", enable_evolution_compatibility="no")
AC_ARG_ENABLE(developer-mode,
AC_HELP_STRING([--enable-developer-mode],
[The dynamic loadble backend libraries is loaded from current build directory instead of the standard library path]),
enable_developer_mode="$enableval", enable_developer_mode="no")
# Maemo hacks:
# - set the (non-standard!) DBUS_DEFAULT_TIMEOUT
# - wrap e_book_from_string() to fix invalid parameter

View File

@ -19,8 +19,8 @@ if COND_GUI
GUI_DIR = gtk-ui
endif
SUBDIRS = $(SYNTHESIS_SUBDIR) $(DBUS_DIR) core $(BACKENDS) $(GUI_DIR)
DIST_SUBDIRS = dbus core $(BACKENDS) gtk-ui
SUBDIRS = $(SYNTHESIS_SUBDIR) $(DBUS_DIR) syncevo $(BACKENDS) $(GUI_DIR)
DIST_SUBDIRS = dbus syncevo $(BACKENDS) gtk-ui
BUILT_SOURCES =
AM_CPPFLAGS = $(SUBDIRS:%=-I$(srcdir)/%) -I$(srcdir)/../test -I$(top_srcdir) $(BACKEND_CPPFLAGS) $(GLIB_CFLAGS)
@ -74,8 +74,8 @@ CORE_SOURCES += $(BACKEND_REGISTRIES)
endif
CORE_CXXFLAGS = $(SYNTHESIS_CFLAGS)
CORE_LDADD = $(SYNCEVOLUTION_LDADD) core/libsyncevolution.la $(GLIB_LIBS) $(LIBS)
CORE_DEP = $(SYNCEVOLUTION_DEP) core/libsyncevolution.la $(SYNTHESIS_DEP)
CORE_LDADD = $(SYNCEVOLUTION_LDADD) syncevo/libsyncevolution.la $(GLIB_LIBS) $(LIBS)
CORE_DEP = $(SYNCEVOLUTION_DEP) syncevo/libsyncevolution.la $(SYNTHESIS_DEP)
CORE_LD_FLAGS = -uSyncEvolution_Module_Version -Wl,--export-dynamic
# put link to static c++ library into current directory, needed if compiling with --enable-static-c++
@ -171,9 +171,11 @@ nodist_client_test_SOURCES = ../test/test.cpp
# ENABLE_INTEGRATION_TESTS. This works without undefined references
# because client-test is linked against all shared backend libraries
# (non-portable, but works).
if ENABLE_MODULES
client_test_SOURCES += $(BACKEND_REGISTRIES)
endif
# Disabled now, the client test can also be dynamically loaded and registered
# just the same as syncevolution
# if ENABLE_MODULES
# client_test_SOURCES += $(BACKEND_REGISTRIES)
# endif
# list of test file base files
#
@ -198,8 +200,8 @@ CLIENT_LIB_TEST_FILES += $(TEST_FILES_GENERATED)
client_test_CPPFLAGS = -DHAVE_CONFIG_H -DENABLE_INTEGRATION_TESTS -DENABLE_UNIT_TESTS $(AM_CPPFLAGS)
client_test_CXXFLAGS = `cppunit-config --cflags` $(SYNCEVOLUTION_CXXFLAGS) $(CORE_CXXFLAGS)
client_test_LDFLAGS = `cppunit-config --libs` `nm core/.libs/libsyncevolution.a | grep funambolAutoRegisterRegistry | sed -e 's/.* /-u /'` $(CORE_LD_FLAGS)
client_test_LDADD = $(CORE_LDADD) $(SYNCSOURCES)
client_test_LDFLAGS = `cppunit-config --libs` `nm synccevo/.libs/libsyncevolution.a | grep funambolAutoRegisterRegistry | sed -e 's/.* /-u /'` $(CORE_LD_FLAGS)
client_test_LDADD = $(CORE_LDADD)
# These dependencies are intentionally a bit too broad:
# they ensure that all files are in place to *run* client-test.

View File

@ -109,10 +109,10 @@ enum {
# define PersonCreateWrapper(_addressbook) ABPersonCreate()
# define PersonSetImageDataWrapper(_person, _dataref) ABPersonSetImageData(_person, _dataref)
#endif
#include "EvolutionSyncClient.h"
#include <syncevo/EvolutionSyncClient.h>
#include "AddressBookSource.h"
#include "Logging.h"
#include <syncevo/Logging.h>
#include <common/base/util/StringBuffer.h>
#include "vocl/VConverter.h"

View File

@ -21,7 +21,7 @@
#define INCL_ADDRESSBOOKSOURCE
#include <config.h>
#include "TrackingSyncSource.h"
#include <syncevo/TrackingSyncSource.h>
#ifdef ENABLE_ADDRESSBOOK

View File

@ -1,11 +1,11 @@
AM_CPPFLAGS = -I$(srcdir)/../../core -I$(top_srcdir)/test $(BACKEND_CPPFLAGS)
AM_CPPFLAGS = -I$(srcdir)/../../ -I$(top_srcdir)/test $(BACKEND_CPPFLAGS)
EXTRA_DIST = configure-sub.in
SYNCSOURCES = syncaddressbook.la
MOSTLYCLEANFILES = $(SYNCSOURCES)
if ENABLE_MODULES
pkglib_LTLIBRARIES = $(SYNCSOURCES)
backend_LTLIBRARIES = $(SYNCSOURCES)
else
noinst_LTLIBRARIES = $(SYNCSOURCES)
endif
@ -19,5 +19,5 @@ SYNCADDRESSBOOK_SOURCES = \
syncaddressbook_la_SOURCES = $(SYNCADDRESSBOOK_SOURCES)
syncaddressbook_la_LIBADD = $(ADDRESSBOOK_LIBS)
syncaddressbook_la_LDFLAGS = -module -rpath '$(pkglibdir)'
syncaddressbook_la_LDFLAGS = -module -avoid-version
syncaddressbook_la_CXXFLAGS = $(SYNCEVOLUTION_CXXFLAGS)

View File

@ -28,13 +28,14 @@ using namespace std;
// include first, it sets HANDLE_LIBICAL_MEMORY for us
#include "libical/icalstrdup.h"
#include "EvolutionSyncClient.h"
#include <syncevo/EvolutionSyncClient.h>
#include <syncevo/EvolutionSmartPtr.h>
#include <syncevo/Logging.h>
#include "EvolutionCalendarSource.h"
#include "EvolutionMemoSource.h"
#include "EvolutionSmartPtr.h"
#include "e-cal-check-timezones.h"
#include "Logging.h"
#include <boost/foreach.hpp>

View File

@ -23,7 +23,7 @@
#include <config.h>
#include "EvolutionSyncSource.h"
#include "EvolutionSmartPtr.h"
#include <syncevo/EvolutionSmartPtr.h>
#include <boost/noncopyable.hpp>

View File

@ -29,11 +29,11 @@ using namespace std;
#ifdef ENABLE_EBOOK
#include "EvolutionSyncClient.h"
#include <syncevo/EvolutionSyncClient.h>
#include "EvolutionContactSource.h"
#include "SyncEvolutionUtil.h"
#include <syncevo/SyncEvolutionUtil.h>
#include "Logging.h"
#include <syncevo/Logging.h>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/join.hpp>

View File

@ -23,7 +23,7 @@
#include <config.h>
#include "EvolutionSyncSource.h"
#include "EvolutionSmartPtr.h"
#include <syncevo/EvolutionSmartPtr.h>
#include <boost/noncopyable.hpp>

View File

@ -26,9 +26,8 @@ using namespace std;
#ifdef ENABLE_ECAL
#include "EvolutionMemoSource.h"
#include "EvolutionSmartPtr.h"
#include "Logging.h"
#include <syncevo/Logging.h>
void EvolutionMemoSource::readItem(const string &luid, std::string &item, bool raw)
{

View File

@ -21,7 +21,7 @@
#define INCL_EVOLUTIONMEMOSOURCE
#include <config.h>
#include "EvolutionCalendarSource.h"
#include <EvolutionCalendarSource.h>
#ifdef ENABLE_ECAL

View File

@ -21,8 +21,8 @@
#ifndef INCL_EVOLUTIONSYNCSOURCE
#define INCL_EVOLUTIONSYNCSOURCE
#include "TrackingSyncSource.h"
#include "eds_abi_wrapper.h"
#include <syncevo/TrackingSyncSource.h>
#include <syncevo/eds_abi_wrapper.h>
using namespace SyncEvolution;

View File

@ -1,11 +1,11 @@
AM_CPPFLAGS = -I$(srcdir)/../../core -I$(top_srcdir)/test $(BACKEND_CPPFLAGS)
AM_CPPFLAGS = -I$(srcdir)/../../ -I$(top_srcdir)/test $(BACKEND_CPPFLAGS)
EXTRA_DIST = configure-sub.in
SYNCSOURCES = syncecal.la syncebook.la
MOSTLYCLEANFILES = $(SYNCSOURCES)
if ENABLE_MODULES
pkglib_LTLIBRARIES = $(SYNCSOURCES)
backend_LTLIBRARIES = $(SYNCSOURCES)
else
noinst_LTLIBRARIES = $(SYNCSOURCES)
endif
@ -35,18 +35,19 @@ SYNCEBOOK_SOURCES = \
EvolutionContactSource.cpp
syncecal_la_SOURCES = $(SYNCECAL_SOURCES)
syncecal_la_LIBADD = @ECAL_LIBS@ ../../core/libsyncevolution.la
syncecal_la_LIBADD = @ECAL_LIBS@ ../../syncevo/libsyncevolution.la
# _GNU_SOURCE and -ldl for libical.c + dlsym():
syncecal_la_CPPFLAGS = -D_GNU_SOURCE \
-De_cal_check_timezones=syncevolution_check_timezones \
-De_cal_tzlookup_ecal=syncevolution_tzlookup_ecal \
-De_cal_tzlookup_icomp=syncevolution_tzlookup_icomp \
-De_cal_match_tzid=syncevolution_match_tzid \
-DENABLE_INTEGRATION_TESTS \
$(AM_CPPFLAGS)
syncecal_la_LDFLAGS = -module -rpath '$(pkglibdir)' -ldl
syncecal_la_LDFLAGS = -module -avoid-version -ldl
syncecal_la_CXXFLAGS = $(SYNCEVOLUTION_CXXFLAGS)
syncebook_la_SOURCES = $(SYNCEBOOK_SOURCES)
syncebook_la_LIBADD = $(EBOOK_LIBS) ../../core/libsyncevolution.la
syncebook_la_LDFLAGS = -module -rpath '$(pkglibdir)'
syncebook_la_CXXFLAGS = $(SYNCEVOLUTION_CXXFLAGS)
syncebook_la_LIBADD = $(EBOOK_LIBS) ../../syncevo/libsyncevolution.la
syncebook_la_LDFLAGS = -module -avoid-version
syncebook_la_CXXFLAGS = $(SYNCEVOLUTION_CXXFLAGS) -DENABLE_INTEGRATION_TESTS

View File

@ -22,7 +22,7 @@
#ifndef E_CAL_CHECK_TIMEZONES_H
#define E_CAL_CHECK_TIMEZONES_H
#include "eds_abi_wrapper.h"
#include <syncevo/eds_abi_wrapper.h>
/* #include <libical/ical.h> */
#include <glib.h>

View File

@ -37,7 +37,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <SyncEvolutionUtil.h>
#include <syncevo/SyncEvolutionUtil.h>
#include <sstream>
#include <fstream>

View File

@ -20,7 +20,7 @@
#ifndef INCL_FILESYNCSOURCE
#define INCL_FILESYNCSOURCE
#include "TrackingSyncSource.h"
#include <syncevo/TrackingSyncSource.h>
#ifdef ENABLE_FILE

View File

@ -1,11 +1,11 @@
AM_CPPFLAGS = -I$(srcdir)/../../core -I$(top_srcdir)/test $(BACKEND_CPPFLAGS)
AM_CPPFLAGS = -I$(srcdir)/../../ -I$(top_srcdir)/test $(BACKEND_CPPFLAGS)
EXTRA_DIST = configure-sub.in
SYNCSOURCES = syncfile.la
MOSTLYCLEANFILES = $(SYNCSOURCES)
if ENABLE_MODULES
pkglib_LTLIBRARIES = $(SYNCSOURCES)
backend_LTLIBRARIES = $(SYNCSOURCES)
else
noinst_LTLIBRARIES = $(SYNCSOURCES)
endif
@ -18,9 +18,8 @@ SYNCFILE_SOURCES = \
syncfile_la_SOURCES = $(SYNCFILE_SOURCES)
syncfile_la_LIBADD = $(FILE_LIBS)
syncfile_la_LDFLAGS = -module -rpath '$(pkglibdir)'
syncfile_la_CXXFLAGS = $(SYNCEVOLUTION_CXXFLAGS)
syncfile_la_LDFLAGS = -module -avoid-version
syncfile_la_CXXFLAGS = $(SYNCEVOLUTION_CXXFLAGS) -DENABLE_INTEGRATION_TESTS
# If you need special test cases for your sync source, then
# install them here. Here's how the sqlite backend does that:
#

View File

@ -1,11 +1,11 @@
AM_CPPFLAGS = -I$(srcdir)/../../core -I$(top_srcdir)/test $(BACKEND_CPPFLAGS)
AM_CPPFLAGS = -I$(srcdir)/../../ -I$(top_srcdir)/test $(BACKEND_CPPFLAGS)
EXTRA_DIST = configure-sub.in
SYNCSOURCES = syncsqlite.la
MOSTLYCLEANFILES = $(SYNCSOURCES)
if ENABLE_MODULES
pkglib_LTLIBRARIES = $(SYNCSOURCES)
backend_LTLIBRARIES = $(SYNCSOURCES)
else
noinst_LTLIBRARIES = $(SYNCSOURCES)
endif
@ -20,7 +20,7 @@ SYNCSQLITE_SOURCES = \
syncsqlite_la_SOURCES = $(SYNCSQLITE_SOURCES)
syncsqlite_la_LIBADD = $(SQLITE_LIBS)
syncsqlite_la_LDFLAGS = -module -rpath '$(pkglibdir)'
syncsqlite_la_LDFLAGS = -module -avoid-version
syncsqlite_la_CXXFLAGS = $(SYNCEVOLUTION_CXXFLAGS)
# SQLiteContactSource does not support all fields from Funambol vCard 2.1

View File

@ -19,13 +19,13 @@
*/
#include "config.h"
#include "SyncSource.h"
#include <syncevo/SyncSource.h>
#ifdef ENABLE_SQLITE
#include "SQLiteContactSource.h"
#include "Logging.h"
#include <syncevo/Logging.h>
#include "vocl/VConverter.h"
#include <algorithm>

View File

@ -20,7 +20,7 @@
#ifndef INCL_SQLITECONTACTSOURCE
#define INCL_SQLITECONTACTSOURCE
#include "TrackingSyncSource.h"
#include <syncevo/TrackingSyncSource.h>
#include "SQLiteUtil.h"
#ifdef ENABLE_SQLITE

View File

@ -21,7 +21,9 @@
#ifndef INCL_EVOLUTION_SMART_POINTER
# define INCL_EVOLUTION_SMART_POINTER
#include <config.h>
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "eds_abi_wrapper.h"
#ifdef HAVE_GLIB

View File

@ -1520,6 +1520,7 @@ SyncMLStatus EvolutionSyncClient::sync(SyncReport *report)
SE_LOG_DEV(NULL, NULL, "client: SyncEvolution %s for %s", getSwv(), getDevType());
SE_LOG_DEV(NULL, NULL, "device ID: %s", getDevID());
SE_LOG_DEV(NULL, NULL, "%s", EDSAbiWrapperDebug());
SE_LOG_DEV(NULL, NULL, "%s", SyncSourceBackendsDebug());
// instantiate backends, but do not open them yet
initSources(sourceList);

View File

@ -21,12 +21,10 @@
#ifndef INCL_EVOLUTIONSYNCCLIENT
#define INCL_EVOLUTIONSYNCCLIENT
#include <config.h>
#include "EvolutionSmartPtr.h"
#include "SyncEvolutionConfig.h"
#include "SyncML.h"
#include "SynthesisEngine.h"
#include <syncevo/EvolutionSmartPtr.h>
#include <syncevo/SyncEvolutionConfig.h>
#include <syncevo/SyncML.h>
#include <syncevo/SynthesisEngine.h>
#include <string>
#include <set>

View File

@ -20,12 +20,12 @@
#ifndef INCL_EVOLUTION_FILTER_CONFIG_NODE
# define INCL_EVOLUTION_FILTER_CONFIG_NODE
#include <ConfigNode.h>
#include <syncevo/ConfigNode.h>
#include <boost/shared_ptr.hpp>
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/algorithm/string.hpp>
#include "SyncEvolutionUtil.h"
#include <syncevo/SyncEvolutionUtil.h>
#include <map>
#include <utility>

View File

@ -1,4 +1,4 @@
AM_CPPFLAGS = @BACKEND_CPPFLAGS@ @GLIB_CFLAGS@ -I$(top_srcdir)/test
AM_CPPFLAGS = @BACKEND_CPPFLAGS@ @GLIB_CFLAGS@ -I$(top_srcdir)/test -I$(top_srcdir)/src -DSYNCEVO_BACKEND=\"$(backendsearchdir)\"
# applies to sources in SyncEvolution repository, but not
# the Funambol C++ client library
@ -18,7 +18,7 @@ else
noinst_LTLIBRARIES = libsyncevolution.la
endif
CORE_SOURCES = \
SYNCEVOLUTION_SOURCES = \
ConfigTree.h \
ConfigNode.h \
HashConfigNode.h \
@ -84,9 +84,27 @@ CORE_SOURCES = \
TrackingSyncSource.h \
TrackingSyncSource.cpp
libsyncevolution_includedir= $(includedir)/syncevo
libsyncevolution_include_HEADERS= TrackingSyncSource.h \
FilterConfigNode.h \
SyncEvolutionConfig.h \
SyncSource.h \
SyncEvolutionUtil.h \
EvolutionSyncClient.h \
SynthesisEngine.h \
Logging.h \
SyncML.h \
eds_abi_wrapper.h \
EvolutionSmartPtr.h \
ConfigNode.h
libsyncevolution_la_SOURCES = $(CORE_SOURCES)
libsyncevolution_la_LIBADD = @EPACKAGE_LIBS@ @GLIB_LIBS@ $(TRANSPORT_LIBS) @LIBS@ $(SYNTHESIS_LIBS) $(SYNCEVOLUTION_LDADD)
pkgconfigdir=$(libdir)/pkgconfig
pkgconfig_DATA=syncevolution.pc
DISTCLEANFILES =syncevolution.pc
EXTRA_DIST =syncevolution.pc.in
libsyncevolution_la_SOURCES = $(SYNCEVOLUTION_SOURCES)
libsyncevolution_la_LIBADD = @EPACKAGE_LIBS@ @GLIB_LIBS@ $(SYNTHESIS_LIBS) $(TRANSPORT_LIBS) @LIBS@ $(SYNCEVOLUTION_LDADD)
libsyncevolution_la_CXXFLAGS = $(TRANSPORT_CFLAGS) $(SYNCEVOLUTION_CXXFLAGS) $(SYNTHESIS_CFLAGS)
libsyncevolution_la_CPPFLAGS = $(AM_CPPFLAGS) -DTEMPLATE_DIR=\""$(sysconfdir)/default/syncevolution"\" -DLIBDIR=\""$(libdir)"\"

View File

@ -179,6 +179,7 @@ bool SyncEvolutionCmdline::run() {
} else if (m_version) {
printf("SyncEvolution %s\n", VERSION);
printf("%s", EDSAbiWrapperInfo());
printf("%s", SyncSourceBackendsInfo());
} else if (m_printServers || boost::trim_copy(m_server) == "?") {
dumpServers("Configured servers:",
EvolutionSyncConfig::getServers());

View File

@ -20,7 +20,7 @@
#ifndef INCL_SYNC_EVOLUTION_CONFIG
# define INCL_SYNC_EVOLUTION_CONFIG
#include "FilterConfigNode.h"
#include <syncevo/FilterConfigNode.h>
#include <boost/shared_ptr.hpp>
#include <boost/algorithm/string/predicate.hpp>

View File

@ -21,7 +21,7 @@
#ifndef INCL_SYNCEVOLUTION_UTIL
# define INCL_SYNCEVOLUTION_UTIL
#include "SyncML.h"
#include <syncevo/SyncML.h>
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/algorithm/string/predicate.hpp>

View File

@ -22,6 +22,8 @@
# define _GNU_SOURCE 1
#endif
#include <dlfcn.h>
#include <sys/types.h>
#include <dirent.h>
#include "SyncSource.h"
#include "EvolutionSyncClient.h"
@ -38,6 +40,7 @@
#include <errno.h>
#include <fstream>
#include <iostream>
void SyncSourceBase::throwError(const string &action, int error)
{
@ -232,40 +235,72 @@ static class ScannedModules {
public:
ScannedModules() {
#ifdef ENABLE_MODULES
list<string> *state;
// possible extension: scan directories for matching module names instead of hard-coding known names
const char *modules[] = {
"syncebook.so.0",
"syncecal.so.0",
"syncsqlite.so.0",
"syncfile.so.0",
"addressbook.so.0",
NULL
};
for (int i = 0; modules[i]; i++) {
void *dlhandle;
// Open the shared object so that backend can register
// itself. We keep that pointer, so never close the
// module!
dlhandle = dlopen(modules[i], RTLD_NOW|RTLD_GLOBAL);
if (!dlhandle) {
string fullpath = LIBDIR "/syncevolution/";
fullpath += modules[i];
dlhandle = dlopen(fullpath.c_str(), RTLD_NOW|RTLD_GLOBAL);
}
// remember which modules were found and which were not
state = dlhandle ? &m_available : &m_missing;
state->push_back(modules[i]);
DIR *dir = opendir (SYNCEVO_BACKEND);
if(!dir) {
info<<"Backend directory open failed"<<endl;
return;
}
struct dirent *entry;
list<pair <string,DIR *> > dirs;
DIR *subdir = NULL;
string dirpath (SYNCEVO_BACKEND);
// possible extension: scan directories for matching module names instead of hard-coding known names
do {
info<<"Scanning backend libraries in " <<dirpath <<endl;
while ((entry = readdir(dir))!=NULL){
void *dlhandle;
if (!strcmp (entry->d_name, ".") || !strcmp(entry->d_name, "..")){
continue;
} else if (entry->d_type == DT_DIR) {
/* This is a 2-level dir, this corresponds to loading
* backends from current building directory. The library
* should reside in .libs sub directory.*/
string path = dirpath + entry->d_name +"/.libs/";
subdir = opendir (path.c_str());
if (subdir) {
dirs.push_back (make_pair(path, subdir));
}
continue;
}
char *p = strrchr(entry->d_name, 's');
if (p && *(p+1)=='o' && *(p+2)=='\0'){
// Open the shared object so that backend can register
// itself. We keep that pointer, so never close the
// module!
string fullpath = dirpath + entry->d_name;
dlhandle = dlopen(fullpath.c_str(), RTLD_NOW|RTLD_GLOBAL);
// remember which modules were found and which were not
if (dlhandle) {
debug<<"Loading backend library "<<entry->d_name<<endl;
m_available.push_back(entry->d_name);
} else {
debug<<"Loading backend library "<<entry->d_name<<"failed "<< dlerror()<<endl;
}
}
}
closedir (dir);
if (!dirs.empty()){
dirpath = dirs.front().first;
dir = dirs.front().second;
dirs.pop_front();
} else {
break;
}
} while (true);
#endif
}
list<string> m_available;
list<string> m_missing;
std::ostringstream debug, info;
} scannedModules;
const char* SyncSourceBackendsInfo() {
return scannedModules.info.str().c_str();
}
const char* SyncSourceBackendsDebug() {
return scannedModules.debug.str().c_str();
}
SyncSource *SyncSource::createSource(const SyncSourceParams &params, bool error)
{
@ -291,10 +326,6 @@ SyncSource *SyncSource::createSource(const SyncSourceParams &params, bool error)
problem += boost::join(scannedModules.m_available, ", ");
problem += ")";
}
if (scannedModules.m_missing.size()) {
problem += ". The following backend(s) were not found: ";
problem += boost::join(scannedModules.m_missing, ", ");
}
EvolutionSyncClient::throwError(problem);
}

View File

@ -21,10 +21,9 @@
#ifndef INCL_SYNCSOURCE
#define INCL_SYNCSOURCE
#include "config.h"
#include "SyncEvolutionConfig.h"
#include "Logging.h"
#include "SyncML.h"
#include <syncevo/SyncEvolutionConfig.h>
#include <syncevo/Logging.h>
#include <syncevo/SyncML.h>
using namespace SyncEvolution;
#include <synthesis/sync_declarations.h>
@ -156,21 +155,254 @@ class RegisterSyncSource
};
typedef list<const RegisterSyncSource *> SourceRegistry;
#ifdef ENABLE_INTEGRATION_TESTS
#include <ClientTest.h>
typedef ClientTest::Config ClientTestConfig;
#else
/**
* this class doesn't exist and cannot be referenced in code which is
* compiled without ENABLE_INTEGRATION_TEST, but we only need to
* declare a reference to it, so that's okay
*/
class ClientTestConfig;
class ClientTest;
class TestingSyncSource;
/**
* Information about a data source. For the sake of simplicity all
* items pointed to are owned by the ClientTest and must
* remain valid throughout a test session. Not setting a pointer
* is okay, but it will disable all tests that need the
* information.
*/
struct ClientTestConfig{
/**
* The name is used in test names and has to be set.
*/
const char *sourceName;
/**
* A default URI to be used when creating a client config.
*/
const char *uri;
/**
* A corresponding source name in the default server template,
* this is used to copy corresponding uri set in the server template
* instead of the uri field above (which is the same for all servers).
*/
const char *sourceNameServerTemplate;
/**
* A member function of a subclass which is called to create a
* sync source referencing the data. This is used in tests of
* the SyncSource API itself as well as in tests which need to
* modify or check the data sources used during synchronization.
*
* The test framework will call beginSync() and then some of
* the functions it wants to test. After a successful test it
* will call endSync() which is then expected to store all
* changes persistently. Creating a sync source again
* with the same call should not report any
* new/updated/deleted items until such changes are made via
* another sync source.
*
* The instance will be deleted by the caller. Because this
* may be in the error case or in an exception handler,
* the sync source's desctructor should not thow exceptions.
*
* @param client the same instance to which this config belongs
* @param source index of the data source (from 0 to ClientTest::getNumSources() - 1)
* @param isSourceA true if the requested SyncSource is the first one accessing that
* data, otherwise the second
*/
typedef TestingSyncSource *(*createsource_t)(ClientTest &client, int source, bool isSourceA);
/**
* Creates a sync source which references the primary database;
* it may report the same changes as the sync source used during
* sync tests.
*/
createsource_t createSourceA;
/**
* A second sync source also referencing the primary data
* source, but configured so that it tracks changes
* independently from the the primary sync source.
*
* In local tests the usage is like this:
* - add item via first SyncSource
* - iterate over new items in second SyncSource
* - check that it lists the added item
*
* In tests with a server the usage is:
* - do a synchronization with the server
* - iterate over items in second SyncSource
* - check that the total number and number of
* added/updated/deleted items is as expected
*/
createsource_t createSourceB;
/**
* The framework can generate vCard and vCalendar/iCalendar items
* automatically by copying a template item and modifying certain
* properties.
*
* This is the template for these automatically generated items.
* It must contain the string <<REVISION>> which will be replaced
* with the revision parameter of the createItem() method.
*/
const char *templateItem;
/**
* This is a colon (:) separated list of properties which need
* to be modified in templateItem.
*/
const char *uniqueProperties;
/**
* the number of items to create during stress tests
*/
int numItems;
/**
* This is a single property in templateItem which can be extended
* to increase the size of generated items.
*/
const char *sizeProperty;
/**
* Type to be set when importing any of the items into the
* corresponding sync sources. Use "" if sync source doesn't
* need this information.
*
* Not currently used! All items are assumed to be in the raw,
* internal format (see SyncSourceRaw and SyncSourceSerialize).
*/
const char *itemType;
/**
* A very simple item that is inserted during basic tests. Ideally
* it only contains properties supported by all servers.
*/
const char *insertItem;
/**
* A slightly modified version of insertItem. If the source has UIDs
* embedded into the item data, then both must have the same UID.
* Again all servers should better support these modified properties.
*/
const char *updateItem;
/**
* A more heavily modified version of insertItem. Same UID if necessary,
* but can test changes to items only supported by more advanced
* servers.
*/
const char *complexUpdateItem;
/**
* To test merge conflicts two different updates of insertItem are
* needed. This is the first such update.
*/
const char *mergeItem1;
/**
* The second merge update item. To avoid true conflicts it should
* update different properties than mergeItem1, but even then servers
* usually have problems perfectly merging items. Therefore the
* test is run without expecting a certain merge result.
*/
const char *mergeItem2;
/**
* These two items are related: one is main one, the other is
* a subordinate one. The semantic is that the main item is
* complete on it its own, while the other normally should only
* be used in combination with the main one.
*
* Because SyncML cannot express such dependencies between items,
* a SyncSource has to be able to insert, updated and remove
* both items independently. However, operations which violate
* the semantic of the related items (like deleting the parent, but
* not the child) may have unspecified results (like also deleting
* the child). See LINKED_ITEMS_RELAXED_SEMANTIC.
*
* One example for main and subordinate items are a recurring
* iCalendar 2.0 event and a detached recurrence.
*/
const char *parentItem, *childItem;
/**
* Backends atomic modification tests
*/
bool atomicModification;
/**
* define to 0 to disable tests which slightly violate the
* semantic of linked items by inserting children
* before/without their parent
*/
#ifndef LINKED_ITEMS_RELAXED_SEMANTIC
# define LINKED_ITEMS_RELAXED_SEMANTIC 1
#endif
/**
* setting this to false disables tests which depend
* on the source's support for linked item semantic
* (testLinkedItemsInsertParentTwice, testLinkedItemsInsertChildTwice)
*/
bool sourceKnowsItemSemantic;
/**
* called to dump all items into a file, required by tests which need
* to compare items
*
* ClientTest::dump can be used: it will simply dump all items of the source
* with a blank line as separator.
*
* @param source sync source A already created and with beginSync() called
* @param file a file name
* @return error code, 0 for success
*/
int (*dump)(ClientTest &client, TestingSyncSource &source, const char *file);
/**
* import test items: which these are is determined entirely by
* the implementor, but tests work best if several complex items are
* imported
*
* ClientTest::import can be used if the file contains items separated by
* empty lines.
*
* @param source sync source A already created and with beginSync() called
* @param file the name of the file to import
* @retval realfile the name of the file that was really imported;
* this may depend on the current server that is being tested
* @return error code, 0 for success
*/
int (*import)(ClientTest &client, TestingSyncSource &source, const char *file, std::string &realfile);
/**
* a function which compares two files with items in the format used by "dump"
*
* @param fileA first file name
* @param fileB second file name
* @return true if the content of the files is considered equal
*/
bool (*compare)(ClientTest &client, const char *fileA, const char *fileB);
/**
* a file with test cases in the format expected by import and compare
*/
const char *testcases;
/**
* the item type normally used by the source (not used by the tests
* themselves; client-test.cpp uses it to initialize source configs)
*/
const char *type;
/**
* TRUE if the source supports recovery from an interrupted
* synchronization. Enables the Client::Sync::*::Retry group
* of tests.
*/
bool retrySync;
bool suspendSync;
bool resendSync;
};
/**
* In addition to registering the sync source itself by creating an
* instance of RegisterSyncSource, configurations for testing it can
@ -1194,4 +1426,9 @@ class TestingSyncSource : public SyncSource,
}
};
//global function to convey the information for dynamic loaded modules
//cannot log at the load time because the logger may still have not been
//initialized.
const char* SyncSourceBackendsInfo();
const char* SyncSourceBackendsDebug();
#endif // INCL_SYNCSOURCE

View File

@ -21,9 +21,7 @@
#ifndef INCL_SYNTHESISENGINE
#define INCL_SYNTHESISENGINE
#include <config.h>
#include <Logging.h>
#include <syncevo/Logging.h>
#include <synthesis/generic_types.h>
#include <synthesis/sync_declarations.h>

View File

@ -21,8 +21,8 @@
#ifndef INCL_TRACKINGSYNCSOURCE
#define INCL_TRACKINGSYNCSOURCE
#include "SyncSource.h"
#include "ConfigNode.h"
#include <syncevo/SyncSource.h>
#include <syncevo/ConfigNode.h>
#include <boost/shared_ptr.hpp>
#include <string>

View File

@ -39,7 +39,9 @@
#ifndef INCL_EDS_ABI_WRAPPER
#define INCL_EDS_ABI_WRAPPER
#include "config.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_EDS
#include <glib-object.h>

View File

@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libsyncevolution
Description: SyncEvolution Library
Version: @VERSION@
Cflags: -I${includedir}
Requires: synthesis
Libs: -L${libdir} -lsyncevolution

View File

@ -36,6 +36,7 @@ class TestingSyncSource;
#include <SyncML.h>
#include <TransportAgent.h>
#include <SyncSource.h>
#include "test.h"
@ -212,7 +213,7 @@ class ClientTest {
*/
virtual void registerTests();
class Config;
typedef ClientTestConfig Config;
/**
* Creates an instance of LocalTests (default implementation) or a
@ -261,7 +262,7 @@ class ClientTest {
*/
static bool compare(ClientTest &client, const char *fileA, const char *fileB);
struct Config;
struct ClientTestConfig config;
/**
* A derived class can use this call to get default test
@ -279,246 +280,6 @@ class ClientTest {
*/
static void getTestData(const char *type, Config &config);
/**
* Information about a data source. For the sake of simplicity all
* items pointed to are owned by the ClientTest and must
* remain valid throughout a test session. Not setting a pointer
* is okay, but it will disable all tests that need the
* information.
*/
struct Config {
/**
* The name is used in test names and has to be set.
*/
const char *sourceName;
/**
* A default URI to be used when creating a client config.
*/
const char *uri;
/**
* A corresponding source name in the default server template,
* this is used to copy corresponding uri set in the server template
* instead of the uri field above (which is the same for all servers).
*/
const char *sourceNameServerTemplate;
/**
* A member function of a subclass which is called to create a
* sync source referencing the data. This is used in tests of
* the SyncSource API itself as well as in tests which need to
* modify or check the data sources used during synchronization.
*
* The test framework will call beginSync() and then some of
* the functions it wants to test. After a successful test it
* will call endSync() which is then expected to store all
* changes persistently. Creating a sync source again
* with the same call should not report any
* new/updated/deleted items until such changes are made via
* another sync source.
*
* The instance will be deleted by the caller. Because this
* may be in the error case or in an exception handler,
* the sync source's desctructor should not thow exceptions.
*
* @param client the same instance to which this config belongs
* @param source index of the data source (from 0 to ClientTest::getNumSources() - 1)
* @param isSourceA true if the requested SyncSource is the first one accessing that
* data, otherwise the second
*/
typedef TestingSyncSource *(*createsource_t)(ClientTest &client, int source, bool isSourceA);
/**
* Creates a sync source which references the primary database;
* it may report the same changes as the sync source used during
* sync tests.
*/
createsource_t createSourceA;
/**
* A second sync source also referencing the primary data
* source, but configured so that it tracks changes
* independently from the the primary sync source.
*
* In local tests the usage is like this:
* - add item via first SyncSource
* - iterate over new items in second SyncSource
* - check that it lists the added item
*
* In tests with a server the usage is:
* - do a synchronization with the server
* - iterate over items in second SyncSource
* - check that the total number and number of
* added/updated/deleted items is as expected
*/
createsource_t createSourceB;
/**
* The framework can generate vCard and vCalendar/iCalendar items
* automatically by copying a template item and modifying certain
* properties.
*
* This is the template for these automatically generated items.
* It must contain the string <<REVISION>> which will be replaced
* with the revision parameter of the createItem() method.
*/
const char *templateItem;
/**
* This is a colon (:) separated list of properties which need
* to be modified in templateItem.
*/
const char *uniqueProperties;
/**
* the number of items to create during stress tests
*/
int numItems;
/**
* This is a single property in templateItem which can be extended
* to increase the size of generated items.
*/
const char *sizeProperty;
/**
* Type to be set when importing any of the items into the
* corresponding sync sources. Use "" if sync source doesn't
* need this information.
*
* Not currently used! All items are assumed to be in the raw,
* internal format (see SyncSourceRaw and SyncSourceSerialize).
*/
const char *itemType;
/**
* A very simple item that is inserted during basic tests. Ideally
* it only contains properties supported by all servers.
*/
const char *insertItem;
/**
* A slightly modified version of insertItem. If the source has UIDs
* embedded into the item data, then both must have the same UID.
* Again all servers should better support these modified properties.
*/
const char *updateItem;
/**
* A more heavily modified version of insertItem. Same UID if necessary,
* but can test changes to items only supported by more advanced
* servers.
*/
const char *complexUpdateItem;
/**
* To test merge conflicts two different updates of insertItem are
* needed. This is the first such update.
*/
const char *mergeItem1;
/**
* The second merge update item. To avoid true conflicts it should
* update different properties than mergeItem1, but even then servers
* usually have problems perfectly merging items. Therefore the
* test is run without expecting a certain merge result.
*/
const char *mergeItem2;
/**
* These two items are related: one is main one, the other is
* a subordinate one. The semantic is that the main item is
* complete on it its own, while the other normally should only
* be used in combination with the main one.
*
* Because SyncML cannot express such dependencies between items,
* a SyncSource has to be able to insert, updated and remove
* both items independently. However, operations which violate
* the semantic of the related items (like deleting the parent, but
* not the child) may have unspecified results (like also deleting
* the child). See LINKED_ITEMS_RELAXED_SEMANTIC.
*
* One example for main and subordinate items are a recurring
* iCalendar 2.0 event and a detached recurrence.
*/
const char *parentItem, *childItem;
/**
* define to 0 to disable tests which slightly violate the
* semantic of linked items by inserting children
* before/without their parent
*/
#ifndef LINKED_ITEMS_RELAXED_SEMANTIC
# define LINKED_ITEMS_RELAXED_SEMANTIC 1
#endif
/**
* setting this to false disables tests which depend
* on the source's support for linked item semantic
* (testLinkedItemsInsertParentTwice, testLinkedItemsInsertChildTwice)
*/
bool sourceKnowsItemSemantic;
/**
* called to dump all items into a file, required by tests which need
* to compare items
*
* ClientTest::dump can be used: it will simply dump all items of the source
* with a blank line as separator.
*
* @param source sync source A already created and with beginSync() called
* @param file a file name
* @return error code, 0 for success
*/
int (*dump)(ClientTest &client, TestingSyncSource &source, const char *file);
/**
* import test items: which these are is determined entirely by
* the implementor, but tests work best if several complex items are
* imported
*
* ClientTest::import can be used if the file contains items separated by
* empty lines.
*
* @param source sync source A already created and with beginSync() called
* @param file the name of the file to import
* @retval realfile the name of the file that was really imported;
* this may depend on the current server that is being tested
* @return error code, 0 for success
*/
int (*import)(ClientTest &client, TestingSyncSource &source, const char *file, std::string &realfile);
/**
* a function which compares two files with items in the format used by "dump"
*
* @param fileA first file name
* @param fileB second file name
* @return true if the content of the files is considered equal
*/
bool (*compare)(ClientTest &client, const char *fileA, const char *fileB);
/**
* a file with test cases in the format expected by import and compare
*/
const char *testcases;
/**
* the item type normally used by the source (not used by the tests
* themselves; client-test.cpp uses it to initialize source configs)
*/
const char *type;
/**
* TRUE if the source supports recovery from an interrupted
* synchronization. Enables the Client::Sync::*::Retry group
* of tests.
*/
bool retrySync;
bool suspendSync;
bool resendSync;
};
/**
* Data sources are enumbered from 0 to n-1 for the purpose of
* testing. This call returns n.