Commit 4d17051f authored by Alexander Alekhin's avatar Alexander Alekhin

android: backport Android SDK build script

parent 9285dddb
......@@ -274,6 +274,17 @@ macro(add_android_project target path)
file(GLOB_RECURSE android_proj_jni_files "${path}/jni/*.c" "${path}/jni/*.h" "${path}/jni/*.cpp" "${path}/jni/*.hpp")
ocv_list_filterout(android_proj_jni_files "\\\\.svn")
foreach(lib "opencv_java")
get_property(f TARGET ${lib} PROPERTY LOCATION)
get_filename_component(f_name ${f} NAME)
add_custom_command(
OUTPUT "${android_proj_bin_dir}/libs/${ANDROID_NDK_ABI_NAME}/${f_name}"
COMMAND ${CMAKE_COMMAND} -E copy "${f}" "${android_proj_bin_dir}/libs/${ANDROID_NDK_ABI_NAME}/${f_name}"
DEPENDS "${lib}" VERBATIM
COMMENT "Embedding ${f}")
list(APPEND android_proj_file_deps "${android_proj_bin_dir}/libs/${ANDROID_NDK_ABI_NAME}/${f_name}")
endforeach()
if(android_proj_jni_files AND EXISTS ${path}/jni/Android.mk AND NOT DEFINED JNI_LIB_NAME)
# find local module name in Android.mk file to build native lib
file(STRINGS "${path}/jni/Android.mk" JNI_LIB_NAME REGEX "LOCAL_MODULE[ ]*:=[ ]*.*" )
......@@ -307,6 +318,7 @@ macro(add_android_project target path)
# copy opencv_java, tbb if it is shared and dynamicuda if present if FORCE_EMBED_OPENCV flag is set
if(android_proj_FORCE_EMBED_OPENCV)
set(native_deps ${android_proj_NATIVE_DEPS})
list(REMOVE_ITEM native_deps "opencv_java")
# filter out gpu module as it is always static library on Android
list(REMOVE_ITEM native_deps "opencv_gpu")
if(ENABLE_DYNAMIC_CUDA)
......
......@@ -110,6 +110,10 @@ else
OPENCV_INSTALL_MODULES:=on
endif
ifeq ($(OPENCV_INSTALL_MODULES),)
OPENCV_INSTALL_MODULES:=on
endif
define add_opencv_module
include $(CLEAR_VARS)
LOCAL_MODULE:=opencv_$1
......
package org.opencv.android;
import android.content.Context;
import android.util.Log;
/**
* Helper class provides common initialization methods for OpenCV library.
*/
public class OpenCVLoader
{
private static final String TAG = "OpenCVLoader";
/**
* OpenCV Library version 2.4.2.
*/
......@@ -62,6 +65,11 @@ public class OpenCVLoader
*/
public static final String OPENCV_VERSION_2_4_12 = "2.4.12";
/**
* OpenCV Library version 2.4.13.
*/
public static final String OPENCV_VERSION_2_4_13 = "2.4.13";
/**
* Loads and initializes OpenCV library from current application package. Roughly, it's an analog of system.loadLibrary("opencv_java").
* @return Returns true is initialization of OpenCV was successful.
......@@ -91,6 +99,11 @@ public class OpenCVLoader
public static boolean initAsync(String Version, Context AppContext,
LoaderCallbackInterface Callback)
{
if (initDebug()) {
Callback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
return true;
}
Log.w(TAG, "OpenCV binaries are not packaged with application. Trying to use OpenCV Manager...");
return AsyncServiceHelper.initOpenCV(Version, AppContext, Callback);
}
}
......@@ -10,13 +10,13 @@ class Fail(Exception):
def __str__(self):
return "ERROR" if self.t is None else self.t
def execute(cmd, shell=False):
def execute(cmd, shell=False, allowFail=False):
try:
log.info("Executing: %s" % cmd)
retcode = subprocess.call(cmd, shell=shell)
if retcode < 0:
raise Fail("Child was terminated by signal:" %s -retcode)
elif retcode > 0:
elif retcode > 0 and not allowFail:
raise Fail("Child returned: %s" % retcode)
except OSError as e:
raise Fail("Execution failed: %d / %s" % (e.errno, e.strerror))
......@@ -45,44 +45,37 @@ def check_dir(d, create=False, clean=False):
os.makedirs(d)
return d
def determine_engine_version(manifest_path):
with open(manifest_path, "rt") as f:
return re.search(r'android:versionName="(\d+\.\d+)"', f.read(), re.MULTILINE).group(1)
def determine_opencv_version(version_hpp_path):
# version in 2.4 - CV_VERSION_EPOCH.CV_VERSION_MAJOR.CV_VERSION_MINOR.CV_VERSION_REVISION
# version in master - CV_VERSION_MAJOR.CV_VERSION_MINOR.CV_VERSION_REVISION-CV_VERSION_STATUS
with open(version_hpp_path, "rt") as f:
data = f.read()
epoch = re.search(r'^#define\W+CV_VERSION_EPOCH\W+(\d+)$', data, re.MULTILINE).group(1)
major = re.search(r'^#define\W+CV_VERSION_MAJOR\W+(\d+)$', data, re.MULTILINE).group(1)
minor = re.search(r'^#define\W+CV_VERSION_MINOR\W+(\d+)$', data, re.MULTILINE).group(1)
revision = re.search(r'^#define\W+CV_VERSION_REVISION\W+(\d+)$', data, re.MULTILINE).group(1)
version_status = re.search(r'^#define\W+CV_VERSION_STATUS\W+"([^"]*)"$', data, re.MULTILINE).group(1)
return "%(major)s.%(minor)s.%(revision)s%(version_status)s" % locals()
revision = '' if revision == '0' else '.' + revision
return "%(epoch)s.%(major)s.%(minor)s%(revision)s" % locals()
#===================================================================================================
class ABI:
def __init__(self, platform_id, name, toolchain, cmake_name=None):
def __init__(self, platform_id, name, toolchain, api_level=8, cmake_name=None):
self.platform_id = platform_id # platform code to add to apk version (for cmake)
self.name = name # general name (official Android ABI identifier)
self.toolchain = toolchain # toolchain identifier (for cmake)
self.api_level = api_level
self.cmake_name = cmake_name # name of android toolchain (for cmake)
if self.cmake_name is None:
self.cmake_name = self.name
def __str__(self):
return "%s (%s)" % (self.name, self.toolchain)
def haveIPP(self):
return self.name == "x86" or self.name == "x86_64"
ABIs = [
ABI("2", "armeabi-v7a", "arm-linux-androideabi-4.8", cmake_name="armeabi-v7a with NEON"),
ABI("1", "armeabi", "arm-linux-androideabi-4.8"),
ABI("3", "arm64-v8a", "aarch64-linux-android-4.9"),
ABI("5", "x86_64", "x86_64-4.9"),
ABI("4", "x86", "x86-4.8"),
ABI("7", "mips64", "mips64el-linux-android-4.9"),
ABI("6", "mips", "mipsel-linux-android-4.8")
ABI("2", "armeabi-v7a", "arm-linux-androideabi-4.6", cmake_name="armeabi-v7a with NEON"),
ABI("1", "armeabi", "arm-linux-androideabi-4.6"),
ABI("4", "x86", "x86-clang3.1", api_level=9),
ABI("6", "mips", "mipsel-linux-android-4.6", api_level=9)
]
#===================================================================================================
......@@ -91,38 +84,30 @@ class Builder:
def __init__(self, workdir, opencvdir):
self.workdir = check_dir(workdir, create=True)
self.opencvdir = check_dir(opencvdir)
self.extra_modules_path = None
self.libdest = check_dir(os.path.join(self.workdir, "o4a"), create=True, clean=True)
self.docdest = check_dir(os.path.join(self.workdir, "javadoc"), create=True, clean=True)
self.resultdest = check_dir(os.path.join(self.workdir, "OpenCV-android-sdk"), create=True, clean=True)
self.extra_packs = []
self.opencv_version = determine_opencv_version(os.path.join(self.opencvdir, "modules", "core", "include", "opencv2", "core", "version.hpp"))
self.engine_version = determine_engine_version(os.path.join(self.opencvdir, "platforms", "android", "service", "engine", "AndroidManifest.xml"))
self.use_ccache = True
def get_toolchain_file(self):
return os.path.join(self.opencvdir, "platforms", "android", "android.toolchain.cmake")
def get_engine_apk_dest(self, engdest):
return os.path.join(engdest, "platforms", "android", "service", "engine", ".build")
def add_extra_pack(self, ver, path):
if path is None:
return
self.extra_packs.append((ver, check_dir(path)))
def clean_library_build_dir(self):
for d in ["CMakeCache.txt", "CMakeFiles/", "bin/", "libs/", "lib/", "package/", "install/samples/"]:
rm_one(d)
def build_library(self, abi, do_install):
def build_library(self, abi, do_install, build_docs):
cmd = [
"cmake",
"-GNinja",
"-DCMAKE_TOOLCHAIN_FILE='%s'" % self.get_toolchain_file(),
"-DWITH_OPENCL=OFF",
"-DWITH_CUDA=OFF",
"-DWITH_IPP=%s" % ("ON" if abi.haveIPP() else "OFF"),
"-DINSTALL_CREATE_DISTRIB=ON",
#"-DWITH_OPENCL=OFF",
"-DWITH_CUDA=OFF", "-DBUILD_opencv_gpu=OFF",
"-DBUILD_opencv_nonfree=OFF",
"-DWITH_TBB=OFF",
"-DWITH_IPP=OFF",
"-DBUILD_EXAMPLES=OFF",
"-DBUILD_TESTS=OFF",
"-DBUILD_PERF_TESTS=OFF",
......@@ -130,68 +115,28 @@ class Builder:
"-DBUILD_ANDROID_EXAMPLES=ON",
"-DINSTALL_ANDROID_EXAMPLES=ON",
"-DANDROID_STL=gnustl_static",
"-DANDROID_NATIVE_API_LEVEL=9",
"-DANDROID_NATIVE_API_LEVEL=%s" % abi.api_level,
"-DANDROID_ABI='%s'" % abi.cmake_name,
"-DWITH_TBB=ON",
"-DANDROID_TOOLCHAIN_NAME=%s" % abi.toolchain
]
if self.extra_modules_path is not None:
cmd.append("-DOPENCV_EXTRA_MODULES_PATH='%s'" % self.extra_modules_path)
cmd.append(self.opencvdir)
if self.use_ccache == True:
cmd.append("-DNDK_CCACHE=ccache")
if do_install:
cmd.extend(["-DBUILD_TESTS=ON", "-DINSTALL_TESTS=ON"])
if do_install and build_docs:
cmd.extend(["-DBUILD_DOCS=ON"])
execute(cmd)
if do_install:
execute(["ninja"])
for c in ["libs", "dev", "java", "samples"]:
execute(["cmake", "--build", "."])
if do_install and build_docs:
execute(["cmake", "--build", ".", "--target", "docs"])
for c in ["libs", "dev", "java", "samples"] + (["docs"] if do_install and build_docs else []):
execute(["cmake", "-DCOMPONENT=%s" % c, "-P", "cmake_install.cmake"])
else:
execute(["ninja", "install/strip"])
def build_engine(self, abi, engdest):
cmd = [
"cmake",
"-GNinja",
"-DCMAKE_TOOLCHAIN_FILE='%s'" % self.get_toolchain_file(),
"-DANDROID_ABI='%s'" % abi.cmake_name,
"-DBUILD_ANDROID_SERVICE=ON",
"-DANDROID_PLATFORM_ID=%s" % abi.platform_id,
"-DWITH_CUDA=OFF",
"-DWITH_OPENCL=OFF",
"-DWITH_IPP=OFF",
self.opencvdir
]
execute(cmd)
apkdest = self.get_engine_apk_dest(engdest)
# Add extra data
apkxmldest = check_dir(os.path.join(apkdest, "res", "xml"), create=True)
apklibdest = check_dir(os.path.join(apkdest, "libs", abi.name), create=True)
for ver, d in self.extra_packs + [("3.1.0", os.path.join(self.libdest, "lib"))]:
r = ET.Element("library", attrib={"version": ver})
log.info("Adding libraries from %s", d)
for f in glob.glob(os.path.join(d, abi.name, "*.so")):
log.info("Copy file: %s", f)
shutil.copy2(f, apklibdest)
if "libnative_camera" in f:
continue
log.info("Register file: %s", os.path.basename(f))
n = ET.SubElement(r, "file", attrib={"name": os.path.basename(f)})
if len(list(r)) > 0:
xmlname = os.path.join(apkxmldest, "config%s.xml" % ver.replace(".", ""))
log.info("Generating XML config: %s", xmlname)
ET.ElementTree(r).write(xmlname, encoding="utf-8")
execute(["ninja", "opencv_engine"])
execute(["ant", "-f", os.path.join(apkdest, "build.xml"), "debug"],
shell=(sys.platform == 'win32'))
# TODO: Sign apk
execute(["cmake", "--build", ".", "--target", "install/strip"])
def build_javadoc(self):
classpaths = [os.path.join(self.libdest, "bin", "classes")]
......@@ -201,6 +146,7 @@ class Builder:
classpaths.append(os.path.join(dir, f))
cmd = [
"javadoc",
"-encoding", "UTF-8",
"-header", "OpenCV %s" % self.opencv_version,
"-nodeprecated",
"-footer", '<a href="http://docs.opencv.org">OpenCV %s Documentation</a>' % self.opencv_version,
......@@ -211,9 +157,9 @@ class Builder:
]
for _, dirs, _ in os.walk(os.path.join(self.libdest, "src", "org", "opencv")):
cmd.extend(["org.opencv." + d for d in dirs])
execute(cmd)
execute(cmd, allowFail=True) # FIXIT javadoc currenly reports some errors
def gather_results(self, engines):
def gather_results(self, with_samples_apk):
# Copy all files
root = os.path.join(self.libdest, "install")
for item in os.listdir(root):
......@@ -226,13 +172,6 @@ class Builder:
log.info("Copy file: %s", item)
shutil.copy2(item, os.path.join(self.resultdest, name))
# Copy engines for all platforms
for abi, engdest in engines:
log.info("Copy engine: %s (%s)", abi, engdest)
f = os.path.join(self.get_engine_apk_dest(engdest), "bin", "opencv_engine-debug.apk")
resname = "OpenCV_%s_Manager_%s_%s.apk" % (self.opencv_version, self.engine_version, abi)
shutil.copy2(f, os.path.join(self.resultdest, "apk", resname))
# Copy javadoc
log.info("Copy docs: %s", self.docdest)
shutil.copytree(self.docdest, os.path.join(self.resultdest, "sdk", "java", "javadoc"))
......@@ -244,6 +183,9 @@ class Builder:
if os.path.isdir(item):
for name in ["build.xml", "local.properties", "proguard-project.txt"]:
rm_one(os.path.join(item, name))
if not with_samples_apk:
if re.search(r'\.apk$', item): # reduce size of SDK
rm_one(item)
#===================================================================================================
......@@ -254,11 +196,10 @@ if __name__ == "__main__":
parser.add_argument("opencv_dir", help="Path to OpenCV source dir")
parser.add_argument('--ndk_path', help="Path to Android NDK to use for build")
parser.add_argument('--sdk_path', help="Path to Android SDK to use for build")
parser.add_argument("--extra_modules_path", help="Path to extra modules to use for build")
parser.add_argument('--sign_with', help="Sertificate to sign the Manager apk")
parser.add_argument('--build_doc', action="store_true", help="Build javadoc")
parser.add_argument('--build_doc', action="store_true", help="Build documentation")
parser.add_argument('--build_javadoc', action="store_true", help="Build javadoc")
parser.add_argument('--no_ccache', action="store_true", help="Do not use ccache during library build")
parser.add_argument('--extra_pack', action='append', help="provide extra OpenCV libraries for Manager apk in form <version>:<path-to-native-libs>, for example '2.4.11:unpacked/sdk/native/libs'")
parser.add_argument('--with_samples_apk', action="store_true", help="Include samples APKs")
args = parser.parse_args()
log.basicConfig(format='%(message)s', level=log.DEBUG)
......@@ -274,27 +215,13 @@ if __name__ == "__main__":
builder = Builder(args.work_dir, args.opencv_dir)
if args.extra_modules_path is not None:
builder.extra_modules_path = os.path.abspath(args.extra_modules_path)
if args.no_ccache:
builder.use_ccache = False
log.info("Detected OpenCV version: %s", builder.opencv_version)
log.info("Detected Engine version: %s", builder.engine_version)
if args.extra_pack:
for one in args.extra_pack:
i = one.find(":")
if i > 0 and i < len(one) - 1:
builder.add_extra_pack(one[:i], one[i+1:])
else:
raise Fail("Bad extra pack provided: %s, should be in form '<version>:<path-to-native-libs>'" % one)
engines = []
for i, abi in enumerate(ABIs):
do_install = (i == 0)
engdest = check_dir(os.path.join(builder.workdir, "build_service_%s" % abi.name), create=True, clean=True)
log.info("=====")
log.info("===== Building library for %s", abi)
......@@ -302,20 +229,12 @@ if __name__ == "__main__":
os.chdir(builder.libdest)
builder.clean_library_build_dir()
builder.build_library(abi, do_install)
log.info("=====")
log.info("===== Building engine for %s", abi)
log.info("=====")
os.chdir(engdest)
builder.build_engine(abi, engdest)
engines.append((abi.name, engdest))
builder.build_library(abi, do_install, build_docs=args.build_doc)
if args.build_doc:
if args.build_doc or args.build_javadoc:
builder.build_javadoc()
builder.gather_results(engines)
builder.gather_results(with_samples_apk=args.with_samples_apk)
log.info("=====")
log.info("===== Build finished")
......
......@@ -2,5 +2,3 @@ if(BUILD_ANDROID_SERVICE)
add_subdirectory(engine)
#add_subdirectory(engine_test)
endif()
install(FILES "readme.txt" DESTINATION "apk/" COMPONENT libs)
......@@ -79,3 +79,11 @@ OpenCV version constants
.. data:: OPENCV_VERSION_2_4_11
OpenCV Library version 2.4.11
.. data:: OPENCV_VERSION_2_4_12
OpenCV Library version 2.4.12
.. data:: OPENCV_VERSION_2_4_13
OpenCV Library version 2.4.13
How to select the proper version of OpenCV Manager
--------------------------------------------------
DEPRECATED: This information is outdated since OpenCV 2.4.12
Since version 1.7 several packages of OpenCV Manager are built. Every package is targeted for some
specific hardware platform and includes corresponding OpenCV binaries. So, in most cases OpenCV
Manager uses built-in version of OpenCV. Separate package with OpenCV binaries is currently used in
......
......@@ -3,7 +3,6 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
#OPENCV_CAMERA_MODULES:=off
#OPENCV_INSTALL_MODULES:=off
#OPENCV_LIB_TYPE:=SHARED
include ../../sdk/native/jni/OpenCV.mk
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment