3 import os, sys, subprocess, argparse, shutil, glob, re, multiprocessing
6 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
9 def __init__(self, text=None):
12 return "ERROR" if self.t is None else self.t
14 def execute(cmd, shell=False):
16 log.info("Executing: %s" % cmd)
17 env = os.environ.copy()
19 retcode = subprocess.call(cmd, shell=shell, env=env)
21 raise Fail("Child was terminated by signal: %s" % -retcode)
23 raise Fail("Child returned: %s" % retcode)
25 raise Fail("Execution failed: %d / %s" % (e.errno, e.strerror))
28 d = os.path.abspath(d)
31 log.info("Removing dir: %s", d)
33 elif os.path.isfile(d):
34 log.info("Removing file: %s", d)
37 def check_dir(d, create=False, clean=False):
38 d = os.path.abspath(d)
39 log.info("Check dir %s (create: %s, clean: %s)", d, create, clean)
41 if not os.path.isdir(d):
42 raise Fail("Not a directory: %s" % d)
44 for x in glob.glob(os.path.join(d, "*")):
52 d = os.path.abspath(d)
60 def find_file(name, path):
61 for root, dirs, files in os.walk(path):
63 return os.path.join(root, name)
66 def __init__(self, options):
67 self.options = options
68 self.build_dir = check_dir(options.build_dir, create=True)
69 self.opencv_dir = check_dir(options.opencv_dir)
70 self.emscripten_dir = check_dir(options.emscripten_dir)
72 def get_toolchain_file(self):
73 return os.path.join(self.emscripten_dir, "cmake", "Modules", "Platform", "Emscripten.cmake")
75 def clean_build_dir(self):
76 for d in ["CMakeCache.txt", "CMakeFiles/", "bin/", "libs/", "lib/", "modules"]:
79 def get_cmake_cmd(self):
81 "-DENABLE_PIC=FALSE", # To workaround emscripten upstream backend issue https://github.com/emscripten-core/emscripten/issues/8761
82 "-DCMAKE_BUILD_TYPE=Release",
83 "-DCMAKE_TOOLCHAIN_FILE='%s'" % self.get_toolchain_file(),
87 "-DBUILD_SHARED_LIBS=OFF",
93 "-DWITH_GSTREAMER=OFF",
100 "-DWITH_OPENEXR=OFF",
104 "-DWITH_OPENNI2=OFF",
110 "-DWITH_OPENCL_SVM=OFF",
111 "-DWITH_OPENCLAMDFFT=OFF",
112 "-DWITH_OPENCLAMDBLAS=OFF",
113 "-DWITH_GPHOTO2=OFF",
118 "-DBUILD_opencv_apps=OFF",
119 "-DBUILD_opencv_calib3d=ON",
120 "-DBUILD_opencv_dnn=ON",
121 "-DBUILD_opencv_features2d=ON",
122 "-DBUILD_opencv_flann=ON", # No bindings provided. This module is used as a dependency for other modules.
123 "-DBUILD_opencv_gapi=OFF",
124 "-DBUILD_opencv_ml=OFF",
125 "-DBUILD_opencv_photo=ON",
126 "-DBUILD_opencv_imgcodecs=OFF",
127 "-DBUILD_opencv_shape=OFF",
128 "-DBUILD_opencv_videoio=OFF",
129 "-DBUILD_opencv_videostab=OFF",
130 "-DBUILD_opencv_highgui=OFF",
131 "-DBUILD_opencv_superres=OFF",
132 "-DBUILD_opencv_stitching=OFF",
133 "-DBUILD_opencv_java=OFF",
134 "-DBUILD_opencv_js=ON",
135 "-DBUILD_opencv_python2=OFF",
136 "-DBUILD_opencv_python3=OFF",
137 "-DBUILD_EXAMPLES=OFF",
138 "-DBUILD_PACKAGE=OFF",
140 "-DBUILD_PERF_TESTS=OFF"]
141 if self.options.cmake_option:
142 cmd += self.options.cmake_option
143 if self.options.build_doc:
144 cmd.append("-DBUILD_DOCS=ON")
146 cmd.append("-DBUILD_DOCS=OFF")
148 if self.options.threads:
149 cmd.append("-DWITH_PTHREADS_PF=ON")
151 cmd.append("-DWITH_PTHREADS_PF=OFF")
153 if self.options.simd:
154 cmd.append("-DCV_ENABLE_INTRINSICS=ON")
156 cmd.append("-DCV_ENABLE_INTRINSICS=OFF")
158 if self.options.build_wasm_intrin_test:
159 cmd.append("-DBUILD_WASM_INTRIN_TESTS=ON")
161 cmd.append("-DBUILD_WASM_INTRIN_TESTS=OFF")
163 flags = self.get_build_flags()
165 cmd += ["-DCMAKE_C_FLAGS='%s'" % flags,
166 "-DCMAKE_CXX_FLAGS='%s'" % flags]
169 def get_build_flags(self):
171 if self.options.build_wasm:
172 flags += "-s WASM=1 "
173 elif self.options.disable_wasm:
174 flags += "-s WASM=0 "
175 if self.options.threads:
176 flags += "-s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=4 "
178 flags += "-s USE_PTHREADS=0 "
179 if self.options.enable_exception:
180 flags += "-s DISABLE_EXCEPTION_CATCHING=0 "
181 if self.options.simd:
182 flags += "-msimd128 "
183 if self.options.build_flags:
184 flags += self.options.build_flags
188 cmd = self.get_cmake_cmd()
189 cmd.append(self.opencv_dir)
192 def build_opencvjs(self):
193 execute(["make", "-j", str(multiprocessing.cpu_count()), "opencv.js"])
195 def build_test(self):
196 execute(["make", "-j", str(multiprocessing.cpu_count()), "opencv_js_test"])
198 def build_perf(self):
199 execute(["make", "-j", str(multiprocessing.cpu_count()), "opencv_js_perf"])
202 execute(["make", "-j", str(multiprocessing.cpu_count()), "doxygen"])
204 def build_loader(self):
205 execute(["make", "-j", str(multiprocessing.cpu_count()), "opencv_js_loader"])
208 #===================================================================================================
210 if __name__ == "__main__":
211 opencv_dir = os.path.abspath(os.path.join(SCRIPT_DIR, '../..'))
212 emscripten_dir = None
213 if "EMSCRIPTEN" in os.environ:
214 emscripten_dir = os.environ["EMSCRIPTEN"]
216 parser = argparse.ArgumentParser(description='Build OpenCV.js by Emscripten')
217 parser.add_argument("build_dir", help="Building directory (and output)")
218 parser.add_argument('--opencv_dir', default=opencv_dir, help='Opencv source directory (default is "../.." relative to script location)')
219 parser.add_argument('--emscripten_dir', default=emscripten_dir, help="Path to Emscripten to use for build")
220 parser.add_argument('--build_wasm', action="store_true", help="Build OpenCV.js in WebAssembly format")
221 parser.add_argument('--disable_wasm', action="store_true", help="Build OpenCV.js in Asm.js format")
222 parser.add_argument('--threads', action="store_true", help="Build OpenCV.js with threads optimization")
223 parser.add_argument('--simd', action="store_true", help="Build OpenCV.js with SIMD optimization")
224 parser.add_argument('--build_test', action="store_true", help="Build tests")
225 parser.add_argument('--build_perf', action="store_true", help="Build performance tests")
226 parser.add_argument('--build_doc', action="store_true", help="Build tutorials")
227 parser.add_argument('--build_loader', action="store_true", help="Build OpenCV.js loader")
228 parser.add_argument('--clean_build_dir', action="store_true", help="Clean build dir")
229 parser.add_argument('--skip_config', action="store_true", help="Skip cmake config")
230 parser.add_argument('--config_only', action="store_true", help="Only do cmake config")
231 parser.add_argument('--enable_exception', action="store_true", help="Enable exception handling")
232 # Use flag --cmake option="-D...=ON" only for one argument, if you would add more changes write new cmake_option flags
233 parser.add_argument('--cmake_option', action='append', help="Append CMake options")
234 # Use flag --build_flags="-s USE_PTHREADS=0 -Os" for one and more arguments as in the example
235 parser.add_argument('--build_flags', help="Append Emscripten build options")
236 parser.add_argument('--build_wasm_intrin_test', default=False, action="store_true", help="Build WASM intrin tests")
237 # Write a path to modify file like argument of this flag
238 parser.add_argument('--config', default=os.path.join(os.path.dirname(os.path.abspath(__file__)), 'opencv_js.config.py'),
239 help="Specify configuration file with own list of exported into JS functions")
241 args = parser.parse_args()
243 log.basicConfig(format='%(message)s', level=log.DEBUG)
244 log.debug("Args: %s", args)
246 os.environ["OPENCV_JS_WHITELIST"] = args.config
248 if args.emscripten_dir is None:
249 log.info("Cannot get Emscripten path, please specify it either by EMSCRIPTEN environment variable or --emscripten_dir option.")
252 builder = Builder(args)
254 os.chdir(builder.build_dir)
256 if args.clean_build_dir:
258 log.info("===== Clean build dir %s", builder.build_dir)
260 builder.clean_build_dir()
262 if not args.skip_config:
263 target = "default target"
266 elif args.disable_wasm:
269 log.info("===== Config OpenCV.js build for %s" % target)
277 log.info("===== Building OpenCV.js")
279 builder.build_opencvjs()
283 log.info("===== Building OpenCV.js tests")
289 log.info("===== Building OpenCV.js performance tests")
295 log.info("===== Building OpenCV.js tutorials")
299 if args.build_loader:
301 log.info("===== Building OpenCV.js loader")
303 builder.build_loader()
306 log.info("===== Build finished")
309 opencvjs_path = os.path.join(builder.build_dir, "bin", "opencv.js")
310 if check_file(opencvjs_path):
311 log.info("OpenCV.js location: %s", opencvjs_path)
314 opencvjs_test_path = os.path.join(builder.build_dir, "bin", "tests.html")
315 if check_file(opencvjs_test_path):
316 log.info("OpenCV.js tests location: %s", opencvjs_test_path)
319 opencvjs_perf_path = os.path.join(builder.build_dir, "bin", "perf")
320 opencvjs_perf_base_path = os.path.join(builder.build_dir, "bin", "perf", "base.js")
321 if check_file(opencvjs_perf_base_path):
322 log.info("OpenCV.js performance tests location: %s", opencvjs_perf_path)
325 opencvjs_tutorial_path = find_file("tutorial_js_root.html", os.path.join(builder.build_dir, "doc", "doxygen", "html"))
326 if check_file(opencvjs_tutorial_path):
327 log.info("OpenCV.js tutorials location: %s", opencvjs_tutorial_path)
329 if args.build_loader:
330 opencvjs_loader_path = os.path.join(builder.build_dir, "bin", "loader.js")
331 if check_file(opencvjs_loader_path):
332 log.info("OpenCV.js loader location: %s", opencvjs_loader_path)