반응형

목표

android 프로젝트에 포함된 네이티브소스(c++)에서 crypto++라이브러리를 사용

 

 

환경

OS

: Windows 10

 

빌드환경(crypto++)

: MINGW32

 

빌드 툴(crypto++을 사용하는 Project)

: Android Studio 4.1

 

빌드 절차

1. crypto++ 라이브러리를 NDK로 빌드하여 동적라이브러리 생성

( Android Studio를 이용하여 함께 빌드하도록 구성하는 방법도 존재하겠으나, 성공하지 못했고

매번 빌드하는것보다는 미리 빌드해놓고 링크하는 것이 효율적이므로, 별도로 빌드하는 방식을 채택)

 

2. 빌드된 동적라이브러리(.so)파일을 링크하여 사용하도록 android.mk 구성

 

 

여기서 기술하는 내용은 아래의 github 프로젝트를 기반으로 하였으며,

 

noloader/cryptopp-android-mk

Android.mk build files for Crypto++ project . Contribute to noloader/cryptopp-android-mk development by creating an account on GitHub.

github.com

추가로 설정해야 하는 환경변수관련 내용과

Window 에서 빌드 할때만 발생할 것으로 추정되는 문제

그리고, Android Project에서 빌드된 동적라이브러리(libcrypto++.so)를 링크하는 방법을

추가 하였다.

( NDK 빌드를 포함하는 Android Project 경험이 있는 상황을 가정하며

사용되는 툴에 대한 설명이나, NDK 를 사용하는 프로젝트 구성등은 다루지 않는다. )

 

 

1. crypto++ 라이브러리를 NDK로 빌드로 빌드하여 동적라이브러리 생성

1) Crypto++ 소스파일 다운로드

https://github.com/weidai11/cryptopp 프로젝트 소스를 다운로드 받아 압축을 해제한다.

* 이후의 과정은 Shell을 통해 실행한다.

 

2) 빌드 스크립트 복사

(다운받은 압축파일에는 cryptopp 소스과 [TestScripts]내에 crypto++을 빌드 할수 있는 스크립트가 존재한다.

여러 가지 빌드 스크립트 중 cryptest-android-mk.sh 를 사용한다.)

(1) 소스 폴더 내로 이동한 후 다음 명령어를 통해 [TestScripts]폴더의 cryptest-android-mk.sh을 소스파일이 있는 폴더로 복사한다.

cp -p TestScripts/cryptest-android-mk.sh .

 

3) 환경변수 설정

다음의 명령어를 통해 빌드 스크립트를 실행하면 되지만

$bash cryptest-android-mk.sh

아마도 다음과 같은 에러가 발생할 확률이 높다.

ERROR: ANDROID_NDK_ROOT is not a valid path for . Please set it
ANDROID_NDK_ROOTis ''
ERROR: ANDROID_SDK_ROOT is not a valid path for . Please set it
ANDROID_SDK_ROOT is ''

빌드에 필요한 Android ndk와 sdk 경로가 설정되지 않을 경우 발생하는 에러로

 

a. 환경변수를 등록하거나

b. shell 실행파라미터로 설정해주면 되지만

 

설명이 길어지니 cryptest-android-mk.sh 파일을 직접 수정하도록 한다.

cryptest-android-mk.sh 을 편집기로 오픈한 후, 다음과 1행과 2행을 추가해 주면 된다.

ANDROID_NDK_ROOT="/c/Users/xxxx/AppData/Local/Android/Sdk/ndk/20.1.5948944"
ANDROID_SDK_ROOT="/c/Users/xxxx/AppData/Local/Android/Sdk"

# Error checking
if [ ! -d "${ANDROID_NDK_ROOT}" ]; then
    echo "ERROR: ANDROID_NDK_ROOT is not a valid path for ${USER}. Please set it."
    echo "ANDROID_NDK_ROOT is '${ANDROID_NDK_ROOT}'"
    exit 1
