Hello!
I've been wondering whether compilation of the open source libsynthesis
and SyncEvolution for Android is possible. There is of course the
official Synthesis SDK for Android, which is the better alternative for
those who need something which works right away *and* has the Java
bindings that are needed for GUI apps on Android.
For those who prefer compiling from source and/or want a working SyncML
client to play with, keep reading...
After some fiddling, I was able to compile both and run syncs with the
SyncEvolution file backend. Limitations:
* no GUI, only the command line tool
* no Java bindings (they are not part of the open source code
base)
* every exception aborts the program (does not happen during
normal runs)
Setup:
* install Android SDK and NDK
* install NDK wrappers (http://umbel.mooo.com/)
* ensure that the arm-linux-* binaries from the NDK wrappers are
in the PATH
* add a symbolic link from arm-linux-pkg-config to /bin/false in
the PATH: this prevents calling the build machine's native
pkg-config and thus detecting packages which don't exist on
Android
* download and compile libcurl, using --host=arm-linux as
configure flag
Compilation of libsynthesis and SyncEvolution uses the normal autotools
scripts. The source of libsynthesis required some fixes to compile
cleanly on Android. These patches were pushed into the "android" branch
on git.moblin.org.
SyncEvolution changes for Android were also pushed into an "android"
branch. The biggest change is a patch which makes exception handling
optional, because that is not supported by the Android compiler and
runtime libraries.
One change in both repos is for static linking: as you will see below,
installing a single binary is fairly easy, so that's how I wanted to
compile syncevolution. The Synthesis engine expects to load plugins
dynamically. Our previous solution for static linking depended on
dlsym(RTLD_DEFAULT) and --export-dynamic. The latter didn't have any
effect on the resulting Android executable, therefore I had to find a
different solution. I went for specifying the addresses of all plugin
functions in the XML config which is generated at runtime.
Another complication was SyncEvolution's dependency on Boost header
files. They work without exceptions, but some of them use typeinfo(),
which is not supported either. As a crude solution (not done 100%
correctly for non-Android platforms and with unknown implications for
the code which depends on runtime type information) I patched the header
files (patch attached).
Copy and prepare some set of Boost header files (I
used /usr/include/boost from Debian's 1.34.1-14) like this:
* mkdir <boost_path>/include
* cp -a /usr/include/boost <boost_path>/include
* cd <boost_path>/include/boost && patch -p1 <boost.patch
Finally, here's how I compiled SyncEvolution:
./configure --with-synthesis-src=<path>/libsynthesis \
CFLAGS="-g -Wall -Werror -Wno-unknown-pragmas" \
CXXFLAGS="-g -Wall -Werror -Wno-unknown-pragmas" \
LDFLAGS=-L<path>/ndk-wrappers/stlport/build/lib/obj/arm-linux-gcc/so/ \
--disable-shared --enable-static --enable-libcurl \
--disable-unit-tests --disable-integration-tests \
--disable-ecal --disable-ebook \
--with-boost=<boost_path> \
--with-xmltok=builtin \
--host=arm-linux
I originally also used --disable-sqlite --disable-ical --disable-reqgex,
but with the arm-linux-pkg-config link that should no longer be
necessary.
Copy SyncEvolution into a running emulator (started via "android"
command earlier):
adb push syncevolution /data/local/bin/syncevolution && \
adb shell chmod 755 /data/local/bin/syncevolution
Configure SyncEvolution for contact sync with ScheduleWorld:
adb shell "cd /data && /data/local/bin/syncevolution --configure
--source-property type=file:text/vcard:3.0
--source-property
evolutionsource=file:///data/syncevolution/addressbook
--source-property sync=two-way
--sync-property username=<username>
--sync-property password=<password>
scheduleworld addressbook"
The "cd" is important because there is no HOME env variable;
SyncEvolution then defaults to the current directory. Files created
above and during a sync end up in /data/.config/syncevolution
(config), /data/.cache (logs) and /data/syncvolution/addressbook (one
vcard file per contact).
Run the initial sync:
adb shell "cd /data && /data/local/bin/syncevolution
--run --sync-property sync=slow
scheduleworld"
I was using the "slow-sync" branch, therefore a slow sync is only done
when expected by the user. All following runs:
adb shell "cd /data && /data/local/bin/syncevolution
scheduleworld"
This was just an experiment. I have not tried to get the automated
testing via "client-test" working, because that depends on CPPUnit and
thus another set of "no exception" patches.
Some of the resulting patches might be generally useful. Lukas, I
suggest that you pick whatever you find useful from the libsynthesis
repo. The static linking part would also be useful for Mac OS X, where
--export-dynamic is not a valid option to start with.
For SyncEvolution I'll probably let this settle a bit and then propose
patches for merging into master.
--
Best Regards, Patrick Ohly
The content of this message is my personal opinion only and although
I am an employee of Intel, the statements I make here in no way
represent Intel's position on the issue, nor am I authorized to speak
on behalf of Intel on this matter.
diff --git a/config/stdlib/stlport.hpp b/config/stdlib/stlport.hpp
index 98fdd43..baa72e1 100644
--- a/config/stdlib/stlport.hpp
+++ b/config/stdlib/stlport.hpp
@@ -126,6 +126,10 @@
&& (defined(__STL_VENDOR_GLOBAL_CSTD) || defined (_STLP_VENDOR_GLOBAL_CSTD))
# define BOOST_NO_STDC_NAMESPACE
# define BOOST_NO_EXCEPTION_STD_NAMESPACE
+
+// necessary on Android so that BOOST_FUNCTION_STD_NS::type_info with
+// empty BOOST_FUNCTION_STD_NS works
+using std::type_info;
# endif
#elif defined(__BORLANDC__) && __BORLANDC__ < 0x560
// STLport doesn't import std::abs correctly:
@@ -157,7 +161,7 @@ namespace std{ using _STLP_VENDOR_CSTD::strcmp; using _STLP_VENDOR_CSTD::strcpy;
// only if BOOST_NO_STDC_NAMESPACE is not defined (if it is then we do the import
// into std:: ourselves).
//
-#if defined(_STLP_NO_NATIVE_WIDE_FUNCTIONS) && !defined(BOOST_NO_STDC_NAMESPACE)
+#if 1 || defined(_STLP_NO_NATIVE_WIDE_FUNCTIONS) && !defined(BOOST_NO_STDC_NAMESPACE)
# define BOOST_NO_CWCHAR
# define BOOST_NO_CWCTYPE
#endif
diff --git a/detail/sp_counted_impl.hpp b/detail/sp_counted_impl.hpp
index 6963f59..ef575d2 100644
--- a/detail/sp_counted_impl.hpp
+++ b/detail/sp_counted_impl.hpp
@@ -36,6 +36,11 @@
#endif
#include <typeinfo> // std::type_info in get_deleter
+#if defined(BOOST_HAVE_TYPEINFO)
+# define BOOST_TYPES_EQUAL(_x, _y) ((_x) == (_y))
+#else
+# define BOOST_TYPES_EQUAL(_x, _y) true
+#endif
#include <cstddef> // std::size_t
namespace boost
@@ -147,7 +152,7 @@ public:
virtual void * get_deleter( std::type_info const & ti )
{
- return ti == typeid(D)? &del: 0;
+ return BOOST_TYPES_EQUAL(ti, typeid(D))? &del: 0;
}
#if defined(BOOST_SP_USE_STD_ALLOCATOR)
@@ -217,7 +222,7 @@ public:
virtual void * get_deleter( std::type_info const & ti )
{
- return ti == typeid( D )? &d_: 0;
+ return BOOST_TYPES_EQUAL(ti, typeid( D ))? &d_: 0;
}
};
diff --git a/function/function_base.hpp b/function/function_base.hpp
index aa7376a..b73c844 100644
--- a/function/function_base.hpp
+++ b/function/function_base.hpp
@@ -46,7 +46,9 @@
// Borrowed from Boost.Python library: determines the cases where we
// need to use std::type_info::name to compare instead of operator==.
-# if (defined(__GNUC__) && __GNUC__ >= 3) \
+# if !defined(BOOST_HAVE_TYPEINFO)
+# define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) true
+# elif (defined(__GNUC__) && __GNUC__ >= 3) \
|| defined(_AIX) \
|| ( defined(__sgi) && defined(__host_mips))
# include <cstring>
@@ -239,7 +241,11 @@ namespace boost {
return;
case get_functor_type_tag:
+#ifdef BOOST_HAVE_TYPEID
out_buffer.const_obj_ptr = &typeid(F);
+#else
+ boost::throw_exception(std::runtime_error("no rtti"));
+#endif
return;
}
}
@@ -279,8 +285,10 @@ namespace boost {
else if (op == destroy_functor_tag)
out_buffer.func_ptr = 0;
else /* op == check_functor_type_tag */ {
+#ifdef BOOST_HAVE_TYPEID
const BOOST_FUNCTION_STD_NS::type_info& check_type =
*static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(out_buffer.const_obj_ptr);
+#endif
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
out_buffer.obj_ptr = &in_buffer.func_ptr;
else
@@ -301,8 +309,10 @@ namespace boost {
// Some compilers (Borland, vc6, ...) are unhappy with ~functor_type.
reinterpret_cast<functor_type*>(&out_buffer.data)->~Functor();
} else /* op == check_functor_type_tag */ {
+#ifdef BOOST_HAVE_TYPEINFO
const BOOST_FUNCTION_STD_NS::type_info& check_type =
*static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(out_buffer.const_obj_ptr);
+#endif
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
out_buffer.obj_ptr = &in_buffer.data;
else
@@ -362,8 +372,10 @@ namespace boost {
# endif // BOOST_NO_STD_ALLOCATOR
out_buffer.obj_ptr = 0;
} else /* op == check_functor_type_tag */ {
+#ifdef BOOST_HAVE_TYPEID
const BOOST_FUNCTION_STD_NS::type_info& check_type =
*static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(out_buffer.const_obj_ptr);
+#endif
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
out_buffer.obj_ptr = in_buffer.obj_ptr;
else
@@ -401,7 +413,11 @@ namespace boost {
typedef typename get_function_tag<functor_type>::type tag_type;
switch (op) {
case get_functor_type_tag:
+#ifdef BOOST_HAVE_TYPEID
out_buffer.const_obj_ptr = &typeid(functor_type);
+#else
+ boost::throw_exception(std::runtime_error("no rtti"));
+#endif
return;
default:
@@ -504,13 +520,21 @@ public:
if this is empty. */
const BOOST_FUNCTION_STD_NS::type_info& target_type() const
{
- if (!vtable) return typeid(void);
+ if (!vtable) {
+#ifdef BOOST_HAVE_TYPEID
+ return typeid(void);
+#else
+ boost::throw_exception(std::runtime_error("no rtti"));
+ return *(BOOST_FUNCTION_STD_NS::type_info *)0;
+#endif
+ }
detail::function::function_buffer type;
vtable->manager(functor, type, detail::function::get_functor_type_tag);
return *static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(type.const_obj_ptr);
}
+#ifdef BOOST_HAVE_TYPEID
template<typename Functor>
Functor* target()
{
@@ -522,7 +546,9 @@ public:
detail::function::check_functor_type_tag);
return static_cast<Functor*>(type_result.obj_ptr);
}
+#endif
+#ifdef BOOST_HAVE_TYPEID
template<typename Functor>
#if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300)
const Functor* target( Functor * = 0 ) const
@@ -540,6 +566,7 @@ public:
// can't do the static_cast that we should do.
return (const Functor*)(type_result.obj_ptr);
}
+#endif
template<typename F>
bool contains(const F& f) const
diff --git a/shared_ptr.hpp b/shared_ptr.hpp
index 9edc86f..838dbaf 100644
--- a/shared_ptr.hpp
+++ b/shared_ptr.hpp
@@ -523,6 +523,7 @@ template<class E, class T, class Y> std::basic_ostream<E, T> & operator<< (std::
#endif // __GNUC__ < 3
+#ifdef BOOST_HAVE_TYPEINFO
// get_deleter (experimental)
#if ( defined(__GNUC__) && BOOST_WORKAROUND(__GNUC__, < 3) ) || \
@@ -546,6 +547,7 @@ template<class D, class T> D * get_deleter(shared_ptr<T> const & p)
}
#endif
+#endif // BOOST_HAVE_TYPEINFO
} // namespace boost
diff --git a/throw_exception.hpp b/throw_exception.hpp
index bb79a37..b68ca89 100644
--- a/throw_exception.hpp
+++ b/throw_exception.hpp
@@ -25,6 +25,18 @@
# include <exception>
#endif
+#ifndef BOOST_HAVE_BADALLOC
+namespace std
+{
+ class bad_alloc : public exception {
+ public:
+ bad_alloc() throw() {}
+ virtual ~bad_alloc() throw() {}
+ virtual const char* what() const throw() { return "bad alloc"; }
+ };
+}
+#endif
+
namespace boost
{
_______________________________________________
os-libsynthesis mailing list
[email protected]
http://lists.synthesis.ch/mailman/listinfo/os-libsynthesis