Skip to content

Commit 4d17051

Browse files
committed
android: backport Android SDK build script
1 parent 9285ddd commit 4d17051

File tree

8 files changed

+77
-122
lines changed

8 files changed

+77
-122
lines changed

cmake/OpenCVDetectAndroidSDK.cmake

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,17 @@ macro(add_android_project target path)
274274
file(GLOB_RECURSE android_proj_jni_files "${path}/jni/*.c" "${path}/jni/*.h" "${path}/jni/*.cpp" "${path}/jni/*.hpp")
275275
ocv_list_filterout(android_proj_jni_files "\\\\.svn")
276276

277+
foreach(lib "opencv_java")
278+
get_property(f TARGET ${lib} PROPERTY LOCATION)
279+
get_filename_component(f_name ${f} NAME)
280+
add_custom_command(
281+
OUTPUT "${android_proj_bin_dir}/libs/${ANDROID_NDK_ABI_NAME}/${f_name}"
282+
COMMAND ${CMAKE_COMMAND} -E copy "${f}" "${android_proj_bin_dir}/libs/${ANDROID_NDK_ABI_NAME}/${f_name}"
283+
DEPENDS "${lib}" VERBATIM
284+
COMMENT "Embedding ${f}")
285+
list(APPEND android_proj_file_deps "${android_proj_bin_dir}/libs/${ANDROID_NDK_ABI_NAME}/${f_name}")
286+
endforeach()
287+
277288
if(android_proj_jni_files AND EXISTS ${path}/jni/Android.mk AND NOT DEFINED JNI_LIB_NAME)
278289
# find local module name in Android.mk file to build native lib
279290
file(STRINGS "${path}/jni/Android.mk" JNI_LIB_NAME REGEX "LOCAL_MODULE[ ]*:=[ ]*.*" )
@@ -307,6 +318,7 @@ macro(add_android_project target path)
307318
# copy opencv_java, tbb if it is shared and dynamicuda if present if FORCE_EMBED_OPENCV flag is set
308319
if(android_proj_FORCE_EMBED_OPENCV)
309320
set(native_deps ${android_proj_NATIVE_DEPS})
321+
list(REMOVE_ITEM native_deps "opencv_java")
310322
# filter out gpu module as it is always static library on Android
311323
list(REMOVE_ITEM native_deps "opencv_gpu")
312324
if(ENABLE_DYNAMIC_CUDA)

cmake/templates/OpenCV.mk.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ else
110110
OPENCV_INSTALL_MODULES:=on
111111
endif
112112

113+
ifeq ($(OPENCV_INSTALL_MODULES),)
114+
OPENCV_INSTALL_MODULES:=on
115+
endif
116+
113117
define add_opencv_module
114118
include $(CLEAR_VARS)
115119
LOCAL_MODULE:=opencv_$1

modules/java/generator/src/java/android+OpenCVLoader.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
package org.opencv.android;
22

33
import android.content.Context;
4+
import android.util.Log;
45

