Merge pull request #28704 from komakai:replace-jazzy-with-docc
Use Xcode DocC tool for buiding Apple platform docs + add quick-start tutorial #28704 ### Pull Request Readiness Checklist - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work This PR resolves https://github.com/opencv/opencv/issues/28702 and https://github.com/opencv/opencv/issues/28703 Additionally it resolves build issues on Apple platforms by making build scripts run with Python 3
@@ -0,0 +1,69 @@
|
||||
|
||||
This is the documentation for the iOS OpenCV framework.
|
||||
|
||||
## Quick Start Tutorial
|
||||
|
||||
Follow the steps below to get a simple "Hello World" app running on iOS
|
||||
|
||||
* Open Xcode and create a new project from the **File** > **New** > **Project...** menu
|
||||
|
||||

|
||||
|
||||
* From template selection dialog select the `iOS` tab and then select `App`
|
||||
|
||||

|
||||
|
||||
* Enter a name for the project and set **Interface** to **Storyboard** and **Language** to **Swift**
|
||||
|
||||

|
||||
|
||||
* Choose a location to save the project
|
||||
|
||||

|
||||
|
||||
* Create a new folder `Framework`
|
||||
|
||||

|
||||
|
||||
* In a Finder window copy the framework file to the newly created folder. The framework should appear in the project navigator as below. (Note: in this case the framework has extension `.framework` but depending on how you built it or from where you obtained it your framework may have extension `.xcframework`)
|
||||
|
||||

|
||||
|
||||
* In the project navigator select the `ViewController.swift` file
|
||||
|
||||

|
||||
|
||||
* Add an `import` for the OpenCV framework below the existing import for `UIKit`
|
||||
|
||||
```swift, copy
|
||||
import opencv2
|
||||
```
|
||||
|
||||
* Replace the implementation of the `viewDidLoad` function with the following code
|
||||
|
||||
```swift, copy
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
let white = Scalar(255, 255, 255, 255)
|
||||
let black = Scalar(0, 0, 0, 255)
|
||||
let m = Mat(rows: 400, cols: Int32(view.frame.width), type: CvType.CV_8UC4, scalar: white)
|
||||
Imgproc.putText(img: m, text: "Hello World", org: Point(x: 10, y: 150), fontFace: HersheyFonts.FONT_HERSHEY_DUPLEX, fontScale: 2, color: black)
|
||||
let image = m.toUIImage()
|
||||
let imageView = UIImageView(image: image)
|
||||
self.view.addSubview(imageView)
|
||||
}
|
||||
```
|
||||
|
||||
* The `ViewController.swift` file should now look like this
|
||||
|
||||

|
||||
|
||||
* Launch the app
|
||||
|
||||

|
||||
|
||||
* The app home screen should look like this
|
||||
|
||||

|
||||
|
||||
If that has all worked well then congratulations. If not then feel free to reach out to the OpenCV community for help. Also feel free to contribute fixes and improvements.
|
||||
@@ -0,0 +1,85 @@
|
||||
|
||||
This is the documentation for the macOS OpenCV framework.
|
||||
|
||||
## Quick Start Tutorial
|
||||
|
||||
Follow the steps below to get a simple "Hello World" app running on macOS
|
||||
|
||||
* Open Xcode and create a new project from the **File** > **New** > **Project...** menu
|
||||
|
||||

|
||||
|
||||
* From the template selection dialog select the **macOS** tab and then select **App**
|
||||
|
||||

|
||||
|
||||
* Enter a name for the project and set **Interface** to **Storyboard** and **Language** to **Swift**
|
||||
|
||||

|
||||
|
||||
* Choose a location to save the project
|
||||
|
||||

|
||||
|
||||
* Create a new folder `Framework`
|
||||
|
||||

|
||||
|
||||
* In a Finder window copy the framework file to the newly created folder. The framework should appear in the project navigator as below. (Note: in this case the framework has extension `.framework` but depending on how you built it or from where you obtained it your framework may have extension `.xcframework`)
|
||||
|
||||

|
||||
|
||||
* Select the project root in the project navigator and on the **General** tab locate the **Frameworks, Libraries and Embedded Content** section
|
||||
|
||||

|
||||
|
||||
* In the **Choose frameworks and libraries to add** dialog add the following
|
||||
* OpenCL.framework
|
||||
* liblapack.tbd
|
||||
* libblas.tbd
|
||||
|
||||

|
||||
|
||||
* The **Frameworks, Libraries and Embedded Content** section should now look like this
|
||||
|
||||

|
||||
|
||||
* In the project navigator select the `ViewController.swift` file
|
||||
|
||||

|
||||
|
||||
* Add an `import` for the OpenCV framework below the existing import for `Cocoa`
|
||||
|
||||
```swift, copy
|
||||
import opencv2
|
||||
```
|
||||
|
||||
* Replace the implementation of the `viewDidLoad` function with the following code
|
||||
|
||||
```swift, copy
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
let white = Scalar(255, 255, 255, 255)
|
||||
let black = Scalar(0, 0, 0, 255)
|
||||
let m = Mat(rows: 400, cols: Int32(view.frame.width), type: CvType.CV_8UC4, scalar: white)
|
||||
Imgproc.putText(img: m, text: "Hello World", org: Point(x: 10, y: 250), fontFace: HersheyFonts.FONT_HERSHEY_DUPLEX, fontScale: 2, color: black)
|
||||
let image = m.toNSImage()
|
||||
let imageView = NSImageView(frame: NSRect(x: 0, y: 0, width: Int(m.cols()), height: Int(m.rows())))
|
||||
imageView.image = image
|
||||
self.view.addSubview(imageView)
|
||||
}
|
||||
```
|
||||
|
||||
* The `ViewController.swift` file should now look like this
|
||||
|
||||

|
||||
|
||||
* Launch the app
|
||||
|
||||

|
||||
|
||||
* The app home screen should look like this
|
||||
|
||||

