android-ndk-r6でopensslを動かす
これは本当に苦労しました。。。泣きました。。。
とりあえず改めて環境の確認ですが
# 環境
Windows7
Eclipse 3.6 Helios
Cygwin
となっています。
# 環境変数の設定
export NDK_DIR=/cygdrive/c/bin/android-ndk-r6
export ANDROID_NDK_ROOT=/cygdrive/c/bin/android-ndk-r6
export PATH=$PATH:$ANDROID_NDK_ROOT
export STLPORT_DIR=$ANDROID_NDK_ROOT/sources/cxx-stl/stlport
こんな感じで設定しています
# まずはgitにてopensslのソースの取得
NDK用のopensslはココで公開されています。
$ cd $NDK_DIR
$ git clone git://android.git.kernel.org/platform/external/openssl.git
で早速ndk-buildしてみるのですが、どんな環境変数、.mkを設定しても絶対に存在しない「jni」の下のAndroid.mkを見に行くので、もう諦めて作成します。
$ cd $NDK_DIR/source/openssl
$ mkdir jni
$ cp -a Android.mk jni
$ ndk-build NDK_LOG=1
で改めてndk-buildするのですが、さっぱりわからずWebを探し回っていたら、この記事にぶつかりました。
まあとりあえずやってみるしかないので、この通りの手順+α(後述)でコンパイルが若干進みました。
1.
# Give the NDK build system the Application.mk it needs. I couldn't
find a way to specify this manually, and it seems the jni bit is
hardcoded.
mkdir jni
と言っているので、ああやっぱり必要なんだね。みたいな
2.
echo "APP_PROJECT_PATH := $(pwd)" >> jni/Application.mk
echo "APP_BUILD_SCRIPT := $(APP_PROJECT_PATH)/Android.mk" >> jni/
Application.mk
との事でApplication.mkをjniの下に作成しました。
APP_PROJECT_PATH := $(call my-dir)
APP_BUILD_SCRIPT := $(APP_PROJECT_PATH)/Android.mk
3.
# Edit crypto/Android to fix the include paths.
nano crypto/Android.mk# Change the last bits to:
#################
LOCAL_C_INCLUDES += \
$(NDK_PROJECT_PATH) \
$(NDK_PROJECT_PATH)/include
# external/zlib# LOCAL_SHARED_LIBRARIES += libz
#ifneq ($(TARGET_SIMULATOR),true)
# LOCAL_SHARED_LIBRARIES += libdl
#endifLOCAL_LDLIBS += -lz
# LOCAL_LDLIBS += -ldl
#################Then it actually starts successfully compiling things, but gets stuck
at some assembly stuff.
と言っております。
確かにさっきndk-buildした際に、多くのヘッダーファイルがNo such or directoryだったので
修正が必要なんだな。
「external/」とか今の状況でみれば意味がわからないし。。。
ただ、LOCAL_C_INCLUDESに関しては上記だと不足だと思います。
なので、私は付け足しをしました。
修正した「crypt/Android.mk」を載せます。
変更箇所を赤でハイライトします。
LOCAL_PATH:= $(call my-dir)arm_cflags := -DOPENSSL_BN_ASM_MONT -DAES_ASM -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM
arm_src_files := \
aes/asm/aes-armv4.S \
bn/asm/armv4-mont.S \
sha/asm/sha1-armv4-large.S \
sha/asm/sha256-armv4.S \
sha/asm/sha512-armv4.S
non_arm_src_files := aes/aes_core.c
local_src_files := \
cryptlib.c \
<-- ここは変更なし -->local_c_includes := \
external/openssl \
external/openssl/crypto/asn1 \
external/openssl/crypto/evp \
external/openssl/include \
external/openssl/include/openssl \
external/zliblocal_c_flags := -DNO_WINDOWS_BRAINDEATH
#######################################
# target
include $(CLEAR_VARS)
include $(LOCAL_PATH)/../android-config.mk
LOCAL_SRC_FILES += $(local_src_files)
LOCAL_CFLAGS += $(local_c_flags)
#LOCAL_C_INCLUDES += $(local_c_includes)
LOCAL_C_INCLUDES += $(NDK_PROJECT_PATH) \
$(NDK_PROJECT_PATH)/include \
$(NDK_PROJECT_PATH)/include/openssl \
$(NDK_PROJECT_PATH)/crypto \
$(NDK_PROJECT_PATH)/crypto/asn1 \
$(NDK_PROJECT_PATH)/crypto/evp
#LOCAL_SHARED_LIBRARIES += libz
ifeq ($(TARGET_ARCH),arm)
LOCAL_SRC_FILES += $(arm_src_files)
LOCAL_CFLAGS += $(arm_cflags)
else
LOCAL_SRC_FILES += $(non_arm_src_files)
endif
#ifeq ($(TARGET_SIMULATOR),true)
# # Make valgrind happy.
# LOCAL_CFLAGS += -DPURIFY
# LOCAL_LDLIBS += -ldl
#else
# LOCAL_SHARED_LIBRARIES += libdl
#endif
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE:= libcrypto
include $(BUILD_SHARED_LIBRARY)#######################################
# host shared library
ifeq ($(WITH_HOST_DALVIK),true)
include $(CLEAR_VARS)
include $(LOCAL_PATH)/../android-config.mk
LOCAL_SRC_FILES += $(local_src_files)
LOCAL_CFLAGS += $(local_c_flags) -DPURIFY
LOCAL_C_INCLUDES += $(local_c_includes)
LOCAL_SRC_FILES += $(non_arm_src_files)
LOCAL_STATIC_LIBRARIES += libz
#LOCAL_LDLIBS += -ldl
LOCAL_LDLIBS += -lz
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE:= libcrypto
include $(BUILD_HOST_SHARED_LIBRARY)
endif########################################
# host static library, which is used by some SDK tools.include $(CLEAR_VARS)
include $(LOCAL_PATH)/../android-config.mk
LOCAL_SRC_FILES += $(local_src_files)
LOCAL_CFLAGS += $(local_c_flags) -DPURIFY
LOCAL_C_INCLUDES += $(local_c_includes)
LOCAL_SRC_FILES += $(non_arm_src_files)
LOCAL_STATIC_LIBRARIES += libz
#LOCAL_LDLIBS += -ldl
LOCAL_LDLIBS += -lz
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE:= libcrypto_static
#include $(BUILD_HOST_STATIC_LIBRARY)
include $(BUILD_STATIC_LIBRARY)
それで、ここからはndk-build NDK_LOG=1との戦いなのですが、初めて全うにコンパイルが始まりました。
ですが暫くすると下記のエラーが
dso_dlfcn.c:445: error: 'Dl_info' undeclared (first use in this function)
これはもうわからないので、こちらのエントリを勝手に信じて(笑)関数を以下のようにすべてコメントアウトしました。
static int dlfcn_pathbyaddr(void *addr,char *path,int sz)
{
/*
#ifdef HAVE_DLINFO
Dl_info dli;
int len;if (addr == NULL)
{
union { int(*f)(void*,char*,int); void *p; } t =
{ dlfcn_pathbyaddr };
addr = t.p;
}if (dladdr(addr,&dli))
{
len = (int)strlen(dli.dli_fname);
if (sz <= 0) return len+1;
if (len >= sz) len=sz-1;
memcpy(path,dli.dli_fname,len);
path[len++]=0;
return len;
}ERR_add_error_data(4, "dlfcn_pathbyaddr(): ", dlerror());
#endif
*/
return -1;
}
次に出たエラーは
make: execvp: /cygdrive/c/bin/android-ndk-r6/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/bin/arm-linux-androideabi-g++: Argument list too long
このサイトによると
1/ Try installing the NDK and your project in top-level directories to make
the final build commands smaller. What I mean would be:
- install the ndk as /cygdrive/c/ndkr5/
- put your project under /cydrive/c/myproj/
2/ Try generating static libraries that contain fewer object files. I.e.
instead of generating libfoo.a, try to make libfoo1.a + libfoo2.a +
libfoo3.a, where each one only contains a third of the object files. Not
ideal, but would help to reduce the size of the static archive command.
との事なので、とりあえず$NDK_DIRを"/cygdrive/c/ndk"に変更して、環境変数も変更しました
#export NDK_DIR=/cygdrive/c/bin/android-ndk-r6
export NDK_DIR=/cygdrive/c/ndk
#export ANDROID_NDK_ROOT=/cygdrive/c/bin/android-ndk-r6
export ANDROID_NDK_ROOT=/cygdrive/c/ndk
で改めて、「 /cygdrive/c/ndk/sources/openssl」でndk-buile NDK_LOG=1します。
いよいよ行けるか!と思ったのですがやっぱりまたエラー。。。
SharedLibrary : libcrypto.so
arm-linux-androideabi-g++.exe: CreateProcess: No such file or directory
で、別にSharedLibraryじゃなくて良いので(むしろstaticの方が良いかも)なので
※どうしても共有ライブラリにしたい方、すみません。
crypto/Android.mkの513行目あたりを「include $(BUILD_STATIC_LIBRARY)」に書き換えて再度ndk-buile NDK_LOG=1すると
の記載が!!!
StaticLibrary : libcrypto.a
ただし、libssl.soでまた落ちましたがこれは一旦無視で
(とりあえず、ssl/Android.mkを「include $(BUILD_STATIC_LIBRARY)」に書き換えておきました)
で見てみると、libcrypto.aがきちんと生成されていました。
$ cd /cygdrive/c/ndk/sources/openssl/obj/local/armeabi
それで、コイツを自分のプロジェクトに組み込みたいので
※私の自作のEclipse Workspaceは「/cygdrive/d/Develop/Eclipse/」以下になっています。
/cygdrive/d/Develop/Eclipse//jni/libs/
の下にコピーします
# openssl以下のフォルダをコピーします。
includeファイルが当然必要なので、コピーしますがとりあえずメンドクサイから全部「/cygdrive/d/Develop/Eclipse/
# 自分の該当プロジェクトのAndroid.mkを変更します。
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)
LOCAL_MODULE := モジュール名
LOCAL_SRC_FILES := ファイル名
LOCAL_LDLIBS := -llog -L$(LOCAL_PATH)/libs -ldebug
LOCAL_C_INCLUDES += $(LOCAL_PATH)/openssl \
$(LOCAL_PATH)/openssl/include \
$(LOCAL_PATH)/openssl/include/openssl \
$(LOCAL_PATH)/openssl/crypto \
$(LOCAL_PATH)/openssl/crypto/asn1 \
$(LOCAL_PATH)/openssl/crypto/evp
LOCAL_CFLAGS += $(LOCAL_C_INCLUDES:%=-I%)include $(BUILD_SHARED_LIBRARY)
でJNI側で適当に「#include "aes.h"」とかして関数を呼んで、ndk-buildでOK!
長かった。。。
■2011/08/01 追記
関数を呼んで「C:/ndk/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/bin/../lib/gcc/arm-linux-androideabi/4.4.3/../../../../arm-linux-androideabi/bin/ld.exe: cannot find -l./libcrypto: ld returned 1 exit statusmake: *** [/cygdrive/d/Develop/Eclipse/
」
とかエラーが出たら、LOCAL_LDLIBSの設定を以下のように変えてみて下さい。
※ミソはhost-pathみたいです。
LOCAL_LDLIBS := -ldl -llog $(call host-path, $(LOCAL_PATH)/libs/libcrypto.a)
ちなみにディレクトリ構成はこんな感じです
[\\D:\Develop\Eclipse]
└ MyProject(+)
└ jni(+)
├ openssl # includeファイルなど
├ Application.mk
├ Android.mk
├ xxxx.h
├ xxxx.cpp
└ libs
└ libcrypto.a
└ res(+)
└ src(+)
└ AndroidManifest.xml
(など。他のDir/Fileは省略)
多分正しくは「LOCAL_STATIC_LIBRARIES」なんでしょうけど、良くわからない&「LOCAL_LDLIBS」で出来るっぽいので(これ導きだすのに6時間も掛かりました。。。)とりあえず良しとしました。