Archive for the ‘develop’ Category

Android MediaScanner Cannot Display Chinese Characters

Tuesday, July 28th, 2009

Problem Description

On Android Develop Phone 1 (ADP1) running HTC-provided system image of Android 1.5, most of the Chinese characters cannot be diplayed in the library of the music player. This is actually due to the media scanner in OpenCore fails to resolve the proper character encoding for Chinese characters in ID3 tags of MP3 files. The problem is also described at

In the parseMP3() function of “external/opencore/android/mediascanner.cpp”, PVID3ParCom from “external/opencore/fileformats/id3parcom/src/pv_id3_parcom.cpp” is used to parse ID3 tag of MP3 files to get frames information. Then the key string is read from each frame. The key string may look like “artist;valtype=char*;char-encoding=UTF8” if the frame contains the name of the artist and the characters are encoded as UTF8. It may also look like “album;valtype=char*” if the frame contains the name of the album and the characters are encoded as one of the native charsets, which can be ISO 8859-1 — a standard character encoding for the Latin alphabet, GBK for simplified Chinese, Big5 for traditional Chiense, etc.

However, in the implementation of parseMP3() function, all the non-UTF8 native charsets are treated as ISO 8859-1 and converted to UTF8 as if they are ISO 8859-1. Then in the endFile() function, possibleEncodings() function is used to “compute a bit mask containing all possible encodings” (quoted from the comment in the original source file, so are the following two quotations). “If the locale encoding matches”, then convertValues() function is called to “untangle the utf8 and convert it back to the original bytes”, which was mistaken to be treated as ISO 8859-1 before. Then the original bytes are converted to UTF8 again by using the charset converter from ICU library. This time the conversion is based on more proper esitimation of the charset.


One obvious solution is to change the locale of your ADP1. For me, most of my music collection use simplified Chinese in the ID3 tags, and most of them are using GBK encodings instead of UTF8. But HTC-provided system image comes with en-US as the only available locale. In order to add more locales, it’s required to build the source code yourself and flash the images to ADP1. For getting and building the source code, flashing the phone, and including Google applications, please refer to Johan de Koning’s 5-post series of “Building Android 1.5”, which starts from

After booting up the ADP1 with the system image you build, change your locale in the Settings. The mediascanner service might not be able to update the ID3 tag information yet because it will skip the media files that haven’t been modified since last time. One way is to force the “scanAlways” parameter in doScanFile() function from “frameworks/base/media/java/android/media/” to be “True” in the code. However, it’s better to only use this trick temporarily, otherwise it is too resource consuming to re-scan all media files every time.

In case you don’t want to change your locale but still would like your media scanner to be able to read Chinese, Japanese or Korean, then an alternative way is to apply some patch to “external/opencore/android/mediascanner.cpp” like this:

diff -Naur src-1.5-git-orig/external/opencore/android/mediascanner.cpp src-1.5-git/external/opencore/android/mediascanner.cpp
--- src-1.5-git-orig/external/opencore/android/mediascanner.cpp	2009-07-24 13:28:09.000000000 +0200
+++ src-1.5-git/external/opencore/android/mediascanner.cpp	2009-07-24 13:30:02.000000000 +0200
@@ -1008,10 +1008,16 @@
         // compute a bit mask containing all possible encodings
         for (int i = 0; i < mNames->size(); i++)
             encoding &amp;= possibleEncodings(mValues->getEntry(i));
