2012年6月6日 星期三

Cross Compile C/C++ using agcc(arm-eabi-gcc/g++ provide by Android)

如果你有Android的 Source Code 然後想要將C/C++ code  cross compile到ARM上面的話,可以使用 Android所提供的cross compiler。但有一個問題是,要真正拿來編譯的時候需要加入很多CFLAG(Include Header Path及Linking Library)。

比較方便的作法是直接使用agcc。這是外國人寫得一個perl的script,避免以後不見先貼上來。

#!/usr/bin/perl -w
use strict;

# Copyright 2008, Andrew Ross andy@plausible.org
# Distributable under the terms of the GNU GPL, see COPYING for details

# The Android toolchain is ... rough.  Rather than try to manage the
# complexity directly, this script wraps the tools into an "agcc" that
# works a lot like a gcc command line does for a native platform or a
# properly integrated cross-compiler.  It accepts arbitrary arguments,
# but interprets the following specially:
#
# -E/-S/-c/-shared - Enable needed arguments (linker flags, include
#                    directories, runtime startup objects...) for the
#                    specified compilation mode when building under
#                    android.
#
# -O - Turn on the optimizer flags used by the Dalvik build.  No
#           control is provided over low-level optimizer flags.
#
# -W - Turn on the warning flags used by the Dalvik build.  No
#           control is provided over specific gcc warning flags.
#
# Notes:
# + The prebuilt arm-eabi-gcc from a built (!) android source
#   directory must be on your PATH.
# + All files are compiled with -fPIC to an ARMv5TE target.  No
#   support is provided for thumb.
# + No need to pass a "-Wl,-soname" argument when linking with
#   -shared, it uses the file name always (so don't pass a directory in
#   the output path for a shared library!)

# Dance around to find the actual android toolchain path (it's very
# deep, so links on $PATH are going to be common.
my $GCC = `which arm-eabi-gcc`;
$GCC = qx(cd `dirname $GCC`; /bin/pwd);
chomp $GCC;
die "bad arm-eabi-gcc path" if $GCC !~ /(.*)\/prebuilt\//;
my $DROID = $1;

my $ALIB = "$DROID/out/target/product/generic/obj/lib";
my $TOOLCHAIN = "$DROID/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1";

my @include_paths = (
    "-I$DROID/system/core/include",
    "-I$DROID/hardware/libhardware/include",
    "-I$DROID/hardware/ril/include",
    "-I$DROID/dalvik/libnativehelper/include",
    "-I$DROID/frameworks/base/include",
    "-I$DROID/external/skia/include",
    "-I$DROID/out/target/product/generic/obj/include",
    "-I$DROID/bionic/libc/arch-arm/include",
    "-I$DROID/bionic/libc/include",
    "-I$DROID/bionic/libstdc++/include",
    "-I$DROID/bionic/libc/kernel/common",
    "-I$DROID/bionic/libc/kernel/arch-arm",
    "-I$DROID/bionic/libm/include",
    "-I$DROID/bionic/libm/include/arch/arm",
    "-I$DROID/bionic/libthread_db/include",
    "-I$DROID/bionic/libm/arm",
    "-I$DROID/bionic/libm",
    "-I$DROID/out/target/product/generic/obj/SHARED_LIBRARIES/libm_intermediates");

my @preprocess_args = (
    "-D__ARM_ARCH_5__",
    "-D__ARM_ARCH_5T__",
    "-D__ARM_ARCH_5E__",
    "-D__ARM_ARCH_5TE__", # Already defined by toolchain
    "-DANDROID",
    "-DSK_RELEASE",
    "-DNDEBUG",
    "-include", "$DROID/system/core/include/arch/linux-arm/AndroidConfig.h",
    "-UDEBUG");

my @warn_args = (
    "-Wall",
    "-Wno-unused", # why?
    "-Wno-multichar", # why?
    "-Wstrict-aliasing=2"); # Implicit in -Wall per texinfo

my @compile_args = (
    "-march=armv5te",
    "-mtune=xscale",
    "-msoft-float",
    "-mthumb-interwork",
    "-fpic",
    "-fno-exceptions",
    "-ffunction-sections",
    "-funwind-tables", # static exception-like tables
    "-fstack-protector", # check guard variable before return
    "-fmessage-length=0"); # No line length limit to error messages

my @optimize_args = (
    "-O2",
    "-finline-functions",
    "-finline-limit=300",
    "-fno-inline-functions-called-once",
    "-fgcse-after-reload",
    "-frerun-cse-after-loop", # Implicit in -O2 per texinfo
    "-frename-registers",
    "-fomit-frame-pointer",
    "-fstrict-aliasing", # Implicit in -O2 per texinfo
    "-funswitch-loops");