fi

# Error checking
if [ ! -d "${ANDROID_SDK_ROOT}" ]; then
    echo "ERROR: ANDROID_SDK_ROOT is not a valid path for ${USER}. Please set it."
    echo "ANDROID_SDK_ROOT is '${ANDROID_SDK_ROOT}'"
    exit 1
fi

 

* 기술해야 하는 경로는 Android Studio의 [File>Project Structure...] 메뉴를 선택 후, SDK Location에서 확인 할 수 있다.

 

4) (아마도 windows에서 발생하는) ndk-build 관련 에러

위의 설정을 마친 후 빌드 커맨드를 실행하면 ndk-build관련 에러가 발생한다.

ERROR: ndk-build is not on-path for . Please set it

cryptest-android-mk.sh 을 편집기로 오픈한 후, ndk-build 라고 기술된 부분을 ndk-build.cmd 로 변경해 준다.

( 총 3군데가 존재한다)

# Error checking
if [ -z "$(command -v ndk-build.cmd 2>/dev/null)"  ]; then
    echo "ERROR: ndk-build is not on-path for ${USER}. Please set it."
    echo "PATH is '${PATH}'"
    exit 1
fi

 

# Clean all past artifacts
ndk-build.cmd APP_ABI=all NDK_PROJECT_PATH="${NDK_PROJECT_PATH}" NDK_APPLICATION_MK="${NDK_APPLICATION_MK}" distclean &>/dev/null

 

if ndk-build.cmd -j "${MAKE_JOBS}" APP_ABI="${platform}" NDK_PROJECT_PATH="${NDK_PROJECT_PATH}" NDK_APPLICATION_MK="${NDK_APPLICATION_MK}" V=1;

(제공되는 빌드 스크립트는 linux를 기준으로 작성되어있고, linux는 ndk-build, windows는 ndk-build.cmd 가 아닌가 추정해 본다)

 

5) 빌드

이제 빌드 스크립트를 실행하여 crypto++라이브러리를 빌드한다.

$bash cryptest-android-mk.sh

정상적이라면 빌드에 사용될 Android.mk와 Application.mk를 다운받은 후, 빌드가 진행된다.

추가로 다운로드 되는 hxx,cxx은 라이브러리 테스트를 위한 소스로 크게 신경쓰지 않아도 된다.

기본적으로 4개의 플랫폼용 라이브러리를 생성하며 문제없이 생성이 완료되면 아래와 같이 표시된다.

빌드시 시간이 꽤 소요되는데, 필요한 플랫폼만 빌드하려면 sh파일의 아래 부분에 필요한 플랫폼만 기술하면 된다.

PLATFORMS=(armeabi-v7a arm64-v8a x86 x86_64)

 

6)라이브러리 확인

빌드를 실행한 폴더의 [libs] 폴더에 각 플랫폼별 바이너리(*.so)가 생성된다.

각각의 폴더 내에는 아래와 같은 4개의 파일이 생성되는데

실제 crypto++ 라이브러리 구동에 필요한 파일은

 

libcryptopp_shared.so 와 

libc++_shared.so 파일이다

(나머지는 라이브러리 테스트를 위한 파일이므로 무시한다)

 

libcryptopp_shared.so 는 crypto++의 구현을 포함하고 있는 라이브러리 이며

libc++_shared.so 는 C++ 표준 라이브러리 이다.

 

libcryptopp_shared.so 이 정상적으로 로드되기 위해서는 libc++_shared.so이 필수적으로 필요한데

이에 대해서는 아래에서 다시 설명한다.

 

2) 빌드된 동적라이브러리(.so)파일을 링크하여 사용하도록 android.mk 구성

1) 폴더 구성

이제 libcryptopp_shared.so를 링크하기 위해 빌드된 libcryptopp_shared.so 파일을 android 프로젝트에 복사해야 한다.