-        // if the locale encoding matches, then assume we have a native encoding.
-        if (encoding &amp; mLocaleEncoding)
-            convertValues(mLocaleEncoding);
+        /* FIX: convert to utf8 accordingly disregard of the current locale */
+        if (encoding &amp; kEncodingGBK)
+            convertValues(kEncodingGBK);
+        else if (encoding &amp; kEncodingBig5)
+            convertValues(kEncodingBig5);
+        else if (encoding &amp; kEncodingEUCKR)
+            convertValues(kEncodingEUCKR);
+        else if (encoding &amp; kEncodingShiftJIS)
+            convertValues(kEncodingShiftJIS);
         // finally, push all name/value pairs to the client
         for (int i = 0; i < mNames->size(); i++) {

Note this is not a proper bug fix, because charset can never be easily estimated. It is not uncommon that the same string can be estimated as GBK, Big5, EUCKR or ShiftJIS at the same time. Depending on the proportion of your music, the sequence can be adjusted in if-statement in the patch above to reflect the charset priorities.

Nevertheless the best way to solve such problems is to convert ID3 tags of all your media files to UTF8 beforehand. Unicode or UTF8 is really the way to go.

Android on the Beagle Board Gains Internet Access by Connecting with the Host Machine Acting as NAT through Ethernet over USB

Tuesday, July 14th, 2009

Brief introduction

There are already solutions to share the mobile network connections of Android phone by the host PC via USB cable, so that browser in the host PC can surf Internet by using Android’s mobile network subscription. This is called tethering. However, today I’m going to present a complete solution to connect Android with the host PC by using ethernet via USB and enable Andriod to access the Internet through the Internet connection of the host PC.

I’m using the Beagle Board ( as the platform to run Android (

Enable ethernet over USB in the linux kernel

– go to the “kernel” directory in the android source, use menuconfig (CC_PATH is mentioned in the link above)

make CROSS_COMPILE=$CC_PATH menuconfig

– enable usb-eth by choosing “Ethernet Gadget (with CDC Ethernet support)” for “Device Drivers -> USB support -> USB Gadget Support -> USB Gadget Drivers”, exit and save
– re-build the uImage


the previous built uImage might need to be removed first

rm arch/arm/boot/uImage

– copy the uImage to the first partition of the sdcard
– make sure the kernel on the host machine is built with usbnet (“Device Drivers -> Network device support -> USB Network Adapters -> Multi-purpose USB Networking Framework” in the menuconfig). Most GNU Linux distributions already come with usbnet built-in, including Ubuntu in my case

Config ethernet over USB

– refer to to download and install the static-linked busybox built for ARM. It’ll be assumed busybox is installed at “/data/busybox” below
– in minicom connected with Beagle Board, wait until Android is fully booted up
– use ifconfig from busybox mentioned above

/data/busybox/ifconfig usb0 up

– config the gateway as well

route add default gw dev usb0

– similarly, type the following command in the shell of the host machine

sudo ifconfig usb0 up


– the ADB daemon may require to be terminated first if already running:

ADBHOST= adb kill-server

– ADBHOST requires to be set if ADB works over ethernet

ADBHOST= adb shell

Config the host machine to act as NAT

– load necessary kernel modules

sudo modprobe ip_tables
sudo modprobe iptable_nat
sudo modprobe ip_nat_ftp
sudo modprobe ip_nat_irc

– enable IP forwarding

echo "1" | sudo dd of=/proc/sys/net/ipv4/ip_forward

– in case the IP address is assigned dynamically

echo "1" | sudo dd of=/proc/sys/net/ipv4/ip_dynaddr

– enable SNAT functionality on the corresponding network interface


Note: [NETWORK_INTERFACE] is the corresponding network interface your host is using to access the Internet.


It’s not uncommon that computer access Internet via network proxy. But WIFI and other network connections in Android require direct network connection and network proxy is not supported.

The code handling network proxy in Android is mainly in “frameworks/base/core/java/android/net/http/”. In the function setProxyConfig(), getHost() from “frameworks/base/core/java/android/net/ is invoked to get the proxy host. However, as illustrated in “frameworks/base/core/java/android/net/”, Android seems to only support WIFI and mobile network as network connection type. WIFI happens to be the default connectivity type, the reason of which is shown below taken from the file “[ANDROID_SRC_DIR]/frameworks/base/core/java/android/net/http/”:

                 * Initializing the network type is really unnecessary,
                 * since as soon as we register with the NCL, we'll
                 * get a CONNECTED event for the active network, and
                 * we'll configure the HTTP proxy accordingly. However,
                 * as a fallback in case that doesn't happen for some
                 * reason, initializing to type WIFI would mean that
                 * we'd start out without a proxy. This seems better
                 * than thinking we have a proxy (which is probably
                 * private to the carrier network and therefore
                 * unreachable outside of that network) when we really
                 * shouldn't.

Then no proxy is set in case of WIFI network, which means WIFI requires direct Internet connection as shown below also taken from the file “frameworks/base/core/java/android/net/http/”. The way to solve it is to comment out the “if (mNetworkStateTracker.getCurrentNetworkType() == ConnectivityManager.TYPE_WIFI)” statement:

    private synchronized void setProxyConfig() {
        /* get rid of this branch */
        if (mNetworkStateTracker.getCurrentNetworkType() == ConnectivityManager.TYPE_WIFI) {
            mProxyHost = null;
	    } else {
            String host = Proxy.getHost(mContext);
            if (HttpLog.LOGV) HttpLog.v("RequestQueue.setProxyConfig " + host);
            if (host == null) {
                mProxyHost = null;
            } else {
                mProxyHost = new HttpHost(host, Proxy.getPort(mContext), "http");

Still in “frameworks/base/core/java/android/net/http/”, setProxyConfig() is only invoked when the NetworkStateTracker sends out message that the network state is changed. And setProxyConfig() is not called during initialization because as soon as Android registers with the NCL, a CONNECTED event is received for the active network. However, this is only true to mobile network, not for WIFI or wired networks. The way to fix this is to invoke setProxyConfig() at the end of enablePlatformNotifications(), so that proxy is properly configured at initialization regardless of what network type it is. The corresonding code is illustrated below:

    public synchronized void enablePlatformNotifications() {
        if (HttpLog.LOGV) HttpLog.v("RequestQueue.enablePlatformNotifications() network");

        if (mProxyChangeReceiver == null) {
            mProxyChangeReceiver =
                    new BroadcastReceiver() {
                        public void onReceive(Context ctx, Intent intent) {
                                      new IntentFilter(Proxy.PROXY_CHANGE_ACTION));

        /* Network state notification is broken on the simulator
           don't register for notifications on SIM */
        String device = SystemProperties.get("ro.product.device");
        boolean simulation = TextUtils.isEmpty(device);

        if (!simulation) {
            if (mNetworkStateTracker == null) {
                mNetworkStateTracker = new NetworkStateTracker(mContext);
        /* call setProxyConfig() as part of the initialization.
          Otherwise, setProxyConfig() will only be invoked in case of
          network state change, and only mobile network get CONNECTED
          event after registration with NCL */

Then in, it uses “frameworks/base/core/java/android/provider/”, which is actually an utility wrapper of sqlite database to get the proxy and port settings. The corresponding table is “secure” from “/data/data/”. The “name”, “value” pair should be “http_proxy”, “[HTTP_PROXY_HOST]:[HTTP_PROXY_PORT]”. The way to append the record is:

adb shell sqlite3 /data/data/ "INSERT INTO secure VALUES(99,'http_proxy','[HTTP_PROXY_HOST]:[HTTP_PROXY_PORT]');"

If nothing is got from the above database, then the system property “net.gprs.http-proxy” is used instead. The way to put it is to add the following command in “on boot” trigger in “init.rc”:

setprop net.gprs.http-proxy [HTTP_PROXY_HOST]:[HTTP_PROXY_PORT]

One more thing to mention is DNS has to be configured to resolve domain names. The way to do that is to add the following commands in “on boot” trigger in “init.rc” as well:

setprop net.dns1 [DNS_SERVER_1_IP]
setprop net.dns2 [DNS_SERVER_2_IP]

Patch Framebuffer Driver of PrimeCell Color LCD Controller with Double-Buffering to Support Android’s Page-Flipping

Monday, May 4th, 2009

Brief introduction

Android uses a screen composition engine called SurfaceFlinger. It takes the input of Surface objects from each Windows, then writes the output to the frame buffer. Each Surface is double-buffered. The front buffer is taken by SurfaceFlinger for composition, while the back buffer is used to perform drawing. Once the drawing is completed, Android does a page-flipping by changing the offset value on Y axis of the frame buffer to switch them. During the initialization of EGLDisplaySurface, if the virtual resolution on the Y axis of the frame buffer is found out to be bigger than the real resolution of the Y axis, then the frame buffer is used directly for double-buffering. Otherwise, the back buffer is simply copied to the front buffer, which causes delay in buffer-swapping. Thus double-buffering would better to be supported by the frame buffer driver for the sake of performance.

Double-buffering is supported in the goldfish frame buffer driver, which is used by the QEMU-based emulator shipped with Android SDK. I happen to be working on porting Android to an ARM RealView board. The board has PL111 PrimeCell Color LCD Controller, which is AMBA compliant SoC peripheral. By comparing the source code of goldfish frame buffer driver (from Android cupcake branch source tree) and that of the ARM LCD controller frame buffer driver (from 2.6.27 vanilla kernel), one can easily figure out what should be patched in the ARM LCD frame buffer driver (kernel/drivers/video/amba-clcd.c) to support double-buffering. Firstly, in the initialization of the driver, change to “fb->fb.fix.ypanstep = 1;” and “fb->fb.var.yres_virtual = fb->panel->mode.yres * 2;” Then in the declaration of “clcdfb_ops”, add this line of code “.fb_pan_display = clcdfb_pan_display,”. Also define this new function “clcdfb_pan_display” by putting an invocation to the function “clcdfb_set_start”. In the definition of the function “clcdfb_check” in kernel/include/linux/amba/clcd.h, change from “var->yres_virtual = var->yres = (var->yres + 1) & ~1;” to “var->yres = (var->yres + 1) & ~1; var->yres_virtual = var->yres * 2;” since the checking happens to reset the value of yres_virtual to that of yres. One more step required is to increase the frame size to needed. In kernel/arch/arm/mach-realview/core.c, change from “static unsigned long framesize = SZ_1M;” to “static unsigned long framesize = 0x12C000;”. 0x12C000 is the value of 640 * 480 * 2 * 2 (VGA, 16bpp and double-buffer), because VGA is the largest display resolution that is provided by PL111 and can still support double-buffering due to the limited display memory.

How page-flipping works

– In frameworks/base/libs/ui/EGLDisplaySurface.cpp, function “EGLDisplaySurface::swapBuffers()” does the real work by calling ioctl of FBIOPUT_VSCREENINFO
– In “kernel/drivers/video/fbmem.c”, function “fb_ioctl” handles over the work in “case FBIOPUT_VSCREENINFO:”, then “fb_set_var” is invoked. In that function, both “fbops->fb_set_par” and “fb_pan_display” are invoked. Similarly, in “fb_pan_display”, “fbops->fb_pan_display” is also invoked. “fbops->fb_set_par” and “fbops->fb_pan_display” mentioned above are provided by the amba clcd frame buffer driver in kernel/drivers/video/amba-clcd.c.
– According to the conventions, “fb_set_par” implementation in the frame buffer driver is supposed to react to possible changes of screen orientation and resolution. And “fb_pan_display” is supposed to re-map the frame buffer as the offset changes in X or Y axis. In this way, page-flipping is properly handled.

Problem of “clcdfb_set_par”

In “clcdfb_set_par” of the current amba clcd implementation, it turns off the power and clock source of the frame buffer, sets clocks and the buffer base, then it turns on the frame buffer. This is not applied to Android because the page-flipping gonna invoke FBIOPUT_VSCREENINFO ioctl so often that “clcdfb_set_par” is going to be invoked a lot as well. Then the whole system is not operatable at all as a result. It’s obviously that at least the implementation of “clcdfb_set_par” is not written in a way that adheres to the conventions. Or writting frame buffer implementation in this case still requires keeping the usage of Android in mind.

The solution to that is to cache the frame buffer settings. Each time “clcd_set_par” is invoked, the new frame buffer settings are compared with the cached ones. If the screen orientation, resolution and other changes that will require reset of clock don’t happen, then simply skip any operations; otherwise, the new frame buffer settings are cached and the clock is reseted.

The actual patch

The patch to the said files above is illustrated below:

diff -Naur kernel-2.6.27.orig/arch/arm/mach-realview/core.c kernel-2.6.27/arch/arm/mach-realview/core.c
--- kernel-2.6.27.orig/arch/arm/mach-realview/core.c	2009-04-29 16:16:29.000000000 +0200
+++ kernel-2.6.27/arch/arm/mach-realview/core.c	2009-04-29 16:12:26.000000000 +0200
@@ -358,7 +358,8 @@
writel(val, sys_clcd);

-static unsigned long framesize = SZ_1M;
+/* 640*480*2*2 (VGA, 16bpp and double-buffer) required by Android */
+static unsigned long framesize = 0x12C000;

static int realview_clcd_setup(struct clcd_fb *fb)
diff -Naur kernel-2.6.27.orig/drivers/video/amba-clcd.c kernel-2.6.27/drivers/video/amba-clcd.c
--- kernel-2.6.27.orig/drivers/video/amba-clcd.c	2009-04-29 16:16:58.000000000 +0200
+++ kernel-2.6.27/drivers/video/amba-clcd.c	2009-04-29 16:13:16.000000000 +0200
@@ -194,6 +194,37 @@
return ret;

+struct fb_var_screeninfo cached_fb_var;
+int is_fb_var_cached = 0;
+static int clcdfb_is_fb_changed(struct clcd_fb *fb)
+    if (!is_fb_var_cached ||
+        fb->fb.var.xres != cached_fb_var.xres ||
+        fb->fb.var.yres != cached_fb_var.yres ||
+        fb->fb.var.xres_virtual != cached_fb_var.xres_virtual ||
+        fb->fb.var.yres_virtual != cached_fb_var.yres_virtual ||
+        fb->fb.var.bits_per_pixel != cached_fb_var.bits_per_pixel ||
+        fb->fb.var.grayscale != cached_fb_var.grayscale ||
+        fb-> != ||
+        fb->fb.var.left_margin != cached_fb_var.left_margin ||
+        fb->fb.var.right_margin != cached_fb_var.right_margin ||
+        fb->fb.var.upper_margin != cached_fb_var.upper_margin ||
+        fb->fb.var.lower_margin != cached_fb_var.lower_margin ||
+        fb->fb.var.hsync_len != cached_fb_var.hsync_len ||
+        fb->fb.var.vsync_len != cached_fb_var.vsync_len ||
+        fb->fb.var.sync != cached_fb_var.sync ||
+        fb->fb.var.rotate != cached_fb_var.rotate) {
+        cached_fb_var = fb->fb.var;
+        is_fb_var_cached = 1;
+        return 1;
+    }
+    else
+        return 0;
static int clcdfb_set_par(struct fb_info *info)
struct clcd_fb *fb = to_clcd(info);
@@ -207,22 +238,25 @@
fb->fb.fix.visual = FB_VISUAL_TRUECOLOR;

-	fb->board->decode(fb, &regs);
+    if (clcdfb_is_fb_changed(fb)) {
+	    fb->board->decode(fb, &regs);

-	clcdfb_disable(fb);
+	    clcdfb_disable(fb);

-	writel(regs.tim0, fb->regs + CLCD_TIM0);
-	writel(regs.tim1, fb->regs + CLCD_TIM1);
-	writel(regs.tim2, fb->regs + CLCD_TIM2);
-	writel(regs.tim3, fb->regs + CLCD_TIM3);
+	    writel(regs.tim0, fb->regs + CLCD_TIM0);
+	    writel(regs.tim1, fb->regs + CLCD_TIM1);
+	    writel(regs.tim2, fb->regs + CLCD_TIM2);
+	    writel(regs.tim3, fb->regs + CLCD_TIM3);

-	clcdfb_set_start(fb);
+	    clcdfb_set_start(fb);

-	clk_set_rate(fb->clk, (1000000000 / regs.pixclock) * 1000);
+	    clk_set_rate(fb->clk, (1000000000 / regs.pixclock) * 1000);

-	fb->clcd_cntl = regs.cntl;
+	    fb->clcd_cntl = regs.cntl;

-	clcdfb_enable(fb, regs.cntl);
+	    clcdfb_enable(fb, regs.cntl);
+    }

#ifdef DEBUG
printk(KERN_INFO "CLCD: Registers set to\n"
@@ -289,6 +323,17 @@
return regno > 255;

+static int clcdfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+    struct clcd_fb *fb = NULL;
+    info->var = *var;
+	fb = to_clcd(info);
+	clcdfb_set_start(fb);
+	return 0;
*  Blank the screen if blank_mode != 0, else unblank. If blank == NULL
*  then the caller blanks by setting the CLUT (Color Look Up Table) to all
@@ -332,6 +377,7 @@
.fb_check_var	= clcdfb_check_var,
.fb_set_par	= clcdfb_set_par,
.fb_setcolreg	= clcdfb_setcolreg,
+	.fb_pan_display = clcdfb_pan_display,
.fb_blank	= clcdfb_blank,
.fb_fillrect	= cfb_fillrect,
.fb_copyarea	= cfb_copyarea,
@@ -367,14 +413,14 @@
fb->fb.fix.type		= FB_TYPE_PACKED_PIXELS;
fb->fb.fix.type_aux	= 0;
fb->fb.fix.xpanstep	= 0;
-	fb->fb.fix.ypanstep	= 0;
+	fb->fb.fix.ypanstep	= 1;
fb->fb.fix.ywrapstep	= 0;
fb->fb.fix.accel	= FB_ACCEL_NONE;
fb->fb.var.xres		= fb->panel->mode.xres;
fb->fb.var.yres		= fb->panel->mode.yres;
fb->fb.var.xres_virtual	= fb->panel->mode.xres;
-	fb->fb.var.yres_virtual	= fb->panel->mode.yres;
+	fb->fb.var.yres_virtual	= fb->panel->mode.yres * 2;
fb->fb.var.bits_per_pixel = fb->panel->bpp;
fb->fb.var.grayscale	= fb->panel->grayscale;
fb->fb.var.pixclock	= fb->panel->mode.pixclock;
diff -Naur kernel-2.6.27.orig/include/linux/amba/clcd.h kernel-2.6.27/include/linux/amba/clcd.h
--- kernel-2.6.27.orig/include/linux/amba/clcd.h	2009-04-29 16:16:20.000000000 +0200
+++ kernel-2.6.27/include/linux/amba/clcd.h	2009-04-29 16:12:53.000000000 +0200
@@ -232,7 +232,9 @@
static inline int clcdfb_check(struct clcd_fb *fb, struct fb_var_screeninfo *var)
var->xres_virtual = var->xres = (var->xres + 15) & ~15;
-	var->yres_virtual = var->yres = (var->yres + 1) & ~1;
+	//var->yres_virtual = var->yres = (var->yres + 1) & ~1;
+	var->yres = (var->yres + 1) & ~1;
+	var->yres_virtual = var->yres * 2;

#define CHECK(e,l,h) (var->e < l || var->e > h)
if (CHECK(right_margin, (5+1), 256) ||	/* back porch */

How to Cross Compile ICU

Tuesday, March 3rd, 2009


ICU (International Components for Unicode) libraries provide robust and full-featured Unicode services (refer to Gtk+ port of WebKit requires ICU. Not proper installation of ICU can cause problem in Webkit/Gtk+ (refer to

Not compilable in Scratchbox

Due to failure of redirecting path of “gcc” to the corresponding one in cross-compilation toochain (the same problem that compiling Python has) according to the transparency mechanism.

Not really cross-compilable in the Host

After binaries and shared libraries are built from the source, the binary “pkgdata” and its corresponding shared libraries are directly executed in order to package the ICU data. Since it’s cross compiled, the built binary “pkgdata” is not executable on the host, which makes the building process fail.

However, there is work around

It is largely based on the approach by However, changes are made to enable shared libraries instead of only static linking.

– First download ICU and extract the source tgz file. Then go to the extracted source directory:

cd source

– Build PC binaries and backup:

./configure --disable-threads
cp -r bin bin.linux
cp -r data data.linux
cp -r lib lib.linux
cp -r tools tools.linux

– Build ARM binaries and include the path to cross-compilers. In my case, I re-use the same toolchain from Scratchbox:

make distclean
PATH=/scratchbox/compilers/arm-linux-cs2007q3-51sb1/bin:$PATH ./configure --host=arm-none-linux-gnueabi
PATH=/scratchbox/compilers/arm-linux-cs2007q3-51sb1/bin:$PATH make

– There will be error: “/bin/sh: ../bin/icupkg: cannot execute binary file”. The build system tries to execute “icupkg” to package ICU data files, it will fail since “icupkg” is ARM binary. Anyway, back up ARM binaries first:

cp -r bin bin.arm
cp -r data data.arm

– Restore “bin” and “data” with PC binaries:

cp -r bin.linux/* bin
cp -r data.linux/* data

– “icupkg” needs to resolve links to PC binaries of shared libraries, so LD_LIBRARY_PATH is appended. The original LD_LIBRARY_PATH is kept because then build system still needs ARM binaries of shared libraries in the end in order to finalize building and installing:

PATH=/scratchbox/compilers/arm-linux-cs2007q3-51sb1/bin:$PATH LD_LIBRARY_PATH=[ICU_SRC_ABSOLUTE_PATH]/source/lib.linux:$LD_LIBRARY_PATH make

– Get “uconv” built and restore the ARM binaries of “bin”:

rm bin/uconv
PATH=/scratchbox/compilers/arm-linux-cs2007q3-51sb1/bin:$PATH LD_LIBRARY_PATH=[ICU_SRC_ABSOLUTE_PATH]/source/lib.linux:$LD_LIBRARY_PATH make
cp bin/uconv bin.arm
cp bin.arm/* bin

– Use PC binaries of “pkgdata” to install the files in place and restore the ARM binary of “pkgdata” after installing:

cp bin.linux/pkgdata bin
make install PATH=/scratchbox/compilers/arm-linux-cs2007q3-51sb1/bin:$PATH LD_LIBRARY_PATH=/home/esonyua/Projs/Icu/icu/source/lib.linux:$LD_LIBRARY_PATH DESTDIR=[INSTALL_DIR]
cp bin.arm/pkgdata [INSTALL_DIR]/usr/local/bin