56
/**
67
* Helper class provides common initialization methods for OpenCV library.
78
*/
89
public class OpenCVLoader
910
{
11+
private static final String TAG = "OpenCVLoader";
12+
1013
/**
1114
* OpenCV Library version 2.4.2.
1215
*/
@@ -62,6 +65,11 @@ public class OpenCVLoader
6265
*/
6366
public static final String OPENCV_VERSION_2_4_12 = "2.4.12";
6467

68+
/**
69+
* OpenCV Library version 2.4.13.
70+
*/
71+
public static final String OPENCV_VERSION_2_4_13 = "2.4.13";
72+
6573
/**
6674
* Loads and initializes OpenCV library from current application package. Roughly, it's an analog of system.loadLibrary("opencv_java").
6775
* @return Returns true is initialization of OpenCV was successful.
@@ -91,6 +99,11 @@ public static boolean initDebug(boolean InitCuda)
9199
public static boolean initAsync(String Version, Context AppContext,
92100
LoaderCallbackInterface Callback)
93101
{
102+
if (initDebug()) {
103+
Callback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
104+
return true;
105+
}
106+
Log.w(TAG, "OpenCV binaries are not packaged with application. Trying to use OpenCV Manager...");
94107
return AsyncServiceHelper.initOpenCV(Version, AppContext, Callback);
95108
}
96109
}

platforms/android/build_sdk.py

100755100644
Lines changed: 38 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ def __init__(self, text=None):
1010
def __str__(self):
1111
return "ERROR" if self.t is None else self.t
1212

13-
def execute(cmd, shell=False):
13+
def execute(cmd, shell=False, allowFail=False):
1414
try:
1515
log.info("Executing: %s" % cmd)
1616
retcode = subprocess.call(cmd, shell=shell)
1717
if retcode < 0:
1818
raise Fail("Child was terminated by signal:" %s -retcode)
19-
elif retcode > 0:
19+
elif retcode > 0 and not allowFail:
2020
raise Fail("Child returned: %s" % retcode)
2121
except OSError as e:
2222
raise Fail("Execution failed: %d / %s" % (e.errno, e.strerror))
@@ -45,44 +45,37 @@ def check_dir(d, create=False, clean=False):
4545
os.makedirs(d)
4646
return d
4747

48-
def determine_engine_version(manifest_path):
49-
with open(manifest_path, "rt") as f:
50-
return re.search(r'android:versionName="(\d+\.\d+)"', f.read(), re.MULTILINE).group(1)
51-
5248
def determine_opencv_version(version_hpp_path):
5349
# version in 2.4 - CV_VERSION_EPOCH.CV_VERSION_MAJOR.CV_VERSION_MINOR.CV_VERSION_REVISION
5450
# version in master - CV_VERSION_MAJOR.CV_VERSION_MINOR.CV_VERSION_REVISION-CV_VERSION_STATUS
5551
with open(version_hpp_path, "rt") as f:
5652
data = f.read()
53+
epoch = re.search(r'^#define\W+CV_VERSION_EPOCH\W+(\d+)$', data, re.MULTILINE).group(1)
5754
major = re.search(r'^#define\W+CV_VERSION_MAJOR\W+(\d+)$', data, re.MULTILINE).group(1)
5855
minor = re.search(r'^#define\W+CV_VERSION_MINOR\W+(\d+)$', data, re.MULTILINE).group(1)
5956
revision = re.search(r'^#define\W+CV_VERSION_REVISION\W+(\d+)$', data, re.MULTILINE).group(1)
60-
version_status = re.search(r'^#define\W+CV_VERSION_STATUS\W+"([^"]*)"$', data, re.MULTILINE).group(1)
61-
return "%(major)s.%(minor)s.%(revision)s%(version_status)s" % locals()
57+
revision = '' if revision == '0' else '.' + revision
58+
return "%(epoch)s.%(major)s.%(minor)s%(revision)s" % locals()
6259

6360
#===================================================================================================
6461

6562
class ABI:
66-
def __init__(self, platform_id, name, toolchain, cmake_name=None):
63+
def __init__(self, platform_id, name, toolchain, api_level=8, cmake_name=None):
6764
self.platform_id = platform_id # platform code to add to apk version (for cmake)
6865
self.name = name # general name (official Android ABI identifier)
6966
self.toolchain = toolchain # toolchain identifier (for cmake)
67+
self.api_level = api_level
7068
self.cmake_name = cmake_name # name of android toolchain (for cmake)
7169
if self.cmake_name is None:
7270
self.cmake_name = self.name
7371
def __str__(self):
7472
return "%s (%s)" % (self.name, self.toolchain)
75-
def haveIPP(self):
76-
return self.name == "x86" or self.name == "x86_64"
7773

7874
ABIs = [
79-
ABI("2", "armeabi-v7a", "arm-linux-androideabi-4.8", cmake_name="armeabi-v7a with NEON"),
80-
ABI("1", "armeabi", "arm-linux-androideabi-4.8"),
81-
ABI("3", "arm64-v8a", "aarch64-linux-android-4.9"),
82-
ABI("5", "x86_64", "x86_64-4.9"),
83-
ABI("4", "x86", "x86-4.8"),
84-
ABI("7", "mips64", "mips64el-linux-android-4.9"),
85-
ABI("6", "mips", "mipsel-linux-android-4.8")
75+
ABI("2", "armeabi-v7a", "arm-linux-androideabi-4.6", cmake_name="armeabi-v7a with NEON"),
76+
ABI("1", "armeabi", "arm-linux-androideabi-4.6"),
77+
ABI("4", "x86", "x86-clang3.1", api_level=9),
78+
ABI("6", "mips", "mipsel-linux-android-4.6", api_level=9)
8679
]
8780

8881
#===================================================================================================
@@ -91,107 +84,59 @@ class Builder:
9184
def __init__(self, workdir, opencvdir):
9285
self.workdir = check_dir(workdir, create=True)
9386
self.opencvdir = check_dir(opencvdir)
94-
self.extra_modules_path = None
9587
self.libdest = check_dir(os.path.join(self.workdir, "o4a"), create=True, clean=True)
9688
self.docdest = check_dir(os.path.join(self.workdir, "javadoc"), create=True, clean=True)
9789
self.resultdest = check_dir(os.path.join(self.workdir, "OpenCV-android-sdk"), create=True, clean=True)
98-
self.extra_packs = []
9990
self.opencv_version = determine_opencv_version(os.path.join(self.opencvdir, "modules", "core", "include", "opencv2", "core", "version.hpp"))
100-
self.engine_version = determine_engine_version(os.path.join(self.opencvdir, "platforms", "android", "service", "engine", "AndroidManifest.xml"))
10191
self.use_ccache = True
10292

10393
def get_toolchain_file(self):
10494
return os.path.join(self.opencvdir, "platforms", "android", "android.toolchain.cmake")
10595

106-
def get_engine_apk_dest(self, engdest):
107-
return os.path.join(engdest, "platforms", "android", "service", "engine", ".build")
108-
109-
def add_extra_pack(self, ver, path):
110-
if path is None:
111-
return
112-
self.extra_packs.append((ver, check_dir(path)))
113-
11496
def clean_library_build_dir(self):
11597
for d in ["CMakeCache.txt", "CMakeFiles/", "bin/", "libs/", "lib/", "package/", "install/samples/"]:
11698
rm_one(d)
11799

118-
def build_library(self, abi, do_install):
100+
def build_library(self, abi, do_install, build_docs):
119101
cmd = [
120102
"cmake",
121103
"-GNinja",
122104
"-DCMAKE_TOOLCHAIN_FILE='%s'" % self.get_toolchain_file(),
123-
"-DWITH_OPENCL=OFF",
124-
"-DWITH_CUDA=OFF",
125-
"-DWITH_IPP=%s" % ("ON" if abi.haveIPP() else "OFF"),
105+
"-DINSTALL_CREATE_DISTRIB=ON",
106+
#"-DWITH_OPENCL=OFF",
107+
"-DWITH_CUDA=OFF", "-DBUILD_opencv_gpu=OFF",
108+
"-DBUILD_opencv_nonfree=OFF",
109+
"-DWITH_TBB=OFF",
110+
"-DWITH_IPP=OFF",
126111
"-DBUILD_EXAMPLES=OFF",
127112
"-DBUILD_TESTS=OFF",
128113
"-DBUILD_PERF_TESTS=OFF",
129114
"-DBUILD_DOCS=OFF",
130115
"-DBUILD_ANDROID_EXAMPLES=ON",
131116
"-DINSTALL_ANDROID_EXAMPLES=ON",
132117
"-DANDROID_STL=gnustl_static",
133-
"-DANDROID_NATIVE_API_LEVEL=9",
118+
"-DANDROID_NATIVE_API_LEVEL=%s" % abi.api_level,
134119
"-DANDROID_ABI='%s'" % abi.cmake_name,
135-
"-DWITH_TBB=ON",
136120
"-DANDROID_TOOLCHAIN_NAME=%s" % abi.toolchain
137121
]
138122

139-
if self.extra_modules_path is not None:
140-
cmd.append("-DOPENCV_EXTRA_MODULES_PATH='%s'" % self.extra_modules_path)
141-
142123
cmd.append(self.opencvdir)
143124

144125
if self.use_ccache == True:
145126
cmd.append("-DNDK_CCACHE=ccache")
146127
if do_install:
147128
cmd.extend(["-DBUILD_TESTS=ON", "-DINSTALL_TESTS=ON"])
129+
if do_install and build_docs:
130+
cmd.extend(["-DBUILD_DOCS=ON"])
148131
execute(cmd)
149132
if do_install:
150-
execute(["ninja"])
151-
for c in ["libs", "dev", "java", "samples"]:
133+
execute(["cmake", "--build", "."])
134+
if do_install and build_docs:
135+
execute(["cmake", "--build", ".", "--target", "docs"])
136+
for c in ["libs", "dev", "java", "samples"] + (["docs"] if do_install and build_docs else []):
152137
execute(["cmake", "-DCOMPONENT=%s" % c, "-P", "cmake_install.cmake"])
153138
else:
154-
execute(["ninja", "install/strip"])
155-
156-
def build_engine(self, abi, engdest):
157-
cmd = [
158-
"cmake",
159-
"-GNinja",
160-
"-DCMAKE_TOOLCHAIN_FILE='%s'" % self.get_toolchain_file(),
161-
"-DANDROID_ABI='%s'" % abi.cmake_name,
162-
"-DBUILD_ANDROID_SERVICE=ON",
163-
"-DANDROID_PLATFORM_ID=%s" % abi.platform_id,
164-
"-DWITH_CUDA=OFF",
165-
"-DWITH_OPENCL=OFF",
166-
"-DWITH_IPP=OFF",
167-
self.opencvdir
168-
]
169-
execute(cmd)
170-
apkdest = self.get_engine_apk_dest(engdest)
171-
# Add extra data
172-
apkxmldest = check_dir(os.path.join(apkdest, "res", "xml"), create=True)
173-
apklibdest = check_dir(os.path.join(apkdest, "libs", abi.name), create=True)
174-
for ver, d in self.extra_packs + [("3.1.0", os.path.join(self.libdest, "lib"))]:
175-
r = ET.Element("library", attrib={"version": ver})
176-
log.info("Adding libraries from %s", d)
177-
178-
for f in glob.glob(os.path.join(d, abi.name, "*.so")):
179-
log.info("Copy file: %s", f)
180-
shutil.copy2(f, apklibdest)
181-
if "libnative_camera" in f:
182-
continue
183-
log.info("Register file: %s", os.path.basename(f))
184-
n = ET.SubElement(r, "file", attrib={"name": os.path.basename(f)})
185-
186-
if len(list(r)) > 0:
187-
xmlname = os.path.join(apkxmldest, "config%s.xml" % ver.replace(".", ""))
188-
log.info("Generating XML config: %s", xmlname)
189-
ET.ElementTree(r).write(xmlname, encoding="utf-8")
190-
191-
execute(["ninja", "opencv_engine"])
192-
execute(["ant", "-f", os.path.join(apkdest, "build.xml"), "debug"],
193-
shell=(sys.platform == 'win32'))
194-
# TODO: Sign apk
139+
execute(["cmake", "--build", ".", "--target", "install/strip"])
195140

196141
def build_javadoc(self):
197142
classpaths = [os.path.join(self.libdest, "bin", "classes")]
@@ -201,6 +146,7 @@ def build_javadoc(self):
201146
classpaths.append(os.path.join(dir, f))
202147
cmd = [
203148
"javadoc",
149+
"-encoding", "UTF-8",
204150
"-header", "OpenCV %s" % self.opencv_version,
205151
"-nodeprecated",
206152
"-footer", '<a href="http://docs.opencv.org">OpenCV %s Documentation</a>' % self.opencv_version,
@@ -211,9 +157,9 @@ def build_javadoc(self):
211157
]
212158
for _, dirs, _ in os.walk(os.path.join(self.libdest, "src", "org", "opencv")):
213159
cmd.extend(["org.opencv." + d for d in dirs])
214-
execute(cmd)
160+
execute(cmd, allowFail=True) # FIXIT javadoc currenly reports some errors
215161

216-
def gather_results(self, engines):
162+
def gather_results(self, with_samples_apk):
217163
# Copy all files
218164
root = os.path.join(self.libdest, "install")
219165
for item in os.listdir(root):
@@ -226,13 +172,6 @@ def gather_results(self, engines):
226172
log.info("Copy file: %s", item)
227173
shutil.copy2(item, os.path.join(self.resultdest, name))
228174

229-
# Copy engines for all platforms
230-
for abi, engdest in engines:
231-
log.info("Copy engine: %s (%s)", abi, engdest)
232-
f = os.path.join(self.get_engine_apk_dest(engdest), "bin", "opencv_engine-debug.apk")
233-
resname = "OpenCV_%s_Manager_%s_%s.apk" % (self.opencv_version, self.engine_version, abi)
234-
shutil.copy2(f, os.path.join(self.resultdest, "apk", resname))
235-
236175
# Copy javadoc
237176
log.info("Copy docs: %s", self.docdest)
238177
shutil.copytree(self.docdest, os.path.join(self.resultdest, "sdk", "java", "javadoc"))
@@ -244,6 +183,9 @@ def gather_results(self, engines):
244183
if os.path.isdir(item):
245184
for name in ["build.xml", "local.properties", "proguard-project.txt"]:
246185
rm_one(os.path.join(item, name))
186+
if not with_samples_apk:
187+
if re.search(r'\.apk$', item): # reduce size of SDK
188+
rm_one(item)
247189

248190

249191
#===================================================================================================
@@ -254,11 +196,10 @@ def gather_results(self, engines):
254196
parser.add_argument("opencv_dir", help="Path to OpenCV source dir")
255197
parser.add_argument('--ndk_path', help="Path to Android NDK to use for build")
256198
parser.add_argument('--sdk_path', help="Path to Android SDK to use for build")
257-
parser.add_argument("--extra_modules_path", help="Path to extra modules to use for build")
258-
parser.add_argument('--sign_with', help="Sertificate to sign the Manager apk")
259-
parser.add_argument('--build_doc', action="store_true", help="Build javadoc")
199+
parser.add_argument('--build_doc', action="store_true", help="Build documentation")
200+
parser.add_argument('--build_javadoc', action="store_true", help="Build javadoc")
260201
parser.add_argument('--no_ccache', action="store_true", help="Do not use ccache during library build")
261-
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'")
202+
parser.add_argument('--with_samples_apk', action="store_true", help="Include samples APKs")
262203
args = parser.parse_args()
263204

264205
log.basicConfig(format='%(message)s', level=log.DEBUG)
@@ -274,48 +215,26 @@ def gather_results(self, engines):
274215

275216
builder = Builder(args.work_dir, args.opencv_dir)
276217

277-
if args.extra_modules_path is not None:
278-
builder.extra_modules_path = os.path.abspath(args.extra_modules_path)
279-
280218
if args.no_ccache:
281219
builder.use_ccache = False
282220

283221
log.info("Detected OpenCV version: %s", builder.opencv_version)
284-
log.info("Detected Engine version: %s", builder.engine_version)
285222

286-
if args.extra_pack:
287-
for one in args.extra_pack:
288-
i = one.find(":")
289-
if i > 0 and i < len(one) - 1:
290-
builder.add_extra_pack(one[:i], one[i+1:])
291-
else:
292-
raise Fail("Bad extra pack provided: %s, should be in form '<version>:<path-to-native-libs>'" % one)
293-
294-
engines = []
295223
for i, abi in enumerate(ABIs):
296224
do_install = (i == 0)
297-
engdest = check_dir(os.path.join(builder.workdir, "build_service_%s" % abi.name), create=True, clean=True)
298225

299226
log.info("=====")
300227
log.info("===== Building library for %s", abi)
301228
log.info("=====")
302229

303230
os.chdir(builder.libdest)
304231
builder.clean_library_build_dir()
305-
builder.build_library(abi, do_install)
306-
307-
log.info("=====")
308-
log.info("===== Building engine for %s", abi)
309-
log.info("=====")
310-
311-
os.chdir(engdest)
312-
builder.build_engine(abi, engdest)
313-
engines.append((abi.name, engdest))
232+
builder.build_library(abi, do_install, build_docs=args.build_doc)
314233

315-
if args.build_doc:
234+
if args.build_doc or args.build_javadoc:
316235
builder.build_javadoc()
317236

318-
builder.gather_results(engines)
237+
builder.gather_results(with_samples_apk=args.with_samples_apk)
319238

320239
log.info("=====")
321240
log.info("===== Build finished")

platforms/android/service/CMakeLists.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,3 @@ if(BUILD_ANDROID_SERVICE)
22
add_subdirectory(engine)
33
#add_subdirectory(engine_test)
44
endif()
5-
6-
install(FILES "readme.txt" DESTINATION "apk/" COMPONENT libs)

platforms/android/service/doc/JavaHelper.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,11 @@ OpenCV version constants
7979
.. data:: OPENCV_VERSION_2_4_11
8080

8181
OpenCV Library version 2.4.11
82+
83+
.. data:: OPENCV_VERSION_2_4_12
84+
85+
OpenCV Library version 2.4.12
86+
87+
.. data:: OPENCV_VERSION_2_4_13
88+
89+
OpenCV Library version 2.4.13

0 commit comments

Comments
 (0)