기존의 Native code(c++) 파일들이 [Project Root]/app/src/main/jni]폴더 에 존재하고

crypto++ 관련 headr파일은 [jni/include/cryptopp]에

crypto++ 관련 라이브러리는 [jni/libs/cryptopp]에 위치하도록 구성하는 것을 가정한다.

 

2) 파일 복사

빌드에 사용된 crypto++ 소스중 헤더파일(h)을  [jni/include/cryptopp] 폴더에 복사하고

빌드된 crypto++ 라이브러리를 [jni/libs/cryptopp]에 복사한다.

( 지원하고자 하는 플랫폼(ABI)에 해당하는 폴더를 복사하면 되며, so 파일 중 libcryptopp_shared.so 만 복사한다. 

libc++_shared.so 파일은 Android.mk구성을 통해 NDK의 표준 파일을 사용하도록 구성한다.)

아래와 같은 형태로 구성되면 되겠다.

jni

 - libs

      - cryptopp

           - arm64-v8a / libcryptopp_shared.so                 

           - armeabi-v7a / libcryptopp_shared.so

           - x86 / libcryptopp_shared.so

           - x86_64 / libcryptopp_shared.so

 

3) crypto++ 링크를 위한 Android.mk 구성

이제 기존의 모듈이 crypto++ 파일을 포함하도록 android.mk를 구성하면 된다.

foo.cpp 소스가 crypto++ 라이브러리를 사용한다 가정할때 아래와 같은 구성으로 cryptopp를 링크 할 수 있다.

OCAL_C_INCLUDES += $(LOCAL_PATH)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include/cryptopp
LOCAL_MODULE    := foo
LOCAL_SRC_FILES := foo.cpp
LOCAL_LDLIBS += -llog -ldl
LOCAL_SHARED_LIBRARIES += cryptopp
include $(BUILD_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_PATH = $(ROOT_PATH)
LOCAL_MODULE := cryptopp
LOCAL_SRC_FILES := $(LOCAL_PATH)/libs/cryptopp/$(TARGET_ARCH_ABI)/libcryptopp_shared.so
LOCAL_SHARED_LIBRARIES += c++_shared
include $(PREBUILT_SHARED_LIBRARY)

 

* 라인별로 추가 설명을 해보자면 대략 다음과 같다.

LOCAL_C_INCLUDES += $(LOCAL_PATH)/include/cryptopp

- crypto++ 헤더 참조를 위해 include 경로를 설정한다.

 

LOCAL_SHARED_LIBRARIES += cryptopp

- foo 모듈에서 cryptopp 라이브러리를 참조함을 표시한다.

 

LOCAL_SRC_FILES := $(LOCAL_PATH)/libs/cryptopp/$(TARGET_ARCH_ABI)/libcryptopp_shared.so

- cryptopp모듈의 소스가 지정된 경로의 에서 libcryptopp_shared.so 파일임을 나타낸다.

- $(LOCAL_PATH)/libs/cryptopp/$(TARGET_ARCH_ABI) 는  [jni/libs/cryptopp] 폴더내의 각 플랫폼별 폴더를 지칭한다.

 

LOCAL_SHARED_LIBRARIES += c++_shared

- cryptopp 모듈이 c++_shared(즉 libc++_shared)를 링크함을 나타낸다.

- libcryptopp_shared.so 시 생성된 libc++_shared.so를 지정하여 기술해도 되지만 이경우 중복참조 warnnig이 발생한다.

- c++_shared 로 지정하여 NDK 기본 라이브러리를 사용하도록 설정한다.(결국은 같은 파일이긴 하다)

 

include $(PREBUILT_SHARED_LIBRARY)

- 이미 빌드된 라이브러리(*.so)를 포함하는 것을 나타낸다.

 

플래폼에 따라 오픈소스를 빌드하는건 항상 시행착오와 시간 투자를 요구하는거 같다. ㅡㅡ^

 

반응형

+ Recent posts