|
||||
|
||||
If that has all worked well then congratulations. If not then feel free to reach out to the OpenCV community for help. Also feel free to contribute fixes and improvements.
|
||||
@@ -1,13 +0,0 @@
|
||||
## About
|
||||
|
||||
This is the documentation for the Objective-C/Swift OpenCV wrapper
|
||||
|
||||
To get started: add the OpenCV framework to your project and add the following to your source
|
||||
|
||||
###Objective-C
|
||||
|
||||
#import <OpenCV/OpenCV.h>
|
||||
|
||||
###Swift
|
||||
|
||||
import OpenCV
|
||||
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 25 KiB |
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from __future__ import print_function, unicode_literals
|
||||
import sys, re, os.path, errno, fnmatch
|
||||
@@ -100,6 +100,9 @@ method_dict = {
|
||||
("Mat", "dot") : "-dot:"
|
||||
}
|
||||
|
||||
enum_value_lookup = {}
|
||||
enums = set()
|
||||
|
||||
modules = []
|
||||
|
||||
|
||||
@@ -708,12 +711,25 @@ def see_lookup(objc_class, see):
|
||||
if (see_class, see_method) in method_dict:
|
||||
method = method_dict[(see_class, see_method)]
|
||||
if see_class == objc_class:
|
||||
return method
|
||||
return "``{}``".format(method[1:])
|
||||
else:
|
||||
return ("-" if method[0] == "-" else "") + "[" + see_class + " " + method[1:] + "]"
|
||||
return "``{}/{}``".format(see_class, method[1:])
|
||||
else:
|
||||
return see
|
||||
|
||||
def hash_link(link_text, objc_class, function_name):
|
||||
if link_text == function_name:
|
||||
return "*{}*".format(link_text) # make bold
|
||||
elif link_text in enums:
|
||||
return "``{}``".format(link_text)
|
||||
elif link_text in enum_value_lookup:
|
||||
return "``{}/{}``".format(enum_value_lookup[link_text], link_text)
|
||||
elif (objc_class, link_text) in method_dict:
|
||||
return "``{}/{}``".format(objc_class, link_text)
|
||||
elif ("Core", link_text) in method_dict:
|
||||
return "``Core/{}``".format(link_text)
|
||||
else:
|
||||
return "#{}".format(link_text) # leave as is
|
||||
|
||||
class ObjectiveCWrapperGenerator(object):
|
||||
def __init__(self):
|
||||
@@ -1115,13 +1131,16 @@ class ObjectiveCWrapperGenerator(object):
|
||||
if fi.docstring:
|
||||
lines = fi.docstring.splitlines()
|
||||
toWrite = []
|
||||
last_line_was_param = False
|
||||
for index, line in enumerate(lines):
|
||||
line = re.sub(r"([(\s])#(.+?)([).,\s]|$)", lambda x: x.group(1) + hash_link(x.group(2), ci.objc_name, fi.name) + x.group(3), line)
|
||||
p0 = line.find("@param")
|
||||
if p0 != -1:
|
||||
p0 += 7 # len("@param" + 1)
|
||||
p1 = line.find(' ', p0)
|
||||
p1 = len(line) if p1 == -1 else p1
|
||||
name = line[p0:p1]
|
||||
last_line_was_param = True
|
||||
for arg in args:
|
||||
if arg.name == name:
|
||||
toWrite.append(re.sub(r'\*\s*@param ', '* @param ', line))
|
||||
@@ -1129,10 +1148,14 @@ class ObjectiveCWrapperGenerator(object):
|
||||
else:
|
||||
s0 = line.find("@see")
|
||||
if s0 != -1:
|
||||
if last_line_was_param:
|
||||
# separate from @param lines
|
||||
toWrite.append(" *")
|
||||
sees = line[(s0 + 5):].split(",")
|
||||
toWrite.append(line[:(s0 + 5)] + ", ".join(["`" + see_lookup(ci.objc_name, see.strip()) + "`" for see in sees]))
|
||||
toWrite.append(line[:s0] + "- SeeAlso " + ", ".join([see_lookup(ci.objc_name, see.strip()) for see in sees]))
|
||||
else:
|
||||
toWrite.append(line)
|
||||
last_line_was_param = False
|
||||
|
||||
for line in toWrite:
|
||||
method_declarations.write(line + "\n")
|
||||
@@ -1317,6 +1340,10 @@ $unrefined_call$epilogue$ret
|
||||
if ci.cname in enum_fix:
|
||||
typeNameShort = enum_fix[ci.cname].get(typeNameShort, typeNameShort)
|
||||
|
||||
enums.add(typeNameShort)
|
||||
for c in consts:
|
||||
enum_value_lookup[c.name] = typeNameShort
|
||||
|
||||
ci.enum_declarations.write("""
|
||||
// C++: enum {1} ({2})
|
||||
typedef NS_ENUM(int, {1}) {{
|
||||
@@ -1462,16 +1489,37 @@ typedef NS_ENUM(int, {1}) {{
|
||||
self.save(opencv_modulemap_file, opencv_modulemap)
|
||||
available_modules = " ".join(["-DAVAILABLE_" + m['name'].upper() for m in config['modules']])
|
||||
cmakelist_template = read_contents(os.path.join(SCRIPT_DIR, 'templates/cmakelists.template'))
|
||||
cmakelist = Template(cmakelist_template).substitute(modules = ";".join(modules), framework = framework_name, objc_target=objc_target, module_availability_defines=available_modules)
|
||||
doc_catalog = output_objc_path + "/../Documentation.docc"
|
||||
doc_resources = os.path.join(doc_catalog, "Resources")
|
||||
cmakelist = Template(cmakelist_template).substitute(
|
||||
modules = ";".join(modules),
|
||||
framework = framework_name,
|
||||
objc_target = objc_target,
|
||||
module_availability_defines = available_modules,
|
||||
)
|
||||
self.save(os.path.join(dstdir, "CMakeLists.txt"), cmakelist)
|
||||
mkdir_p(doc_resources)
|
||||
mkdir_p(os.path.join(output_objc_build_path, "framework_build"))
|
||||
mkdir_p(os.path.join(output_objc_build_path, "test_build"))
|
||||
mkdir_p(os.path.join(output_objc_build_path, "doc_build"))
|
||||
with open(os.path.join(SCRIPT_DIR, '../doc/README.md')) as readme_in:
|
||||
readme_body = readme_in.read()
|
||||
readme_body += "\n\n\n##Modules\n\n" + ", ".join(["`" + m.capitalize() + "`" for m in modules])
|
||||
with open(os.path.join(output_objc_build_path, "doc_build/README.md"), "w") as readme_out:
|
||||
readme_out.write(readme_body)
|
||||
landing_page_body_in = ""
|
||||
if objc_target == "ios" or objc_target == "osx":
|
||||
with open(os.path.join(SCRIPT_DIR, '../doc/LandingPage_' + objc_target + '.md')) as landing_page_in:
|
||||
landing_page_body_in = landing_page_in.read()
|
||||
landing_page_body_out = "# ``" + framework_name + "`` Framework\n\n" + landing_page_body_in
|
||||
landing_page_body_out += "\n\n\n## Modules\n\n" + ", ".join(["``" + m.capitalize() + "``" for m in modules]) + "\n"
|
||||
with open(os.path.join(doc_catalog, "LandingPage.md"), "w") as landing_page_out:
|
||||
landing_page_out.write(landing_page_body_out)
|
||||
for m in config['modules']:
|
||||
pic_files = os.path.join(ROOT_DIR, m['location'], 'doc', 'pics')
|
||||
if os.path.exists(pic_files):
|
||||
copy_tree(pic_files, doc_resources)
|
||||
if objc_target == "ios":
|
||||
copy_tree(os.path.join(SCRIPT_DIR, '../doc/pics/ios'), doc_resources)
|
||||
if objc_target == "osx":
|
||||
copy_tree(os.path.join(SCRIPT_DIR, '../doc/pics/osx'), doc_resources)
|
||||
if objc_target == "ios" or objc_target == "osx":
|
||||
copy_tree(os.path.join(SCRIPT_DIR, '../doc/pics/common'), doc_resources)
|
||||
|
||||
if framework_name != "OpenCV":
|
||||
for dirname, dirs, files in os.walk(os.path.join(testdir, "test")):
|
||||
if dirname.endswith('/resources'):
|
||||
@@ -1541,10 +1589,11 @@ def sanitize_documentation_string(doc, type):
|
||||
doc = re.sub(re.compile('\\\\f\\$(.*?)\\\\f\\$', re.DOTALL), lambda x: '`$$' + fix_tex(x.group(1)) + '$$`', doc)
|
||||
doc = re.sub(re.compile('\\\\f\\[(.*?)\\\\f\\]', re.DOTALL), lambda x: '`$$' + fix_tex(x.group(1)) + '$$`', doc)
|
||||
doc = re.sub(re.compile('\\\\f\\{(.*?)\\\\f\\}', re.DOTALL), lambda x: '`$$' + fix_tex(x.group(1)) + '$$`', doc)
|
||||
doc = re.sub(r"!\[(.*)]\((?:.*/)*(.+)\.(?:png|jpg|svg)\)", "", doc)
|
||||
|
||||
doc = doc.replace("@anchor", "") \
|
||||
.replace("@brief ", "").replace("\\brief ", "") \
|
||||
.replace("@cite", "CITE:") \
|
||||
.replace("@cite", "*Cite:*") \
|
||||
.replace("@code{.cpp}", "<code>") \
|
||||
.replace("@code{.txt}", "<code>") \
|
||||
.replace("@code", "<code>") \
|
||||
@@ -1556,14 +1605,14 @@ def sanitize_documentation_string(doc, type):
|
||||
.replace("@endcode", "</code>") \
|
||||
.replace("@endinternal", "") \
|
||||
.replace("@file", "") \
|
||||
.replace("@include", "INCLUDE:") \
|
||||
.replace("@include", "Include:") \
|
||||
.replace("@ingroup", "") \
|
||||
.replace("@internal", "") \
|
||||
.replace("@overload", "") \
|
||||
.replace("@param[in]", "@param") \
|
||||
.replace("@param[out]", "@param") \
|
||||
.replace("@ref", "REF:") \
|
||||
.replace("@note", "NOTE:") \
|
||||
.replace("@ref", "*Ref:*") \
|
||||
.replace("@note", "*Note:*") \
|
||||
.replace("@returns", "@return") \
|
||||
.replace("@sa ", "@see ") \
|
||||
.replace("@snippet", "SNIPPET:") \
|
||||
|
||||
@@ -22,7 +22,14 @@ else()
|
||||
endif()
|
||||
file(GLOB_RECURSE objc_headers "*\.h")
|
||||
|
||||
add_library($framework STATIC $${objc_sources})
|
||||
set_source_files_properties(Documentation.docc PROPERTIES
|
||||
XCODE_LAST_KNOWN_FILE_TYPE folder.documentationcatalog
|
||||
)
|
||||
|
||||
add_library($framework STATIC
|
||||
$${objc_sources}
|
||||
Documentation.docc
|
||||
)
|
||||
|
||||
set_target_properties($framework PROPERTIES LINKER_LANGUAGE CXX)
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# $framework Documentation - How To View
|
||||
|
||||
## View Locally
|
||||
|
||||
* Start a web server in the directory where this HowTo file is located. For example ``python3 -m http.server 8000``
|
||||
* In a browser navigate to URL http://127.0.0.1:8000/$hosting_base_path/documentation/$framework/
|
||||
|
||||
## Deploying to a server
|
||||
|
||||
* Upload the content of the directory where this HowTo file is located to the document root of the web server maintaining the same folder hierarchy
|
||||
* In a browser navigate to URL https://{server-domain}/$hosting_base_path/documentation/$framework/
|
||||
@@ -82,6 +82,7 @@ if __name__ == "__main__":
|
||||
visionos_script_path = os.path.abspath(os.path.abspath(os.path.dirname(__file__))+'/../ios/build_visionos_framework.py')
|
||||
|
||||
build_folders = []
|
||||
docs_build_folder_dict = {}
|
||||
|
||||
def get_or_create_build_folder(base_dir, platform):
|
||||
build_folder = "{}/{}".format(base_dir, platform).replace(" ", "\\ ") # Escape spaces in output path
|
||||
@@ -91,6 +92,7 @@ if __name__ == "__main__":
|
||||
if iphoneos_archs:
|
||||
build_folder = get_or_create_build_folder(args.out, "iphoneos")
|
||||
build_folders.append(build_folder)
|
||||
docs_build_folder_dict["ios"] = build_folder
|
||||
command = ["python3", ios_script_path, build_folder, "--iphoneos_archs", iphoneos_archs, "--framework_name", args.framework_name, "--build_only_specified_archs"] + unknown_args
|
||||
print_header("Building iPhoneOS frameworks")
|
||||
print(command)
|
||||
@@ -98,12 +100,15 @@ if __name__ == "__main__":
|
||||
if iphonesimulator_archs:
|
||||
build_folder = get_or_create_build_folder(args.out, "iphonesimulator")
|
||||
build_folders.append(build_folder)
|
||||
if not iphoneos_archs:
|
||||
docs_build_folder_dict["ios"] = build_folder
|
||||
command = ["python3", ios_script_path, build_folder, "--iphonesimulator_archs", iphonesimulator_archs, "--framework_name", args.framework_name, "--build_only_specified_archs"] + unknown_args
|
||||
print_header("Building iPhoneSimulator frameworks")
|
||||
execute(command, cwd=os.getcwd())
|
||||
if visionos_archs:
|
||||
build_folder = get_or_create_build_folder(args.out, "visionos")
|
||||
build_folders.append(build_folder)
|
||||
docs_build_folder_dict["visionos"] = build_folder
|
||||
command = ["python3", visionos_script_path, build_folder, "--visionos_archs", visionos_archs, "--framework_name", args.framework_name, "--build_only_specified_archs"] + unknown_args
|
||||
print_header("Building visionOS frameworks")
|
||||
print(command)
|
||||
@@ -111,18 +116,22 @@ if __name__ == "__main__":
|
||||
if visionsimulator_archs:
|
||||
build_folder = get_or_create_build_folder(args.out, "visionsimulator")
|
||||
build_folders.append(build_folder)
|
||||
if not visionos_archs:
|
||||
docs_build_folder_dict["visionos"] = build_folder
|
||||
command = ["python3", visionos_script_path, build_folder, "--visionsimulator_archs", visionsimulator_archs, "--framework_name", args.framework_name, "--build_only_specified_archs"] + unknown_args
|
||||
print_header("Building visionSimulator frameworks")
|
||||
execute(command, cwd=os.getcwd())
|
||||
if macos_archs:
|
||||
build_folder = get_or_create_build_folder(args.out, "macos")
|
||||
build_folders.append(build_folder)
|
||||
docs_build_folder_dict["macos"] = build_folder
|
||||
command = ["python3", osx_script_path, build_folder, "--macos_archs", macos_archs, "--framework_name", args.framework_name, "--build_only_specified_archs"] + unknown_args
|
||||
print_header("Building MacOS frameworks")
|
||||
execute(command, cwd=os.getcwd())
|
||||
if catalyst_archs:
|
||||
build_folder = get_or_create_build_folder(args.out, "catalyst")
|
||||
build_folders.append(build_folder)
|
||||
docs_build_folder_dict["catalyst"] = build_folder
|
||||
command = ["python3", osx_script_path, build_folder, "--catalyst_archs", catalyst_archs, "--framework_name", args.framework_name, "--build_only_specified_archs"] + unknown_args
|
||||
print_header("Building Catalyst frameworks")
|
||||
execute(command, cwd=os.getcwd())
|
||||
@@ -150,6 +159,23 @@ if __name__ == "__main__":
|
||||
|
||||
print("")
|
||||
print_header("Finished building {}".format(xcframework_path))
|
||||
|
||||
# Phase 3: copy documentation
|
||||
|
||||
print_header("Copying documentation")
|
||||
|
||||
for platform, build_folder in docs_build_folder_dict.items():
|
||||
docs_src = "{}/docs".format(build_folder)
|
||||
docs_dst = "{}/docs_{}".format(args.out, platform)
|
||||
# Remove the docs folder if it exists
|
||||
with contextlib.suppress(FileNotFoundError):
|
||||
shutil.rmtree(docs_dst)
|
||||
print("Removed existing documentation at {}".format(docs_dst))
|
||||
shutil.copytree(docs_src, docs_dst)
|
||||
|
||||
print("")
|
||||
print_header("Finished copying documentation")
|
||||
|
||||
except Exception as e:
|
||||
print_error(e)
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
|
||||
@@ -63,3 +63,17 @@ def get_cmake_version():
|
||||
return (int(m.group(1)), int(m.group(2)), int(m.group(3)))
|
||||
else:
|
||||
raise Exception("Failed to parse CMake version")
|
||||
|
||||
def get_current_branch(opencv_dir):
|
||||
ret = check_output(["git", "branch", "--show-current"], cwd = opencv_dir).decode('utf-8').strip()
|
||||
if ret != "":
|
||||
return ret
|
||||
else:
|
||||
raise Exception("Failed to get current branch")
|
||||
|
||||
def find_directory(base_dir, search_dir):
|
||||
dirs = check_output(["find", base_dir, "-type", "d", "-name", search_dir]).decode('utf-8').splitlines()
|
||||
if dirs and len(dirs) > 0:
|
||||
return dirs[0]
|
||||
else:
|
||||
raise Exception("Failed to find directory: " + search_dir)
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
This script builds OpenCV docs for iOS.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import os, sys, multiprocessing, argparse, traceback
|
||||
from subprocess import check_call, check_output, CalledProcessError, Popen
|
||||
|
||||
def execute(cmd, cwd = None, output = None):
|
||||
if not output:
|
||||
print("Executing: %s in %s" % (cmd, cwd), file=sys.stderr)
|
||||
print('Executing: ' + ' '.join(cmd))
|
||||
retcode = check_call(cmd, cwd = cwd)
|
||||
if retcode != 0:
|
||||
raise Exception("Child returned:", retcode)
|
||||
else:
|
||||
with open(output, "a") as f:
|
||||
f.flush()
|
||||
p = Popen(cmd, cwd = cwd, stdout = f)
|
||||
os.waitpid(p.pid, 0)
|
||||
|
||||
class DocBuilder:
|
||||
def __init__(self, script_dir, framework_dir, output_dir, framework_header, framework_name, arch, target):
|
||||
self.script_dir = script_dir
|
||||
self.framework_dir = framework_dir
|
||||
self.output_dir = output_dir
|
||||
self.framework_header = framework_header
|
||||
self.framework_name = framework_name
|
||||
self.arch = arch
|
||||
self.target = target
|
||||
|
||||
def _build(self):
|
||||
if not os.path.isdir(self.output_dir):
|
||||
os.makedirs(self.output_dir)
|
||||
|
||||
self.buildDocs()
|
||||
|
||||
def build(self):
|
||||
try:
|
||||
self._build()
|
||||
except Exception as e:
|
||||
print("="*60, file=sys.stderr)
|
||||
print("ERROR: %s" % e, file=sys.stderr)
|
||||
print("="*60, file=sys.stderr)
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
def getToolchain(self):
|
||||
return None
|
||||
|
||||
def getSourceKitten(self):
|
||||
ret = check_output(["gem", "which", "jazzy"])
|
||||
if ret.find('ERROR:') == 0:
|
||||
raise Exception("Failed to find jazzy")
|
||||
else:
|
||||
return os.path.join(ret[0:ret.rfind('/')], '../bin/sourcekitten')
|
||||
|
||||
def buildDocs(self):
|
||||
sourceKitten = self.getSourceKitten()
|
||||
sourceKittenSwiftDoc = [sourceKitten, "doc", "--module-name", self.framework_name, "--", "-project", self.framework_name + ".xcodeproj", "ARCHS=" + self.arch, "-sdk", self.target, "-configuration", "Release", "-parallelizeTargets", "-jobs", str(multiprocessing.cpu_count()), "-target", "opencv_objc_framework"]
|
||||
execute(sourceKittenSwiftDoc, cwd = self.framework_dir, output = os.path.join(self.output_dir, "swiftDoc.json"))
|
||||
sdk_dir = check_output(["xcrun", "--show-sdk-path", "--sdk", self.target]).rstrip()
|
||||
sourceKittenObjcDoc = [sourceKitten, "doc", "--objc", self.framework_header, "--", "-x", "objective-c", "-isysroot", sdk_dir, "-fmodules"]
|
||||
print(sourceKittenObjcDoc)
|
||||
execute(sourceKittenObjcDoc, cwd = self.framework_dir, output = os.path.join(self.output_dir, "objcDoc.json"))
|
||||
execute(["jazzy", "--author", "OpenCV", "--author_url", "http://opencv.org", "--github_url", "https://github.com/opencv/opencv", "--module", self.framework_name, "--undocumented-text", "\"\"", "--sourcekitten-sourcefile", "swiftDoc.json,objcDoc.json"], cwd = self.output_dir)
|
||||
|
||||
class iOSDocBuilder(DocBuilder):
|
||||
|
||||
def getToolchain(self):
|
||||
return None
|
||||
|
||||
if __name__ == "__main__":
|
||||
script_dir = os.path.abspath(os.path.dirname(sys.argv[0]))
|
||||
parser = argparse.ArgumentParser(description='The script builds OpenCV docs for iOS.')
|
||||
parser.add_argument('framework_dir', metavar='FRAMEWORK_DIR', help='folder where framework build files are located')
|
||||
parser.add_argument('--output_dir', default=None, help='folder where docs will be built (default is "../doc_build" relative to framework_dir)')
|
||||
parser.add_argument('--framework_header', default=None, help='umbrella header for OpenCV framework (default is "../../../lib/Release/{framework_name}.framework/Headers/{framework_name}.h")')
|
||||
parser.add_argument('--framework_name', default='opencv2', help='Name of OpenCV framework (default: opencv2, will change to OpenCV in future version)')
|
||||
args = parser.parse_args()
|
||||
|
||||
arch = "x86_64"
|
||||
target = "iphonesimulator"
|
||||
|
||||
b = iOSDocBuilder(script_dir, args.framework_dir, args.output_dir if args.output_dir else os.path.join(args.framework_dir, "../doc_build"), args.framework_header if args.framework_header else os.path.join(args.framework_dir, "../../../lib/Release/" + args.framework_name + ".framework/Headers/" + args.framework_name + ".h"), args.framework_name, arch, target)
|
||||
b.build()
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
The script builds OpenCV.framework for iOS.
|
||||
The built framework is universal, it can be used to build app and run it on either iOS simulator or real device.
|
||||
@@ -42,7 +42,7 @@ else:
|
||||
from distutils.dir_util import copy_tree
|
||||
|
||||
sys.path.insert(0, os.path.abspath(os.path.abspath(os.path.dirname(__file__))+'/../apple'))
|
||||
from cv_build_utils import execute, print_error, get_xcode_major, get_xcode_setting, get_xcode_version, get_cmake_version
|
||||
from cv_build_utils import execute, print_error, get_xcode_major, get_xcode_setting, get_xcode_version, get_cmake_version, get_current_branch, find_directory
|
||||
|
||||
IPHONEOS_DEPLOYMENT_TARGET='9.0' # default, can be changed via command line options or environment variable
|
||||
|
||||
@@ -50,7 +50,7 @@ CURRENT_FILE_DIR = os.path.dirname(__file__)
|
||||
|
||||
|
||||
class Builder:
|
||||
def __init__(self, opencv, contrib, dynamic, exclude, disable, enablenonfree, targets, debug, debug_info, framework_name, run_tests, build_docs, swiftdisabled):
|
||||
def __init__(self, opencv, contrib, dynamic, exclude, disable, enablenonfree, targets, debug, debug_info, framework_name, run_tests, hosting_base_path, swiftdisabled):
|
||||
self.opencv = os.path.abspath(opencv)
|
||||
self.contrib = None
|
||||
if contrib:
|
||||
@@ -69,8 +69,15 @@ class Builder:
|
||||
self.debug_info = debug_info
|
||||
self.framework_name = framework_name
|
||||
self.run_tests = run_tests
|
||||
self.build_docs = build_docs
|
||||
if hosting_base_path is None:
|
||||
current_branch = get_current_branch(self.opencv)
|
||||
objc_target = self.getObjcTarget(self.targets[0][1])
|
||||
self.hosting_base_path = os.path.join(current_branch, "macos" if objc_target == "osx" else objc_target)
|
||||
else:
|
||||
self.hosting_base_path = hosting_base_path
|
||||
self.swiftdisabled = swiftdisabled
|
||||
self.docs_built = False
|
||||
self.build_docs = False
|
||||
|
||||
def checkCMakeVersion(self):
|
||||
if get_xcode_version() >= (12, 2):
|
||||
@@ -95,12 +102,17 @@ class Builder:
|
||||
dirs = []
|
||||
|
||||
xcode_ver = get_xcode_major()
|
||||
xcode_supports_ios_32bit_arch = xcode_ver <= 13
|
||||
self.build_docs = xcode_ver >= 13
|
||||
|
||||
# build each architecture separately
|
||||
alltargets = []
|
||||
|
||||
for target_group in self.targets:
|
||||
for arch in target_group[0]:
|
||||
if arch in ["armv7", "armv7s", "i386"] and not xcode_supports_ios_32bit_arch:
|
||||
print("Skipping unsupported architecture: " + arch)
|
||||
continue
|
||||
current = ( arch, target_group[1] )
|
||||
alltargets.append(current)
|
||||
|
||||
@@ -149,20 +161,20 @@ class Builder:
|
||||
|
||||
self.makeFramework(outdir, dirs)
|
||||
if self.build_objc_wrapper:
|
||||
doc_output = os.path.join(outdir, "docs")
|
||||
if os.path.exists(doc_output):
|
||||
shutil.rmtree(doc_output)
|
||||
|
||||
doc_build_path = os.path.join(dirs[0], "lib", self.getConfiguration(), "docs")
|
||||
if os.path.exists(doc_build_path):
|
||||
copy_tree(doc_build_path, doc_output)
|
||||
else:
|
||||
print("Documentation not found at: " + doc_build_path);
|
||||
if self.run_tests:
|
||||
check_call([sys.argv[0].replace("build_framework", "run_tests"), "--framework_dir=" + outdir, "--framework_name=" + self.framework_name, dirs[0] + "/modules/objc_bindings_generator/{}/test".format(self.getObjcTarget(target[1]))])
|
||||
else:
|
||||
print("To run tests call:")
|
||||
print(sys.argv[0].replace("build_framework", "run_tests") + " --framework_dir=" + outdir + " --framework_name=" + self.framework_name + " " + dirs[0] + "/modules/objc_bindings_generator/{}/test".format(self.getObjcTarget(target[1])))
|
||||
if self.build_docs:
|
||||
check_call([sys.argv[0].replace("build_framework", "build_docs"), dirs[0] + "/modules/objc/framework_build"])
|
||||
doc_path = os.path.join(dirs[0], "modules", "objc", "doc_build", "docs")
|
||||
if os.path.exists(doc_path):
|
||||
shutil.copytree(doc_path, os.path.join(outdir, "docs"))
|
||||
shutil.copyfile(os.path.join(self.opencv, "doc", "opencv.ico"), os.path.join(outdir, "docs", "favicon.ico"))
|
||||
else:
|
||||
print("To build docs call:")
|
||||
print(sys.argv[0].replace("build_framework", "build_docs") + " " + dirs[0] + "/modules/objc/framework_build")
|
||||
self.copy_samples(outdir)
|
||||
if self.swiftdisabled:
|
||||
swift_sources_dir = os.path.join(outdir, "SwiftSources")
|
||||
@@ -245,6 +257,31 @@ class Builder:
|
||||
|
||||
return buildcmd
|
||||
|
||||
def getDocBuildCommand(self, base_build_dir, source_dir, framework_build_dir, docs_dir):
|
||||
output_dir = docs_dir if self.hosting_base_path == "" else os.path.join(docs_dir, self.hosting_base_path)
|
||||
if not os.path.exists(output_dir):
|
||||
os.makedirs(output_dir)
|
||||
symbol_graph_dir = find_directory(os.path.join(framework_build_dir, "build", self.framework_name + ".build"), "symbol-graph")
|
||||
doc_buildcmd = [
|
||||
"xcrun",
|
||||
"docc",
|
||||
"convert",
|
||||
"--emit-lmdb-index",
|
||||
"--fallback-display-name", self.framework_name,
|
||||
"--fallback-bundle-identifier", "org.opencv." + self.framework_name,
|
||||
"--fallback-bundle-version", "1",
|
||||
"--output-dir", output_dir,
|
||||
"--transform-for-static-hosting",
|
||||
"--ide-console-output",
|
||||
os.path.join(source_dir, "Documentation.docc"),
|
||||
"--additional-symbol-graph-dir", symbol_graph_dir
|
||||
]
|
||||
|
||||
if self.hosting_base_path != "":
|
||||
doc_buildcmd += ["--hosting-base-path", self.hosting_base_path]
|
||||
|
||||
return doc_buildcmd
|
||||
|
||||
def getInfoPlist(self, builddirs):
|
||||
return os.path.join(builddirs[0], "ios", "Info.plist")
|
||||
|
||||
@@ -320,16 +357,33 @@ class Builder:
|
||||
execute(buildcmd + ["-target", "ALL_BUILD", "build"], cwd = builddir)
|
||||
execute(["cmake", "-DBUILD_TYPE=%s" % self.getConfiguration(), "-P", "cmake_install.cmake"], cwd = builddir)
|
||||
if self.build_objc_wrapper:
|
||||
cmakecmd = self.makeCMakeCmd(arch, target, builddir + "/modules/objc_bindings_generator/{}/gen".format(self.getObjcTarget(target)), cmakeargs)
|
||||
objc_source_dir = builddir + "/modules/objc_bindings_generator/{}/gen".format(self.getObjcTarget(target))
|
||||
cmakecmd = self.makeCMakeCmd(arch, target, objc_source_dir, cmakeargs)
|
||||
if self.swiftdisabled:
|
||||
cmakecmd.append("-DSWIFT_DISABLED=1")
|
||||
cmakecmd.append("-DBUILD_ROOT=%s" % builddir)
|
||||
cmakecmd.append("-DCMAKE_INSTALL_NAME_TOOL=install_name_tool")
|
||||
cmakecmd.append("--no-warn-unused-cli")
|
||||
execute(cmakecmd, cwd = builddir + "/modules/objc/framework_build")
|
||||
|
||||
execute(buildcmd + ["-target", "ALL_BUILD", "build"], cwd = builddir + "/modules/objc/framework_build")
|
||||
execute(["cmake", "-DBUILD_TYPE=%s" % self.getConfiguration(), "-DCMAKE_INSTALL_PREFIX=%s" % (builddir + "/install"), "-P", "cmake_install.cmake"], cwd = builddir + "/modules/objc/framework_build")
|
||||
framework_build_dir = builddir + "/modules/objc/framework_build"
|
||||
execute(cmakecmd, cwd = framework_build_dir)
|
||||
execute(buildcmd + ["-target", "ALL_BUILD", "build"], cwd = framework_build_dir)
|
||||
if self.build_docs and not self.docs_built:
|
||||
# build the syntax graphs
|
||||
execute(buildcmd + ["-target", "ALL_BUILD", "docbuild"], cwd = framework_build_dir)
|
||||
# build the document catalog
|
||||
docs_dir = os.path.join(builddir, "lib", self.getConfiguration(), "docs")
|
||||
doc_buildcmd2 = self.getDocBuildCommand(builddir, objc_source_dir, framework_build_dir, docs_dir)
|
||||
execute(doc_buildcmd2, cwd = objc_source_dir)
|
||||
with open(os.path.join(self.opencv, "modules", "objc", "generator", "templates", "doc_howto.template"), "r") as f:
|
||||
howto_template = f.read()
|
||||
howto = string.Template(howto_template).substitute(
|
||||
framework = self.framework_name,
|
||||
hosting_base_path = self.hosting_base_path
|
||||
)
|
||||
with codecs.open(os.path.join(docs_dir, "HOWTO.md"), "w", "utf-8") as file:
|
||||
file.write(howto)
|
||||
self.docs_built = True
|
||||
execute(["cmake", "-DBUILD_TYPE=%s" % self.getConfiguration(), "-DCMAKE_INSTALL_PREFIX=%s" % (builddir + "/install"), "-P", "cmake_install.cmake"], cwd = framework_build_dir)
|
||||
|
||||
def mergeLibs(self, builddir):
|
||||
res = os.path.join(builddir, "lib", self.getConfiguration(), "libopencv_merged.a")
|
||||
@@ -540,7 +594,7 @@ if __name__ == "__main__":
|
||||
parser.add_argument('--framework_name', default='opencv2', dest='framework_name', help='Name of OpenCV framework (default: opencv2, will change to OpenCV in future version)')
|
||||
parser.add_argument('--legacy_build', default=False, dest='legacy_build', action='store_true', help='Build legacy opencv2 framework (default: False, equivalent to "--framework_name=opencv2 --without=objc")')
|
||||
parser.add_argument('--run_tests', default=False, dest='run_tests', action='store_true', help='Run tests')
|
||||
parser.add_argument('--build_docs', default=False, dest='build_docs', action='store_true', help='Build docs')
|
||||
parser.add_argument('--doc_hosting_base_path', default=None, dest='hosting_base_path', action='store_true', help='Documentation hosting base path')
|
||||
parser.add_argument('--disable-swift', default=False, dest='swiftdisabled', action='store_true', help='Disable building of Swift extensions')
|
||||
|
||||
args, unknown_args = parser.parse_known_args()
|
||||
@@ -595,6 +649,6 @@ if __name__ == "__main__":
|
||||
if iphonesimulator_archs:
|
||||
targets.append((iphonesimulator_archs, "iPhoneSimulator"))
|
||||
|
||||
b = iOSBuilder(args.opencv, args.contrib, args.dynamic, args.without, args.disable, args.enablenonfree, targets, args.debug, args.debug_info, args.framework_name, args.run_tests, args.build_docs, args.swiftdisabled)
|
||||
b = iOSBuilder(args.opencv, args.contrib, args.dynamic, args.without, args.disable, args.enablenonfree, targets, args.debug, args.debug_info, args.framework_name, args.run_tests, args.hosting_base_path, args.swiftdisabled)
|
||||
|
||||
b.build(args.out)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
The script builds OpenCV.framework for visionOS.
|
||||
"""
|
||||
@@ -69,7 +69,7 @@ if __name__ == "__main__":
|
||||
parser.add_argument('--framework_name', default='opencv2', dest='framework_name', help='Name of OpenCV framework (default: opencv2, will change to OpenCV in future version)')
|
||||
parser.add_argument('--legacy_build', default=False, dest='legacy_build', action='store_true', help='Build legacy framework (default: False, equivalent to "--framework_name=opencv2 --without=objc")')
|
||||
parser.add_argument('--run_tests', default=False, dest='run_tests', action='store_true', help='Run tests')
|
||||
parser.add_argument('--build_docs', default=False, dest='build_docs', action='store_true', help='Build docs')
|
||||
parser.add_argument('--doc_hosting_base_path', default=None, dest='hosting_base_path', action='store_true', help='Documentation hosting base path')
|
||||
parser.add_argument('--disable-swift', default=False, dest='swiftdisabled', action='store_true', help='Disable building of Swift extensions')
|
||||
|
||||
args, unknown_args = parser.parse_known_args()
|
||||
@@ -112,5 +112,5 @@ if __name__ == "__main__":
|
||||
if visionsimulator_archs:
|
||||
targets.append((visionsimulator_archs, "XRSimulator")),
|
||||
|
||||
b = visionOSBuilder(args.opencv, args.contrib, args.dynamic, args.without, args.disable, args.enablenonfree, targets, args.debug, args.debug_info, args.framework_name, args.run_tests, args.build_docs, args.swiftdisabled)
|
||||
b = visionOSBuilder(args.opencv, args.contrib, args.dynamic, args.without, args.disable, args.enablenonfree, targets, args.debug, args.debug_info, args.framework_name, args.run_tests, args.hosting_base_path, args.swiftdisabled)
|
||||
b.build(args.out)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
This script runs OpenCV.framework tests for iOS.
|
||||
"""
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
This script builds OpenCV docs for macOS.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import os, sys, multiprocessing, argparse, traceback
|
||||
from subprocess import check_call, check_output, CalledProcessError, Popen
|
||||
|
||||
# import common code
|
||||
sys.path.insert(0, os.path.abspath(os.path.abspath(os.path.dirname(__file__))+'/../ios'))
|
||||
from build_docs import DocBuilder
|
||||
|
||||
class OSXDocBuilder(DocBuilder):
|
||||
|
||||
def getToolchain(self):
|
||||
return None
|
||||
|
||||
if __name__ == "__main__":
|
||||
script_dir = os.path.abspath(os.path.dirname(sys.argv[0]))
|
||||
parser = argparse.ArgumentParser(description='The script builds OpenCV docs for macOS.')
|
||||
parser.add_argument('framework_dir', metavar='FRAMEWORK_DIR', help='folder where framework build files are located')
|
||||
parser.add_argument('--output_dir', default=None, help='folder where docs will be built (default is "../doc_build" relative to framework_dir)')
|
||||
parser.add_argument('--framework_header', default=None, help='umbrella header for OpenCV framework (default is "../../../lib/Release/{framework_name}.framework/Headers/{framework_name}.h")')
|
||||
parser.add_argument('--framework_name', default='opencv2', help='Name of OpenCV framework (default: opencv2, will change to OpenCV in future version)')
|
||||
|
||||
args = parser.parse_args()
|
||||
arch = "x86_64"
|
||||
target = "macosx"
|
||||
|
||||
b = OSXDocBuilder(script_dir, args.framework_dir, args.output_dir if args.output_dir else os.path.join(args.framework_dir, "../doc_build"), args.framework_header if args.framework_header else os.path.join(args.framework_dir, "../../../lib/Release/" + args.framework_name + ".framework/Headers/" + args.framework_name + ".h"), args.framework_name, arch, target)
|
||||
b.build()
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
The script builds OpenCV.framework for OSX.
|
||||
"""
|
||||
@@ -76,7 +76,7 @@ if __name__ == "__main__":
|
||||
parser.add_argument('--framework_name', default='opencv2', dest='framework_name', help='Name of OpenCV framework (default: opencv2, will change to OpenCV in future version)')
|
||||
parser.add_argument('--legacy_build', default=False, dest='legacy_build', action='store_true', help='Build legacy framework (default: False, equivalent to "--framework_name=opencv2 --without=objc")')
|
||||
parser.add_argument('--run_tests', default=False, dest='run_tests', action='store_true', help='Run tests')
|
||||
parser.add_argument('--build_docs', default=False, dest='build_docs', action='store_true', help='Build docs')
|
||||
parser.add_argument('--doc_hosting_base_path', default=None, dest='hosting_base_path', action='store_true', help='Documentation hosting base path')
|
||||
parser.add_argument('--disable-swift', default=False, dest='swiftdisabled', action='store_true', help='Disable building of Swift extensions')
|
||||
|
||||
args, unknown_args = parser.parse_known_args()
|
||||
@@ -128,5 +128,5 @@ if __name__ == "__main__":
|
||||
if catalyst_archs:
|
||||
targets.append((catalyst_archs, "Catalyst")),
|
||||
|
||||
b = OSXBuilder(args.opencv, args.contrib, args.dynamic, args.without, args.disable, args.enablenonfree, targets, args.debug, args.debug_info, args.framework_name, args.run_tests, args.build_docs, args.swiftdisabled)
|
||||
b = OSXBuilder(args.opencv, args.contrib, args.dynamic, args.without, args.disable, args.enablenonfree, targets, args.debug, args.debug_info, args.framework_name, args.run_tests, args.hosting_base_path, args.swiftdisabled)
|
||||
b.build(args.out)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
This script runs OpenCV.framework tests for OSX.
|
||||
"""
|
||||
|
||||