my @link_args = (
    "-Bdynamic",
    "-Wl,-T,$DROID/build/core/armelf.x",
    "-Wl,-dynamic-linker,/system/bin/linker",
    "-Wl,--gc-sections",
    "-Wl,-z,nocopyreloc",
    "-Wl,--no-undefined",
    "-Wl,-rpath-link=$ALIB",
    "-L$ALIB",
    "-nostdlib",
    "$ALIB/crtend_android.o",
    "$ALIB/crtbegin_dynamic.o",
    "$TOOLCHAIN/lib/gcc/arm-eabi/4.2.1/interwork/libgcc.a",
    "-lc",
    "-lm");
    
# Also need: -Wl,-soname,libXXXX.so
my @shared_args = (
    "-nostdlib",
    "-Wl,-T,$DROID/build/core/armelf.xsc",
    "-Wl,--gc-sections",
    "-Wl,-shared,-Bsymbolic",
    "-L$ALIB",
    "-Wl,--no-whole-archive",
    "-lc",
    "-lm",
    "-Wl,--no-undefined",
    "$TOOLCHAIN/lib/gcc/arm-eabi/4.2.1/interwork/libgcc.a",
    "-Wl,--whole-archive"); # .a, .o input files go *after* here

# Now implement a quick parser for a gcc-like command line

my %MODES = ("-E"=>1, "-c"=>1, "-S"=>1, "-shared"=>1);

my $mode = "DEFAULT";
my $out;
my $warn = 0;
my $opt = 0;
my @args = ();
my $have_src = 0;
while(@ARGV) {
    my $a = shift;
    if(defined $MODES{$a}) {
 die "Can't specify $a and $mode" if $mode ne "DEFAULT";
 $mode = $a;
    } elsif($a eq "-o") {
 die "Missing -o argument" if !@ARGV;
 die "Duplicate -o argument" if defined $out;
 $out = shift;
    } elsif($a =~ /^-W.*/) {
 $warn = 1;
    } elsif($a =~ /^-O.*/) {
 $opt = 1;
    } else {
 if($a =~ /\.(c|cpp|cxx)$/i) { $have_src = 1; }
 push @args, $a;
    }
}

my $need_cpp = 0;
my $need_compile = 0;
my $need_link = 0;
my $need_shlink = 0;
if($mode eq "DEFAULT") { $need_cpp = $need_compile = $need_link = 1; }
if($mode eq "-E") { $need_cpp = 1; }
if($mode eq "-c") { $need_cpp = $need_compile = 1; }
if($mode eq "-S") { $need_cpp = $need_compile = 1; }
if($mode eq "-shared") { $need_shlink = 1; }

if($have_src and $mode ne "-E") { $need_cpp = $need_compile = 1; }

# Assemble the command:
my @cmd = ("arm-eabi-gcc");
if($mode ne "DEFAULT") { @cmd = (@cmd, $mode); }
if(defined $out) { @cmd = (@cmd, "-o", $out); }
if($need_cpp) { @cmd = (@cmd, @include_paths, @preprocess_args); }
if($need_compile){
    @cmd = (@cmd, @compile_args);
    if($warn) { @cmd = (@cmd, @warn_args); }
    if($opt) { @cmd = (@cmd, @optimize_args); }
}
if($need_link) { @cmd = (@cmd, @link_args); }
if($need_shlink) { @cmd = (@cmd, @shared_args); }
@cmd = (@cmd, @args);

#print join(" ", @cmd), "\n"; # Spit it out if you're curious
exec(@cmd);
但是,有一個問題是他很多的變數都是寫死得,因此有幾個地方需要修改。下面是我修改的地方。要注意的是,我下面的修改是要編譯C++的程式,如果是要編譯C的話,要記得把g++改成gcc。

  1. Line 37:將路徑修改成你電腦上的arm-eabi-g++的位置
      $GCC = "/opt/compal/android/15r1/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-g++";
  2. Line 40:將$DROID改成你電腦上Android的位置
      my $DROID = "/opt/compal/android/15r1";
  3. Line 42:一般來說,如果是build模擬器的話可以把cardhu改成generic
      my $ALIB = "$DROID/out/target/product/cardhu/obj/lib";
  4. Line 43:一樣修改arm-eabi-g++的位置
      my $TOOLCHAIN = "/opt/compal/android/15r1/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-g++";
  5. Line 119:  
      "/opt/compal/android/15r1/prebuilt/darwin-x86/toolchain/arm-eabi-4.4.3/lib/gcc/arm-eabi/4.4.3/libgcc.a",
  6. Line 134:  d
      "/opt/compal/android/15r1/prebuilt/darwin-x86/toolchain/arm-eabi-4.4.3/lib/gcc/arm-eabi/4.4.3/libgcc.a",

沒有留言: