Compare commits

..

1 Commits

Author SHA1 Message Date
02e3cbaa18 Increased minimum required version of Node.js to 22 2025-02-04 11:47:29 +03:00
102 changed files with 1164 additions and 4898 deletions

View File

@ -1,88 +0,0 @@
name: Git Operations
on:
workflow_dispatch:
inputs:
operation:
description: 'Operation to perform'
required: true
type: choice
options:
- create
- remove
default: 'create'
branch_name:
description: 'Branch name to create or remove'
required: true
type: string
base_branch:
description: 'Base branch to work from (for create operation)'
required: false
type: string
default: 'develop'
branding:
description: 'Branding name'
required: false
type: string
default: 'onlyoffice'
branding_url:
description: 'Branding repository URL (relative to git host)'
required: false
type: string
default: 'ONLYOFFICE/onlyoffice.git'
jobs:
git-operations:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
path: ONLYOFFICE/build_tools
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
# Install any Python dependencies if requirements.txt exists
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Configure Git
run: |
git config --global user.name "GitHub Actions Bot"
git config --global user.email "actions@github.com"
- name: Run Git Operations
run: |
cd ONLYOFFICE/build_tools/scripts/develop
python git_operations.py ${{ inputs.operation }} "${{ inputs.branch_name }}" \
--base-branch="${{ inputs.base_branch }}" \
--branding="${{ inputs.branding }}" \
--branding-url="${{ inputs.branding_url }}" \
--modules="${{ inputs.modules }}"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Operation Summary
run: |
echo "## Git Operations Summary" >> $GITHUB_STEP_SUMMARY
echo "- **Operation**: ${{ inputs.operation }}" >> $GITHUB_STEP_SUMMARY
echo "- **Branch Name**: ${{ inputs.branch_name }}" >> $GITHUB_STEP_SUMMARY
echo "- **Base Branch**: ${{ inputs.base_branch }}" >> $GITHUB_STEP_SUMMARY
echo "- **Branding**: ${{ inputs.branding }}" >> $GITHUB_STEP_SUMMARY
echo "- **Branding URL**: ${{ inputs.branding_url }}" >> $GITHUB_STEP_SUMMARY
echo "- **Modules**: ${{ inputs.modules }}" >> $GITHUB_STEP_SUMMARY
if [ "${{ inputs.operation }}" = "remove" ] && [ "${{ inputs.force_remove }}" = "true" ]; then
echo "- **Force Remove**: Yes" >> $GITHUB_STEP_SUMMARY
fi

4
.gitignore vendored
View File

@ -7,7 +7,6 @@ config
*.*~
**~
*.DS_Store
.idea
scripts/license_checker/reports
tests/puppeteer/node_modules
tests/puppeteer/work_directory
@ -15,6 +14,3 @@ tests/puppeteer/package.json
tests/puppeteer/package-lock.json
scripts/sdkjs_common/jsdoc/node_modules
scripts/sdkjs_common/jsdoc/package-lock.json
tools/linux/python3/
tools/linux/python3.tar.gz
tools/linux/sysroot/sysroot_ubuntu_1604

View File

@ -1,22 +1,14 @@
FROM ubuntu:20.04
FROM ubuntu:16.04
ENV TZ=Etc/UTC
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN apt-get -y update && \
apt-get -y install tar \
sudo \
wget
apt-get -y install python \
python3 \
sudo
RUN rm /usr/bin/python && ln -s /usr/bin/python2 /usr/bin/python
ADD . /build_tools
WORKDIR /build_tools
RUN mkdir -p /opt/python3 && \
wget -P /opt/python3/ https://github.com/ONLYOFFICE-data/build_tools_data/raw/refs/heads/master/python/python3.tar.gz && \
tar -xzf /opt/python3/python3.tar.gz -C /opt/python3 --strip-components=1
ENV PATH="/opt/python3/bin:${PATH}"
RUN ln -s /opt/python3/bin/python3.10 /usr/bin/python
CMD ["sh", "-c", "cd tools/linux && python3 ./automate.py"]

View File

@ -8,8 +8,8 @@ necessary for the compilation process, all the dependencies required for the
correct work, as well as to get the latest version of
**ONLYOFFICE products** source code and build all their components.
**Important!** We can only guarantee the correct work of the products built
from the `master` branch.
**Important!** We can only guarantee the correct work of the products built from
the `master` branch.
## How to use - Linux

View File

@ -14,7 +14,7 @@ parser.add_option("--clean", action="store", type="string", dest="clean", defaul
parser.add_option("--module", action="store", type="string", dest="module", default="builder", help="defines what modules to build. You can specify several of them, e.g. --module 'core desktop builder server mobile'")
parser.add_option("--develop", action="store", type="string", dest="develop", default="0", help="defines develop mode")
parser.add_option("--beta", action="store", type="string", dest="beta", default="0", help="defines beta mode")
parser.add_option("--platform", action="store", type="string", dest="platform", default="native", help="defines the destination platform for your build ['win_64', 'win_32', 'win_64_xp', 'win_32_xp', 'win_arm64', 'linux_64', 'linux_32', 'mac_64', 'ios', 'android_arm64_v8a', 'android_armv7', 'android_x86', 'android_x86_64'; combinations: 'native': your current system (windows/linux/mac only); 'all': all available systems; 'windows': win_64 win_32 win_64_xp win_32_xp; 'linux': linux_64 linux_32; 'mac': mac_64; 'android': android_arm64_v8a android_armv7 android_x86 android_x86_64]")
parser.add_option("--platform", action="store", type="string", dest="platform", default="native", help="defines the destination platform for your build ['win_64', 'win_32', 'win_64_xp', 'win_32_xp', 'linux_64', 'linux_32', 'mac_64', 'ios', 'android_arm64_v8a', 'android_armv7', 'android_x86', 'android_x86_64'; combinations: 'native': your current system (windows/linux/mac only); 'all': all available systems; 'windows': win_64 win_32 win_64_xp win_32_xp; 'linux': linux_64 linux_32; 'mac': mac_64; 'android': android_arm64_v8a android_armv7 android_x86 android_x86_64]")
parser.add_option("--config", action="store", type="string", dest="config", default="", help="provides ability to specify additional parameters for qmake")
parser.add_option("--qt-dir", action="store", type="string", dest="qt-dir", default="", help="defines qmake directory path. qmake can be found in qt-dir/compiler/bin directory")
parser.add_option("--qt-dir-xp", action="store", type="string", dest="qt-dir-xp", default="", help="defines qmake directory path for Windows XP. qmake can be found in 'qt-dir/compiler/bin directory")
@ -42,7 +42,6 @@ parser.add_option("--vs-version", action="store", type="string", dest="vs-versio
parser.add_option("--vs-path", action="store", type="string", dest="vs-path", default="", help="path to vcvarsall")
parser.add_option("--siteUrl", action="store", type="string", dest="siteUrl", default="127.0.0.1", help="site url")
parser.add_option("--multiprocess", action="store", type="string", dest="multiprocess", default="1", help="provides ability to specify single process for make")
parser.add_option("--sysroot", action="store", type="string", dest="sysroot", default="0", help="provides ability to use sysroot (ubuntu 16.04) to build c++ code. If value is \"1\", then the sysroot from tools/linux/sysroot will be used, and if it is not there, it will download it and unpack it. You can also set value as the path to the your own sysroot (rarely used). Only for linux")
(options, args) = parser.parse_args(arguments)
configOptions = vars(options)

View File

@ -1,3 +1,3 @@
sdkjs-plugin="ai, photoeditor, ocr, translator, thesaurus, youtube, highlightcode"
sdkjs-plugin-server="speech, zotero, mendeley, speechrecognition"
sdkjs-plugin="photoeditor, macros, ocr, translator, thesaurus, youtube, highlightcode, zotero"
sdkjs-plugin-server="speech, zotero, mendeley, speechrecognition, drawio"
sdkjs-addons="sdkjs-forms"

View File

@ -6,10 +6,6 @@ but don't want to compile pretty compilcated core product to make those changes.
## System requirements
**Note**: ARM-based architectures are currently **NOT** supported;
attempting to run the images on ARM devices may result in startup failures
or other runtime issues.
### Windows
You need the latest

View File

@ -8,7 +8,7 @@ import run_server
import config
import base
git_dir = sys.argv[1]
git_dir = sys.argv[1];
base.print_info('argv :'+' '.join(sys.argv))
base.cmd_in_dir(git_dir + '/build_tools/', 'python3', ['configure.py', '--develop', '1'] + sys.argv[2:])
@ -18,7 +18,7 @@ config.parse_defaults()
if base.is_exist(git_dir + "/server/FileConverter/bin/fonts.log"):
base.print_info('remove font cache to regenerate fonts in external sdkjs volume')
base.delete_file(git_dir + "/server/FileConverter/bin/fonts.log")
base.delete_file(git_dir + "/server/FileConverter/bin/fonts.log");
# external server volume
if base.is_exist(sys.argv[1] + '/server/DocService/package.json'):
@ -28,7 +28,7 @@ if base.is_exist(sys.argv[1] + '/server/DocService/package.json'):
base.replaceInFileRE("/etc/supervisor/conf.d/ds-converter.conf", "command=.*", "command=node " + git_dir + "/server/FileConverter/sources/convertermaster.js")
base.replaceInFileRE("/app/ds/setup/config/supervisor/ds/ds-converter.conf", "command=.*", "command=node " + git_dir + "/server/FileConverter/sources/convertermaster.js")
base.print_info('run_server.run_docker_server')
run_server.run_docker_server()
run_server.run_docker_server();
else:
#Fix theme generation for external sdkjs volume
if base.is_exist(git_dir + "/server/FileConverter/bin/DoctRenderer.config"):

View File

@ -19,6 +19,8 @@ import make_common
import develop
import argparse
base.check_python()
parser = argparse.ArgumentParser(description="options")
parser.add_argument("--build-only-branding", action="store_true")
args = parser.parse_args()
@ -28,7 +30,6 @@ if (args.build_only_branding):
# parse configuration
config.parse()
base.check_python()
base_dir = base.get_script_dir(__file__)
@ -91,6 +92,8 @@ if config.check_option("module", "desktop"):
config.extend_option("config", "updmodule")
base.set_env("DESKTOP_URL_UPDATES_MAIN_CHANNEL", "https://download.onlyoffice.com/install/desktop/editors/windows/onlyoffice/appcast.json")
base.set_env("DESKTOP_URL_UPDATES_DEV_CHANNEL", "https://download.onlyoffice.com/install/desktop/editors/windows/onlyoffice/appcastdev.json")
base.set_env("DESKTOP_URL_INSTALL_CHANNEL", "https://download.onlyoffice.com/install/desktop/editors/windows/distrib/onlyoffice/<file>")
base.set_env("DESKTOP_URL_INSTALL_DEV_CHANNEL", "https://download.onlyoffice.com/install/desktop/editors/windows/onlyoffice/onlineinstallerdev/<file>")
# build
build_sln.make()

View File

@ -15,8 +15,6 @@ import stat
import json
__file__script__path__ = os.path.dirname( os.path.realpath(__file__))
icu_ver = "74"
icu_ver_old = "58" # for win_xp support
# common functions --------------------------------------
def get_script_dir(file=""):
@ -74,7 +72,7 @@ def check_build_version(dir):
version_number = version_number.replace("\n", "")
set_env("PRODUCT_VERSION", version_number)
if ("" == get_env("BUILD_NUMBER")):
set_env("BUILD_NUMBER", "0")
set_env("BUILD_NUMBER", "0")
return
def print_info(info=""):
@ -198,11 +196,11 @@ def move_dir(src, dst):
delete_dir(src)
return
def copy_dir(src, dst, symlinks=False):
def copy_dir(src, dst):
if is_dir(dst):
delete_dir(dst)
try:
shutil.copytree(get_path(src), get_path(dst), symlinks=symlinks)
shutil.copytree(get_path(src), get_path(dst))
except:
if ("windows" == host_platform()) and copy_dir_windows(src, dst):
return
@ -256,7 +254,7 @@ def delete_dir(path):
def copy_lib(src, dst, name):
if (config.check_option("config", "bundle_dylibs")) and is_dir(src + "/" + name + ".framework"):
copy_dir(src + "/" + name + ".framework", dst + "/" + name + ".framework", symlinks=True)
copy_dir(src + "/" + name + ".framework", dst + "/" + name + ".framework")
if (config.check_option("config", "bundle_xcframeworks")) and is_dir(src + "/simulator/" + name + ".framework"):
create_dir(dst + "/simulator")
@ -265,9 +263,9 @@ def copy_lib(src, dst, name):
if is_dir(dst + "/" + name + ".xcframework"):
delete_dir(dst + "/" + name + ".xcframework")
cmd("xcodebuild", ["-create-xcframework",
"-framework", dst + "/" + name + ".framework",
"-framework", dst + "/simulator/" + name + ".framework",
cmd("xcodebuild", ["-create-xcframework",
"-framework", dst + "/" + name + ".framework",
"-framework", dst + "/simulator/" + name + ".framework",
"-output", dst + "/" + name + ".xcframework"])
delete_dir(dst + "/" + name + ".framework")
@ -370,7 +368,7 @@ def writeFile(path, data):
return
# system cmd methods ------------------------------------
def cmd(prog, args=[], is_no_errors=False):
def cmd(prog, args=[], is_no_errors=False):
ret = 0
if ("windows" == host_platform()):
sub_args = args[:]
@ -385,7 +383,7 @@ def cmd(prog, args=[], is_no_errors=False):
sys.exit("Error (" + prog + "): " + str(ret))
return ret
def cmd2(prog, args=[], is_no_errors=False):
def cmd2(prog, args=[], is_no_errors=False):
ret = 0
command = prog if ("windows" != host_platform()) else get_path(prog)
for arg in args:
@ -430,13 +428,6 @@ def cmd_in_dir(directory, prog, args=[], is_no_errors=False):
os.chdir(cur_dir)
return ret
def cmd_in_dir_qemu(platform, directory, prog, args=[], is_no_errors=False):
if (platform == "linux_arm64"):
return cmd_in_dir(directory, "qemu-aarch64", ["-L", "/usr/aarch64-linux-gnu", prog] + args, is_no_errors)
if (platform == "linux_arm32"):
return cmd_in_dir(directory, "qemu-arm", ["-L", "/usr/arm-linux-gnueabi", prog] + args, is_no_errors)
return 0
def cmd_and_return_cwd(prog, args=[], is_no_errors=False):
cur_dir = os.getcwd()
ret = cmd(prog, args, is_no_errors)
@ -455,7 +446,7 @@ def run_command(sCommand):
finally:
popen.stdout.close()
popen.stderr.close()
return result
def run_command_in_dir(directory, sCommand):
@ -470,7 +461,7 @@ def run_command_in_dir(directory, sCommand):
if (host == 'windows'):
os.chdir(cur_dir)
return ret
def exec_command_in_dir(directory, sCommand):
host = host_platform()
if (host == 'windows'):
@ -523,27 +514,6 @@ def git_get_origin():
os.chdir(cur_dir)
return ret
def git_get_base_url():
"""Get the base URL for git operations, with fallback to GitHub"""
origin = git_get_origin()
if origin:
# Extract base URL from origin
if origin.startswith("https://"):
# For HTTPS URLs like https://git.example.com/owner/repo.git
parts = origin.split("/")
if len(parts) >= 4:
return "/".join(parts[:3]) + "/"
elif ":" in origin and "@" in origin:
# For SSH URLs like git@git.example.com:owner/repo.git
at_pos = origin.find("@")
colon_pos = origin.find(":", at_pos)
if at_pos != -1 and colon_pos != -1:
host = origin[at_pos+1:colon_pos]
return f"https://{host}/"
# Fallback to GitHub
return "https://github.com/"
def git_is_ssh():
git_protocol = config.option("git-protocol")
if (git_protocol == "https"):
@ -565,7 +535,7 @@ def get_ssh_base_url():
def git_update(repo, is_no_errors=False, is_current_dir=False, git_owner=""):
print("[git] update: " + repo)
owner = git_owner if git_owner else "ONLYOFFICE"
url = git_get_base_url() + owner + "/" + repo + ".git"
url = "https://github.com/" + owner + "/" + repo + ".git"
if git_is_ssh():
url = get_ssh_base_url() + repo + ".git"
folder = get_script_dir() + "/../../" + repo
@ -637,7 +607,7 @@ def get_branding_repositories(checker):
def create_pull_request(branches_to, repo, is_no_errors=False, is_current_dir=False):
print("[git] create pull request: " + repo)
url = git_get_base_url() + "ONLYOFFICE/" + repo + ".git"
url = "https://github.com/ONLYOFFICE/" + repo + ".git"
if git_is_ssh():
url = get_ssh_base_url() + repo + ".git"
folder = get_script_dir() + "/../../" + repo
@ -664,7 +634,7 @@ def create_pull_request(branches_to, repo, is_no_errors=False, is_current_dir=Fa
cmd("git", ["merge", "--abort"], is_no_errors)
else:
cmd("git", ["push"], is_no_errors)
os.chdir(old_cur)
return
@ -676,7 +646,7 @@ def update_repositories(repositories):
git_update(repo, value[0], False)
else:
if is_dir(current_dir + "/.git"):
delete_dir_with_access_error(current_dir)
delete_dir_with_access_error(current_dir);
delete_dir(current_dir)
if not is_dir(current_dir):
create_dir(current_dir)
@ -698,12 +668,9 @@ def get_prefix_cross_compiler_arm64():
return ""
def get_gcc_version():
gcc_path = "gcc"
if config.option("sysroot") != "":
gcc_path = config.option("sysroot") + "/usr/bin/gcc"
gcc_version_major = 4
gcc_version_minor = 0
gcc_version_str = run_command(gcc_path + " -dumpfullversion -dumpversion")['stdout']
gcc_version_str = run_command("gcc -dumpfullversion -dumpversion")['stdout']
if (gcc_version_str != ""):
try:
gcc_ver = gcc_version_str.split(".")
@ -741,14 +708,6 @@ def qt_setup(platform):
if ("gcc_arm" == compiler_platform):
qt_dir = config.option("qt-dir") + "/gcc"
# OVERRIDE IF NEEDED
set_env("QT_QMAKE_ADDON", "")
if platform == "win_arm64" and not is_dir(qt_dir):
override_qt_directory = os.path.abspath(os.path.dirname(__file__) + "/../tools/win/arm64/qt_build/Qt-5.15.2/win_arm64")
if is_dir(override_qt_directory):
qt_dir = os.path.abspath(override_qt_directory).replace("\\", "/")
set_env("QT_QMAKE_ADDON", "-spec win32-arm64-msvc2017")
set_env("QT_DEPLOY", qt_dir + "/bin")
if ("linux_arm64" == platform):
@ -757,7 +716,7 @@ def qt_setup(platform):
set_env("ARM64_TOOLCHAIN_BIN", cross_compiler_arm64)
set_env("ARM64_TOOLCHAIN_BIN_PREFIX", get_prefix_cross_compiler_arm64())
return qt_dir
return qt_dir
def qt_version():
qt_dir = get_env("QT_DEPLOY")
@ -843,9 +802,6 @@ def qt_config(platform):
if ("linux_arm64" == platform):
config_param += " linux_arm64"
if ("win_arm64" == platform):
config_param += " win_arm64"
config_param += qt_config_platform_addon(platform)
return config_param
@ -870,12 +826,6 @@ def qt_config_as_param(value):
def qt_copy_lib(lib, dir):
qt_dir = get_env("QT_DEPLOY")
# TODO: remove version from library name
qt_major = qt_major_version()
if ("5" != qt_major):
lib = lib.replace("Qt5", "Qt" + qt_major)
if ("windows" == host_platform()):
if ("" == qt_dst_postfix()):
copy_lib(qt_dir, dir, lib)
@ -884,7 +834,7 @@ def qt_copy_lib(lib, dir):
else:
src_file = qt_dir + "/../lib/lib" + lib + ".so." + qt_version()
if (is_file(src_file)):
copy_file(src_file, dir + "/lib" + lib + ".so." + qt_major)
copy_file(src_file, dir + "/lib" + lib + ".so." + qt_major_version())
else:
libFramework = lib
libFramework = libFramework.replace("Qt5", "Qt")
@ -908,24 +858,9 @@ def _check_icu_common(dir, out):
return isExist
def qt_copy_icu(out):
tests = [get_env("QT_DEPLOY") + "/../lib"]
prefix = ""
postfixes = [""]
# TODO add for linux arm desktop build
if config.option("sysroot") != "":
prefix = config.option("sysroot")
else:
prefix = ""
postfixes += ["/x86_64-linux-gnu"]
postfixes += ["/i386-linux-gnu"]
for postfix in postfixes:
tests += [prefix + "/lib" + postfix]
tests += [prefix + "/lib64" + postfix]
tests += [prefix + "/usr/lib" + postfix]
tests += [prefix + "/usr/lib64" + postfix]
tests = [get_env("QT_DEPLOY") + "/../lib", "/lib", "/lib/x86_64-linux-gnu", "/lib64", "/lib64/x86_64-linux-gnu"]
tests += ["/usr/lib", "/usr/lib/x86_64-linux-gnu", "/usr/lib64", "/usr/lib64/x86_64-linux-gnu"]
tests += ["/lib/i386-linux-gnu", "/usr/lib/i386-linux-gnu"]
for test in tests:
if (_check_icu_common(test, out)):
@ -937,7 +872,7 @@ def qt_copy_plugin(name, out):
src = get_env("QT_DEPLOY") + "/../plugins/" + name
if not is_dir(src):
return
copy_dir(src, out + "/" + name)
if ("windows" == host_platform()):
@ -949,7 +884,7 @@ def qt_copy_plugin(name, out):
else:
delete_file(fileCheck)
for file in glob.glob(out + "/" + name + "/*.pdb"):
delete_file(file)
delete_file(file)
return
def qt_dst_postfix():
@ -1014,14 +949,14 @@ def generate_doctrenderer_config(path, root, product, vendor = "", dictionaries
file.close()
return
def generate_plist(file, platform):
def generate_plist_framework_folder(file):
bundle_id_url = "com.onlyoffice."
if ("" != get_env("PUBLISHER_BUNDLE_ID")):
bundle_id_url = get_env("PUBLISHER_BUNDLE_ID")
bundle_creator = "Ascensio System SIA"
if ("" != get_env("PUBLISHER_NAME")):
bundle_creator = get_env("PUBLISHER_NAME")
bundle_version_natural = readFile(get_script_dir() + "/../../core/Common/version.txt").split(".")
bundle_version = []
for n in bundle_version_natural:
@ -1048,14 +983,11 @@ def generate_plist(file, platform):
content += "\t<string>????</string>\n"
content += "\t<key>CFBundleVersion</key>\n"
content += "\t<string>" + bundle_version[0] + "." + bundle_version[1] + "." + bundle_version[2] + "</string>\n"
if platform.find("ios") == 0:
content += "\t<key>MinimumOSVersion</key>\n"
content += "\t<string>13.0</string>\n"
content += "\t<key>MinimumOSVersion</key>\n"
content += "\t<string>13.0</string>\n"
content += "</dict>\n"
content += "</plist>"
if platform.find("mac") == 0:
file += "/Resources"
fileDst = file + "/Info.plist"
if is_file(fileDst):
delete_file(fileDst)
@ -1065,33 +997,7 @@ def generate_plist(file, platform):
fileInfo.close()
return
def generate_xcprivacy(file, platform):
content = \
"""<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
\t<key>NSPrivacyTracking</key>
\t<false/>
\t<key>NSPrivacyCollectedDataTypes</key>
\t<array/>
\t<key>NSPrivacyTrackingDomains</key>
\t<array/>
\t<key>NSPrivacyAccessedAPITypes</key>
\t<array/>
</dict>
</plist>"""
fileDst = os.path.join(file, "PrivacyInfo.xcprivacy")
fileInfo = codecs.open(fileDst, "w", "utf-8")
fileInfo.write(content)
fileInfo.close()
return
def for_each_framework(path, platform, callbacks, max_depth=512):
if not config.check_option("config", "bundle_dylibs"):
return
if max_depth == 0:
return
def generate_plist(path):
src_folder = path
if ("/" != path[-1:]):
src_folder += "/"
@ -1099,10 +1005,9 @@ def for_each_framework(path, platform, callbacks, max_depth=512):
for file in glob.glob(src_folder):
if (is_dir(file)):
if file.endswith(".framework"):
for callback in callbacks:
callback(file, platform)
generate_plist_framework_folder(file)
else:
for_each_framework(file, platform, callbacks, max_depth - 1)
generate_plist(file)
return
def correct_bundle_identifier(bundle_identifier):
@ -1301,95 +1206,71 @@ def get_file_last_modified_url(url):
key = key.upper()
if key == "LAST-MODIFIED":
retvalue = value
return retvalue
def mac_change_rpath_binary(bin, old, new):
cmd("install_name_tool", ["-change", old, new, bin], True)
def mac_change_rpath_library(lib_name, old, new):
# converts library name to actual library file name (dylib or binary file in framework)
def lib_name_to_file_name(lib_name):
if config.check_option("config", "bundle_dylibs"):
lib = lib_name + ".framework/" + lib_name
else:
lib = "lib" + lib_name + ".dylib"
return lib
mac_change_rpath_binary(lib_name_to_file_name(lib_name), old, new)
def mac_correct_rpath_binary(path, libs):
# if framework are built, instead of correcting lib paths add `@loader_path` to rpaths with `mac_add_loader_path_to_rpath()`
if config.check_option("config", "bundle_dylibs"):
return
for lib in libs:
mac_change_rpath_binary(path, "lib" + lib + ".dylib", "@rpath/lib" + lib + ".dylib")
cmd("install_name_tool", ["-change", "lib" + lib + ".dylib", "@rpath/lib" + lib + ".dylib", path], True)
return
def mac_correct_rpath_library(name, libs):
return mac_correct_rpath_binary("./lib" + name + ".dylib", libs)
mac_icu_libs = ["icudata." + icu_ver, "icuuc." + icu_ver]
def mac_correct_rpath_x2t(dir):
cur_dir = os.getcwd()
os.chdir(dir)
mac_correct_rpath_library("icudata." + icu_ver, [])
mac_correct_rpath_library("icuuc." + icu_ver, ["icudata." + icu_ver])
mac_correct_rpath_library("UnicodeConverter", mac_icu_libs)
mac_correct_rpath_library("icudata.58", [])
mac_correct_rpath_library("icuuc.58", ["icudata.58"])
mac_correct_rpath_library("UnicodeConverter", ["icuuc.58", "icudata.58"])
mac_correct_rpath_library("kernel", ["UnicodeConverter"])
mac_correct_rpath_library("kernel_network", ["UnicodeConverter", "kernel"])
mac_correct_rpath_library("graphics", ["UnicodeConverter", "kernel"])
mac_correct_rpath_library("doctrenderer", ["UnicodeConverter", "kernel", "kernel_network", "graphics", "PdfFile", "XpsFile", "OFDFile", "DjVuFile", "DocxRenderer"])
mac_correct_rpath_library("doctrenderer", ["UnicodeConverter", "kernel", "kernel_network", "graphics", "PdfFile", "XpsFile", "DjVuFile", "DocxRenderer"])
mac_correct_rpath_library("HtmlFile2", ["UnicodeConverter", "kernel", "kernel_network", "graphics"])
mac_correct_rpath_library("EpubFile", ["UnicodeConverter", "kernel", "HtmlFile2", "graphics"])
mac_correct_rpath_library("Fb2File", ["UnicodeConverter", "kernel", "graphics"])
mac_correct_rpath_library("PdfFile", ["UnicodeConverter", "kernel", "graphics", "kernel_network"])
mac_correct_rpath_library("DjVuFile", ["UnicodeConverter", "kernel", "graphics", "PdfFile"])
mac_correct_rpath_library("XpsFile", ["UnicodeConverter", "kernel", "graphics", "PdfFile"])
mac_correct_rpath_library("OFDFile", ["UnicodeConverter", "kernel", "graphics", "PdfFile"])
mac_correct_rpath_library("DocxRenderer", ["UnicodeConverter", "kernel", "graphics"])
mac_correct_rpath_library("IWorkFile", ["UnicodeConverter", "kernel"])
mac_correct_rpath_library("HWPFile", ["UnicodeConverter", "kernel", "graphics"])
def correct_core_executable(name, libs):
cmd("chmod", ["-v", "+x", name])
cmd("install_name_tool", ["-add_rpath", "@executable_path", name], True)
mac_correct_rpath_binary(name, mac_icu_libs + libs)
return
correct_core_executable("x2t", ["UnicodeConverter", "kernel", "kernel_network", "graphics", "PdfFile", "XpsFile", "OFDFile", "DjVuFile", "HtmlFile2", "Fb2File", "EpubFile", "doctrenderer", "DocxRenderer", "IWorkFile", "HWPFile"])
cmd("chmod", ["-v", "+x", "./x2t"])
cmd("install_name_tool", ["-add_rpath", "@executable_path", "./x2t"], True)
mac_correct_rpath_binary("./x2t", ["icudata.58", "icuuc.58", "UnicodeConverter", "kernel", "kernel_network", "graphics", "PdfFile", "XpsFile", "DjVuFile", "HtmlFile2", "Fb2File", "EpubFile", "doctrenderer", "DocxRenderer", "IWorkFile", "HWPFile"])
if is_file("./allfontsgen"):
correct_core_executable("allfontsgen", ["UnicodeConverter", "kernel", "graphics"])
cmd("chmod", ["-v", "+x", "./allfontsgen"])
cmd("install_name_tool", ["-add_rpath", "@executable_path", "./allfontsgen"], True)
mac_correct_rpath_binary("./allfontsgen", ["icudata.58", "icuuc.58", "UnicodeConverter", "kernel", "graphics"])
if is_file("./allthemesgen"):
correct_core_executable("allthemesgen", ["UnicodeConverter", "kernel", "graphics", "kernel_network", "doctrenderer", "PdfFile", "XpsFile", "OFDFile", "DjVuFile", "DocxRenderer"])
cmd("chmod", ["-v", "+x", "./allthemesgen"])
cmd("install_name_tool", ["-add_rpath", "@executable_path", "./allthemesgen"], True)
mac_correct_rpath_binary("./allthemesgen", ["icudata.58", "icuuc.58", "UnicodeConverter", "kernel", "graphics", "kernel_network", "doctrenderer", "PdfFile", "XpsFile", "DjVuFile", "DocxRenderer"])
if is_file("./pluginsmanager"):
correct_core_executable("pluginsmanager", ["UnicodeConverter", "kernel", "kernel_network"])
cmd("chmod", ["-v", "+x", "./pluginsmanager"])
cmd("install_name_tool", ["-add_rpath", "@executable_path", "./pluginsmanager"], True)
mac_correct_rpath_binary("./pluginsmanager", ["icudata.58", "icuuc.58", "UnicodeConverter", "kernel", "kernel_network"])
if is_file("./vboxtester"):
correct_core_executable("vboxtester", ["UnicodeConverter", "kernel", "kernel_network"])
if is_file("./x2ttester"):
correct_core_executable("x2ttester", ["UnicodeConverter", "kernel", "graphics"])
cmd("chmod", ["-v", "+x", "./vboxtester"])
cmd("install_name_tool", ["-add_rpath", "@executable_path", "./vboxtester"], True)
mac_correct_rpath_binary("./vboxtester", ["icudata.58", "icuuc.58", "UnicodeConverter", "kernel", "kernel_network"])
os.chdir(cur_dir)
return
def mac_add_loader_path_to_rpath(libs):
for lib in libs:
if config.check_option("config", "bundle_dylibs"):
# icu libs are linked statically for frameworks
if lib in mac_icu_libs:
continue
cmd("install_name_tool", ["-add_rpath", "@loader_path/../../..", lib + ".framework/" + lib], True)
else:
cmd("install_name_tool", ["-add_rpath", "@loader_path", "lib" + lib + ".dylib"], True)
def mac_correct_rpath_docbuilder(dir):
cur_dir = os.getcwd()
os.chdir(dir)
cmd("chmod", ["-v", "+x", "./docbuilder"])
cmd("install_name_tool", ["-add_rpath", "@executable_path", "./docbuilder"], True)
mac_correct_rpath_binary("./docbuilder", mac_icu_libs + ["UnicodeConverter", "kernel", "kernel_network", "graphics", "PdfFile", "XpsFile", "OFDFile", "DjVuFile", "HtmlFile2", "Fb2File", "EpubFile", "IWorkFile", "HWPFile", "doctrenderer", "DocxRenderer"])
mac_correct_rpath_library("docbuilder.c", mac_icu_libs + ["UnicodeConverter", "kernel", "kernel_network", "graphics", "doctrenderer", "PdfFile", "XpsFile", "OFDFile", "DjVuFile", "DocxRenderer"])
mac_correct_rpath_binary("./docbuilder", ["icudata.58", "icuuc.58", "UnicodeConverter", "kernel", "kernel_network", "graphics", "PdfFile", "XpsFile", "DjVuFile", "HtmlFile2", "Fb2File", "EpubFile", "IWorkFile", "HWPFile", "doctrenderer", "DocxRenderer"])
mac_correct_rpath_library("docbuilder.c", ["icudata.58", "icuuc.58", "UnicodeConverter", "kernel", "kernel_network", "graphics", "doctrenderer", "PdfFile", "XpsFile", "DjVuFile", "DocxRenderer"])
mac_add_loader_path_to_rpath(["icuuc." + icu_ver, "UnicodeConverter", "kernel", "kernel_network", "graphics", "doctrenderer", "PdfFile", "XpsFile", "OFDFile", "DjVuFile", "DocxRenderer", "docbuilder.c"])
def add_loader_path_to_rpath(libs):
for lib in libs:
cmd("install_name_tool", ["-add_rpath", "@loader_path", "lib" + lib + ".dylib"], True)
add_loader_path_to_rpath(["icuuc.58", "UnicodeConverter", "kernel", "kernel_network", "graphics", "doctrenderer", "PdfFile", "XpsFile", "DjVuFile", "DocxRenderer", "docbuilder.c"])
os.chdir(cur_dir)
return
@ -1399,9 +1280,9 @@ def mac_correct_rpath_desktop(dir):
os.chdir(dir)
mac_correct_rpath_library("hunspell", [])
mac_correct_rpath_library("ooxmlsignature", ["kernel"])
mac_correct_rpath_library("ascdocumentscore", ["UnicodeConverter", "kernel", "graphics", "kernel_network", "PdfFile", "XpsFile", "DjVuFile", "hunspell", "ooxmlsignature", "doctrenderer"])
mac_change_rpath_library("ascdocumentscore", "@executable_path/../Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework", "@rpath/Chromium Embedded Framework.framework/Chromium Embedded Framework")
mac_correct_rpath_binary("./editors_helper.app/Contents/MacOS/editors_helper", ["ascdocumentscore", "UnicodeConverter", "kernel", "kernel_network", "graphics", "PdfFile", "XpsFile", "OFDFile", "DjVuFile", "hunspell", "ooxmlsignature", "doctrenderer"])
mac_correct_rpath_library("ascdocumentscore", ["UnicodeConverter", "kernel", "graphics", "kernel_network", "PdfFile", "XpsFile", "DjVuFile", "hunspell", "ooxmlsignature"])
cmd("install_name_tool", ["-change", "@executable_path/../Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework", "@rpath/Chromium Embedded Framework.framework/Chromium Embedded Framework", "libascdocumentscore.dylib"])
mac_correct_rpath_binary("./editors_helper.app/Contents/MacOS/editors_helper", ["ascdocumentscore", "UnicodeConverter", "kernel", "kernel_network", "graphics", "PdfFile", "XpsFile", "DjVuFile", "hunspell", "ooxmlsignature"])
cmd("install_name_tool", ["-add_rpath", "@executable_path/../../../../Frameworks", "./editors_helper.app/Contents/MacOS/editors_helper"], True)
cmd("install_name_tool", ["-add_rpath", "@executable_path/../../../../Resources/converter", "./editors_helper.app/Contents/MacOS/editors_helper"], True)
cmd("chmod", ["-v", "+x", "./editors_helper.app/Contents/MacOS/editors_helper"])
@ -1435,7 +1316,7 @@ def linux_set_origin_rpath_libraries(dir, libs):
return
def linux_correct_rpath_docbuilder(dir):
linux_set_origin_rpath_libraries(dir, ["docbuilder.jni.so", "docbuilder.c.so", "icuuc.so." + icu_ver, "doctrenderer.so", "graphics.so", "kernel.so", "kernel_network.so", "UnicodeConverter.so", "PdfFile.so", "XpsFile.so", "OFDFile.so", "DjVuFile.so", "DocxRenderer.so"])
linux_set_origin_rpath_libraries(dir, ["docbuilder.jni.so", "docbuilder.c.so", "icuuc.so.58", "doctrenderer.so", "graphics.so", "kernel.so", "kernel_network.so", "UnicodeConverter.so", "PdfFile.so", "XpsFile.so", "DjVuFile.so", "DocxRenderer.so"])
return
def common_check_version(name, good_version, clean_func):
@ -1518,12 +1399,12 @@ def copy_sdkjs_plugins(dst_dir, is_name_as_guid=False, is_desktop_local=False, i
plugins_dir = __file__script__path__ + "/../../onlyoffice.github.io/sdkjs-plugins/content"
plugins_list_config = config.option("sdkjs-plugin")
if isXp:
plugins_list_config="photoeditor, highlightcode, doc2md"
plugins_list_config="photoeditor, macros, highlightcode, doc2md"
if ("" == plugins_list_config):
return
plugins_list = plugins_list_config.rsplit(", ")
for name in plugins_list:
copy_sdkjs_plugin(plugins_dir, dst_dir, name, is_name_as_guid, is_desktop_local)
copy_sdkjs_plugin(plugins_dir, dst_dir, name, is_name_as_guid, is_desktop_local)
return
def copy_sdkjs_plugins_server(dst_dir, is_name_as_guid=False, is_desktop_local=False):
@ -1533,7 +1414,7 @@ def copy_sdkjs_plugins_server(dst_dir, is_name_as_guid=False, is_desktop_local=F
return
plugins_list = plugins_list_config.rsplit(", ")
for name in plugins_list:
copy_sdkjs_plugin(plugins_dir, dst_dir, name, is_name_as_guid, is_desktop_local)
copy_sdkjs_plugin(plugins_dir, dst_dir, name, is_name_as_guid, is_desktop_local)
return
def support_old_versions_plugins(out_dir):
@ -1547,11 +1428,11 @@ def support_old_versions_plugins(out_dir):
content_plugin_base += file.read()
content_plugin_base += "\n\n"
with open(get_path(out_dir + "/plugins-ui.js"), "r") as file:
content_plugin_base += file.read()
content_plugin_base += file.read()
with open(get_path(out_dir + "/pluginBase.js"), "w") as file:
file.write(content_plugin_base)
delete_file(out_dir + "/plugins.js")
delete_file(out_dir + "/plugins-ui.js")
delete_file(out_dir + "/plugins-ui.js")
return
def generate_sdkjs_plugin_list(dst):
@ -1584,7 +1465,7 @@ def hack_xcode_ios():
filedata += "\n"
filedata += content_hack
filedata += "\n\n"
delete_file(qmake_spec_file)
with open(get_path(qmake_spec_file), "w") as file:
file.write(filedata)
@ -1665,12 +1546,12 @@ def copy_v8_files(core_dir, deploy_dir, platform, is_xp=False):
if (-1 != config.option("config").find("use_javascript_core")):
return
directory_v8 = core_dir + "/Common/3dParty"
if is_xp:
directory_v8 += "/v8/v8_xp"
copy_files(directory_v8 + platform + "/release/icudt*.dll", deploy_dir + "/")
return
if config.check_option("config", "v8_version_60"):
directory_v8 += "/v8/v8/out.gn/"
else:
@ -1682,7 +1563,7 @@ def copy_v8_files(core_dir, deploy_dir, platform, is_xp=False):
copy_files(directory_v8 + platform + "/icudt*.dat", deploy_dir + "/")
return
def clone_marketplace_plugin(out_dir, is_name_as_guid=False, is_replace_paths=False, is_delete_git_dir=True, git_owner=""):
def clone_marketplace_plugin(out_dir, is_name_as_guid=False, is_replace_paths=False, is_delete_git_dir=True, git_owner=""):
old_cur = os.getcwd()
os.chdir(out_dir)
git_update("onlyoffice.github.io", False, True, git_owner)
@ -1703,11 +1584,11 @@ def clone_marketplace_plugin(out_dir, is_name_as_guid=False, is_replace_paths=Fa
if is_dir(dst_dir_path):
delete_dir(dst_dir_path)
copy_dir(out_dir + "/onlyoffice.github.io/store/plugin", dst_dir_path)
if is_replace_paths:
for file in glob.glob(dst_dir_path + "/*.html"):
replaceInFile(file, "https://onlyoffice.github.io/sdkjs-plugins/", "../")
if is_delete_git_dir:
delete_dir_with_access_error(out_dir + "/onlyoffice.github.io")
return
@ -1732,7 +1613,7 @@ def restorePathForBuilder(new_path):
old_path = new_path[:-4]
delete_file(old_path)
copy_file(new_path, old_path)
delete_file(new_path)
delete_file(new_path);
return
def generate_check_linux_system(build_tools_dir, out_dir):
@ -1744,20 +1625,20 @@ def generate_check_linux_system(build_tools_dir, out_dir):
def convert_ios_framework_to_xcframework(folder, lib):
cur_dir = os.getcwd()
os.chdir(folder)
create_dir(lib + "_xc_tmp")
create_dir(lib + "_xc_tmp/iphoneos")
create_dir(lib + "_xc_tmp/iphonesimulator")
copy_dir(lib + ".framework", lib + "_xc_tmp/iphoneos/" + lib + ".framework")
copy_dir(lib + ".framework", lib + "_xc_tmp/iphonesimulator/" + lib + ".framework")
cmd("xcrun", ["lipo", "-remove", "x86_64", "./" + lib + "_xc_tmp/iphoneos/" + lib + ".framework/" + lib,
cmd("xcrun", ["lipo", "-remove", "x86_64", "./" + lib + "_xc_tmp/iphoneos/" + lib + ".framework/" + lib,
"-o", "./" + lib + "_xc_tmp/iphoneos/" + lib + ".framework/" + lib])
cmd("xcrun", ["lipo", "-remove", "arm64", "./" + lib + "_xc_tmp/iphonesimulator/" + lib + ".framework/" + lib,
cmd("xcrun", ["lipo", "-remove", "arm64", "./" + lib + "_xc_tmp/iphonesimulator/" + lib + ".framework/" + lib,
"-o", "./" + lib + "_xc_tmp/iphonesimulator/" + lib + ".framework/" + lib])
cmd("xcodebuild", ["-create-xcframework",
"-framework", "./" + lib + "_xc_tmp/iphoneos/" + lib + ".framework/",
cmd("xcodebuild", ["-create-xcframework",
"-framework", "./" + lib + "_xc_tmp/iphoneos/" + lib + ".framework/",
"-framework", "./" + lib + "_xc_tmp/iphonesimulator/" + lib + ".framework/",
"-output", lib + ".xcframework"])
@ -1773,7 +1654,7 @@ def convert_ios_framework_to_xcframework_folder(folder, libs):
def change_elf_rpath(path, origin):
# excludes ---
if (-1 != path.find("libicudata.so." + icu_ver)):
if (-1 != path.find("libicudata.so.58")):
return
# ------------
tools_dir = get_script_dir() + "/../tools/linux/elf/"
@ -1805,7 +1686,7 @@ def change_elf_rpath(path, origin):
cmd(tools_dir + "patchelf", ["--set-rpath", new_path, path], True)
#print("[" + os.path.basename(path) + "] old: " + old_path + "; new: " + new_path)
return
def correct_elf_rpath_directory(directory, origin, is_recursion = True):
for file in glob.glob(directory + "/*"):
if is_file(file):
@ -1858,14 +1739,14 @@ def copy_dictionaries(src, dst, is_hyphen = True, is_spell = True):
if is_hyphen and is_hyphen_present:
copy_dir_content(file, lang_folder, "hyph_", "")
if is_spell and is_spell_present:
copy_dir_content(file, lang_folder, "", "hyph_")
if is_file(dst + "/en_US/en_US_thes.dat"):
delete_file(dst + "/en_US/en_US_thes.dat")
delete_file(dst + "/en_US/en_US_thes.idx")
if is_file(dst + "/ru_RU/ru_RU_oo3.dic"):
delete_file(dst + "/ru_RU/ru_RU_oo3.dic")
delete_file(dst + "/ru_RU/ru_RU_oo3.aff")
@ -1887,25 +1768,6 @@ def check_module_version(actual_version, clear_func):
clear_func()
return
def set_sysroot_env():
global ENV_BEFORE_SYSROOT
ENV_BEFORE_SYSROOT = dict(os.environ)
if "linux" == host_platform() and config.option("sysroot") != "":
os.environ['PATH'] = config.option("sysroot") + "/usr/bin:" + get_env("PATH")
os.environ['LD_LIBRARY_PATH'] = config.get_custom_sysroot_lib()
os.environ['QMAKE_CUSTOM_SYSROOT'] = config.option("sysroot")
os.environ['PKG_CONFIG_PATH'] = config.get_custom_sysroot_lib() + "/pkgconfig"
os.environ['CC'] = config.get_custom_sysroot_bin() + "/gcc"
os.environ['CXX'] = config.get_custom_sysroot_bin() + "/g++"
os.environ['CFLAGS'] = "--sysroot=" + config.option("sysroot")
os.environ['CXXFLAGS'] = "--sysroot=" + config.option("sysroot")
check_python()
def restore_sysroot_env():
os.environ.clear()
os.environ.update(ENV_BEFORE_SYSROOT)
def check_python():
if ("linux" != host_platform()):
return
@ -1913,7 +1775,6 @@ def check_python():
directory_bin = __file__script__path__ + "/../tools/linux/python3/bin"
if not is_dir(directory + "/python3"):
download('https://github.com/ONLYOFFICE-data/build_tools_data/raw/refs/heads/master/python/python3.tar.gz', directory + "/python3.tar.gz")
cmd("tar", ["xfz", directory + "/python3.tar.gz", "-C", directory])
cmd("ln", ["-s", directory_bin + "/python3", directory_bin + "/python"])
directory_bin = directory_bin.replace(" ", "\\ ")
@ -1944,11 +1805,9 @@ def get_autobuild_version(product, platform="", branch="", build=""):
download_platform = platform
if ("" == download_platform):
osType = get_platform()
isArm = True if (-1 != osType.find("arm")) else False
is64 = True if (osType.endswith("64")) else False
isArm = False
if (-1 != osType.find("arm")) or (-1 != osType.find("aarch64")):
isArm = True
if ("windows" == host_platform()):
download_platform = "win-"
elif ("linux" == host_platform()):
@ -1972,15 +1831,8 @@ def get_autobuild_version(product, platform="", branch="", build=""):
download_addon = download_branch + "/" + download_build + "/" + product + "-" + download_platform + ".7z"
return "http://repo-doc-onlyoffice-com.s3.amazonaws.com/archive/" + download_addon
def create_x2t_js_cache(dir, product, platform):
# mac
if is_file(dir + "/libdoctrenderer.dylib") or is_dir(dir + "/doctrenderer.framework"):
doctrenderer_lib = "libdoctrenderer.dylib" if is_file(dir + "/libdoctrenderer.dylib") else "doctrenderer.framework/doctrenderer"
if os.path.getsize(dir + "/" + doctrenderer_lib) < 5*1024*1024:
return
if ((platform == "linux_arm64") and not is_os_arm()):
cmd_in_dir_qemu(platform, dir, "./x2t", ["-create-js-snapshots"], True)
def create_x2t_js_cache(dir, product):
if is_file(dir + "/libdoctrenderer.dylib") and (os.path.getsize(dir + "/libdoctrenderer.dylib") < 5*1024*1024):
return
cmd_in_dir(dir, "./x2t", ["-create-js-snapshots"], True)
@ -1988,35 +1840,6 @@ def create_x2t_js_cache(dir, product, platform):
def setup_local_qmake(dir_qmake):
dir_base = os.path.dirname(dir_qmake)
writeFile(dir_base + "/onlyoffice_qt.conf", "Prefix = " + dir_base)
return
def deploy_icu(core_dir, dst_dir, platform):
if (0 == platform.find("android")):
src_dir = core_dir + "/Common/3dParty/icu/android/build/" + platform[8:]
copy_file(src_dir + "/icudt" + icu_ver + "l.dat", dst_dir + "/icudt" + icu_ver + "l.dat")
return
isXp = False
if platform.endswith("xp"):
isXp = True
platform = platform[0:-3]
src_dir = core_dir + "/Common/3dParty/icu/" + platform + "/build"
if (0 == platform.find("win")):
icu_ver_win = icu_ver
if isXp:
icu_ver_win = icu_ver_old
src_dir += "/xp"
copy_file(src_dir + "/icudt" + icu_ver_win + ".dll", dst_dir + "/icudt" + icu_ver_win + ".dll")
copy_file(src_dir + "/icuuc" + icu_ver_win + ".dll", dst_dir + "/icuuc" + icu_ver_win + ".dll")
if (0 == platform.find("linux")):
copy_file(src_dir + "/libicudata.so." + icu_ver, dst_dir + "/libicudata.so." + icu_ver)
copy_file(src_dir + "/libicuuc.so." + icu_ver, dst_dir + "/libicuuc.so." + icu_ver)
if (0 == platform.find("mac") and not config.check_option("config", "bundle_dylibs")):
copy_file(src_dir + "/libicudata." + icu_ver + ".dylib", dst_dir + "/libicudata." + icu_ver + ".dylib")
copy_file(src_dir + "/libicuuc." + icu_ver + ".dylib", dst_dir + "/libicuuc." + icu_ver + ".dylib")
writeFile(dir_base + "/onlyoffice_qt.conf", "Prefix = " + dir_base)
return

View File

@ -33,29 +33,24 @@ def make():
base.set_env('NODE_ENV', 'production')
base_dir = base.get_script_dir() + "/.."
out_dir = base_dir + "/out/js/"
out_dir = base_dir + "/out/js/";
branding = config.option("branding-name")
if ("" == branding):
branding = "onlyoffice"
out_dir += branding
base.create_dir(out_dir)
isOnlyMobile = False
if (config.option("module") == "mobile"):
isOnlyMobile = True
# builder
if not isOnlyMobile:
base.cmd_in_dir(base_dir + "/../web-apps/translation", "python", ["merge_and_check.py"])
build_interface(base_dir + "/../web-apps/build")
build_sdk_builder(base_dir + "/../sdkjs/build")
base.create_dir(out_dir + "/builder")
base.copy_dir(base_dir + "/../web-apps/deploy/web-apps", out_dir + "/builder/web-apps")
base.copy_dir(base_dir + "/../sdkjs/deploy/sdkjs", out_dir + "/builder/sdkjs")
correct_sdkjs_licence(out_dir + "/builder/sdkjs")
base.cmd_in_dir(base_dir + "/../web-apps/translation", "python", ["merge_and_check.py"])
build_interface(base_dir + "/../web-apps/build")
build_sdk_builder(base_dir + "/../sdkjs/build")
base.create_dir(out_dir + "/builder")
base.copy_dir(base_dir + "/../web-apps/deploy/web-apps", out_dir + "/builder/web-apps")
base.copy_dir(base_dir + "/../sdkjs/deploy/sdkjs", out_dir + "/builder/sdkjs")
correct_sdkjs_licence(out_dir + "/builder/sdkjs")
# desktop
if config.check_option("module", "desktop") and not isOnlyMobile:
if config.check_option("module", "desktop"):
build_sdk_desktop(base_dir + "/../sdkjs/build")
base.create_dir(out_dir + "/desktop")
base.copy_dir(base_dir + "/../sdkjs/deploy/sdkjs", out_dir + "/desktop/sdkjs")
@ -65,6 +60,10 @@ def make():
deldirs = ['ie', 'mobile', 'embed']
[base.delete_dir(root + "/" + d) for root, dirs, f in os.walk(out_dir + "/desktop/web-apps/apps") for d in dirs if d in deldirs]
# for bug 62528. remove empty folders
walklist = list(os.walk(out_dir + "/desktop/sdkjs"))
[os.remove(p) for p, _, _ in walklist[::-1] if len(os.listdir(p)) == 0]
base.copy_file(base_dir + "/../web-apps/apps/api/documents/index.html.desktop", out_dir + "/desktop/web-apps/apps/api/documents/index.html")
build_interface(base_dir + "/../desktop-apps/common/loginpage/build")
@ -73,7 +72,7 @@ def make():
# mobile
if config.check_option("module", "mobile"):
build_sdk_native(base_dir + "/../sdkjs/build")
build_sdk_native(base_dir + "/../sdkjs/build", False)
base.create_dir(out_dir + "/mobile")
base.create_dir(out_dir + "/mobile/sdkjs")
vendor_dir_src = base_dir + "/../web-apps/vendor/"
@ -105,10 +104,7 @@ def make():
# JS build
def _run_npm(directory):
retValue = base.cmd_in_dir(directory, "npm", ["install"], True)
if (0 != retValue):
retValue = base.cmd_in_dir(directory, "npm", ["install", "--verbose"])
return retValue
return base.cmd_in_dir(directory, "npm", ["install"])
def _run_npm_ci(directory):
return base.cmd_in_dir(directory, "npm", ["ci"])
@ -121,7 +117,7 @@ def _run_grunt(directory, params=[]):
def build_interface(directory):
_run_npm(directory)
_run_grunt(directory, ["--force", "--verbose"] + base.web_apps_addons_param())
_run_grunt(directory, ["--force"] + base.web_apps_addons_param())
return
def get_build_param(minimize=True):

View File

@ -38,8 +38,7 @@ def make():
if(base.is_exist(custom_public_key)):
base.copy_file(custom_public_key, server_dir + '/Common/sources')
#node22 packaging has issue https://github.com/yao-pkg/pkg/issues/87
pkg_target = "node20"
pkg_target = "node16"
if ("linux" == base.host_platform()):
pkg_target += "-linux"
@ -52,7 +51,6 @@ def make():
base.cmd_in_dir(server_dir + "/DocService", "pkg", [".", "-t", pkg_target, "--options", "max_old_space_size=4096", "-o", "docservice"])
base.cmd_in_dir(server_dir + "/FileConverter", "pkg", [".", "-t", pkg_target, "-o", "converter"])
base.cmd_in_dir(server_dir + "/Metrics", "pkg", [".", "-t", pkg_target, "-o", "metrics"])
base.cmd_in_dir(server_dir + "/AdminPanel/server", "pkg", [".", "-t", pkg_target, "-o", "adminpanel"])
example_dir = base.get_script_dir() + "/../../document-server-integration/web/documentserver-example/nodejs"
base.delete_dir(example_dir + "/node_modules")
@ -66,9 +64,10 @@ def build_server_with_addons():
for addon in addons:
if (addon):
addon_dir = base.get_script_dir() + "/../../" + addon
if (base.is_exist(addon_dir)):
base.cmd_in_dir(addon_dir, "npm", ["ci"])
base.cmd_in_dir(addon_dir, "npm", ["run", "build"])
base.cmd_in_dir(addon_dir, "npm", ["ci"])
base.cmd_in_dir(addon_dir, "npm", ["run", "build"])
def build_server_develop():
build_server_with_addons()
server_dir = base.get_script_dir() + "/../../server"
base.cmd_in_dir(server_dir, "npm", ["ci"])
base.cmd_in_dir(server_dir, "grunt", ["develop", "-v"] + base.server_addons_param())

View File

@ -35,18 +35,6 @@ def make(solution=""):
qmake.make(platform, pro, "xcframework_platform_ios_simulator")
if config.check_option("module", "builder") and base.is_windows() and "onlyoffice" == config.branding():
# check branding libs
if (config.option("branding-name") == "onlyoffice"):
for platform in platforms:
if not platform in config.platforms:
continue
core_lib_unbranding_dir = os.getcwd() + "/../core/build/lib/" + platform + base.qt_dst_postfix()
if not base.is_dir(core_lib_unbranding_dir):
base.create_dir(core_lib_unbranding_dir)
core_lib_branding_dir = os.getcwd() + "/../core/build/onlyoffice/lib/" + platform + base.qt_dst_postfix()
base.copy_file(core_lib_branding_dir + "/doctrenderer.dll", core_lib_unbranding_dir + "/doctrenderer.dll")
base.copy_file(core_lib_branding_dir + "/doctrenderer.lib", core_lib_unbranding_dir + "/doctrenderer.lib")
# check replace
directory_builder_branding = os.getcwd() + "/../core/DesktopEditor/doctrenderer"
if base.is_dir(directory_builder_branding):

View File

@ -24,7 +24,7 @@ def parse():
# all platforms
global platforms
platforms = ["win_64", "win_32", "win_64_xp", "win_32_xp", "win_arm64",
platforms = ["win_64", "win_32", "win_64_xp", "win_32_xp",
"linux_64", "linux_32", "linux_arm64",
"mac_64", "mac_arm64",
"ios",
@ -57,12 +57,6 @@ def parse():
if not check_option("platform", "mac_64"):
options["platform"] = "mac_64 " + options["platform"]
if (False):
# use qemu on deploy for emulation
if ("windows" == host_platform) and check_option("platform", "win_arm64") and not base.is_os_arm():
if not check_option("platform", "win_64"):
options["platform"] = "win_64 " + options["platform"]
if ("linux" == host_platform) and check_option("platform", "linux_arm64") and not base.is_os_arm():
if not check_option("platform", "linux_64"):
# linux_64 binaries need only for desktop
@ -83,27 +77,6 @@ def parse():
if ("windows" == host_platform) and ("2019" == option("vs-version")):
extend_option("config", "vs2019")
# sysroot setup
if "linux" != host_platform and "sysroot" in options:
options["sysroot"] = ""
if "linux" == host_platform and "sysroot" in options:
if options["sysroot"] == "0":
options["sysroot"] = ""
elif options["sysroot"] == "1":
dst_dir = os.path.abspath(base.get_script_dir(__file__) + '/../tools/linux/sysroot')
custom_sysroot = dst_dir + '/sysroot_ubuntu_1604'
options["sysroot"] = custom_sysroot
if not os.path.isdir(custom_sysroot):
print("Sysroot is not found, downloading...")
sysroot_url = 'https://github.com/ONLYOFFICE-data/build_tools_data/raw/refs/heads/master/sysroot/sysroot_ubuntu_1604.tar.xz'
base.download(sysroot_url, dst_dir + '/sysroot_ubuntu_1604.tar.xz')
os.mkdir(custom_sysroot)
print("Unpacking...")
base.cmd2('tar', ['-xf', dst_dir + '/sysroot_ubuntu_1604.tar.xz', '-C', dst_dir])
if os.path.exists(dst_dir + '/sysroot_ubuntu_1604.tar.xz'):
os.remove(dst_dir + '/sysroot_ubuntu_1604.tar.xz')
if is_cef_107():
extend_option("config", "cef_version_107")
@ -132,10 +105,7 @@ def parse():
options["sdkjs-plugin-server"] = "default"
if not "arm64-toolchain-bin" in options:
if not "sysroot" in options:
options["arm64-toolchain-bin"] = "/usr/bin"
else:
options["arm64-toolchain-bin"] = get_custom_sysroot_bin()
options["arm64-toolchain-bin"] = "/usr/bin"
if check_option("platform", "ios"):
if not check_option("config", "no_bundle_xcframeworks"):
@ -146,10 +116,6 @@ def parse():
if not check_option("config", "bundle_dylibs"):
extend_option("config", "bundle_dylibs")
if ("mac" == host_platform) and check_option("module", "desktop"):
if not check_option("config", "bundle_dylibs"):
extend_option("config", "bundle_dylibs")
if check_option("use-system-qt", "1"):
base.cmd_in_dir(base.get_script_dir() + "/../tools/linux", "python", ["use_system_qt.py"])
options["qt-dir"] = base.get_script_dir() + "/../tools/linux/system_qt"
@ -173,9 +139,6 @@ def check_compiler(platform):
if (0 == platform.find("win")):
compiler["compiler"] = "msvc" + options["vs-version"]
compiler["compiler_64"] = "msvc" + options["vs-version"] + "_64"
if (0 == platform.find("win_arm")):
compiler["compiler"] = "msvc" + options["vs-version"] + "_arm"
compiler["compiler_64"] = "msvc" + options["vs-version"] + "_arm64"
elif (0 == platform.find("linux")):
compiler["compiler"] = "gcc"
compiler["compiler_64"] = "gcc_64"
@ -236,14 +199,6 @@ def is_mobile_platform():
return True
return False
def get_custom_sysroot_bin():
return option("sysroot") + "/usr/bin"
# todo 32bit support?
def get_custom_sysroot_lib():
if base.is_os_64bit():
return option("sysroot") + "/usr/lib/x86_64-linux-gnu"
def parse_defaults():
defaults_path = base.get_script_dir() + "/../defaults"
if ("" != option("branding")):

View File

@ -17,16 +17,12 @@ import websocket_all
import v8
import html2
import iwork
import md
import hunspell
import glew
import harfbuzz
import oo_brotli
import hyphen
import googletest
import libvlc
import heif
import webp
def check_android_ndk_macos_arm(dir):
if base.is_dir(dir + "/darwin-x86_64") and not base.is_dir(dir + "/darwin-arm64"):
@ -48,19 +44,15 @@ def make():
v8.make()
html2.make()
iwork.make(False)
md.make()
hunspell.make(False)
harfbuzz.make()
glew.make()
hyphen.make()
googletest.make()
oo_brotli.make()
heif.make()
webp.make()
if config.check_option("build-libvlc", "1"):
libvlc.make()
if config.check_option("module", "mobile"):
if (config.check_option("platform", "android")):
curl.make()

View File

@ -71,6 +71,13 @@ else:
"arch" : "darwin-x86_64"
}
def get_android_ndk_version():
#return "26.2.11394342"
return "21.1.6352462"
def get_android_ndk_version_major():
return int(get_android_ndk_version().split(".")[0])
def get_options_dict_as_array(opts):
value = []
for key in opts:

View File

@ -11,8 +11,8 @@ current_dir = os.path.abspath(current_dir)
if not current_dir.endswith("/"):
current_dir += "/"
icu_major = "74"
icu_minor = "2"
icu_major = "58"
icu_minor = "3"
options = {
"--enable-strict" : "no",
@ -41,12 +41,12 @@ cpp_flags_base = [
cpp_flags = [
"-fno-short-wchar",
"-fno-short-enums",
"-DU_USING_ICU_NAMESPACE=0",
"-DU_HAVE_NL_LANGINFO_CODESET=0",
"-DU_TIMEZONE=0",
"-DU_DISABLE_RENAMING=0",
"-DUCONFIG_NO_COLLATION=0",
"-DUCONFIG_NO_FORMATTING=0",
"-DUCONFIG_NO_REGULAR_EXPRESSIONS=0",
@ -55,11 +55,16 @@ cpp_flags = [
"-DU_STATIC_IMPLEMENTATION"
]
def fetch_icu(major, minor):
def fetch_icu():
if not base.is_dir(current_dir + "icu"):
base.cmd("git", ["clone", "--depth", "1", "--branch", "release-" + major + "-" + minor, "https://github.com/unicode-org/icu.git", current_dir + "icu2"])
base.cmd("git", ["clone", "--depth", "1", "--branch", "maint/maint-" + icu_major, "https://github.com/unicode-org/icu.git", current_dir + "icu2"])
base.copy_dir(current_dir + "icu2/icu4c", current_dir + "icu")
base.delete_dir_with_access_error(current_dir + "icu2")
if ("linux" == base.host_platform()):
base.replaceInFile(current_dir + "/icu/source/i18n/digitlst.cpp", "xlocale", "locale")
if False and ("mac" == base.host_platform()):
base.replaceInFile(current_dir + "/icu/source/tools/pkgdata/pkgdata.cpp", "cmd, \"%s %s -o %s%s %s %s%s %s %s\",", "cmd, \"%s %s -o %s%s %s %s %s %s %s\",")
return
def build_host():
@ -106,9 +111,9 @@ def build_arch(arch):
cross_build_dir = os.path.abspath(current_dir + "icu/cross_build")
arch_build_dir = os.path.abspath(current_dir + "build/tmp")
base.create_dir(arch_build_dir)
os.chdir(arch_build_dir)
base.cmd("./../../icu/source/configure", ["--with-cross-build=" + cross_build_dir] +
base.cmd("./../../icu/source/configure", ["--with-cross-build=" + cross_build_dir] +
android_ndk.get_options_dict_as_array(options) + ["--host=" + android_ndk.platforms[arch]["target"], "--prefix=" + arch_build_dir])
base.cmd("make", ["-j4"])
os.chdir(current_dir)
@ -127,7 +132,7 @@ def make():
old_env = dict(os.environ)
fetch_icu(icu_major, icu_minor)
fetch_icu()
build_host()

View File

@ -22,10 +22,10 @@ def move_debug_libs_windows(dir):
def clean():
if base.is_dir("boost_1_58_0"):
base.delete_dir_with_access_error("boost_1_58_0")
base.delete_dir_with_access_error("boost_1_58_0");
base.delete_dir("boost_1_58_0")
if base.is_dir("boost_1_72_0"):
base.delete_dir_with_access_error("boost_1_72_0")
base.delete_dir_with_access_error("boost_1_72_0");
base.delete_dir("boost_1_72_0")
if base.is_dir("build"):
base.delete_dir("build")
@ -85,36 +85,14 @@ def make():
base.cmd("b2.exe", ["headers"])
base.cmd("b2.exe", ["--clean"])
base.cmd("b2.exe", ["--prefix=./../build/win_32", "link=static", "--with-filesystem", "--with-system", "--with-date_time", "--with-regex", "--toolset=" + win_toolset, "address-model=32", "install"])
if (-1 != config.option("platform").find("win_arm64") and not base.is_file("../build/win_arm64/lib/libboost_system-" + win_vs_version + "-mt-a64-1_72.lib")):
boost_bat = []
boost_bat.append("call bootstrap.bat " + win_boot_arg) # first build b2 for win64, so vcvarsall_call with arm64 later
vcvarsall_call = ("call \"" + config.option("vs-path") + "/vcvarsall.bat\" " + "x64_arm64")
boost_bat.append(vcvarsall_call)
boost_bat.append("call b2.exe headers")
boost_bat.append("call b2.exe --clean")
boost_bat.append("call b2.exe --prefix=./../build/win_arm64 architecture=arm link=static --with-filesystem --with-system --with-date_time --with-regex --toolset=" + win_toolset + " address-model=64 install")
base.run_as_bat(boost_bat)
correct_install_includes_win(base_dir, "win_64")
correct_install_includes_win(base_dir, "win_32")
correct_install_includes_win(base_dir, "win_arm64")
correct_install_includes_win(base_dir, "win_32")
if config.check_option("platform", "linux_64") and not base.is_dir("../build/linux_64"):
if config.option("sysroot") == "":
addon_config = []
addon_compile = []
if "1" == config.option("use-clang"):
addon_config = ["--with-toolset=clang"]
addon_compile = ["cxxflags=-stdlib=libc++", "linkflags=-stdlib=libc++", "define=_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION"]
base.cmd("./bootstrap.sh", ["--with-libraries=filesystem,system,date_time,regex"] + addon_config)
base.cmd("./b2", ["headers"])
base.cmd("./b2", ["--clean"])
base.cmd("./b2", ["--prefix=./../build/linux_64", "link=static", "cxxflags=-fPIC"] + addon_compile + ["install"])
else: # build via qmake when custom sysroot is needed
boost_qt.make(os.getcwd(), ["filesystem", "system", "date_time", "regex"], "linux_64")
directory_build = base_dir + "/build/linux_64/lib"
base.delete_file(directory_build + "/libboost_system.a")
base.delete_file(directory_build + "/libboost_system.dylib")
base.copy_files(directory_build + "/linux_64/*.a", directory_build)
base.cmd("./bootstrap.sh", ["--with-libraries=filesystem,system,date_time,regex"])
base.cmd("./b2", ["headers"])
base.cmd("./b2", ["--clean"])
base.cmd("./b2", ["--prefix=./../build/linux_64", "link=static", "cxxflags=-fPIC", "install"])
# TODO: support x86
if config.check_option("platform", "linux_arm64") and not base.is_dir("../build/linux_arm64"):

View File

@ -9,24 +9,11 @@ import qmake
def make(src_dir, modules, build_platform="android", qmake_addon=""):
old_cur = os.getcwd()
old_env = dict(os.environ)
b2_addon = ""
print("boost-headers...")
# for b2 checks
if config.option("sysroot") != "":
base.set_sysroot_env()
b2_addon = "cflags=\"--sysroot=" + config.option("sysroot") + "\""
b2_addon = "cxxflags=\"--sysroot=" + config.option("sysroot") + "\""
b2_addon = "linkflags=\"--sysroot=" + config.option("sysroot") + "\""
base.cmd("./bootstrap.sh", ["--with-libraries=system"])
base.cmd("./b2", ["--prefix=./../build/" + build_platform, "headers", "install", b2_addon])
if config.option("sysroot") != "":
base.restore_sysroot_env()
base.cmd("./bootstrap.sh", ["--with-libraries=system"])
base.cmd("./b2", ["--prefix=./../build/" + build_platform, "headers", "install"])
for module in modules:
print("boost-module: " + module + " ...")
module_dir = src_dir + "/libs/" + module
@ -53,8 +40,6 @@ def make(src_dir, modules, build_platform="android", qmake_addon=""):
base.save_as_script(module_dir + "/" + module + ".pro", pro_file_content)
os.chdir(module_dir)
qmake.make_all_platforms(module_dir + "/" + module + ".pro", qmake_addon)
os.environ.clear()
os.environ.update(old_env)
os.chdir(old_cur)
return

View File

@ -5,13 +5,6 @@ sys.path.append('../..')
import config
import base
import os
import glob
def clear_module():
for child in glob.glob("./*"):
if base.is_dir(child):
base.delete_dir(child)
return
def make():
print("[fetch & build]: cef")
@ -20,14 +13,13 @@ def make():
old_cur = os.getcwd()
os.chdir(base_dir)
base.check_module_version("2", clear_module)
platforms = ["win_64", "win_32", "win_64_xp", "win_32_xp", "linux_64", "linux_32", "mac_64", "mac_arm64", "win_arm64"]
platforms = ["win_64", "win_32", "win_64_xp", "win_32_xp", "linux_64", "linux_32", "mac_64", "mac_arm64"]
for platform in platforms:
if not config.check_option("platform", platform):
continue
url = "https://github.com/ONLYOFFICE-data/build_tools_data/raw/refs/heads/master/cef/"
url = "http://d2ettrnqo7v976.cloudfront.net/cef/"
archive_name = "./cef_binary.7z"
if (-1 != platform.find("_xp")):

View File

@ -8,7 +8,7 @@ import os
def clean():
if base.is_dir("glew-2.1.0"):
base.delete_dir("glew-2.1.0")
base.delete_dir("glew-2.1.0");
return
def make():
@ -16,7 +16,7 @@ def make():
return
if not config.check_option("module", "mobile"):
return
return;
print("[fetch & build]: glew")
base_dir = base.get_script_dir() + "/../../core/Common/3dParty/glew"
@ -26,7 +26,7 @@ def make():
base.common_check_version("glew", "1", clean)
if not base.is_dir("glew-2.1.0"):
base.download("https://github.com/ONLYOFFICE-data/build_tools_data/raw/refs/heads/master/glew/glew-2.1.0-win32.zip", "./archive.zip")
base.download("https://deac-ams.dl.sourceforge.net/project/glew/glew/2.1.0/glew-2.1.0-win32.zip", "./archive.zip")
base.extract("./archive.zip", "./")
base.delete_file("./archive.zip")

View File

@ -1,415 +0,0 @@
import sys
sys.path.append('../..')
import base
import os
import config
# NOTE:
# - requires CMake >= 3.21, < 4.0.0
# libs versions
X265_VERSION = "4.1"
DE265_VERSION = "1.0.16"
# 1.18.2 - the latest version of libheif supporting C++11 builds (as for now)
HEIF_VERSION = "1.18.2"
# ios cmake toolchain
IOS_CMAKE_VERSION = "4.5.0"
IOS_CMAKE_TOOLCHAIN_FILE = base.get_script_dir() + "/../../core/Common/3dParty/heif/ios-cmake/ios.toolchain.cmake"
# android cmake toolchain
ANDROID_CMAKE_TOOLCHAIN_FILE = base.get_env("ANDROID_NDK_ROOT") + "/build/cmake/android.toolchain.cmake"
# linux arm64 cmake toolchain
LINUX_ARM64_CMAKE_TOOLCHAIN_FILE = base.get_script_dir() + "/../tools/linux/arm/cross_arm64/linux-arm64.toolchain.cmake"
LINUX_CUSTOM_SYSROOT_TOOLCHAIN_FILE = base.get_script_dir() + "/../tools/linux/sysroot/custom-sysroot.toolchain.cmake"
OLD_ENV = dict()
# get custom sysroot vars as str
def setup_custom_sysroot_env() -> str:
env_vars = []
env_vars += ['LD_LIBRARY_PATH=\"' + config.get_custom_sysroot_lib() + "\""]
env_vars += ['PATH=\"' + config.option("sysroot") + "/usr/bin:" + base.get_env("PATH") + "\""]
env_vars += ['CC=\"' + config.get_custom_sysroot_bin() + "/gcc\""]
env_vars += ['CXX=\"' + config.get_custom_sysroot_bin() + "/g++\""]
env_vars += ['AR=\"' + config.get_custom_sysroot_bin() + "/ar\""]
env_vars += ['RABLIB=\"' + config.get_custom_sysroot_bin() + "/ranlib\""]
env_vars += ['CFLAGS=\"' + "--sysroot=" + config.option("sysroot") + "\""]
env_vars += ['CXXFLAGS=\"' + "--sysroot=" + config.option("sysroot") + "\""]
env_vars += ['LDFLAGS=\"' + "--sysroot=" + config.option("sysroot") + "\""]
env_str = ""
for env_var in env_vars:
env_str += env_var + " "
return env_str
def get_vs_version():
vs_version = "14 2015"
if config.option("vs-version") == "2019":
vs_version = "16 2019"
return vs_version
def get_xcode_sdk(platform):
xcode_sdk = "iphoneos"
if "simulator" in platform:
xcode_sdk = "iphonesimulator"
return xcode_sdk
def fetch_repo(repo_url, branch_or_tag):
base.cmd("git", ["clone", "--depth", "1", "--branch", branch_or_tag, repo_url])
return
def get_build_dir(base_dir, repo_dir, platform, build_type):
return os.path.join(base_dir, repo_dir, "build", platform, build_type.lower())
# general build function that builds for ONE platform (supposing we are located in the build directory)
def build_with_cmake(platform, cmake_args, build_type):
# extend cmake arguments
cmake_args_ext = []
# WINDOWS
if "win" in platform:
cmake_args_ext = [
"-G", f"Visual Studio {get_vs_version()}"
]
if platform == "win_64" or platform == "win_64_xp":
cmake_args_ext += ["-A", "x64"]
elif platform == "win_32" or platform == "win_32_xp":
cmake_args_ext += ["-A", "Win32"]
elif platform == "win_arm64":
cmake_args_ext += ["-A", "ARM64"]
# LINUX, MAC
elif "linux" in platform or "mac" in platform:
cmake_args_ext = [
"-G", "Unix Makefiles",
"-DCMAKE_POSITION_INDEPENDENT_CODE=ON" # on UNIX we need to compile with fPIC
]
if platform == "mac_64":
cmake_args_ext += ["-DCMAKE_OSX_DEPLOYMENT_TARGET=10.11", "-DCMAKE_OSX_ARCHITECTURES=x86_64"]
elif platform == "mac_arm64":
cmake_args_ext += ["-DCMAKE_OSX_DEPLOYMENT_TARGET=11.0", "-DCMAKE_OSX_ARCHITECTURES=arm64"]
elif platform == "linux_arm64":
cmake_args += ["-DCMAKE_TOOLCHAIN_FILE=" + LINUX_ARM64_CMAKE_TOOLCHAIN_FILE]
elif config.option("sysroot") != "":
cmake_args += ["-DCMAKE_TOOLCHAIN_FILE=" + LINUX_CUSTOM_SYSROOT_TOOLCHAIN_FILE] # force use custom CXXFLAGS with Release/Debug build
# IOS
elif "ios" in platform:
cmake_args_ext = [
"-G", "Xcode",
"-DCMAKE_TOOLCHAIN_FILE=" + IOS_CMAKE_TOOLCHAIN_FILE,
"-DDEPLOYMENT_TARGET=11.0"
]
if platform == "ios":
cmake_args_ext += ["-DPLATFORM=OS64"]
elif platform == "ios_simulator":
cmake_args_ext += ["-DPLATFORM=SIMULATOR64COMBINED"]
# ANDROID
elif "android" in platform:
cmake_args_ext = [
"-G", "Unix Makefiles",
"-DCMAKE_TOOLCHAIN_FILE=" + ANDROID_CMAKE_TOOLCHAIN_FILE,
"-DCMAKE_POSITION_INDEPENDENT_CODE=ON"
]
def get_cmake_args_android(arch, api_level):
return [
"-DANDROID_ABI=" + arch,
"-DANDROID_NATIVE_API_LEVEL=" + api_level
]
if platform == "android_arm64_v8a":
cmake_args_ext += get_cmake_args_android("arm64-v8a", "21")
elif platform == "android_armv7":
cmake_args_ext += get_cmake_args_android("armeabi-v7a", "16")
elif platform == "android_x86":
cmake_args_ext += get_cmake_args_android("x86", "16")
elif platform == "android_x86_64":
cmake_args_ext += get_cmake_args_android("x86_64", "21")
# env setup for custom sysroot
env_str = setup_custom_sysroot_env() if config.option("sysroot") != "" else ""
# run cmake
base.cmd(env_str + "cmake", cmake_args + cmake_args_ext)
# build
if "Unix Makefiles" in cmake_args_ext:
base.cmd(env_str + "make", ["-j4"])
else:
base.cmd("cmake", ["--build", ".", "--config", build_type])
return
# general make function that calls `build_func` callback for configured platform(s) with specified cmake arguments
def make_common(build_func, cmake_args):
# WINDOWS
if "windows" == base.host_platform():
# win_64
if config.check_option("platform", "win_64") or config.check_option("platform", "win_64_xp"):
build_func("win_64", cmake_args)
# win_32
if config.check_option("platform", "win_32") or config.check_option("platform", "win_32_xp"):
build_func("win_32", cmake_args)
# win_arm64
if config.check_option("platform", "win_arm64"):
build_func("win_arm64", cmake_args)
# LINUX
elif "linux" == base.host_platform():
# linux_64
if config.check_option("platform", "linux_64"):
build_func("linux_64", cmake_args)
# linux_arm64
if config.check_option("platform", "linux_arm64"):
build_func("linux_arm64", cmake_args)
# MAC
elif "mac" == base.host_platform():
# mac_64
if config.check_option("platform", "mac_64"):
build_func("mac_64", cmake_args)
# mac_arm64
if config.check_option("platform", "mac_arm64"):
build_func("mac_arm64", cmake_args)
# IOS
if -1 != config.option("platform").find("ios"):
# ios (arm64)
build_func("ios", cmake_args)
# ios simulator (x86_64 and arm64 FAT lib)
build_func("ios_simulator", cmake_args)
# ANDROID
if -1 != config.option("platform").find("android"):
# android_arm64_v8a
if config.check_option("platform", "android_arm64_v8a"):
build_func("android_arm64_v8a", cmake_args)
# android_armv7
if config.check_option("platform", "android_armv7"):
build_func("android_armv7", cmake_args)
# android_x86
if config.check_option("platform", "android_x86"):
build_func("android_x86", cmake_args)
# android_x86_64
if config.check_option("platform", "android_x86_64"):
build_func("android_x86_64", cmake_args)
return
def make_x265(base_dir, build_type):
# fetch lib repo
if not base.is_dir("x265_git"):
fetch_repo("https://bitbucket.org/multicoreware/x265_git.git", f"Release_{X265_VERSION}")
# fix x265 version detection so it reads version from x265Version.txt instead of parsing it from .git
base.replaceInFile(
base_dir + "/x265_git/source/cmake/Version.cmake",
"elseif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../x265Version.txt)",
"endif()\n if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../x265Version.txt)"
)
# prepare cmake args
cmake_dir = base_dir + "/x265_git/source"
cmake_args = [
cmake_dir,
"-DCMAKE_BUILD_TYPE=" + build_type,
"-DENABLE_CLI=OFF", # do not build standalone CLI app
"-DENABLE_SHARED=OFF", # do not build shared libs
"-DENABLE_ASSEMBLY=OFF", # disable assembly optimizations
"-DENABLE_LIBNUMA=OFF", # disable libnuma usage (affects Linux only)
]
# lib build function
def build_x265(platform, cmake_args):
# check if target lib has already been built
build_dir = get_build_dir(base_dir, "x265_git", platform, build_type)
if platform.find("win") != -1:
target_lib = os.path.join(build_dir, build_type, "x265-static.lib")
else:
target_lib = os.path.join(build_dir, "libx265.a")
if base.is_file(target_lib):
return
# go to the build directory
base.create_dir(build_dir)
os.chdir(build_dir)
# run build
build_with_cmake(platform, cmake_args, build_type)
# for iOS there is no target for building libx265.a, so we need to form it ourselves from libcommon.a and libencoder.a
if platform.find("ios") != -1:
xcode_sdk = get_xcode_sdk(platform)
base.cmd("libtool", [
"-static",
"-o", "libx265.a",
f"build/common.build/{build_type}-{xcode_sdk}/libcommon.a",
f"build/encoder.build/{build_type}-{xcode_sdk}/libencoder.a"
])
# copy header
base.copy_file(base_dir + "/x265_git/source/x265.h", build_dir)
# reset directory
os.chdir(base_dir)
return
make_common(build_x265, cmake_args)
return
def make_de265(base_dir, build_type):
# fetch lib repo
if not base.is_dir("libde265"):
fetch_repo("https://github.com/strukturag/libde265.git", f"v{DE265_VERSION}")
# prepare cmake args
cmake_dir = base_dir + "/libde265"
cmake_args = [
cmake_dir,
"-DCMAKE_BUILD_TYPE=" + build_type,
"-DBUILD_SHARED_LIBS=OFF", # do not build shared libs
"-DENABLE_SDL=OFF", # disable SDL
"-DENABLE_DECODER=OFF", # do not build decoder CLI executable
"-DENABLE_ENCODER=OFF", # do not build encoder CLI executable
]
# lib build function
def build_de265(platform, cmake_args):
# check if target lib has already been built
build_dir = get_build_dir(base_dir, "libde265", platform, build_type)
if platform.find("win") != -1:
target_lib = os.path.join(build_dir, "libde265", build_type, "libde265.lib")
else:
target_lib = os.path.join(build_dir, "libde265/libde265.a")
if base.is_file(target_lib):
return
# go to the build directory
base.create_dir(build_dir)
os.chdir(build_dir)
# run build
build_with_cmake(platform, cmake_args, build_type)
# for ios copy target library from the default build path
if platform.find("ios") != -1:
xcode_sdk = get_xcode_sdk(platform)
base.copy_file(f"libde265/{build_type}-{xcode_sdk}/libde265.a", "libde265")
# copy header
base.copy_file(base_dir + "/libde265/libde265/de265.h", "libde265")
# reset directory
os.chdir(base_dir)
return
make_common(build_de265, cmake_args)
return
def make_heif(base_dir, build_type):
# fetch lib repo
if not base.is_dir("libheif"):
fetch_repo("https://github.com/strukturag/libheif.git", f"v{HEIF_VERSION}")
# do not build heifio module
base.replaceInFile(
base_dir + "/libheif/CMakeLists.txt",
"add_subdirectory(heifio)",
"# add_subdirectory(heifio)"
)
base.replaceInFile(
base_dir + "/libheif/CMakeLists.txt",
"if (DOXYGEN_FOUND)",
"if (FALSE)"
)
# prepare cmake args
cmake_dir = base_dir + "/libheif"
cmake_args = [
cmake_dir,
"--preset=release-noplugins", # preset to disable plugins system
"-DCMAKE_BUILD_TYPE=" + build_type,
"-DBUILD_SHARED_LIBS=OFF", # do not build shared libs
"-DWITH_LIBSHARPYUV=OFF", # do not build libsharpyuv (for RGB <--> YUV color space conversions)
"-DWITH_AOM_DECODER=OFF", # do not build AOM V1 decoder (for AVIF image format)
"-DWITH_AOM_ENCODER=OFF", # do not build AOM V1 encoder (for AVIF image format)
"-DWITH_GDK_PIXBUF=OFF", # do not build gdk-pixbuf plugin (UNIX only)
"-DWITH_GNOME=OFF", # do not build gnome plugin (Linux only)
"-DWITH_EXAMPLES=OFF", # do not build examples
"-DWITH_EXAMPLE_HEIF_VIEW=OFF", # do not build heif-view CLI tool
"-DWITH_X265=ON", # enable x265 codec
"-DWITH_LIBDE265=ON", # enable de265 codec
"-DCMAKE_CXX_FLAGS=-DLIBDE265_STATIC_BUILD", # add macro definition to properly compile with de265 static library
"-DCMAKE_C_FLAGS=-DLIBDE265_STATIC_BUILD", # same ^
]
# lib build function
def build_heif(platform, cmake_args):
# check if target lib has already been built
build_dir = get_build_dir(base_dir, "libheif", platform, build_type)
if platform.find("win") != -1:
target_lib = os.path.join(build_dir, "libheif", build_type, "heif.lib")
else:
target_lib = os.path.join(build_dir, "libheif/libheif.a")
if base.is_file(target_lib):
return
# go to the build directory
base.create_dir(build_dir)
os.chdir(build_dir)
# add paths to dependent libraries and includes to cmake args
de265_build_dir = get_build_dir(base_dir, "libde265", platform, build_type)
x265_build_dir = get_build_dir(base_dir, "x265_git", platform, build_type)
cmake_args_ext = [
f"-DLIBDE265_INCLUDE_DIR={de265_build_dir}",
f"-DX265_INCLUDE_DIR={x265_build_dir}"
]
if platform.find("win") != -1:
cmake_args_ext += [
f"-DLIBDE265_LIBRARY={de265_build_dir}/libde265/{build_type}/libde265.lib",
f"-DX265_LIBRARY={x265_build_dir}/{build_type}/x265-static.lib"
]
else:
cmake_args_ext += [
f"-DLIBDE265_LIBRARY={de265_build_dir}/libde265/libde265.a",
f"-DX265_LIBRARY={x265_build_dir}/libx265.a"
]
# run build
build_with_cmake(platform, cmake_args + cmake_args_ext, build_type)
# for ios copy target library from the default build path
if platform.find("ios") != -1:
xcode_sdk = get_xcode_sdk(platform)
base.copy_file(f"libheif/{build_type}-{xcode_sdk}/libheif.a", "libheif")
# reset directory
os.chdir(base_dir)
return
make_common(build_heif, cmake_args)
return
def clear_module():
if base.is_dir("libde265"):
base.delete_dir_with_access_error("libde265")
if base.is_dir("x265_git"):
base.delete_dir_with_access_error("x265_git")
if base.is_dir("libheif"):
base.delete_dir_with_access_error("libheif")
return
def make():
print("[fetch & build]: heif")
base_dir = base.get_script_dir() + "/../../core/Common/3dParty/heif"
old_dir = os.getcwd()
os.chdir(base_dir)
base.check_module_version("2", clear_module)
build_type = "Release"
if (-1 != config.option("config").lower().find("debug")):
build_type = "Debug"
# fetch custom cmake toolchain for ios
if -1 != config.option("platform").find("ios"):
if not base.is_file(IOS_CMAKE_TOOLCHAIN_FILE):
fetch_repo("https://github.com/leetal/ios-cmake.git", IOS_CMAKE_VERSION)
# build encoder library
make_x265(base_dir, build_type)
# build decoder library
make_de265(base_dir, build_type)
# build libheif
make_heif(base_dir, build_type)
os.chdir(old_dir)
return
if __name__ == '__main__':
make()

View File

@ -7,27 +7,7 @@ import base
import os
import subprocess
def clear_module():
directories = ["gumbo-parser", "katana-parser"]
for dir in directories:
if base.is_dir(dir):
base.delete_dir_with_access_error(dir)
def make():
old_cur_dir = os.getcwd()
print("[fetch]: html")
base_dir = base.get_script_dir() + "/../../core/Common/3dParty/html"
os.chdir(base_dir)
base.check_module_version("2", clear_module)
os.chdir(old_cur_dir)
base.cmd_in_dir(base_dir, "python", ["fetch.py"])
return
if __name__ == '__main__':
# manual compile
make()

View File

@ -9,12 +9,11 @@ import os
import glob
import icu_android
def fetch_icu(major, minor, target_dir="icu"):
if (base.is_dir("./icu2")):
base.delete_dir_with_access_error("icu2")
base.cmd("git", ["clone", "--depth", "1", "--branch", "release-" + major + "-" + minor, "https://github.com/unicode-org/icu.git", "./icu2"])
base.copy_dir("./icu2/icu4c", target_dir)
def fetch_icu(major, minor):
base.cmd("git", ["clone", "--depth", "1", "--branch", "maint/maint-" + major, "https://github.com/unicode-org/icu.git", "./icu2"])
base.copy_dir("./icu2/icu4c", "./icu")
base.delete_dir_with_access_error("icu2")
#base.cmd("svn", ["export", "https://github.com/unicode-org/icu/tags/release-" + icu_major + "-" + icu_minor + "/icu4c", "./icu", "--non-interactive", "--trust-server-cert"])
return
def clear_module():
@ -35,26 +34,18 @@ def make():
old_cur = os.getcwd()
os.chdir(base_dir)
base.check_module_version("7", clear_module)
base.check_module_version("3", clear_module)
if (-1 != config.option("platform").find("android")):
icu_android.make()
os.chdir(base_dir)
icu_major = "74"
icu_minor = "2"
icu_major = "58"
icu_minor = "3"
if not base.is_dir("icu"):
fetch_icu(icu_major, icu_minor)
# old version for win_xp
icu_major_old = "58"
icu_minor_old = "3"
if config.check_option("platform", "win_64_xp") or config.check_option("platform", "win_32_xp"):
if not base.is_dir("icu58"):
fetch_icu(icu_major_old, icu_minor_old, "icu58")
fetch_icu(icu_major, icu_minor)
if ("windows" == base.host_platform()):
platformToolset = "v140"
@ -65,103 +56,53 @@ def make():
need_platforms.append("win_64")
if (-1 != config.option("platform").find("win_32")):
need_platforms.append("win_32")
if (-1 != config.option("platform").find("win_arm64")):
need_platforms.append("win_64") # for exe files
need_platforms.append("win_arm64")
def build_icu_win(source_dir, out_dir, icu_major):
if base.is_dir(out_dir):
return
compile_bat = []
compile_bat.append("setlocal")
args = {
"win_32" : {
"msbuild_platfrom" : "Win32",
"vcvarsall_arch" : "x86",
"out_bin_dir" : source_dir + "/bin/",
"out_lib_dir" : source_dir + "/lib/"
},
"win_64" : {
"msbuild_platfrom" : "X64",
"vcvarsall_arch" : "x64",
"out_bin_dir" : source_dir + "/bin64/",
"out_lib_dir" : source_dir + "/lib64/"
},
"win_arm64" : {
"msbuild_platfrom" : "ARM64",
"vcvarsall_arch" : "x64_arm64",
"out_bin_dir" : source_dir + "/binARM64/",
"out_lib_dir" : source_dir + "/libARM64/"
}
}
platform_args = args[platform]
compile_bat.append("call \"" + config.option("vs-path") + "/vcvarsall.bat\" " + platform_args['vcvarsall_arch'])
compile_bat.append("call MSBuild.exe " + source_dir + "/source/allinone/allinone.sln /p:Configuration=Release /p:PlatformToolset=" + platformToolset + " /p:Platform=" + platform_args['msbuild_platfrom'])
compile_bat.append("endlocal")
base.run_as_bat(compile_bat)
base.create_dir(out_dir)
base.copy_file(platform_args['out_bin_dir'] + "icudt" + icu_major + ".dll", out_dir)
base.copy_file(platform_args['out_bin_dir'] + "icuuc" + icu_major + ".dll", out_dir)
base.copy_file(platform_args['out_lib_dir'] + "icudt.lib", out_dir)
base.copy_file(platform_args['out_lib_dir'] + "icuuc.lib", out_dir)
for platform in need_platforms:
if not config.check_option("platform", platform) and not config.check_option("platform", platform + "_xp"):
continue
if not (config.check_option("platform", "win_64_xp") or config.check_option("platform", "win_32_xp")):
build_icu_win("icu", platform + "/build", icu_major)
else:
# xp
build_icu_win("icu58", platform + "/build/xp", icu_major_old)
if not base.is_dir(platform + "/build"):
base.create_dir(platform)
compile_bat = []
compile_bat.append("setlocal")
compile_bat.append("call \"" + config.option("vs-path") + "/vcvarsall.bat\" " + ("x86" if base.platform_is_32(platform) else "x64"))
compile_bat.append("call MSBuild.exe icu/source/allinone/allinone.sln /p:Configuration=Release /p:PlatformToolset=" + platformToolset + " /p:Platform=" + ("Win32" if base.platform_is_32(platform) else "X64"))
compile_bat.append("endlocal")
base.run_as_bat(compile_bat)
bin_dir = "icu/bin64/" if ("win_64" == platform) else "icu/bin/"
lib_dir = "icu/lib64/" if ("win_64" == platform) else "icu/lib/"
base.create_dir(platform + "/build")
base.copy_file(bin_dir + "icudt" + icu_major + ".dll", platform + "/build/")
base.copy_file(bin_dir + "icuuc" + icu_major + ".dll", platform + "/build/")
base.copy_file(lib_dir + "icudt.lib", platform + "/build/")
base.copy_file(lib_dir + "icuuc.lib", platform + "/build/")
os.chdir(old_cur)
return
if ("linux" == base.host_platform()):
if not base.is_file("./icu/source/i18n/digitlst.cpp.bak"):
base.copy_file("./icu/source/i18n/digitlst.cpp", "./icu/source/i18n/digitlst.cpp.bak")
base.replaceInFile("./icu/source/i18n/digitlst.cpp", "xlocale", "locale")
if base.is_dir(base_dir + "/linux_64"):
base.delete_dir(base_dir + "/linux_64")
if base.is_dir(base_dir + "/linux_arm64"):
base.delete_dir(base_dir + "/linux_arm64")
if not base.is_dir(base_dir + "/linux_64"):
base.create_dir(base_dir + "/icu/cross_build")
os.chdir("icu/cross_build")
command_configure = "./../source/runConfigureICU"
command_compile_addon = "-static-libstdc++ -static-libgcc"
if "1" == config.option("use-clang"):
command_configure = "CXXFLAGS=-stdlib=libc++ " + command_configure
command_compile_addon = "-stdlib=libc++"
if "" == config.option("sysroot"):
base.cmd(command_configure, ["Linux", "--prefix=" + base_dir + "/icu/cross_build_install"])
base.replaceInFile("./../source/icudefs.mk.in", "LDFLAGS = @LDFLAGS@ $(RPATHLDFLAGS)", "LDFLAGS = @LDFLAGS@ $(RPATHLDFLAGS) " + command_compile_addon)
else:
base.set_sysroot_env()
base.cmd_exe("./../source/configure", ["--prefix=" + base_dir + "/icu/cross_build_install",
"CC=" + config.get_custom_sysroot_bin() + "/gcc", "CXX=" + config.get_custom_sysroot_bin() + "/g++",
"AR=" + config.get_custom_sysroot_bin() + "/ar", "RANLIB=" + config.get_custom_sysroot_bin() + "/ranlib",
"CFLAGS=--sysroot=" + config.option("sysroot"),
"CXXFLAGS=--sysroot=" + config.option("sysroot") + " " + command_compile_addon,
"LDFLAGS=--sysroot=" + config.option("sysroot")])
if "" == config.option("sysroot"):
base.cmd("make", ["-j4"])
base.cmd("make", ["install"], True)
else:
base.cmd_exe("make", ["-j4"])
base.cmd_exe("make", ["install"], True)
base.restore_sysroot_env()
base.cmd("./../source/runConfigureICU", ["Linux", "--prefix=" + base_dir + "/icu/cross_build_install"])
base.replaceInFile("./../source/icudefs.mk.in", "LDFLAGS = @LDFLAGS@ $(RPATHLDFLAGS)", "LDFLAGS = @LDFLAGS@ $(RPATHLDFLAGS) -static-libstdc++ -static-libgcc")
base.cmd("make", ["-j4"])
base.cmd("make", ["install"], True)
base.create_dir(base_dir + "/linux_64")
base.create_dir(base_dir + "/linux_64/build")
base.copy_file(base_dir + "/icu/cross_build_install/lib/libicudata.so." + icu_major + "." + icu_minor, base_dir + "/linux_64/build/libicudata.so." + icu_major)
base.copy_file(base_dir + "/icu/cross_build_install/lib/libicuuc.so." + icu_major + "." + icu_minor, base_dir + "/linux_64/build/libicuuc.so." + icu_major)
base.copy_dir(base_dir + "/icu/cross_build_install/include", base_dir + "/linux_64/build/include")
if config.check_option("platform", "linux_arm64") and not base.is_dir(base_dir + "/linux_arm64") and not base.is_os_arm():
base.create_dir(base_dir + "/icu/linux_arm64")
os.chdir(base_dir + "/icu/linux_arm64")
base_arm_tool_dir = config.option('arm64-toolchain-bin') + '/' + base.get_prefix_cross_compiler_arm64()
base_arm_tool_dir = base.get_prefix_cross_compiler_arm64()
base.cmd("./../source/configure", ["--host=arm-linux", "--prefix=" + base_dir + "/icu/linux_arm64_install", "--with-cross-build=" + base_dir + "/icu/cross_build",
"CC=" + base_arm_tool_dir + "gcc", "CXX=" + base_arm_tool_dir + "g++", "AR=" + base_arm_tool_dir + "ar", "RANLIB=" + base_arm_tool_dir + "ranlib"])
base.cmd("make", ["-j4"])
@ -187,6 +128,6 @@ def make():
if (-1 != config.option("platform").find("ios")):
if not base.is_dir("build"):
base.bash("./icu_ios")
os.chdir(old_cur)
return

View File

@ -5,29 +5,37 @@ sys.path.append('../..')
import base
import os
def change_icu_defs(arch):
old_env = dict(os.environ)
def change_icu_defs(current_dir, arch):
icudef_file = current_dir + "/icudefs.mk"
icudef_file_old = current_dir + "/icudefs.mk.back"
param = "-arch x86_64"
if arch == "arm64":
param = "-arch arm64"
param = "-arch arm64 -isysroot " + base.find_mac_sdk()
param += " -isysroot " + base.find_mac_sdk()
param += " -mmacosx-version-min=10.12"
os.environ["CFLAGS"] = param
os.environ["CXXFLAGS"] = param + " --std=c++11"
os.environ["LDFLAGS"] = param
base.copy_file(icudef_file, icudef_file_old)
return old_env
base.replaceInFile(icudef_file, "CFLAGS = ", "CFLAGS = " + param + " ")
base.replaceInFile(icudef_file, "CXXFLAGS = ", "CXXFLAGS = " + param + " ")
base.replaceInFile(icudef_file, "RPATHLDFLAGS =", "RPATHLDFLAGS2 =")
base.replaceInFile(icudef_file, "LDFLAGS = ", "LDFLAGS = " + param + " ")
base.replaceInFile(icudef_file, "RPATHLDFLAGS2 =", "RPATHLDFLAGS =")
def restore_icu_defs(old_env):
os.environ.clear()
os.environ.update(old_env)
return
icu_major = "74"
icu_minor = "2"
def restore_icu_defs(current_dir):
icudef_file = current_dir + "/icudefs.mk"
icudef_file_old = current_dir + "/icudefs.mk.back"
base.delete_file(icudef_file)
base.copy_file(icudef_file_old, icudef_file)
base.delete_file(icudef_file_old)
return
icu_major = "58"
icu_minor = "3"
current_dir_old = os.getcwd()
current_dir = base.get_script_dir() + "/../../core/Common/3dParty/icu"
@ -38,33 +46,29 @@ if not base.is_dir(current_dir + "/mac_cross_64"):
base.create_dir(current_dir + "/mac_cross_64")
os.chdir(current_dir + "/mac_cross_64")
old_env = change_icu_defs("x86_64")
base.cmd("../icu/source/runConfigureICU", ["MacOSX",
"--prefix=" + current_dir + "/mac_cross_64", "--enable-static"])
"--prefix=" + current_dir + "/mac_cross_64", "CFLAGS=-Os CXXFLAGS=--std=c++11"])
change_icu_defs(current_dir + "/mac_cross_64", "x86_64")
base.cmd("make", ["-j4"])
base.cmd("make", ["install"], True)
restore_icu_defs(old_env)
restore_icu_defs(current_dir + "/mac_cross_64")
os.chdir(current_dir)
os.chdir(current_dir + "/icu/source")
old_env = change_icu_defs("arm64")
base.cmd("./configure", ["--prefix=" + current_dir + "/mac_arm_64",
"--with-cross-build=" + current_dir + "/mac_cross_64", "VERBOSE=1"])
addon = []
if not base.is_os_arm():
addon = ["--host=aarch64-apple-darwin"]
base.cmd("./configure", ["--prefix=" + current_dir + "/mac_arm_64",
"--with-cross-build=" + current_dir + "/mac_cross_64", "--enable-static", "VERBOSE=1"] + addon)
change_icu_defs(current_dir + "/icu/source", "arm64")
base.cmd("make", ["-j4"])
base.cmd("make", ["install"])
restore_icu_defs(old_env)
restore_icu_defs(current_dir + "/icu/source")
os.chdir(current_dir)
@ -81,22 +85,12 @@ base.create_dir(current_dir + "/mac_arm64")
base.create_dir(current_dir + "/mac_arm64/build")
base.copy_dir(current_dir + "/mac_cross_64/include", current_dir + "/mac_64/build/include")
# copy shared libs
base.copy_file(current_dir + "/mac_cross_64/lib/libicudata." + icu_major + "." + icu_minor + ".dylib", current_dir + "/mac_64/build/libicudata." + icu_major + ".dylib")
base.copy_file(current_dir + "/mac_cross_64/lib/libicuuc." + icu_major + "." + icu_minor + ".dylib", current_dir + "/mac_64/build/libicuuc." + icu_major + ".dylib")
# copy static libs
base.copy_file(current_dir + "/mac_cross_64/lib/libicudata.a", current_dir + "/mac_64/build")
base.copy_file(current_dir + "/mac_cross_64/lib/libicui18n.a", current_dir + "/mac_64/build")
base.copy_file(current_dir + "/mac_cross_64/lib/libicuuc.a", current_dir + "/mac_64/build")
base.copy_dir(current_dir + "/mac_arm_64/include", current_dir + "/mac_arm64/build/include")
# copy shared libs
base.copy_file(current_dir + "/mac_arm_64/lib/libicudata." + icu_major + "." + icu_minor + ".dylib", current_dir + "/mac_arm64/build/libicudata." + icu_major + ".dylib")
base.copy_file(current_dir + "/mac_arm_64/lib/libicuuc." + icu_major + "." + icu_minor + ".dylib", current_dir + "/mac_arm64/build/libicuuc." + icu_major + ".dylib")
# copy static libs
base.copy_file(current_dir + "/mac_arm_64/lib/libicudata.a", current_dir + "/mac_arm64/build")
base.copy_file(current_dir + "/mac_arm_64/lib/libicui18n.a", current_dir + "/mac_arm64/build")
base.copy_file(current_dir + "/mac_arm_64/lib/libicuuc.a", current_dir + "/mac_arm64/build")
base.delete_dir(current_dir + "/mac_cross_64")
base.delete_dir(current_dir + "/mac_arm_64")

View File

@ -1,20 +0,0 @@
#!/usr/bin/env python
import sys
sys.path.append('../..')
import config
import base
import os
import subprocess
def make():
print("[fetch]: md")
base_dir = base.get_script_dir() + "/../../core/Common/3dParty/md"
base.cmd_in_dir(base_dir, "python", ["fetch.py"])
return
if __name__ == '__main__':
# manual compile
make()

View File

@ -1,15 +0,0 @@
#!/usr/bin/env python
import sys
sys.path.append('../..')
import base
import os
def make():
print("[fetch & build]: brotli")
base.cmd_in_dir(base.get_script_dir() + "/../../core/Common/3dParty/brotli", "./make.py")
return
if __name__ == '__main__':
# manual compile
make()

View File

@ -54,14 +54,6 @@ def make():
qmake_bat.append("call nmake clean")
qmake_bat.append("call nmake build_libs install")
base.run_as_bat(qmake_bat, True)
if (-1 != config.option("platform").find("win_arm64")) and not base.is_dir("../build/win_arm64"):
base.create_dir("./../build/win_arm64")
qmake_bat = []
qmake_bat.append("call \"" + config.option("vs-path") + "/vcvarsall.bat\" x64_arm64")
qmake_bat.append("perl Configure VC-WIN64-ARM --prefix=" + old_cur_dir + "\\build\\win_arm64 --openssldir=" + old_cur_dir + "\\build\\win_arm64 no-shared no-asm enable-md2")
qmake_bat.append("call nmake clean")
qmake_bat.append("call nmake build_libs install")
base.run_as_bat(qmake_bat, True)
os.chdir(old_cur)
# xp ----------------------------------------------------------------------------------------------------
os.chdir(base_dir + "/openssl")
@ -87,32 +79,14 @@ def make():
# -------------------------------------------------------------------------------------------------------
return
if (-1 != config.option("platform").find("linux")) and not base.is_dir("../build/linux_64"):
if (-1 != config.option("platform").find("linux")) and not base.is_dir("../build/linux_64"):
base.cmd("./config", ["enable-md2", "no-shared", "no-asm", "--prefix=" + old_cur_dir + "/build/linux_64", "--openssldir=" + old_cur_dir + "/build/linux_64"])
if "1" == config.option("use-clang"):
base.replaceInFile("./Makefile", "CC=$(CROSS_COMPILE)gcc", "CC=$(CROSS_COMPILE)clang")
base.replaceInFile("./Makefile", "CXX=$(CROSS_COMPILE)g++", "CXX=$(CROSS_COMPILE)clang++")
base.replaceInFile("./Makefile", "CFLAGS=-Wall -O3", "CFLAGS=-Wall -O3 -fvisibility=hidden")
base.replaceInFile("./Makefile", "CXXFLAGS=-Wall -O3", "CXXFLAGS=-Wall -O3 -fvisibility=hidden -stdlib=libc++")
base.replaceInFile("./Makefile", "LDFLAGS=", "LDFLAGS=-stdlib=libc++")
elif config.option("sysroot") == "":
base.replaceInFile("./Makefile", "CFLAGS=-Wall -O3", "CFLAGS=-Wall -O3 -fvisibility=hidden")
base.replaceInFile("./Makefile", "CXXFLAGS=-Wall -O3", "CXXFLAGS=-Wall -O3 -fvisibility=hidden")
else:
base.replaceInFile("./Makefile", "CROSS_COMPILE=", "CROSS_COMPILE=" + config.get_custom_sysroot_bin() + "/")
base.replaceInFile("./Makefile", "CFLAGS=-Wall -O3", "CFLAGS=-Wall -O3 -fvisibility=hidden --sysroot=" + config.option("sysroot"))
base.replaceInFile("./Makefile", "CXXFLAGS=-Wall -O3", "CXXFLAGS=-Wall -O3 -fvisibility=hidden --sysroot=" + config.option("sysroot"))
if config.option("sysroot") == "":
base.cmd("make", [])
base.cmd("make", ["install"])
base.cmd("make", ["clean"], True)
else:
base.set_sysroot_env()
base.cmd_exe("make", [])
base.cmd_exe("make", ["install"])
base.cmd_exe("make", ["clean"], True)
base.restore_sysroot_env()
base.replaceInFile("./Makefile", "CFLAGS=-Wall -O3", "CFLAGS=-Wall -O3 -fvisibility=hidden")
base.replaceInFile("./Makefile", "CXXFLAGS=-Wall -O3", "CXXFLAGS=-Wall -O3 -fvisibility=hidden")
base.cmd("make")
base.cmd("make", ["install"])
base.cmd("make", ["clean"], True)
# TODO: support x86
if (-1 != config.option("platform").find("linux_arm64")) and not base.is_dir("../build/linux_arm64"):
if ("x86_64" != platform.machine()):

View File

@ -10,10 +10,10 @@ import v8_89
def clean():
if base.is_dir("depot_tools"):
base.delete_dir_with_access_error("depot_tools")
base.delete_dir_with_access_error("depot_tools");
base.delete_dir("depot_tools")
if base.is_dir("v8"):
base.delete_dir_with_access_error("v8")
base.delete_dir_with_access_error("v8");
base.delete_dir("v8")
if base.is_exist("./.gclient"):
base.delete_file("./.gclient")
@ -26,8 +26,6 @@ def clean():
def is_main_platform():
if (config.check_option("platform", "win_64") or config.check_option("platform", "win_32")):
return True
if (config.check_option("platform", "win_arm64")):
return True
if (config.check_option("platform", "linux_64") or config.check_option("platform", "linux_32") or config.check_option("platform", "linux_arm64")):
return True
if config.check_option("platform", "mac_64"):
@ -47,7 +45,7 @@ def is_use_clang():
gcc_version = base.get_gcc_version()
is_clang = "false"
if config.option("sysroot") == "" and (gcc_version >= 6000 or "1" == config.option("use-clang")):
if (gcc_version >= 6000):
is_clang = "true"
print("gcc version: " + str(gcc_version) + ", use clang:" + is_clang)
@ -271,7 +269,7 @@ def make_xp():
"for file in projects:",
" replaceInFile(file, '<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>', '<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>')",
" replaceInFile(file, '<RuntimeLibrary>MultiThreaded</RuntimeLibrary>', '<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>')",
])
]);
programFilesDir = base.get_env("ProgramFiles")
if ("" != base.get_env("ProgramFiles(x86)")):

View File

@ -23,9 +23,6 @@ def change_bootstrap():
base.replaceInFile("./depot_tools/bootstrap/bootstrap.py",
"raise subprocess.CalledProcessError(proc.returncode, argv, None)", "return")
base.replaceInFile("./depot_tools/bootstrap/bootstrap.py",
" _win_git_bootstrap_config()", " #_win_git_bootstrap_config()")
base.writeFile("./depot_tools/bootstrap/manifest.txt", content)
return
@ -44,13 +41,7 @@ def make_args(args, platform, is_64=True, is_debug=False):
args_copy.append("target_cpu=\\\"arm64\\\"")
args_copy.append("v8_target_cpu=\\\"arm64\\\"")
args_copy.append("use_sysroot=true")
if (platform == "win_arm64"):
args_copy = args[:]
args_copy.append("target_cpu=\\\"arm64\\\"")
args_copy.append("v8_target_cpu=\\\"arm64\\\"")
args_copy.append("is_clang=false")
if is_debug:
args_copy.append("is_debug=true")
if (platform == "windows"):
@ -58,42 +49,20 @@ def make_args(args, platform, is_64=True, is_debug=False):
else:
args_copy.append("is_debug=false")
linux_clang = False
if platform == "linux":
if "" != config.option("sysroot"):
args_copy.append("use_sysroot=false")
args_copy.append("is_clang=false")
else:
args_copy.append("is_clang=true")
if "1" == config.option("use-clang"):
linux_clang = True
else:
args_copy.append("use_sysroot=false")
if (platform == "linux"):
args_copy.append("is_clang=true")
args_copy.append("use_sysroot=false")
if (platform == "windows"):
args_copy.append("is_clang=false")
if linux_clang != True:
args_copy.append("use_custom_libcxx=false")
return "--args=\"" + " ".join(args_copy) + "\""
def ninja_windows_make(args, is_64=True, is_debug=False, is_arm=False):
def ninja_windows_make(args, is_64=True, is_debug=False):
directory_out = "out.gn/"
if is_arm:
directory_out += "win_arm64/"
else:
directory_out += ("win_64/" if is_64 else "win_32/")
directory_out += ("win_64/" if is_64 else "win_32/")
directory_out += ("debug" if is_debug else "release")
if is_arm:
base.cmd2("gn", ["gen", directory_out, make_args(args, "win_arm64", is_64, is_debug)])
else:
base.cmd2("gn", ["gen", directory_out, make_args(args, "windows", is_64, is_debug)])
base.cmd2("gn", ["gen", directory_out, make_args(args, "windows", is_64, is_debug)])
base.copy_file("./" + directory_out + "/obj/v8_wrappers.ninja", "./" + directory_out + "/obj/v8_wrappers.ninja.bak")
base.replaceInFile("./" + directory_out + "/obj/v8_wrappers.ninja", "target_output_name = v8_wrappers", "target_output_name = v8_wrappers\nbuild obj/v8_wrappers.obj: cxx ../../../src/base/platform/wrappers.cc")
base.replaceInFile("./" + directory_out + "/obj/v8_wrappers.ninja", "build obj/v8_wrappers.lib: alink", "build obj/v8_wrappers.lib: alink obj/v8_wrappers.obj")
@ -103,10 +72,7 @@ def ninja_windows_make(args, is_64=True, is_debug=False, is_arm=False):
if (-1 == win_toolset_wrapper_file_content.find("line = line.decode('utf8')")):
base.replaceInFile(win_toolset_wrapper_file, "for line in link.stdout:\n", "for line in link.stdout:\n line = line.decode('utf8')\n")
base.cmd("ninja", ["-C", directory_out, "v8_wrappers"])
if is_arm:
base.copy_file('./' + directory_out + '/obj/v8_wrappers.lib', './' + directory_out + '/x64/obj/v8_wrappers.lib')
base.cmd("ninja", ["-C", directory_out])
base.delete_file("./" + directory_out + "/obj/v8_wrappers.ninja")
base.move_file("./" + directory_out + "/obj/v8_wrappers.ninja.bak", "./" + directory_out + "/obj/v8_wrappers.ninja")
@ -172,19 +138,8 @@ def make():
if ("windows" == base.host_platform()):
base.replaceInFile("v8/build/config/win/BUILD.gn", ":static_crt", ":dynamic_crt")
# fix for new depot_tools and vs2019, as VC folder contains a folder with a symbol in the name
# sorting is done by increasing version, so 0 is a dummy value
replace_src = " def to_int_if_int(x):\n try:\n return int(x)\n except ValueError:\n return x"
replace_dst = " def to_int_if_int(x):\n try:\n return int(x)\n except ValueError:\n return 0"
base.replaceInFile("v8/build/vs_toolchain.py", replace_src, replace_dst)
if not base.is_file("v8/src/base/platform/wrappers.cc"):
base.writeFile("v8/src/base/platform/wrappers.cc", "#include \"src/base/platform/wrappers.h\"\n")
if config.check_option("platform", "win_arm64"):
base.replaceInFile("v8/build/toolchain/win/setup_toolchain.py", "SDK_VERSION = \'10.0.26100.0\'", "SDK_VERSION = \'10.0.22621.0\'")
else:
base.replaceInFile("depot_tools/gclient_paths.py", "@functools.lru_cache", "")
@ -203,27 +158,12 @@ def make():
"is_component_build=false",
"v8_monolithic=true",
"v8_use_external_startup_data=false",
"use_custom_libcxx=false",
"treat_warnings_as_errors=false"]
if config.check_option("platform", "linux_64"):
if config.option("sysroot") != "":
src_replace = "config(\"compiler\") {\n asmflags = []\n cflags = []\n cflags_c = []\n cflags_cc = []\n cflags_objc = []\n cflags_objcc = []\n ldflags = []"
dst_replace = "config(\"compiler\") {\n asmflags = []\n cflags = [\"--sysroot=" + config.option("sysroot") + "\"]" + "\n cflags_c = []\n cflags_cc = [\"--sysroot=" + config.option("sysroot") + "\"]" + "\n cflags_objc = []\n cflags_objcc = []\n ldflags = [\"--sysroot=" + config.option("sysroot") + "\"]"
base.replaceInFile("build/config/compiler/BUILD.gn", src_replace, dst_replace)
src_replace = "gcc_toolchain(\"x64\") {\n cc = \"gcc\"\n cxx = \"g++\""
dst_replace = "gcc_toolchain(\"x64\") {\n cc = \""+ config.get_custom_sysroot_bin() + "/gcc\"\n cxx = \"" + config.get_custom_sysroot_bin() + "/g++\""
base.replaceInFile("build/toolchain/linux/BUILD.gn", src_replace, dst_replace)
old_env = dict(os.environ)
base.set_sysroot_env()
base.cmd2("gn", ["gen", "out.gn/linux_64", make_args(gn_args, "linux")], False)
base.cmd2("ninja", ["-C", "out.gn/linux_64"], False)
base.restore_sysroot_env()
else:
base.cmd2("gn", ["gen", "out.gn/linux_64", make_args(gn_args, "linux")], False)
base.cmd2("ninja", ["-C", "out.gn/linux_64"], False)
base.cmd2("gn", ["gen", "out.gn/linux_64", make_args(gn_args, "linux")])
base.cmd("ninja", ["-C", "out.gn/linux_64"])
if config.check_option("platform", "linux_32"):
base.cmd2("gn", ["gen", "out.gn/linux_32", make_args(gn_args, "linux", False)])
@ -237,9 +177,6 @@ def make():
if config.check_option("platform", "mac_64"):
base.cmd2("gn", ["gen", "out.gn/mac_64", make_args(gn_args, "mac")])
base.cmd("ninja", ["-C", "out.gn/mac_64"])
if config.check_option("platform", "win_arm64") and not base.is_file("out.gn/win_arm64/release/obj/v8_monolith.lib"):
ninja_windows_make(gn_args, True, False, True)
if config.check_option("platform", "win_64"):
if (-1 != config.option("config").lower().find("debug")):

View File

@ -1,208 +0,0 @@
import sys
sys.path.append('../..')
import base
import os
import config
ARCHES = {"win_64" : "x64",
"win_32" : "x86",
"linux_64" : "x86_64-linux-gnu",
"linux_arm64" : "aarch64-linux-gnu",
"mac_64" : "x86_64-apple-darwin",
"mac_arm64" : "arm-apple-darwin",
"android_arm64_v8a" : "aarch64-linux-android",
"android_armv7" : "armv7a-linux-androideabi",
"android_x86" : "i686-linux-android",
"android_x86_64" : "x86_64-linux-android",
"ios" : "arm-apple-darwin",
"ios_simulator" : "x86_64-apple-darwin"}
def get_xcode_sdk(platform):
xcode_sdk = "iphoneos"
if "simulator" in platform:
xcode_sdk = "iphonesimulator"
return xcode_sdk
def get_ios_min_version(platform):
res = " -miphoneos-version-min=11.0"
if "simulator" in platform:
res = " -mios-simulator-version-min=11.0"
return res
def fetch_repo():
base_dir = base.get_script_dir() + "/../../core/Common/3dParty/webp"
if not base.is_dir(base_dir):
base.create_dir(base_dir)
old_dir = os.getcwd()
os.chdir(base_dir)
if (base.is_dir("libwebp")):
base.delete_dir_with_access_error("libwebp")
if not base.is_dir("libwebp"):
base.cmd("git", ["clone", "--branch","v1.6.0", "https://chromium.googlesource.com/webm/libwebp"])
os.chdir(base_dir + "/libwebp")
return old_dir
def create_build_dir(platform, build_type) -> str:
build_dir = ""
if "win" in platform:
target_file = "libwebp"
if build_type == "debug":
target_file += "-debug"
target_file += ".lib"
build_dir = "./../build/" + platform + "/"
if not base.is_dir(build_dir):
base.create_dir(build_dir)
elif base.is_file(build_dir + build_type + "/" + ARCHES[platform] + "/lib/" + target_file):
build_dir = ""
else:
build_dir = "./../build/" + platform + "/" + build_type
if not base.is_dir(build_dir):
base.create_dir(build_dir)
if base.is_file(build_dir + "/src/.libs/libwebp.a"):
build_dir = ""
return build_dir
# get custom sysroot vars as str
def setup_custom_sysroot_env() -> str:
env_vars = []
env_vars += ['LD_LIBRARY_PATH=\"' + config.get_custom_sysroot_lib() + "\""]
env_vars += ['PATH=\"' + config.option("sysroot") + "/usr/bin:" + base.get_env("PATH") + "\""]
env_vars += ['CC=\"' + config.get_custom_sysroot_bin() + "/gcc\""]
env_vars += ['CXX=\"' + config.get_custom_sysroot_bin() + "/g++\""]
env_vars += ['AR=\"' + config.get_custom_sysroot_bin() + "/ar\""]
env_vars += ['RABLIB=\"' + config.get_custom_sysroot_bin() + "/ranlib\""]
env_vars += ['CFLAGS=\"' + "--sysroot=" + config.option("sysroot") + "\""]
env_vars += ['CXXFLAGS=\"' + "--sysroot=" + config.option("sysroot") + "\""]
env_vars += ['LDFLAGS=\"' + "--sysroot=" + config.option("sysroot") + "\""]
env_str = ""
for env_var in env_vars:
env_str += env_var + " "
return env_str
def get_args(platform, build_type, build_dir):
if "win" in platform:
args = []
args.append("call \"" + config.option("vs-path") + "/vcvarsall.bat\" " + ARCHES[platform])
args.append("call nmake /f Makefile.vc CFG=" + build_type + "-static" + " OBJDIR=" + build_dir)
return args
elif "linux" in platform:
cflags = "-O3 -DNDEBUG"
if build_type == "debug":
cflags = "-O0 -g"
if config.option("sysroot") != "":
cflags += " --sysroot=" + config.option("sysroot")
cross_arm64 = ""
if platform == "linux_arm64":
cross_cimpile_arm64 = config.option("arm64-toolchain-bin")
if "" == cross_cimpile_arm64:
cross_cimpile_arm64 = "/usr/bin"
cross_arm64 = "--cross-compile-prefix=" + cross_cimpile_arm64 + "/" + base.get_prefix_cross_compiler_arm64()
return ["--host=" + ARCHES[platform], "--enable-static", "--disable-shared",
"--disable-libwebpdecoder", "--disable-libwebpdemux",
"--disable-libwebpmux", "--disable-libwebpextras",
cross_arm64, "CFLAGS=" + cflags, "LDFLAGS=-static"]
elif "mac" in platform:
arch = ARCHES[platform]
short_arch = arch[:arch.find("-")]
if short_arch == "arm":
short_arch += "64"
cflags = "-O3 -DNDEBUG -arch " + short_arch + " -fPIC"
if build_type == "debug":
cflags = "-O0 -g -arch " + short_arch + " -fPIC"
return ["--host=" + arch, "--enable-static", "--disable-shared",
"--disable-libwebpdecoder", "--disable-libwebpdemux",
"--disable-libwebpmux", "--disable-libwebpextras",
"CFLAGS=" + cflags, "LDFLAGS=-arch " + short_arch]
elif "ios" in platform:
arch = ARCHES[platform]
short_arch = arch[:arch.find("-")]
if short_arch == "arm":
short_arch += "64"
xcode_sdk = get_xcode_sdk(platform)
version_min = get_ios_min_version(platform)
cflags = "-O3 -DNDEBUG -arch " + short_arch + version_min + " -fembed-bitcode"
if build_type == "debug":
cflags = "-O0 -g -arch " + short_arch + version_min + " -fembed-bitcode"
return ["--host=" + arch, "--enable-static", "--disable-shared",
"--disable-libwebpdecoder", "--disable-libwebpdemux",
"--disable-libwebpmux", "--disable-libwebpextras",
"CC=clang -arch " + short_arch + " -isysroot $(xcrun --sdk " + xcode_sdk + " --show-sdk-path)",
"CFLAGS=" + cflags]
elif "android" in platform:
cflags = "-O3 -DNDEBUG"
if build_type == "debug":
cflags = "-O0 -g"
return ["--host=" + ARCHES[platform], "--enable-static", "--disable-shared",
"--disable-libwebpdecoder", "--disable-libwebpdemux",
"--disable-libwebpmux", "--disable-libwebpextras",
"CFLAGS=" + cflags, "LDFLAGS=-static"]
def make():
print("[fetch & build]: webp")
old_dir = fetch_repo()
build_type = "release"
if -1 != config.option("config").lower().find("debug"):
build_type = "debug"
platform = config.option("platform")
build_dir = create_build_dir(platform, build_type)
if -1 != platform.find("ios"):
args_simulator = get_args("iossimulator", build_type, build_dir)
args = get_args(platform, build_type, build_dir)
if build_dir == "":
return
# WINDOWS
if "windows" == base.host_platform():
base.run_as_bat(args, True)
# LINUX
elif -1 != platform.find("linux"):
base.cmd("./autogen.sh")
os.chdir(build_dir)
if config.option("sysroot") != "":
args += ["CROSS_COMPILE=" + config.get_custom_sysroot_bin() + "/"]
env_str = setup_custom_sysroot_env() if config.option("sysroot") != "" else ""
base.cmd(env_str + "./../../../libwebp/configure", args)
base.cmd(env_str + "make", ["-j$(nproc)"])
# MAC, ANDROID
elif -1 != platform.find("mac") or -1 != platform.find("ios") or -1 != platform.find("android"):
base.cmd("./autogen.sh")
os.chdir(build_dir)
base.cmd("./../../../libwebp/configure", args)
base.cmd("make", ["-j$(sysctl -n hw.ncpu)"])
# IOS
elif -1 != platform.find("ios"):
base.cmd("./autogen.sh")
os.chdir(build_dir + "/ios")
base.cmd("./../../../libwebp/configure", args)
base.cmd("make", ["-j$(sysctl -n hw.ncpu)"])
os.chdir(build_dir + "/iossimulator")
base.cmd("./../../../libwebp/configure", args_simulator)
base.cmd("make", ["-j$(sysctl -n hw.ncpu)"])
os.chdir(build_dir)
base.cmd("lipo", ["-create", "/ios/src/.libs/libwebp.a", "/iossimulator/src/.libs/libwebp.a", "-output", "/libwebp.a"])
base.cmd("lipo", ["-create", "/ios/src/.libs/libwebpdecoder.a", "/iossimulator/src/.libs/libwebpdecoder.a", "-output", "/libwebpdecoder.a"])
base.cmd("lipo", ["-create", "/ios/src/.libs/libwebpdemux.a", "/iossimulator/src/.libs/libwebpdemux.a", "-output", "/libwebpdemux.a"])
base.cmd("lipo", ["-create", "/ios/src/.libs/libwebpmux.a", "/iossimulator/src/.libs/libwebpmux.a", "-output", "/libwebpmux.a"])
os.chdir(old_dir)
return

View File

@ -15,7 +15,6 @@ def make():
continue
root_dir = base_dir + ("/" + native_platform + "/" + branding + ("/DocumentBuilder" if base.is_windows() else "/documentbuilder"))
root_dir_win64 = base_dir + "/win_64/" + branding + "/DocumentBuilder"
if (base.is_dir(root_dir)):
base.delete_dir(root_dir)
base.create_dir(root_dir)
@ -40,7 +39,6 @@ def make():
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, root_dir, "PdfFile")
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, root_dir, "DjVuFile")
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, root_dir, "XpsFile")
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, root_dir, "OFDFile")
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, root_dir, "HtmlFile2")
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, root_dir, "Fb2File")
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, root_dir, "EpubFile")
@ -58,7 +56,17 @@ def make():
# base.generate_check_linux_system(git_dir + "/build_tools", root_dir)
# icu
base.deploy_icu(core_dir, root_dir, native_platform)
if (0 == platform.find("win")):
base.copy_file(core_dir + "/Common/3dParty/icu/" + platform + "/build/icudt58.dll", root_dir + "/icudt58.dll")
base.copy_file(core_dir + "/Common/3dParty/icu/" + platform + "/build/icuuc58.dll", root_dir + "/icuuc58.dll")
if (0 == platform.find("linux")):
base.copy_file(core_dir + "/Common/3dParty/icu/" + platform + "/build/libicudata.so.58", root_dir + "/libicudata.so.58")
base.copy_file(core_dir + "/Common/3dParty/icu/" + platform + "/build/libicuuc.so.58", root_dir + "/libicuuc.so.58")
if (0 == platform.find("mac")):
base.copy_file(core_dir + "/Common/3dParty/icu/" + platform + "/build/libicudata.58.dylib", root_dir + "/libicudata.58.dylib")
base.copy_file(core_dir + "/Common/3dParty/icu/" + platform + "/build/libicuuc.58.dylib", root_dir + "/libicuuc.58.dylib")
# doctrenderer
if isWindowsXP:
@ -97,51 +105,39 @@ def make():
if (0 == platform.find("win")):
base.copy_file(core_dir + "/DesktopEditor/doctrenderer/docbuilder.com/src/docbuilder_midl.h", root_dir + "/include/docbuilder_midl.h")
base.replaceInFile(root_dir + "/include/docbuilder.h", "Q_DECL_EXPORT", "BUILDING_DOCBUILDER")
if ("win_64" == platform):
base.copy_file(core_dir + "/DesktopEditor/doctrenderer/docbuilder.com/deploy/win_64/docbuilder.com.dll", root_dir + "/docbuilder.com.dll")
base.copy_file(core_dir + "/DesktopEditor/doctrenderer/docbuilder.net/deploy/win_64/docbuilder.net.dll", root_dir + "/docbuilder.net.dll")
elif ("win_32" == platform):
base.copy_file(core_dir + "/DesktopEditor/doctrenderer/docbuilder.com/deploy/win_32/docbuilder.com.dll", root_dir + "/docbuilder.com.dll")
base.copy_file(core_dir + "/DesktopEditor/doctrenderer/docbuilder.net/deploy/win_32/docbuilder.net.dll", root_dir + "/docbuilder.net.dll")
# correct ios frameworks
if ("ios" == platform):
base.for_each_framework(root_dir, "ios", callbacks=[base.generate_plist, base.generate_xcprivacy])
base.generate_plist(root_dir)
if (0 == platform.find("linux")):
base.linux_correct_rpath_docbuilder(root_dir)
if (0 == platform.find("mac")):
base.for_each_framework(root_dir, "mac", callbacks=[base.generate_plist], max_depth=1)
base.mac_correct_rpath_x2t(root_dir)
base.mac_correct_rpath_docbuilder(root_dir)
base.create_x2t_js_cache(root_dir, "builder", platform)
base.create_dir(root_dir + "/fonts")
base.copy_dir(git_dir + "/core-fonts/asana", root_dir + "/fonts/asana")
base.copy_dir(git_dir + "/core-fonts/caladea", root_dir + "/fonts/caladea")
base.copy_dir(git_dir + "/core-fonts/crosextra", root_dir + "/fonts/crosextra")
base.copy_dir(git_dir + "/core-fonts/openoffice", root_dir + "/fonts/openoffice")
base.copy_file(git_dir + "/core-fonts/ASC.ttf", root_dir + "/fonts/ASC.ttf")
base.create_x2t_js_cache(root_dir, "builder")
# delete unnecessary builder files
def delete_files(files):
for file in files:
base.delete_file(file)
delete_files(base.find_files(root_dir, "*.wasm"))
delete_files(base.find_files(root_dir, "*_ie.js"))
base.delete_file(root_dir + "/sdkjs/pdf/src/engine/cmap.bin")
if 0 != platform.find("mac"):
delete_files(base.find_files(root_dir, "sdk-all.js"))
delete_files(base.find_files(root_dir, "sdk-all-min.js"))
base.delete_dir(root_dir + "/sdkjs/slide/themes")
base.delete_dir(root_dir + "/sdkjs/cell/css")
base.delete_file(root_dir + "/sdkjs/pdf/src/engine/viewer.js")
base.delete_file(root_dir + "/sdkjs/common/spell/spell/spell.js.mem")
base.delete_dir(root_dir + "/sdkjs/common/Images")
return

View File

@ -32,7 +32,6 @@ def make():
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, archive_dir, "doctrenderer")
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, archive_dir, "DjVuFile")
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, archive_dir, "XpsFile")
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, archive_dir, "OFDFile")
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, archive_dir, "PdfFile")
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, archive_dir, "HtmlFile2")
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, archive_dir, "UnicodeConverter")
@ -53,8 +52,7 @@ def make():
if ("windows" == base.host_platform()):
base.copy_files(core_dir + "/Common/3dParty/icu/" + platform + "/build/*.dll", archive_dir + "/")
else:
if not (0 == platform.find("mac") and config.check_option("config", "bundle_dylibs")):
base.copy_files(core_dir + "/Common/3dParty/icu/" + platform + "/build/*", archive_dir + "/")
base.copy_files(core_dir + "/Common/3dParty/icu/" + platform + "/build/*", archive_dir + "/")
base.copy_v8_files(core_dir, archive_dir, platform)
base.copy_exe(core_build_dir + "/bin/" + platform_postfix, archive_dir, "allfontsgen")
@ -67,16 +65,12 @@ def make():
base.copy_exe(core_build_dir + "/bin/" + platform_postfix, archive_dir, "metafiletester")
base.copy_exe(core_build_dir + "/bin/" + platform_postfix, archive_dir, "dictionariestester")
# correct mac frameworks
if (0 == platform.find("mac")):
base.for_each_framework(archive_dir, "mac", callbacks=[base.generate_plist], max_depth=1)
base.mac_correct_rpath_x2t(archive_dir)
# js cache
base.generate_doctrenderer_config(archive_dir + "/DoctRenderer.config", "./", "builder", "", "./dictionaries")
base.create_x2t_js_cache(archive_dir, "core", platform)
base.create_x2t_js_cache(archive_dir, "core")
base.delete_file(archive_dir + "/DoctRenderer.config")
# dictionaries
base.copy_dictionaries(git_dir + "/dictionaries", archive_dir + "/dictionaries", True, False)
return

View File

@ -12,7 +12,7 @@ def copy_lib_with_links(src_dir, dst_dir, lib, version):
lib_major_name = lib + "." + major_version
base.copy_file(src_dir + "/" + lib_full_name, dst_dir + "/" + lib_full_name)
base.cmd_in_dir(dst_dir, "ln", ["-s", "./" + lib_full_name, "./" + lib_major_name])
base.cmd_in_dir(dst_dir, "ln", ["-s", "./" + lib_major_name, "./" + lib])
@ -40,7 +40,7 @@ def make():
isWindowsXP = False if (-1 == native_platform.find("_xp")) else True
platform = native_platform[0:-3] if isWindowsXP else native_platform
apps_postfix = "build" + base.qt_dst_postfix()
apps_postfix = "build" + base.qt_dst_postfix();
if ("" != config.option("branding")):
apps_postfix += ("/" + config.option("branding"))
apps_postfix += "/"
@ -65,14 +65,13 @@ def make():
base.copy_lib(build_libraries_path, root_dir + "/converter", "PdfFile")
base.copy_lib(build_libraries_path, root_dir + "/converter", "DjVuFile")
base.copy_lib(build_libraries_path, root_dir + "/converter", "XpsFile")
base.copy_lib(build_libraries_path, root_dir + "/converter", "OFDFile")
base.copy_lib(build_libraries_path, root_dir + "/converter", "HtmlFile2")
base.copy_lib(build_libraries_path, root_dir + "/converter", "Fb2File")
base.copy_lib(build_libraries_path, root_dir + "/converter", "EpubFile")
base.copy_lib(build_libraries_path, root_dir + "/converter", "IWorkFile")
base.copy_lib(build_libraries_path, root_dir + "/converter", "HWPFile")
base.copy_lib(build_libraries_path, root_dir + "/converter", "DocxRenderer")
if ("ios" == platform):
base.copy_lib(build_libraries_path, root_dir + "/converter", "x2t")
else:
@ -82,13 +81,24 @@ def make():
# base.generate_check_linux_system(git_dir + "/build_tools", root_dir + "/converter")
# icu
base.deploy_icu(core_dir, root_dir + "/converter", native_platform)
if (0 == platform.find("win")):
base.copy_file(core_dir + "/Common/3dParty/icu/" + platform + "/build/icudt58.dll", root_dir + "/converter/icudt58.dll")
base.copy_file(core_dir + "/Common/3dParty/icu/" + platform + "/build/icuuc58.dll", root_dir + "/converter/icuuc58.dll")
#base.copy_file(git_dir + "/desktop-apps/common/converter/package.config", root_dir + "/converter/package.config")
if (0 == platform.find("linux")):
base.copy_file(core_dir + "/Common/3dParty/icu/" + platform + "/build/libicudata.so.58", root_dir + "/converter/libicudata.so.58")
base.copy_file(core_dir + "/Common/3dParty/icu/" + platform + "/build/libicuuc.so.58", root_dir + "/converter/libicuuc.so.58")
if (0 == platform.find("mac")):
base.copy_file(core_dir + "/Common/3dParty/icu/" + platform + "/build/libicudata.58.dylib", root_dir + "/converter/libicudata.58.dylib")
base.copy_file(core_dir + "/Common/3dParty/icu/" + platform + "/build/libicuuc.58.dylib", root_dir + "/converter/libicuuc.58.dylib")
# doctrenderer
if isWindowsXP:
base.copy_lib(build_libraries_path + "/xp", root_dir + "/converter", "doctrenderer")
else:
base.copy_lib(build_libraries_path, root_dir + "/converter", "doctrenderer")
base.copy_lib(build_libraries_path, root_dir + "/converter", "doctrenderer")
base.copy_v8_files(core_dir, root_dir + "/converter", platform, isWindowsXP)
base.generate_doctrenderer_config(root_dir + "/converter/DoctRenderer.config", "../editors/", "desktop", "", "../dictionaries")
@ -105,6 +115,8 @@ def make():
base.copy_dir(git_dir + "/core-fonts/openoffice", root_dir + "/fonts/openoffice")
base.copy_file(git_dir + "/core-fonts/ASC.ttf", root_dir + "/fonts/ASC.ttf")
base.copy_file(git_dir + "/desktop-apps/common/package/license/3dparty/3DPARTYLICENSE", root_dir + "/3DPARTYLICENSE")
# cef
build_dir_name = "build"
if (0 == platform.find("linux")) and (config.check_option("config", "cef_version_107")):
@ -117,20 +129,6 @@ def make():
else:
base.copy_files(core_dir + "/Common/3dParty/cef/" + native_platform + "/" + build_dir_name + "/*", root_dir)
if (0 == platform.find("mac")):
dir_base_old = os.getcwd()
os.chdir(root_dir + "/Chromium Embedded Framework.framework")
base.create_dir("Versions")
base.create_dir("Versions/A")
base.move_file("Chromium Embedded Framework", "Versions/A/Chromium Embedded Framework")
base.move_dir("Resources", "Versions/A/Resources")
base.move_dir("Libraries", "Versions/A/Libraries")
base.cmd("ln", ["-s", "Versions/A/Chromium Embedded Framework", "Chromium Embedded Framework"])
base.cmd("ln", ["-s", "Versions/A/Resources", "Resources"])
base.cmd("ln", ["-s", "Versions/A/Libraries", "Libraries"])
base.cmd("ln", ["-s", "A", "Versions/Current"])
os.chdir(dir_base_old);
isUseQt = True
if (0 == platform.find("mac")) or (0 == platform.find("ios")):
isUseQt = False
@ -141,18 +139,18 @@ def make():
base.copy_lib(build_libraries_path + ("/xp" if isWindowsXP else ""), root_dir, "ascdocumentscore")
if (0 != platform.find("mac")):
base.copy_lib(build_libraries_path + ("/xp" if isWindowsXP else ""), root_dir, "qtascdocumentscore")
if (0 == platform.find("mac")):
base.copy_dir(core_build_dir + "/bin/" + platform_postfix + "/editors_helper.app", root_dir + "/editors_helper.app")
else:
base.copy_exe(core_build_dir + "/bin/" + platform_postfix + ("/xp" if isWindowsXP else ""), root_dir, "editors_helper")
if isUseQt:
base.qt_copy_lib("Qt5Core", root_dir)
base.qt_copy_lib("Qt5Gui", root_dir)
base.qt_copy_lib("Qt5PrintSupport", root_dir)
base.qt_copy_lib("Qt5Svg", root_dir)
base.qt_copy_lib("Qt5Widgets", root_dir)
base.qt_copy_lib("Qt5Widgets", root_dir)
base.qt_copy_lib("Qt5Network", root_dir)
base.qt_copy_lib("Qt5OpenGL", root_dir)
@ -161,7 +159,7 @@ def make():
base.qt_copy_plugin("imageformats", root_dir)
base.qt_copy_plugin("platforms", root_dir)
base.qt_copy_plugin("platforminputcontexts", root_dir)
base.qt_copy_plugin("printsupport", root_dir)
base.qt_copy_plugin("printsupport", root_dir)
base.qt_copy_plugin("platformthemes", root_dir)
base.qt_copy_plugin("xcbglintegrations", root_dir)
@ -186,6 +184,7 @@ def make():
base.copy_file(git_dir + "/desktop-apps/win-linux/extras/projicons/" + apps_postfix + "/projicons.exe", root_dir + "/DesktopEditors.exe")
if not isWindowsXP:
base.copy_file(git_dir + "/desktop-apps/win-linux/extras/update-daemon/" + apps_postfix + "/updatesvc.exe", root_dir + "/updatesvc.exe")
base.copy_file(git_dir + "/desktop-apps/win-linux/extras/online-installer/" + apps_postfix + "/online-installer.exe", root_dir + "/online-installer.exe")
base.copy_file(git_dir + "/desktop-apps/win-linux/" + apps_postfix + "/DesktopEditors.exe", root_dir + "/editors.exe")
base.copy_file(git_dir + "/desktop-apps/win-linux/res/icons/desktopeditors.ico", root_dir + "/app.ico")
elif (0 == platform.find("linux")):
@ -193,9 +192,9 @@ def make():
if base.check_congig_option_with_platfom(platform, "libvlc"):
vlc_dir = git_dir + "/core/Common/3dParty/libvlc/build/" + platform + "/lib"
if (0 == platform.find("win")):
base.copy_dir(vlc_dir + "/plugins", root_dir + "/plugins")
base.copy_dir(vlc_dir + "/plugins", root_dir + "/plugins")
base.copy_files(vlc_dir + "/*.dll", root_dir)
base.copy_file(vlc_dir + "/vlc-cache-gen.exe", root_dir + "/vlc-cache-gen.exe")
elif (0 == platform.find("linux")):
@ -241,20 +240,7 @@ def make():
#base.copy_dir(git_dir + "/desktop-sdk/ChromiumBasedEditors/plugins/encrypt/ui/common/{14A8FC87-8E26-4216-B34E-F27F053B2EC4}", root_dir + "/editors/sdkjs-plugins/{14A8FC87-8E26-4216-B34E-F27F053B2EC4}")
#base.copy_dir(git_dir + "/desktop-sdk/ChromiumBasedEditors/plugins/encrypt/ui/engine/database/{9AB4BBA8-A7E5-48D5-B683-ECE76A020BB1}", root_dir + "/editors/sdkjs-plugins/{9AB4BBA8-A7E5-48D5-B683-ECE76A020BB1}")
base.copy_sdkjs_plugin(git_dir + "/desktop-sdk/ChromiumBasedEditors/plugins", root_dir + "/editors/sdkjs-plugins", "sendto", True)
isUseAgent = True
if isWindowsXP:
isUseAgent = False
if (isUseAgent):
agent_plugin_dir = git_dir + "/desktop-sdk/ChromiumBasedEditors/plugins/ai-agent"
if (False):
base.cmd_in_dir(agent_plugin_dir, "npm", ["install"], True)
base.cmd_in_dir(agent_plugin_dir, "npm", ["run", "build"], True)
base.copy_dir(agent_plugin_dir + "/{9DC93CDB-B576-4F0C-B55E-FCC9C48DD777}", root_dir + "/editors/sdkjs-plugins/{9DC93CDB-B576-4F0C-B55E-FCC9C48DD777}")
else:
base.copy_dir(agent_plugin_dir + "/deploy/{9DC93CDB-B576-4F0C-B55E-FCC9C48DD777}", root_dir + "/editors/sdkjs-plugins/{9DC93CDB-B576-4F0C-B55E-FCC9C48DD777}")
base.copy_file(base_dir + "/js/" + branding + "/desktop/index.html", root_dir + "/index.html")
base.create_dir(root_dir + "/editors/webext")
base.copy_file(base_dir + "/js/" + branding + "/desktop/noconnect.html", root_dir + "/editors/webext/noconnect.html")
@ -267,10 +253,7 @@ def make():
isUseJSC = False
if (0 == platform.find("mac")):
doctrenderer_lib = "libdoctrenderer.dylib"
if config.check_option("config", "bundle_dylibs"):
doctrenderer_lib = "doctrenderer.framework/doctrenderer"
file_size_doctrenderer = os.path.getsize(root_dir + "/converter/" + doctrenderer_lib)
file_size_doctrenderer = os.path.getsize(root_dir + "/converter/libdoctrenderer.dylib")
print("file_size_doctrenderer: " + str(file_size_doctrenderer))
if (file_size_doctrenderer < 5*1024*1024):
isUseJSC = True
@ -278,42 +261,35 @@ def make():
if isUseJSC:
base.delete_file(root_dir + "/converter/icudtl.dat")
base.create_x2t_js_cache(root_dir + "/converter", "desktop", platform)
base.create_x2t_js_cache(root_dir + "/converter", "desktop")
if (0 == platform.find("win")):
base.delete_file(root_dir + "/cef_sandbox.lib")
base.delete_file(root_dir + "/libcef.lib")
is_host_not_arm = False
host_platform = ""
if (platform == "mac_arm64" or platform == "win_arm64") and not base.is_os_arm():
is_host_not_arm = True
if platform == "mac_arm64":
host_platform = "mac_64"
elif platform == "win_arm64":
host_platform = "win_64"
isMacArmPlaformOnIntel = False
if (platform == "mac_arm64") and not base.is_os_arm():
isMacArmPlaformOnIntel = True
# all themes generate ----
base.copy_exe(core_build_dir + "/bin/" + platform_postfix, root_dir + "/converter", "allfontsgen")
base.copy_exe(core_build_dir + "/bin/" + platform_postfix, root_dir + "/converter", "allthemesgen")
if (0 == platform.find("mac")):
# gen plists with max_depth 2 because frameworks are only located in root_dir and converter subdirectory
base.for_each_framework(root_dir, "mac", callbacks=[base.generate_plist], max_depth=2)
base.mac_correct_rpath_desktop(root_dir)
if is_host_not_arm:
if isMacArmPlaformOnIntel:
sdkjs_dir = root_dir + "/editors/sdkjs"
end_find_platform = sdkjs_dir.rfind("/" + platform + "/")
sdkjs_dir_64 = sdkjs_dir[0:end_find_platform] + "/" + host_platform + "/" + sdkjs_dir[end_find_platform+11:]
end_find_platform = sdkjs_dir.rfind("/mac_arm64/")
sdkjs_dir_mac64 = sdkjs_dir[0:end_find_platform] + "/mac_64/" + sdkjs_dir[end_find_platform+11:]
base.delete_dir(sdkjs_dir)
base.copy_dir(sdkjs_dir_64, sdkjs_dir)
base.copy_dir(sdkjs_dir_mac64, sdkjs_dir)
else:
themes_params = []
if ("" != config.option("themesparams")):
themes_params = ["--params=\"" + config.option("themesparams") + "\""]
base.cmd_exe(root_dir + "/converter/allfontsgen", ["--use-system=\"1\"", "--input=\"" + root_dir + "/fonts\"", "--input=\"" + git_dir + "/core-fonts\"", "--allfonts=\"" + root_dir + "/converter/AllFonts.js\"", "--selection=\"" + root_dir + "/converter/font_selection.bin\""], True)
base.cmd_exe(root_dir + "/converter/allthemesgen", ["--converter-dir=\"" + root_dir + "/converter\"", "--src=\"" + root_dir + "/editors/sdkjs/slide/themes\"", "--allfonts=\"AllFonts.js\"", "--output=\"" + root_dir + "/editors/sdkjs/common/Images\""] + themes_params, True)
base.cmd_exe(root_dir + "/converter/allfontsgen", ["--use-system=\"1\"", "--input=\"" + root_dir + "/fonts\"", "--input=\"" + git_dir + "/core-fonts\"", "--allfonts=\"" + root_dir + "/converter/AllFonts.js\"", "--selection=\"" + root_dir + "/converter/font_selection.bin\""])
base.cmd_exe(root_dir + "/converter/allthemesgen", ["--converter-dir=\"" + root_dir + "/converter\"", "--src=\"" + root_dir + "/editors/sdkjs/slide/themes\"", "--allfonts=\"AllFonts.js\"", "--output=\"" + root_dir + "/editors/sdkjs/common/Images\""] + themes_params)
base.delete_file(root_dir + "/converter/AllFonts.js")
base.delete_file(root_dir + "/converter/font_selection.bin")
base.delete_file(root_dir + "/converter/fonts.log")
@ -325,3 +301,4 @@ def make():
base.delete_file(root_dir + "/editors/sdkjs/slide/sdk-all.cache")
return

View File

@ -18,7 +18,7 @@ def deploy_fonts(git_dir, root_dir, platform=""):
if (platform == "android"):
base.copy_dir(git_dir + "/core-fonts/dejavu", root_dir + "/fonts/dejavu")
base.copy_dir(git_dir + "/core-fonts/liberation", root_dir + "/fonts/liberation")
return
return
def make():
base_dir = base.get_script_dir() + "/../out"
@ -35,7 +35,7 @@ def make():
if base.get_env("DESTDIR_BUILD_OVERRIDE") != "":
return
if (base.is_dir(root_dir)):
base.delete_dir(root_dir)
base.create_dir(root_dir)
@ -57,7 +57,6 @@ def make():
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, root_dir, "PdfFile")
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, root_dir, "DjVuFile")
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, root_dir, "XpsFile")
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, root_dir, "OFDFile")
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, root_dir, "HtmlFile2")
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, root_dir, "doctrenderer")
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, root_dir, "Fb2File")
@ -73,14 +72,29 @@ def make():
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, root_dir, "x2t")
# icu
base.deploy_icu(core_dir, root_dir, platform)
if (0 == platform.find("win")):
base.copy_file(core_dir + "/Common/3dParty/icu/" + platform + "/build/icudt58.dll", root_dir + "/icudt58.dll")
base.copy_file(core_dir + "/Common/3dParty/icu/" + platform + "/build/icuuc58.dll", root_dir + "/icuuc58.dll")
if (0 == platform.find("linux")):
base.copy_file(core_dir + "/Common/3dParty/icu/" + platform + "/build/libicudata.so.58", root_dir + "/libicudata.so.58")
base.copy_file(core_dir + "/Common/3dParty/icu/" + platform + "/build/libicuuc.so.58", root_dir + "/libicuuc.so.58")
if (0 == platform.find("mac")):
base.copy_file(core_dir + "/Common/3dParty/icu/" + platform + "/build/libicudata.58.dylib", root_dir + "/libicudata.58.dylib")
base.copy_file(core_dir + "/Common/3dParty/icu/" + platform + "/build/libicuuc.58.dylib", root_dir + "/libicuuc.58.dylib")
if (0 == platform.find("android")):
#base.copy_file(core_dir + "/Common/3dParty/icu/android/build/" + platform[8:] + "/libicudata.so", root_dir + "/libicudata.so")
#base.copy_file(core_dir + "/Common/3dParty/icu/android/build/" + platform[8:] + "/libicuuc.so", root_dir + "/libicuuc.so")
base.copy_file(core_dir + "/Common/3dParty/icu/android/build/" + platform[8:] + "/icudt58l.dat", root_dir + "/icudt58l.dat")
# js
base.copy_dir(base_dir + "/js/" + branding + "/mobile/sdkjs", root_dir + "/sdkjs")
# correct ios frameworks
if ("ios" == platform):
base.for_each_framework(root_dir, "ios", callbacks=[base.generate_plist, base.generate_xcprivacy])
base.generate_plist(root_dir)
deploy_fonts(git_dir, root_dir)
base.copy_dictionaries(git_dir + "/dictionaries", root_dir + "/dictionaries", True, False)
@ -100,7 +114,7 @@ def make():
deploy_fonts(git_dir, root_dir, "android")
base.copy_dictionaries(git_dir + "/dictionaries", root_dir + "/dictionaries", True, False)
# app
base.generate_doctrenderer_config(root_dir + "/DoctRenderer.config", "./", "builder", "", "./dictionaries")
base.generate_doctrenderer_config(root_dir + "/DoctRenderer.config", "./", "builder", "", "./dictionaries")
libs_dir = root_dir + "/lib"
base.create_dir(libs_dir + "/arm64-v8a")
base.copy_files(base_dir + "/android_arm64_v8a/" + branding + "/mobile/*.so", libs_dir + "/arm64-v8a")

View File

@ -18,7 +18,7 @@ def make():
if base.get_env("DESTDIR_BUILD_OVERRIDE") != "":
return
if (base.is_dir(root_dir)):
base.delete_dir(root_dir)
base.create_dir(root_dir)
@ -37,7 +37,7 @@ def make():
# correct ios frameworks
if ("ios" == platform):
base.for_each_framework(root_dir, "ios", callbacks=[base.generate_plist, base.generate_xcprivacy])
base.generate_plist(root_dir)
for native_platform in platforms:
if native_platform == "android":

View File

@ -58,14 +58,6 @@ def make():
base.create_dir(build_server_dir + '/Metrics/node_modules/modern-syslog/build/Release')
base.copy_file(server_dir + "/Metrics/node_modules/modern-syslog/build/Release/core.node", build_server_dir + "/Metrics/node_modules/modern-syslog/build/Release/core.node")
# AdminPanel server part
base.create_dir(build_server_dir + '/AdminPanel/server')
base.copy_exe(server_dir + "/AdminPanel/server", build_server_dir + '/AdminPanel/server', "adminpanel")
# AdminPanel client part
base.create_dir(build_server_dir + '/AdminPanel/client/build')
base.copy_dir(server_dir + '/AdminPanel/client/build', build_server_dir + '/AdminPanel/client/build')
qt_dir = base.qt_setup(native_platform)
platform = native_platform
@ -85,7 +77,6 @@ def make():
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, converter_dir, "PdfFile")
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, converter_dir, "DjVuFile")
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, converter_dir, "XpsFile")
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, converter_dir, "OFDFile")
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, converter_dir, "HtmlFile2")
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, converter_dir, "doctrenderer")
base.copy_lib(core_build_dir + "/lib/" + platform_postfix, converter_dir, "Fb2File")
@ -102,18 +93,24 @@ def make():
base.generate_doctrenderer_config(converter_dir + "/DoctRenderer.config", "../../../", "server", "", "../../../dictionaries")
# icu
base.deploy_icu(core_dir, converter_dir, platform)
if (0 == platform.find("win")):
base.copy_file(core_dir + "/Common/3dParty/icu/" + platform + "/build/icudt58.dll", converter_dir + "/icudt58.dll")
base.copy_file(core_dir + "/Common/3dParty/icu/" + platform + "/build/icuuc58.dll", converter_dir + "/icuuc58.dll")
if (0 == platform.find("linux")):
base.copy_file(core_dir + "/Common/3dParty/icu/" + platform + "/build/libicudata.so.58", converter_dir + "/libicudata.so.58")
base.copy_file(core_dir + "/Common/3dParty/icu/" + platform + "/build/libicuuc.so.58", converter_dir + "/libicuuc.so.58")
if (0 == platform.find("mac")):
base.copy_file(core_dir + "/Common/3dParty/icu/" + platform + "/build/libicudata.58.dylib", converter_dir + "/libicudata.58.dylib")
base.copy_file(core_dir + "/Common/3dParty/icu/" + platform + "/build/libicuuc.58.dylib", converter_dir + "/libicuuc.58.dylib")
base.copy_v8_files(core_dir, converter_dir, platform)
# builder
base.copy_exe(core_build_dir + "/bin/" + platform_postfix, converter_dir, "docbuilder")
base.copy_dir(git_dir + "/document-templates/new/en-US", converter_dir + "/empty")
# correct mac frameworks
if (0 == platform.find("mac")):
base.for_each_framework(converter_dir, "mac", callbacks=[base.generate_plist], max_depth=1)
# js
js_dir = root_dir
base.copy_dir(base_dir + "/js/" + branding + "/builder/sdkjs", js_dir + "/sdkjs")
@ -122,11 +119,11 @@ def make():
+ glob.glob(js_dir + "/web-apps/apps/*/mobile/dist/js/*.js.map"):
base.delete_file(file)
base.create_x2t_js_cache(converter_dir, "server", platform)
base.create_x2t_js_cache(converter_dir, "server")
# add embed worker code
base.cmd_in_dir(git_dir + "/sdkjs/common/embed", "python", ["make.py", js_dir + "/web-apps/apps/api/documents/api.js"])
# plugins
base.create_dir(js_dir + "/sdkjs-plugins")
base.copy_marketplace_plugin(js_dir + "/sdkjs-plugins", False, True)
@ -148,7 +145,7 @@ def make():
base.copy_exe(core_build_dir + "/bin/" + platform_postfix, tools_dir, "allthemesgen")
if ("1" != config.option("preinstalled-plugins")):
base.copy_exe(core_build_dir + "/bin/" + platform_postfix, tools_dir, "pluginsmanager")
branding_dir = server_dir + "/branding"
if("" != config.option("branding") and "onlyoffice" != config.option("branding")):
branding_dir = git_dir + '/' + config.option("branding") + '/server'
@ -187,7 +184,6 @@ def make():
base.copy_file(license_file1, build_server_dir)
base.copy_file(license_file2, build_server_dir)
base.copy_dir(license_dir, license)
base.copy_dir(server_dir + '/dictionaries', build_server_dir + '/dictionaries')
#branding
welcome_files = branding_dir + '/welcome'
@ -230,3 +226,4 @@ def make():
base.delete_file(root_dir_snap + '/example/nodejs/example')
return

View File

@ -1,104 +0,0 @@
# This script was successfully executed on Ubuntu 22.04.5 LTS
# Before starting, make sure that:
# 1. Python >= 3.9
# 2. The current working folder with the script and its path do not contain spaces and use Latin characters.
# 3. Antivirus is turned off
# 4. There is enough free space on the disk (50GB Libre Office and during the unpacking of packages, it's recommended that you allocate at least 80 gigabytes of free space)
# 5. The current working folder with the script and its path do not contain spaces and use Latin characters.
# If the error "You must put some 'source' URIs in your sources.list" occurs, you need to run the command:
# software-properties-gtk
# in the terminal, and then under the "Ubuntu Software" tab, click "Source code" if it's not turned on and submit
# after completion, the file will appear:
# current_folder_with_script/libreoffice_build/instdir/soffice
# debugging can be done via MVS 2022
# https://wiki.documentfoundation.org/Development/IDE#Microsoft_Visual_Studio
# or via VS Code with c/c++ tools
# https://wiki.documentfoundation.org/Development/IDE#Visual_Studio_Code_(VSCode)
# or via Qt Creator
# https://wiki.documentfoundation.org/Development/IDE#Qt_Creator
# or via attatch to the soffice.bin process
# https://wiki.documentfoundation.org/Development/How_to_debug#Debugging_with_gdb
import subprocess
import sys
import os
CONFIGURE_PARAMS = [
"--enable-dbgutil",
"--without-doxygen",
"--enable-pch",
"--disable-ccache",
# "--with-visual-studio=2022",
'--enable-symbols="all"'
]
SUDO_DEPENDENCIES = [
"git", "build-essential", "zip", "ccache", "junit4", "libkrb5-dev", "nasm", "graphviz", "python3",
"python3-dev", "python3-setuptools", "qtbase5-dev", "libkf5coreaddons-dev", "libkf5i18n-dev",
"libkf5config-dev", "libkf5windowsystem-dev", "libkf5kio-dev", "libqt5x11extras5-dev", "autoconf",
"libcups2-dev", "libfontconfig1-dev", "gperf", "openjdk-17-jdk", "doxygen", "libxslt1-dev",
"xsltproc", "libxml2-utils", "libxrandr-dev", "libx11-dev", "bison", "flex", "libgtk-3-dev",
"libgstreamer-plugins-base1.0-dev", "libgstreamer1.0-dev", "ant", "ant-optional", "libnss3-dev",
"libavahi-client-dev", "libxt-dev"
]
DIR_NAME = "libreoffice"
OFFICE_PATH = "instdir/program/soffice"
class bcolors:
OKBLUE = '\033[94m'
OKCYAN = '\033[96m'
OKGREEN = '\033[92m'
FAIL = '\033[91m'
RESET = '\033[0m'
def run_command(command, exit_on_error=True):
try:
subprocess.run(command, shell=True, check=True)
except subprocess.CalledProcessError as e:
print(f"{bcolors.FAIL}Error executing command: {command}{bcolors.RESET}")
if exit_on_error:
sys.exit(1)
def install_dependencies():
print("Updating package list...")
run_command("sudo apt update")
print("Adding PPA for GCC/G++ update...")
run_command("sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test")
run_command("sudo apt update")
print("Installing dependencies for LibreOffice...")
run_command("sudo apt-get build-dep -y libreoffice")
run_command(f"sudo apt-get install {' '.join(map(str, SUDO_DEPENDENCIES))}")
print("Updating GCC/G++ to v12...")
run_command("sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 60 --slave /usr/bin/g++ g++ /usr/bin/g++-12", exit_on_error=False)
print(bcolors.OKGREEN + "All dependencies successfully installed!" + bcolors.RESET)
def build_libreoffice():
print("Cloning LibreOffice repository...")
run_command(f"git clone https://git.libreoffice.org/core {DIR_NAME}", exit_on_error=False)
print("Changing to build directory...")
os.chdir(f"./{DIR_NAME}")
print("Start configurator autogen.sh...")
run_command(f"./autogen.sh {' '.join(map(str, CONFIGURE_PARAMS))}")
print(bcolors.OKCYAN + "Starting libreoffice build, this may take up to 24 hours and takes up about 20 GB of drive space. You will also most likely need at least 8 GBs of RAM, otherwise the machine might fall into swap and appear to freeze up..." + bcolors.RESET)
run_command("make")
print(bcolors.OKGREEN + "LibreOffice build completed!" + bcolors.RESET)
# print(bcolors.OKCYAN + "Running LibreOffice..." + bcolors.RESET)
# run_command(OFFICE_PATH, exit_on_error=False)
if __name__ == "__main__":
install_dependencies()
build_libreoffice()

View File

@ -1,202 +0,0 @@
# Before starting, make sure that:
# 1. MVS 2022 is installed and the necessary individual components are in its installer
# <20> Windows Universal C Runtime
# <20> .NET Framework 4.x SDK (.NET Framework 5.x SDK and later are currently not supported. These don't register their information to registry, don't have csc.exe and they use dotnet command with csc.dll instead for compiling.)
# <20> C++ 20xx Redistributable MSMs (only required to build MSI installer)
# <20> C++ Clang Compiler for Windows (x.x.x)
# 2. Java JDK >= 17
# 3. Antivirus is turned off
# 4. There is enough free space on the disk (50GB Libre Office, 50Gb cygwin64)
# after completion, the files will appear:
# {LO_BUILD_PATH}/sources/libo-core/instdir/program/soffice.exe
# {LO_BUILD_PATH}/sources/libo-core/LibreOffice.sln
# debugging can be done via MVS 2022
# https://wiki.documentfoundation.org/Development/IDE#Microsoft_Visual_Studio
# or via attatch to the soffice.bin process
# https://wiki.documentfoundation.org/Development/How_to_debug#Debugging_with_gdb
import sys
sys.path.append('../../scripts')
import threading
import os
import subprocess
import shutil
import argparse
import base
CYGWIN_DOWNLOAD_URL = 'https://cygwin.com/setup-x86_64.exe'
CYGWIN_TEMP_PATH = './tmp'
CYGWIN_SETUP_FILENAME = 'setup-x86_64.exe'
CYGWIN_SETUP_PARAMS = [
"-P", "autoconf",
"-P", "automake",
"-P", "bison",
"-P", "cabextract",
"-P", "doxygen",
"-P", "flex",
"-P", "gawk=5.2.2-1",
"-P", "gcc-g++",
"-P", "gettext-devel",
"-P", "git",
"-P", "gnupg",
"-P", "gperf",
"-P", "make",
"-P", "mintty",
"-P", "nasm",
"-P", "openssh",
"-P", "openssl",
"-P", "patch",
"-P", "perl",
"-P", "python",
"-P", "python3",
"-P", "pkg-config",
"-P", "rsync",
"-P", "unzip",
"-P", "vim",
"-P", "wget",
"-P", "zip",
"-P", "perl-Archive-Zip",
"-P", "perl-Font-TTF",
"-P", "perl-IO-String",
"--no-admin",
"--quiet-mode"
]
CYGWIN_BAT_PATH = 'C:/cygwin64/Cygwin.bat'
LO_BUILD_PATH = os.path.normpath(os.path.join(os.getcwd(), '../../../LO'))
CONFIGURE_PARAMS = [f'--with-external-tar="{LO_BUILD_PATH}/sources/lo-externalsrc"',
f'--with-junit="{LO_BUILD_PATH}/sources/junit-4.10.jar"',
f'--with-ant-home="{LO_BUILD_PATH}/sources/apache-ant-1.9.5"',
"--enable-pch",
"--disable-ccache",
"--with-visual-studio=2022",
"--enable-dbgutil",
'--enable-symbols="all"']
def create_folder_safe(folder_path):
if not os.path.exists(folder_path):
try:
os.mkdir(folder_path)
print(f"Folder '{folder_path}' created successfully.")
except Exception as e:
print(f"Error creating folder: {e}")
else:
print(f"Folder '{folder_path}' already exists.")
class CygwinRunner:
@staticmethod
def process_commands(commands: list[str]):
proc = subprocess.Popen(
[CYGWIN_BAT_PATH], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True,
shell=True, creationflags=subprocess.CREATE_NEW_CONSOLE
)
def read_stdout():
for line in iter(proc.stdout.readline, ''):
sys.stdout.write(line)
proc.stdout.close()
def read_stderr():
for line in iter(proc.stderr.readline, ''):
sys.stderr.write(line)
proc.stderr.close()
stdout_thread = threading.Thread(target=read_stdout)
stderr_thread = threading.Thread(target=read_stderr)
stdout_thread.start()
stderr_thread.start()
for command in commands:
proc.stdin.write(command + '\n')
proc.stdin.flush()
stdout_thread.join()
stderr_thread.join()
proc.stdin.close()
proc.wait()
@staticmethod
def install_gnu_make():
base.print_info("install_gnu_make")
commands = ['mkdir -p /opt/lo/bin',
'cd /opt/lo/bin',
'wget https://dev-www.libreoffice.org/bin/cygwin/make-4.2.1-msvc.exe',
'cp make-4.2.1-msvc.exe make',
'chmod +x make',
'exit']
CygwinRunner.process_commands(commands)
@staticmethod
def install_ant_and_junit():
base.print_info("install_ant_and_junit")
commands = [f'mkdir -p {LO_BUILD_PATH}/sources',
f'cd {LO_BUILD_PATH}/sources',
'wget https://archive.apache.org/dist/ant/binaries/apache-ant-1.9.5-bin.tar.bz2',
'tar -xjvf apache-ant-1.9.5-bin.tar.bz2',
'wget http://downloads.sourceforge.net/project/junit/junit/4.10/junit-4.10.jar',
'exit']
CygwinRunner.process_commands(commands)
@staticmethod
def clone_lo():
base.print_info("clone_lo")
commands = [f'cd {LO_BUILD_PATH}/sources',
'git clone https://gerrit.libreoffice.org/core libo-core',
'exit']
CygwinRunner.process_commands(commands)
@staticmethod
def build_autogen():
base.print_info("build_autogen")
commands = [f'cd {LO_BUILD_PATH}/sources/libo-core',
f"./autogen.sh {' '.join(map(str, CONFIGURE_PARAMS))}",
'exit']
CygwinRunner.process_commands(commands)
@staticmethod
def run_make_build():
base.print_info("run_make")
commands = [f'cd {LO_BUILD_PATH}/sources/libo-core',
f'/opt/lo/bin/make gb_COLOR=1',
"exit"]
CygwinRunner.process_commands(commands)
@staticmethod
def build_vs_integration():
base.print_info("run_make")
commands = [f'cd {LO_BUILD_PATH}/sources/libo-core',
f'/opt/lo/bin/make gb_COLOR=1 vs-ide-integration',
"exit"]
CygwinRunner.process_commands(commands)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="options")
parser.add_argument("--lo_build_path", dest="build_path", default=f'../../../LO')
parser.add_argument("--disable_sln", dest="disable_sln", action=argparse.BooleanOptionalAction)
args = parser.parse_args()
LO_BUILD_PATH = args.build_path
DISABLE_SLN = args.disable_sln
create_folder_safe(f'{LO_BUILD_PATH}/sources/lo-externalsrc')
create_folder_safe(CYGWIN_TEMP_PATH)
os.chdir(CYGWIN_TEMP_PATH)
base.download(CYGWIN_DOWNLOAD_URL, CYGWIN_SETUP_FILENAME)
subprocess.run([CYGWIN_SETUP_FILENAME] + CYGWIN_SETUP_PARAMS)
os.chdir('..')
shutil.rmtree(CYGWIN_TEMP_PATH)
CygwinRunner.install_gnu_make()
CygwinRunner.install_ant_and_junit()
CygwinRunner.clone_lo()
CygwinRunner.build_autogen()
CygwinRunner.run_make_build()
if not DISABLE_SLN:
CygwinRunner.build_vs_integration()

View File

@ -190,7 +190,7 @@ def check_nodejs():
nodejs_cur_version_major = int(nodejs_version.split('.')[0][1:])
nodejs_cur_version_minor = int(nodejs_version.split('.')[1])
print('Installed Node.js version: ' + nodejs_version[1:])
nodejs_min_version = '18'
nodejs_min_version = '22'
nodejs_min_version_minor = 0
major_minor_min_version = nodejs_min_version.split('.')
nodejs_min_version_major = int(major_minor_min_version[0])
@ -214,7 +214,7 @@ def check_nodejs():
isNeedReinstall = True
if (True == isNeedReinstall):
print('Installed Node.js version must be 18 or higher.')
print('Installed Node.js version must be 22 or higher.')
if (host_platform == 'windows'):
dependence.append_uninstall('Node.js')
dependence.append_install('Node.js')
@ -950,7 +950,7 @@ def install_postgresql():
return code
def install_nodejs():
os.system('curl -sSL https://deb.nodesource.com/setup_18.x | sudo -E bash -')
os.system('curl -sSL https://deb.nodesource.com/setup_22.x | sudo -E bash -')
base.print_info("Install node.js...")
install_command = 'yes | sudo apt install nodejs'
print(install_command)
@ -959,7 +959,7 @@ def install_nodejs():
downloads_list = {
'Windows': {
'Git': 'https://github.com/git-for-windows/git/releases/download/v2.29.0.windows.1/Git-2.29.0-64-bit.exe',
'Node.js': 'https://nodejs.org/dist/v18.17.1/node-v18.17.1-x64.msi',
'Node.js': 'https://nodejs.org/dist/v22.13.1/node-v22.13.1-x64.msi',
'Java': 'https://aka.ms/download-jdk/microsoft-jdk-11.0.18-windows-x64.msi',
'RabbitMQ': 'https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.8.9/rabbitmq-server-3.8.9.exe',
'Erlang': 'http://erlang.org/download/otp_win64_23.1.exe',

View File

@ -1,342 +0,0 @@
#!/usr/bin/env python3
"""
Git Operations Script
Provides functionality to clone repositories and create branches.
Uses existing methods from base module and integrates with release.py patterns.
"""
import sys
import argparse
import logging
from typing import Dict
# Add parent directory to path to import modules
sys.path.append('../')
import base
import config
import dependence
# Setup logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
class GitOperations:
"""Class to handle git clone and branch creation using existing base module methods."""
def __init__(self, branding: str = "onlyoffice", base_branch: str = "develop",
branding_url: str = "ONLYOFFICE/onlyoffice.git", branch_name: str = None,
modules: str = "core desktop builder server mobile"):
"""
Initialize GitOperations with branding configuration and configure repositories.
Args:
branding: Branding name (default: onlyoffice)
base_branch: Base branch to work from (default: develop)
branding_url: Relative path from git host base (default: ONLYOFFICE/onlyoffice.git)
branch_name: Name of the branch to create (required for branch operations)
modules: Modules to include (default: core desktop builder server mobile)
"""
self.branding = branding
self.base_branch = base_branch
self.branding_url = branding_url
self.branch_name = branch_name
self.modules = modules
self.work_dir = None
# Configure repositories immediately
self._configure()
# Update repositories after configuration
repositories = self.get_configured_repositories()
#base.update_repositories(repositories)
def create_branch(self, branch_name: str, repo_dir: str = None) -> bool:
"""
Create a new branch using base.cmd_in_dir.
Args:
branch_name: Name of the new branch
repo_dir: Repository directory (optional, uses current if not specified)
from_branch: Branch to create from (optional, uses current if not specified)
Returns:
bool: True if successful, False otherwise
"""
work_dir = repo_dir or self.work_dir
logger.info(f"Creating branch '{branch_name}' in {work_dir}")
try:
# Create and checkout new branch
base.cmd_in_dir(work_dir, "git", ["checkout", "-b", branch_name], True)
logger.info(f"Successfully created branch: {branch_name}")
return True
except SystemExit:
logger.error(f"Failed to create branch: {branch_name}")
return False
def push_branch(self, branch_name: str, repo_dir: str = None, set_upstream: bool = True) -> bool:
"""
Push a branch to remote repository using base.cmd_in_dir.
Args:
branch_name: Name of the branch to push
repo_dir: Repository directory (optional, uses current if not specified)
set_upstream: Whether to set upstream tracking (default: True)
Returns:
bool: True if successful, False otherwise
"""
work_dir = repo_dir or self.work_dir
logger.info(f"Pushing branch '{branch_name}' in {work_dir}")
try:
if set_upstream:
# Push branch and set upstream tracking
base.cmd_in_dir(work_dir, "git", ["push", "-u", "origin", branch_name], True)
else:
# Just push the branch
base.cmd_in_dir(work_dir, "git", ["push", "origin", branch_name], True)
logger.info(f"Successfully pushed branch: {branch_name}")
return True
except SystemExit:
logger.error(f"Failed to push branch: {branch_name}")
return False
def _configure(self) -> bool:
"""
Configure repositories using existing configure.py pattern from release.py.
Returns:
bool: True if successful, False otherwise
"""
logger.info(f"Configuring and cloning repositories for branch: {self.base_branch}")
try:
# Get build_tools origin and construct branding URL from git host base
build_tools_origin = base.git_get_origin()
# Extract git host base (everything up to the host)
# For https://github.com/ORG/build_tools.git -> https://github.com/
# For git@github.com:ORG/build_tools.git -> git@github.com:
if '://' in build_tools_origin: # HTTPS
host_base = build_tools_origin.split('/', 3)[0] + '//' + build_tools_origin.split('/', 3)[2] + '/'
else: # SSH
host_base = build_tools_origin.split(':', 1)[0] + ':'
branding_url = host_base + self.branding_url
logger.info(f"Build tools origin: {build_tools_origin}")
logger.info(f"Git host base: {host_base}")
logger.info(f"Using branding URL: {branding_url}")
# Check platform and dependencies like in release.py
platform = base.host_platform()
if platform == "windows":
dependence.check_pythonPath()
dependence.check_gitPath()
# Run configure.py like in release.py
configure_args = [
'configure.py',
'--branding', self.branding,
'--branding-url', branding_url,
'--branch', self.base_branch,
'--module', self.modules,
'--update', '1',
'--clean', '0'
]
base.cmd_in_dir('../../', 'python', configure_args)
# Parse configuration like in release.py
config.parse()
# Update build_tools repository
base.git_update('build_tools')
# Update branding repository
base.git_update(self.branding)
# Correct defaults (the branding repo is already updated)
config.parse_defaults()
logger.info("Successfully configured")
return True
except Exception as e:
logger.error(f"Failed to configure and clone: {e}")
return False
def get_configured_repositories(self) -> Dict:
"""Get repositories using existing base.get_repositories() pattern from release.py."""
repositories = base.get_repositories()
repositories['core-ext'] = [True, False]
repositories['build_tools'] = [True, False]
repositories[self.branding] = [True, False]
return repositories
def _iterate_repositories(self, operation_func, operation_name: str) -> bool:
"""
Iterate over all repositories and apply the given operation function.
Args:
operation_func: Function to apply to each repository (takes repo_name and repo_path)
operation_name: Name of the operation for logging
Returns:
bool: True if at least one operation succeeded, False otherwise
"""
repositories = self.get_configured_repositories()
success_count = 0
total_count = len(repositories)
for repo_name in repositories:
current_dir = repositories[repo_name][1]
repo_path = f"../../../{repo_name}" if current_dir == False else current_dir
if base.is_dir(repo_path):
if operation_func(repo_name, repo_path):
success_count += 1
else:
logger.warning(f"✗ Failed to {operation_name} in {repo_name}")
else:
logger.warning(f"Repository {repo_name} not found at {repo_path}")
logger.info(f"{operation_name.capitalize()} completed in {success_count}/{total_count} repositories")
return success_count > 0
def delete_branch(self, branch_name: str, repo_dir: str = None, force: bool = False) -> bool:
"""
Delete a branch using base.cmd_in_dir.
Args:
branch_name: Name of the branch to delete
repo_dir: Repository directory (optional, uses current if not specified)
force: Whether to force delete the branch (default: False)
Returns:
bool: True if successful, False otherwise
"""
work_dir = repo_dir or self.work_dir
logger.info(f"Deleting branch '{branch_name}' in {work_dir}")
try:
# Switch to base branch first to avoid deleting current branch
base.cmd_in_dir(work_dir, "git", ["checkout", self.base_branch], True)
# Delete local branch
delete_flag = "-D" if force else "-d"
base.cmd_in_dir(work_dir, "git", ["branch", delete_flag, branch_name], True)
logger.info(f"Successfully deleted local branch: {branch_name}")
# Delete remote branch
try:
base.cmd_in_dir(work_dir, "git", ["push", "origin", "--delete", branch_name], True)
logger.info(f"Successfully deleted remote branch: {branch_name}")
except SystemExit:
logger.warning(f"Failed to delete remote branch: {branch_name} (may not exist)")
return True
except SystemExit:
logger.error(f"Failed to delete branch: {branch_name}")
return False
def create_branches(self) -> bool:
"""
Create a branch with the given name in all repositories.
Returns:
bool: True if successful, False otherwise
"""
logger.info(f"Creating branch '{self.branch_name}' in all repositories")
def create_and_push_branch(repo_name: str, repo_path: str) -> bool:
"""Create and push branch for a single repository."""
if self.create_branch(self.branch_name, repo_path):
logger.info(f"✓ Created branch '{self.branch_name}' in {repo_name}")
# Push the created branch
if self.push_branch(self.branch_name, repo_path):
logger.info(f"✓ Pushed branch '{self.branch_name}' in {repo_name}")
return True
else:
logger.warning(f"✗ Failed to push branch '{self.branch_name}' in {repo_name}")
return False
else:
logger.warning(f"✗ Failed to create branch '{self.branch_name}' in {repo_name}")
return False
try:
return self._iterate_repositories(create_and_push_branch, f"create and push branch '{self.branch_name}'")
except Exception as e:
logger.error(f"Failed to create branch in all repositories: {e}")
return False
def remove_branches(self, force: bool = False) -> bool:
"""
Remove a branch with the given name from all repositories.
Args:
force: Whether to force delete the branch (default: False)
Returns:
bool: True if successful, False otherwise
"""
logger.info(f"Removing branch '{self.branch_name}' from all repositories")
def delete_branch_operation(repo_name: str, repo_path: str) -> bool:
"""Delete branch for a single repository."""
if self.delete_branch(self.branch_name, repo_path, force):
logger.info(f"✓ Removed branch '{self.branch_name}' from {repo_name}")
return True
else:
logger.warning(f"✗ Failed to remove branch '{self.branch_name}' from {repo_name}")
return False
try:
return self._iterate_repositories(delete_branch_operation, f"remove branch '{self.branch_name}'")
except Exception as e:
logger.error(f"Failed to remove branch from all repositories: {e}")
return False
def main():
"""Main function to handle command line arguments."""
parser = argparse.ArgumentParser(description='Git Operations Tool - Create and Remove Branches')
subparsers = parser.add_subparsers(dest='command', help='Available commands')
# Create branch command (configure, clone and create branch in all repositories)
branch_parser = subparsers.add_parser('create', help='Configure, clone and create branch in all repositories')
branch_parser.add_argument('branch_name', help='Name of the branch to create')
branch_parser.add_argument('--base-branch', default='develop', help='Base branch to work from (default: develop)')
branch_parser.add_argument('--branding', default='onlyoffice', help='Branding name')
branch_parser.add_argument('--branding-url', default='ONLYOFFICE/onlyoffice.git', help='Relative path from git host base (default: ONLYOFFICE/onlyoffice.git)')
branch_parser.add_argument('--modules', default='core desktop builder server mobile', help='Modules to include')
# Remove branch command (configure, clone and remove branch from all repositories)
remove_parser = subparsers.add_parser('remove', help='Configure, clone and remove branch from all repositories')
remove_parser.add_argument('branch_name', help='Name of the branch to remove')
remove_parser.add_argument('--base-branch', default='develop', help='Base branch to work from (default: develop)')
remove_parser.add_argument('--branding', default='onlyoffice', help='Branding name')
remove_parser.add_argument('--branding-url', default='ONLYOFFICE/onlyoffice.git', help='Relative path from git host base (default: ONLYOFFICE/onlyoffice.git)')
remove_parser.add_argument('--modules', default='core desktop builder server mobile', help='Modules to include')
remove_parser.add_argument('--force', action='store_true', help='Force delete the branch (equivalent to git branch -D)')
args = parser.parse_args()
if not args.command:
parser.print_help()
return
git_ops = GitOperations(args.branding, args.base_branch, args.branding_url, args.branch_name, args.modules)
if args.command == 'create':
success = git_ops.create_branches()
sys.exit(0 if success else 1)
elif args.command == 'remove':
success = git_ops.remove_branches(args.force)
sys.exit(0 if success else 1)
if __name__ == '__main__':
main()

View File

@ -6,7 +6,6 @@ import base
import shutil
import optparse
import dependence
import config
arguments = sys.argv[1:]
@ -18,10 +17,6 @@ parser.add_option("--remove-path", action="append", type="string", dest="remove-
(options, args) = parser.parse_args(arguments)
configOptions = vars(options)
# parse configuration
config.parse()
config.parse_defaults()
for item in configOptions["uninstall"]:
dependence.uninstallProgram(item)
for item in configOptions["remove-path"]:

View File

@ -8,13 +8,6 @@ import dependence
import traceback
import develop
# if (sys.version_info[0] >= 3):
# unicode = str
# host_platform = base.host_platform()
# if (host_platform == 'windows'):
# import libwindows
base_dir = base.get_script_dir(__file__)
def install_module(path):
@ -28,18 +21,11 @@ def find_rabbitmqctl(base_path):
return base.find_file(os.path.join(base_path, 'RabbitMQ Server'), 'rabbitmqctl.bat')
def restart_win_rabbit():
# todo maybe restarting is not relevant after many years and versions?
base.print_info('restart RabbitMQ node to prevent "Erl.exe high CPU usage every Monday morning on Windows" https://groups.google.com/forum/#!topic/rabbitmq-users/myl74gsYyYg')
rabbitmqctl = find_rabbitmqctl(os.environ['PROGRAMW6432']) or find_rabbitmqctl(os.environ['ProgramFiles(x86)'])
if rabbitmqctl is not None:
try:
# code = libwindows.sudo(unicode(sys.executable), ['net', 'stop', 'rabbitmq'])
# code = libwindows.sudo(unicode(sys.executable), ['net', 'start', 'rabbitmq'])
base.cmd_in_dir(base.get_script_dir(rabbitmqctl), 'rabbitmqctl.bat', ['stop_app'])
base.cmd_in_dir(base.get_script_dir(rabbitmqctl), 'rabbitmqctl.bat', ['start_app'])
except SystemExit:
base.print_error('Perhaps Erlang cookies are different: Replace %userprofile%/.erlang.cookie with %WINDIR%/System32/config/systemprofile/.erlang.cookie')
raise
base.cmd_in_dir(base.get_script_dir(rabbitmqctl), 'rabbitmqctl.bat', ['stop_app'])
base.cmd_in_dir(base.get_script_dir(rabbitmqctl), 'rabbitmqctl.bat', ['start_app'])
else:
base.print_info('Missing rabbitmqctl.bat')

View File

@ -198,11 +198,6 @@
"editors-ios/Vendor/ThreadSafeMutable/ThreadSafeMutableDictionary.h",
"editors-ios/Vendor/ThreadSafeMutable/ThreadSafeMutableDictionary.m"
]
},
{
"dir": "editors-webview-ios",
"fileExtensions": [".swift", ".xcconfig"],
"licensePath": "header.license",
}
]
}

View File

@ -1,5 +1,5 @@
/*
* (c) Copyright Ascensio System SIA 2010-2025
* (c) Copyright Ascensio System SIA 2010-2024
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)

View File

@ -1,32 +0,0 @@
#!/usr/bin/env python
import sys
sys.path.append('../../build_tools/scripts')
import base
import os
args = sys.argv[1:]
if (1 > len(args)):
print("Please use min.py PATH_TO_SCRIPT.js")
exit(0)
script_path = args[0]
script_path = os.path.abspath(script_path)
script_dir = os.path.dirname(script_path)
script_name = os.path.splitext(os.path.basename(script_path))[0]
script_path_min = os.path.join(script_dir, script_name + ".min.js")
#compilation_level = "WHITESPACE_ONLY"
compilation_level = "SIMPLE_OPTIMIZATIONS"
base.cmd("java", ["-jar", "../../sdkjs/build/node_modules/google-closure-compiler-java/compiler.jar",
"--compilation_level", compilation_level,
"--js_output_file", script_path_min,
"--js", script_path])
dev_content = base.readFile(script_path)
license = dev_content[0:dev_content.find("*/")+2]
min_content = base.readFile(script_path_min)
base.delete_file(script_path_min)
base.writeFile(script_path_min, license + "\n\n" + min_content)

View File

@ -30,6 +30,23 @@ if utils.is_macos():
builder_product_name = "Document Builder"
if utils.is_linux():
builder_make_targets = [
{
"make": "tar",
"src": "tar/*.tar*",
"dst": "builder/linux/generic/"
},
{
"make": "deb",
"src": "deb/*.deb",
"dst": "builder/linux/debian/"
},
{
"make": "rpm",
"src": "rpm/build/RPMS/*/*.rpm",
"dst": "builder/linux/rhel/"
}
]
desktop_make_targets = [
{
"make": "tar",

View File

@ -15,9 +15,9 @@ def make():
if utils.is_windows():
make_windows()
elif utils.is_macos():
make_macos_linux()
make_macos()
elif utils.is_linux():
make_macos_linux()
make_linux()
return
def s3_upload(files, dst):
@ -74,14 +74,15 @@ def make_windows():
if common.clean:
utils.log_h2("builder clean")
utils.delete_dir("build")
utils.delete_dir("zip")
utils.delete_files("exe\\*.exe")
utils.delete_files("zip\\*.msi")
if make_prepare():
make_zip()
make_wheel()
make_inno()
else:
utils.set_summary("builder zip build", False)
utils.set_summary("builder python wheel build", False)
utils.set_summary("builder inno build", False)
utils.set_cwd(common.workspace_dir)
return
@ -117,22 +118,33 @@ def make_zip():
utils.set_summary("builder zip deploy", ret)
return
def make_macos_linux():
utils.set_cwd("document-builder-package")
def make_inno():
args = [
"-Version", package_version,
"-Arch", arch
]
if not branding.onlyoffice:
args += ["-Branding", common.branding]
if common.sign:
args += ["-Sign"]
make_tar()
make_wheel()
utils.log_h2("builder inno build")
ret = utils.ps1("make_inno.ps1", args, verbose=True)
utils.set_summary("builder inno build", ret)
utils.set_cwd(common.workspace_dir)
if common.deploy and ret:
utils.log_h2("builder inno deploy")
ret = s3_upload(utils.glob_path("exe/*.exe"), "builder/win/inno/")
utils.set_summary("builder inno deploy", ret)
return
def make_tar():
def make_macos():
utils.set_cwd("document-builder-package")
utils.log_h2("builder tar build")
make_args = ["tar"]
if common.platform == "darwin_arm64":
make_args += ["-e", "UNAME_M=arm64"]
if common.platform == "linux_aarch64":
make_args += ["-e", "UNAME_M=aarch64"]
if not branding.onlyoffice:
make_args += ["-e", "BRANDING_DIR=../" + common.branding + "/document-builder-package"]
ret = utils.sh("make clean && make " + " ".join(make_args), verbose=True)
@ -140,90 +152,29 @@ def make_tar():
if common.deploy:
utils.log_h2("builder tar deploy")
if utils.is_macos():
s3_dest = "builder/mac/generic/"
elif utils.is_linux():
s3_dest = "builder/linux/generic/"
ret = s3_upload(utils.glob_path("tar/*.tar.xz"), s3_dest)
ret = s3_upload(utils.glob_path("tar/*.tar.xz"), "builder/mac/generic/")
utils.set_summary("builder tar deploy", ret)
utils.set_cwd(common.workspace_dir)
return
def make_wheel():
platform_tags = {
"windows_x64": "win_amd64",
"windows_x86": "win32",
"darwin_arm64": "macosx_11_0_arm64",
"darwin_x86_64": "macosx_10_9_x86_64",
"linux_x86_64": "manylinux_2_23_x86_64",
"linux_aarch64": "manylinux_2_23_aarch64"
}
def make_linux():
utils.set_cwd("document-builder-package")
if not common.platform in platform_tags: return
utils.log_h2("builder build")
make_args = [t["make"] for t in branding.builder_make_targets]
if common.platform == "linux_aarch64":
make_args += ["-e", "UNAME_M=aarch64"]
if not branding.onlyoffice:
make_args += ["-e", "BRANDING_DIR=../" + common.branding + "/document-builder-package"]
ret = utils.sh("make clean && make " + " ".join(make_args), verbose=True)
utils.set_summary("builder build", ret)
utils.log_h2("builder python wheel build")
builder_dir = "build"
if utils.is_linux():
builder_dir = "build/opt/onlyoffice/documentbuilder"
utils.delete_dir("python")
utils.copy_dir("../onlyoffice/build_tools/packaging/docbuilder/resources", "python")
utils.copy_dir(builder_dir, "python/docbuilder/lib")
desktop_dir = "../desktop-apps/macos/build/ONLYOFFICE.app/Contents/Resources/converter"
if utils.is_macos() and "desktop" in common.targets and utils.is_exist(desktop_dir):
for f in utils.glob_path(desktop_dir + "/*.dylib") + [desktop_dir + "/x2t"]:
utils.copy_file(f, builder_dir + "/" + utils.get_basename(f))
old_cwd = utils.get_cwd()
utils.set_cwd("python/docbuilder")
if not utils.is_file("docbuilder.py"):
utils.copy_file("lib/docbuilder.py", "docbuilder.py")
# fix docbuilder.py
content = ""
with open("docbuilder.py", "r") as file:
content = file.read()
old_line = "builder_path = os.path.dirname(os.path.realpath(__file__))"
new_line = "builder_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), \"lib\")"
content = content.replace(old_line, new_line)
with open("docbuilder.py", "w") as file:
file.write(content)
# remove unnecessary files
utils.set_cwd("lib")
utils.delete_dir("include")
utils.delete_file("build.date")
utils.delete_file("docbuilder.jar")
utils.delete_file("docbuilder.py")
if utils.is_windows():
utils.delete_file("doctrenderer.lib")
utils.delete_file("docbuilder.com.dll")
utils.delete_file("docbuilder.net.dll")
utils.delete_file("docbuilder.jni.dll")
elif utils.is_macos():
utils.delete_file("libdocbuilder.jni.dylib")
elif utils.is_linux():
utils.delete_file("libdocbuilder.jni.so")
utils.set_env("DOCBUILDER_VERSION", common.version + "." + common.build)
platform = "linux_64"
utils.set_cwd("../..")
plat_name = platform_tags[common.platform]
ret = utils.sh("python setup.py bdist_wheel --plat-name " + plat_name + " --python-tag py2.py3", verbose=True)
utils.set_summary("builder python wheel build", ret)
if common.deploy and ret:
utils.log_h2("builder python wheel deploy")
if utils.is_windows():
s3_dest = "builder/win/python/"
elif utils.is_macos():
s3_dest = "builder/mac/python/"
elif utils.is_linux():
s3_dest = "builder/linux/python/"
ret = s3_upload(utils.glob_path("dist/*.whl"), s3_dest)
utils.set_summary("builder python wheel deploy", ret)
utils.set_cwd(old_cwd)
if common.deploy:
for t in branding.builder_make_targets:
utils.log_h2("builder " + t["make"] + " deploy")
ret = s3_upload(utils.glob_path(t["src"]), t["dst"])
utils.set_summary("builder " + t["make"] + " deploy", ret)
utils.set_cwd(common.workspace_dir)
return

View File

@ -35,7 +35,7 @@ def s3_upload(files, dst):
#
def make_windows():
global package_name, package_version, arch, xp
global package_name, package_version, arch, xp, suffix
utils.set_cwd("desktop-apps\\win-linux\\package\\windows")
package_name = branding.desktop_package_name
@ -47,6 +47,7 @@ def make_windows():
"windows_x86_xp": "x86"
}[common.platform]
xp = common.platform.endswith("_xp")
suffix = arch + ("-xp" if xp else "")
if common.clean:
utils.log_h2("desktop clean")
@ -58,112 +59,135 @@ def make_windows():
utils.delete_files("*.zip")
utils.delete_files("data\\*.exe")
if not xp:
make_prepare()
make_zip()
make_inno()
if branding.onlyoffice:
make_inno("standalone")
make_inno("update")
make_advinst()
make_prepare("commercial")
make_zip("commercial")
make_inno("commercial")
make_advinst("commercial")
else:
make_prepare("xp")
make_zip("xp")
make_inno("xp")
make_prepare()
make_zip()
make_inno()
make_advinst()
make_online()
utils.set_cwd(common.workspace_dir)
return
def make_prepare(edition = "opensource"):
def make_prepare():
args = [
"-Version", package_version,
"-Arch", arch,
"-Target", edition
"-Arch", arch
]
if xp:
args += ["-Target", "xp"]
if common.sign:
args += ["-Sign"]
utils.log_h2("desktop prepare " + edition)
utils.log_h2("desktop prepare")
ret = utils.ps1("make.ps1", args, verbose=True)
utils.set_summary("desktop prepare " + edition, ret)
utils.set_summary("desktop prepare", ret)
return
def make_zip(edition = "opensource"):
if edition == "commercial": zip_file = "%s-Enterprise-%s-%s.zip"
elif edition == "xp": zip_file = "%s-XP-%s-%s.zip"
else: zip_file = "%s-%s-%s.zip"
zip_file = zip_file % (package_name, package_version, arch)
def make_zip():
zip_file = "%s-%s-%s.zip" % (package_name, package_version, suffix)
args = [
"-Version", package_version,
"-Arch", arch,
"-Target", edition
"-Arch", arch
]
if xp:
args += ["-Target", "xp"]
# if common.sign:
# args += ["-Sign"]
utils.log_h2("desktop zip " + edition + " build")
utils.log_h2("desktop zip build")
ret = utils.ps1("make_zip.ps1", args, verbose=True)
utils.set_summary("desktop zip " + edition + " build", ret)
utils.set_summary("desktop zip build", ret)
if common.deploy and ret:
utils.log_h2("desktop zip " + edition + " deploy")
utils.log_h2("desktop zip deploy")
ret = s3_upload([zip_file], "desktop/win/generic/")
utils.set_summary("desktop zip " + edition + " deploy", ret)
utils.set_summary("desktop zip deploy", ret)
return
def make_inno(edition = "opensource"):
if edition == "commercial": inno_file = "%s-Enterprise-%s-%s.exe"
elif edition == "standalone": inno_file = "%s-Standalone-%s-%s.exe"
elif edition == "update": inno_file = "%s-Update-%s-%s.exe"
elif edition == "xp": inno_file = "%s-XP-%s-%s.exe"
else: inno_file = "%s-%s-%s.exe"
inno_file = inno_file % (package_name, package_version, arch)
def make_inno():
inno_file = "%s-%s-%s.exe" % (package_name, package_version, suffix)
inno_sa_file = "%s-Standalone-%s-%s.exe" % (package_name, package_version, suffix)
inno_update_file = "%s-Update-%s-%s.exe" % (package_name, package_version, suffix)
update_wrapper = not (hasattr(branding, 'desktop_updates_skip_iss_wrapper') and branding.desktop_updates_skip_iss_wrapper)
args = [
"-Version", package_version,
"-Arch", arch,
"-Target", edition
"-Arch", arch
]
if common.sign:
args += ["-Sign"]
utils.log_h2("desktop inno build")
if xp:
args += ["-TimestampServer", "http://timestamp.comodoca.com/authenticode"]
ret = utils.ps1("make_inno.ps1", args + ["-Target", "xp"], verbose=True)
else:
ret = utils.ps1("make_inno.ps1", args, verbose=True)
utils.set_summary("desktop inno build", ret)
utils.log_h2("desktop inno " + edition + " build")
ret = utils.ps1("make_inno.ps1", args, verbose=True)
utils.set_summary("desktop inno " + edition + " build", ret)
if branding.onlyoffice and not xp:
utils.log_h2("desktop inno standalone")
ret = utils.ps1("make_inno.ps1", args + ["-Target", "standalone"], verbose=True)
utils.set_summary("desktop inno standalone build", ret)
if common.deploy and ret:
utils.log_h2("desktop inno " + edition + " deploy")
if update_wrapper:
utils.log_h2("desktop inno update build")
if xp:
ret = utils.ps1("make_inno.ps1", args + ["-Target", "xp_update"], verbose=True)
else:
ret = utils.ps1("make_inno.ps1", args + ["-Target", "update"], verbose=True)
utils.set_summary("desktop inno update build", ret)
if common.deploy:
utils.log_h2("desktop inno deploy")
ret = s3_upload([inno_file], "desktop/win/inno/")
utils.set_summary("desktop inno " + edition + " deploy", ret)
utils.set_summary("desktop inno deploy", ret)
if branding.onlyoffice and not xp:
utils.log_h2("desktop inno standalone deploy")
ret = s3_upload([inno_sa_file], "desktop/win/inno/")
utils.set_summary("desktop inno standalone deploy", ret)
utils.log_h2("desktop inno update deploy")
if utils.is_file(inno_update_file):
ret = s3_upload([inno_update_file], "desktop/win/inno/")
elif utils.is_file(inno_file):
ret = s3_upload([inno_file], "desktop/win/inno/" + inno_update_file)
else:
ret = False
utils.set_summary("desktop inno update deploy", ret)
return
def make_advinst(edition = "opensource"):
if edition == "commercial": advinst_file = "%s-Enterprise-%s-%s.msi"
else: advinst_file = "%s-%s-%s.msi"
advinst_file = advinst_file % (package_name, package_version, arch)
def make_advinst():
if not common.platform in ["windows_x64", "windows_x86"]:
return
advinst_file = "%s-%s-%s.msi" % (package_name, package_version, suffix)
args = [
"-Version", package_version,
"-Arch", arch,
"-Target", edition
"-Arch", arch
]
if common.sign:
args += ["-Sign"]
utils.log_h2("desktop advinst " + edition + " build")
utils.log_h2("desktop advinst build")
ret = utils.ps1("make_advinst.ps1", args, verbose=True)
utils.set_summary("desktop advinst " + edition + " build", ret)
utils.set_summary("desktop advinst build", ret)
if common.deploy and ret:
utils.log_h2("desktop advinst " + edition + " deploy")
utils.log_h2("desktop advinst deploy")
ret = s3_upload([advinst_file], "desktop/win/advinst/")
utils.set_summary("desktop advinst " + edition + " deploy", ret)
utils.set_summary("desktop advinst deploy", ret)
return
def make_online():
if not common.platform in ["windows_x64", "windows_x86"]:
return
online_file = "%s-%s-%s.exe" % ("OnlineInstaller", package_version, suffix)
ret = utils.is_file(online_file)
utils.set_summary("desktop online installer build", ret)
if common.deploy and ret:
utils.log_h2("desktop online installer deploy")
ret = s3_upload([online_file], "desktop/win/online/")
utils.set_summary("desktop online installer deploy", ret)
return
#
@ -172,7 +196,7 @@ def make_advinst(edition = "opensource"):
def make_macos():
global package_name, build_dir, branding_dir, updates_dir, changes_dir, \
suffix, lane, scheme, source_dir, released_updates_dir
suffix, lane, scheme, released_updates_dir
package_name = branding.desktop_package_name
build_dir = branding.desktop_build_dir
branding_dir = branding.desktop_branding_dir
@ -237,34 +261,32 @@ def make_macos():
dmg = make_dmg()
if dmg and sparkle_updates:
make_sparkle_updates()
if common.platform != "darwin_x86_64_v8":
make_dmg("commercial")
utils.set_cwd(common.workspace_dir)
return
def make_dmg(target = "opensource"):
utils.log_h2("desktop dmg " + target + " build")
def make_dmg():
utils.log_h2("desktop dmg build")
utils.log_h3(scheme)
utils.log_h3("build/" + package_name + ".app")
args = ["bundler", "exec", "fastlane", lane, "skip_git_bump:true"]
if target == "commercial":
args += ["edition:Enterprise"]
dmg = utils.sh(" ".join(args), verbose=True)
utils.set_summary("desktop dmg " + target + " build", dmg)
dmg = utils.sh(
"bundler exec fastlane " + lane + " skip_git_bump:true",
verbose=True
)
utils.set_summary("desktop dmg build", dmg)
if common.deploy and dmg:
utils.log_h2("desktop dmg " + target + " deploy")
utils.log_h2("desktop dmg deploy")
ret = s3_upload(
utils.glob_path("build/*.dmg"),
"desktop/mac/%s/%s/%s/" % (suffix, common.version, common.build))
utils.set_summary("desktop dmg deploy", ret)
if common.deploy and dmg and target != "commercial":
utils.log_h2("desktop zip " + target + " deploy")
utils.log_h2("desktop zip deploy")
ret = s3_upload(
["build/%s-%s.zip" % (scheme, common.version)],
"desktop/mac/%s/%s/%s/" % (suffix, common.version, common.build))
utils.set_summary("desktop zip " + target + " deploy", ret)
utils.set_summary("desktop zip deploy", ret)
return dmg
def make_sparkle_updates():
@ -314,23 +336,20 @@ def make_sparkle_updates():
def make_linux():
utils.set_cwd("desktop-apps/win-linux/package/linux")
for edition in ["opensource", "commercial"]:
utils.log_h2("desktop " + edition + " build")
make_args = [t["make"] for t in branding.desktop_make_targets]
if edition == "commercial":
make_args += ["-e", "PACKAGE_EDITION=commercial"]
if common.platform == "linux_aarch64":
make_args += ["-e", "UNAME_M=aarch64"]
if not branding.onlyoffice:
make_args += ["-e", "BRANDING_DIR=../../../../" + common.branding + "/desktop-apps/win-linux/package/linux"]
ret = utils.sh("make clean && make " + " ".join(make_args), verbose=True)
utils.set_summary("desktop " + edition + " build", ret)
utils.log_h2("desktop build")
make_args = [t["make"] for t in branding.desktop_make_targets]
if common.platform == "linux_aarch64":
make_args += ["-e", "UNAME_M=aarch64"]
if not branding.onlyoffice:
make_args += ["-e", "BRANDING_DIR=../../../../" + common.branding + "/desktop-apps/win-linux/package/linux"]
ret = utils.sh("make clean && make " + " ".join(make_args), verbose=True)
utils.set_summary("desktop build", ret)
if common.deploy:
for t in branding.desktop_make_targets:
utils.log_h2("desktop " + edition + " " + t["make"] + " deploy")
ret = s3_upload(utils.glob_path(t["src"]), t["dst"])
utils.set_summary("desktop " + edition + " " + t["make"] + " deploy", ret)
if common.deploy:
for t in branding.desktop_make_targets:
utils.log_h2("desktop " + t["make"] + " deploy")
ret = s3_upload(utils.glob_path(t["src"]), t["dst"])
utils.set_summary("desktop " + t["make"] + " deploy", ret)
utils.set_cwd(common.workspace_dir)
return

View File

@ -25,7 +25,7 @@ def get_j_num():
def check_support_platform(platform):
qt_dir = base.qt_setup(platform)
if not base.is_file(qt_dir + "/bin/qmake") and not base.is_file(qt_dir + "/bin/qmake.exe") and not base.is_file(qt_dir + "/bin/qmake.bat"):
if not base.is_file(qt_dir + "/bin/qmake") and not base.is_file(qt_dir + "/bin/qmake.exe"):
return False
return True
@ -91,21 +91,12 @@ def make(platform, project, qmake_config_addon="", is_no_errors=False):
build_params = ["-nocache", file_pro] + base.qt_config_as_param(config_param) + qmake_addon
qmake_app = qt_dir + "/bin/qmake"
# non windows platform
if not base.is_windows():
if base.is_file(qt_dir + "/onlyoffice_qt.conf"):
build_params.append("-qtconf")
build_params.append(qt_dir + "/onlyoffice_qt.conf")
if "1" == config.option("use-clang"):
build_params.append("-spec")
build_params.append("linux-clang-libc++")
if "" != config.option("sysroot"):
base.set_sysroot_env()
base.cmd_exe(qmake_app, build_params) # calls cmd_exe to pass os.env
else:
base.cmd(qmake_app, build_params)
base.cmd(qmake_app, build_params)
base.correct_makefile_after_qmake(platform, makefile)
if ("1" == config.option("clean")):
base.cmd_and_return_cwd("make", clean_params, True)
@ -122,22 +113,12 @@ def make(platform, project, qmake_config_addon="", is_no_errors=False):
if ("" != qmake_addon_string):
qmake_addon_string = " " + qmake_addon_string
vcvarsall_arch = "x64"
if base.platform_is_32(platform):
vcvarsall_arch = "x86"
if (platform == "win_arm64"):
vcvarsall_arch = "x64_arm64"
qmake_env_addon = base.get_env("QT_QMAKE_ADDON")
if (qmake_env_addon != ""):
qmake_env_addon += " "
qmake_bat = []
qmake_bat.append("call \"" + config.option("vs-path") + "/vcvarsall.bat\" " + vcvarsall_arch)
qmake_bat.append("call \"" + config.option("vs-path") + "/vcvarsall.bat\" " + ("x86" if base.platform_is_32(platform) else "x64"))
qmake_addon_string = ""
if ("" != config.option("qmake_addon")):
qmake_addon_string = " " + (" ").join(["\"" + addon + "\"" for addon in qmake_addon])
qmake_bat.append("call \"" + qmake_app + "\" -nocache " + qmake_env_addon + file_pro + config_params_string + qmake_addon_string)
qmake_bat.append("call \"" + qmake_app + "\" -nocache " + file_pro + config_params_string + qmake_addon_string)
if ("1" == config.option("clean")):
qmake_bat.append("call nmake " + " ".join(clean_params))
qmake_bat.append("call nmake " + " ".join(distclean_params))

View File

@ -13,7 +13,7 @@ def writeFile(path, content):
if (os.path.isfile(path)):
os.remove(path)
with open(path, "w", encoding='utf-8') as file:
with open(path, "w") as file:
file.write(content)
return
@ -160,12 +160,6 @@ class EditorApi(object):
editors_support = decoration[index_type_editors:index_type_editors_end]
if -1 == editors_support.find(self.type):
return
decoration = "\n".join(
line for line in decoration.splitlines()
if "@typeofeditors" not in line and "@see" not in line
)
# optimizations for first file
if 0 == self.numfile:
self.records.append(decoration + "\n" + code + "\n")
@ -214,7 +208,7 @@ if __name__ == "__main__":
type=str,
help="Destination directory for the generated documentation",
nargs='?', # Indicates the argument is optional
default="../../../web-apps/vendor/monaco/libs/" # Default value
default="../../../onlyoffice.github.io\sdkjs-plugins\content\macros\libs/" # Default value
)
args = parser.parse_args()
@ -223,7 +217,7 @@ if __name__ == "__main__":
if True == os.path.isdir(args.destination):
shutil.rmtree(args.destination, ignore_errors=True)
os.mkdir(args.destination)
convert_to_interface(["word/apiBuilder.js", "../sdkjs-forms/apiBuilder.js"], "word")
convert_to_interface(["word/apiBuilder.js"], "word")
convert_to_interface(["word/apiBuilder.js", "slide/apiBuilder.js"], "slide")
convert_to_interface(["word/apiBuilder.js", "slide/apiBuilder.js", "cell/apiBuilder.js"], "cell")
os.chdir(old_cur)

View File

@ -1,14 +1,7 @@
# Documentation Generation Guide
This guide explains how to generate documentation for Onlyoffice Builder
and Plugins (Methods/Events) API using the following Python scripts:
- `office-api/generate_docs_json.py`
- `office-api/generate_docs_md.py`
- `plugins/generate_docs_methods_json.py`
- `plugins/generate_docs_methods_md.py`
- `plugins/generate_docs_events_json.py`
- `plugins/generate_docs_events_md.py`
This guide explains how to generate documentation for Onlyoffice Builder/Plugins API using the provided Python scripts: `generate_docs_json.py`, `generate_docs_plugins_json.py`, `generate_docs_md.py`. These scripts are used to create JSON and Markdown documentation for the `apiBuilder.js` files from the word, cell, and slide editors.
## Requirements
@ -27,112 +20,61 @@ npm install
## Scripts Overview
### `office-api/generate_docs_json.py`
### `generate_docs_json.py`
This script generates JSON documentation based on the `apiBuilder.js` files.
- **Usage**:
```bash
python generate_docs_json.py output_path
```
- **Parameters**:
- `output_path` (optional): The directory where the JSON documentation
will be saved. If not specified, the default path is
`../../../../office-js-api-declarations/office-js-api`.
- `output_path` (optional): The directory where the JSON documentation will be saved. If not specified, the default path is `../../../../office-js-api-declarations/office-js-api`.
### `office-api/generate_docs_md.py`
### `generate_docs_plugins_json.py`
This script generates JSON documentation based on the `api_plugins.js` files.
- **Usage**:
```bash
python generate_docs_plugins_json.py output_path
```
- **Parameters**:
- `output_path` (optional): The directory where the JSON documentation will be saved. If not specified, the default path is `../../../../office-js-api-declarations/office-js-api-plugins`.
### `generate_docs_md.py`
This script generates Markdown documentation from the `apiBuilder.js` files.
- **Usage**:
```bash
python generate_docs_md.py output_path
```
- **Parameters**:
- `output_path` (optional): The directory where the Markdown documentation
will be saved. If not specified, the default path is
`../../../../office-js-api/`.
### `plugins/generate_docs_methods_json.py`
This script generates JSON documentation based on the `api_plugins.js` files.
- **Usage**:
```bash
python generate_docs_methods_json.py output_path
```
- **Parameters**:
- `output_path` (optional): The directory where the JSON documentation
will be saved. If not specified, the default path is
`../../../../office-js-api-declarations/office-js-api-plugins`.
### `plugins/generate_docs_events_json.py`
This script generates JSON documentation based on the `plugin-events.js` files.
- **Usage**:
```bash
python generate_docs_events_json.py output_path
```
- **Parameters**:
- `output_path` (optional): The directory where the JSON documentation
will be saved. If not specified, the default path is
`../../../../office-js-api-declarations/office-js-api-plugins`.
### `plugins/generate_docs_methods_md.py`
This script generates Markdown documentation from the `api_plugins.js` files.
- **Usage**:
```bash
python generate_docs_methods_md.py output_path
```
- **Parameters**:
- `output_path` (optional): The directory where the Markdown documentation
will be saved. If not specified, the default path is
`../../../../office-js-api/`.
### `plugins/generate_docs_events_md.py`
This script generates Markdown documentation from the `plugin-events.js` files.
- **Usage**:
```bash
python generate_docs_events_md.py output_path
```
- **Parameters**:
- `output_path` (optional): The directory where the Markdown documentation
will be saved. If not specified, the default path is
`../../../../office-js-api/`.
- `output_path` (optional): The directory where the Markdown documentation will be saved. If not specified, the default path is `../../../../office-js-api/`.
## Example
To generate JSON documentation with the default output path:
```bash
python generate_docs_json.py /path/to/save/json
```
To generate Markdown documentation and specify a custom output path:
To generate JSON documentation with the default output path:
```bash
python generate_docs_plugins_json.py /path/to/save/json
```
To generate Markdown documentation and specify a custom output path:
```bash
python generate_docs_md.py /path/to/save/markdown
```
## Notes
- Make sure to have all necessary permissions to run these scripts and write
to the specified directories.
- Make sure to have all necessary permissions to run these scripts and write to the specified directories.
- The output directories will be created if they do not exist.

View File

@ -0,0 +1,16 @@
{
"source": {
"include": ["../../../../sdkjs/word/apiBuilder.js", "../../../../sdkjs/slide/apiBuilder.js", "../../../../sdkjs/cell/apiBuilder.js"]
},
"plugins": ["./correct_doclets.js"],
"opts": {
"destination": "./out",
"recurse": true,
"encoding": "utf8"
},
"templates": {
"json": {
"pretty": true
}
}
}

View File

@ -82,11 +82,6 @@ exports.handlers = {
doclet.longname = cleanName(doclet.longname);
doclet.name = cleanName(doclet.name);
// skip inherited methods if ovveriden in child class
if (doclet.inherited && filteredDoclets.find((addedDoclet) => addedDoclet['name'] == doclet['name'] && addedDoclet['memberof'] == doclet['memberof'])) {
continue;
}
const filteredDoclet = {
comment: doclet.comment,
description: doclet.description,

View File

@ -1,6 +1,6 @@
{
"source": {
"include": ["../../../../../sdkjs/word/apiBuilder.js", "../../../../../sdkjs-forms/apiBuilder.js"]
"include": ["../../../../sdkjs/word/apiBuilder.js", "../../../../sdkjs-forms/apiBuilder.js"]
},
"plugins": ["./correct_doclets.js"],
"opts": {

View File

@ -1,6 +1,6 @@
{
"source": {
"include": ["../../../../../sdkjs/word/apiBuilder.js", "../../../../../sdkjs/slide/apiBuilder.js"]
"include": ["../../../../sdkjs/word/apiBuilder.js", "../../../../sdkjs/slide/apiBuilder.js"]
},
"plugins": ["./correct_doclets.js"],
"opts": {

View File

@ -1,6 +1,6 @@
{
"source": {
"include": ["../../../../../sdkjs/pdf/apiBuilder.js"]
"include": ["../../../../sdkjs/word/apiBuilder.js"]
},
"plugins": ["./correct_doclets.js"],
"opts": {

View File

@ -0,0 +1,16 @@
{
"source": {
"include": ["../../../../sdkjs/cell/api_plugins.js"]
},
"plugins": ["./correct_doclets.js"],
"opts": {
"destination": "./out",
"recurse": true,
"encoding": "utf8"
},
"templates": {
"json": {
"pretty": true
}
}
}

View File

@ -0,0 +1,16 @@
{
"source": {
"include": ["../../../../sdkjs/common/plugins/plugin_base_api.js" ,"../../../../sdkjs/common/apiBase_plugins.js"]
},
"plugins": ["./correct_doclets.js"],
"opts": {
"destination": "./out",
"recurse": true,
"encoding": "utf8"
},
"templates": {
"json": {
"pretty": true
}
}
}

View File

@ -1,6 +1,6 @@
{
"source": {
"include": ["../../../../../sdkjs/word/apiBuilder.js"]
"include": ["../../../../sdkjs-forms/apiPlugins.js"]
},
"plugins": ["./correct_doclets.js"],
"opts": {

View File

@ -0,0 +1,16 @@
{
"source": {
"include": ["../../../../sdkjs/slide/api_plugins.js"]
},
"plugins": ["./correct_doclets.js"],
"opts": {
"destination": "./out",
"recurse": true,
"encoding": "utf8"
},
"templates": {
"json": {
"pretty": true
}
}
}

View File

@ -0,0 +1,16 @@
{
"source": {
"include": ["../../../../sdkjs/word/api_plugins.js", "../../../../sdkjs-forms/apiPlugins.js"]
},
"plugins": ["./correct_doclets.js"],
"opts": {
"destination": "./out",
"recurse": true,
"encoding": "utf8"
},
"templates": {
"json": {
"pretty": true
}
}
}

View File

@ -5,14 +5,14 @@ import argparse
import re
import platform
root = '../../../../..'
root = '../../../..'
# Configuration files
configs = [
"./config/word.json",
"./config/cell.json",
"./config/slide.json",
"./config/forms.json"
"./config/builder/word.json",
"./config/builder/cell.json",
"./config/builder/slide.json",
"./config/builder/forms.json"
]
editors_maps = {

View File

@ -0,0 +1,399 @@
import os
import json
import re
import shutil
import argparse
import generate_docs_json
# Configuration files
editors = [
"word",
"cell",
"slide",
"forms"
]
missing_examples = []
def load_json(file_path):
with open(file_path, 'r', encoding='utf-8') as f:
return json.load(f)
def write_markdown_file(file_path, content):
with open(file_path, 'w', encoding='utf-8') as md_file:
md_file.write(content)
def remove_js_comments(text):
text = re.sub(r'^\s*//.*$', '', text, flags=re.MULTILINE) # single-line
text = re.sub(r'/\*.*?\*/', '', text, flags=re.DOTALL) # multi-line
return text.strip()
def correct_description(string):
"""
Cleans up or transforms certain tags in a doclet description:
- <b> => **
- <note>...</note> => 💡 ...
- Provide a default if None.
"""
if string is None:
return 'No description provided.'
# Replace <b> tags with markdown bold
string = re.sub(r'<b>', '**', string)
string = re.sub(r'</b>', '**', string)
# Convert <note>...</note> to a little icon + text
string = re.sub(r'<note>(.*?)</note>', r'💡 \1', string, flags=re.DOTALL)
return string
def correct_default_value(value, enumerations, classes):
if value is None:
return ''
if value == True:
value = "true"
elif value == False:
value = "false"
else:
value = str(value)
return generate_data_types_markdown([value], enumerations, classes)
def remove_line_breaks(string):
return re.sub(r'[\r\n]+', ' ', string)
# Convert Array.<T> => T[] (including nested arrays).
def convert_jsdoc_array_to_ts(type_str: str) -> str:
"""
Recursively replaces 'Array.<T>' with 'T[]',
handling nested arrays like 'Array.<Array.<string>>' => 'string[][]'.
"""
pattern = re.compile(r'Array\.<([^>]+)>')
while True:
match = pattern.search(type_str)
if not match:
break
inner_type = match.group(1).strip()
# Recursively convert inner parts
inner_type = convert_jsdoc_array_to_ts(inner_type)
# Replace the outer Array.<...> with ...[]
type_str = (
type_str[:match.start()]
+ f"{inner_type}[]"
+ type_str[match.end():]
)
return type_str
def escape_text_outside_code_blocks(markdown: str) -> str:
"""
Splits content by fenced code blocks, escapes MDX-unsafe characters
(<, >, {, }) only in the text outside those code blocks.
"""
# A regex to capture fenced code blocks with ```
parts = re.split(r'(```.*?```)', markdown, flags=re.DOTALL)
# Even indices (0, 2, 4, ...) are outside code blocks,
# odd indices (1, 3, 5, ...) are actual code blocks.
for i in range(0, len(parts), 2):
# Only escape in parts outside code blocks
parts[i] = (parts[i]
.replace('<', '&lt;')
.replace('>', '&gt;')
.replace('{', '&#123;')
.replace('}', '&#125;')
)
return "".join(parts)
def get_base_type(ts_type: str) -> str:
"""
Given a TypeScript-like type (e.g. "Drawing[][]"), return the
'base' portion by stripping trailing "[]". For "Drawing[][]",
returns "Drawing". For "Array.<Drawing>", you'd convert it first
to "Drawing[]" then return "Drawing".
"""
while ts_type.endswith('[]'):
ts_type = ts_type[:-2]
return ts_type
def generate_data_types_markdown(types, enumerations, classes, root='../../'):
"""
1) Convert each raw JSDoc type from Array.<T> to T[].
2) Split union types if needed (usually they're provided as separate
elements in 'types' already, but let's be safe).
3) For each type, extract the base type (e.g. "Drawing" from "Drawing[]").
4) If the base type matches an enumeration or class, link the entire
T[]-based string.
5) Join with " | ".
"""
# Convert each raw type from JSDoc to TS
converted = [convert_jsdoc_array_to_ts(t) for t in types] # e.g. ["Drawing[]", "Foo[]", ...]
# For each converted type (like "Drawing[]"), see if the base is in enumerations or classes
def link_if_known(ts_type):
base = get_base_type(ts_type) # e.g. "Drawing" from "Drawing[]"
# Check enumerations first
for enum in enumerations:
if enum['name'] == base:
# Replace the entire token with a link
return f"[{ts_type}]({root}Enumeration/{base}.md)"
# Check classes
if base in classes:
return f"[{ts_type}]({root}{base}/{base}.md)"
# Otherwise just return as-is
return ts_type
# Build final list of possibly-linked types
linked = [link_if_known(ts_t) for ts_t in converted]
# Join them with " | "
param_types_md = ' | '.join(linked)
# If there's still leftover angle brackets for generics, gently escape or link them
# e.g. "Object.<string, number>" => "Object.&lt;string, number&gt;"
# or do more specialized linking if you want to handle them deeper.
def replace_leftover_generics(match):
element = match.group(1).strip()
return f"&lt;{element}&gt;"
param_types_md = re.sub(r'<([^<>]+)>', replace_leftover_generics, param_types_md)
return param_types_md
def generate_class_markdown(class_name, methods, properties, enumerations, classes):
content = f"# {class_name}\n\nRepresents the {class_name} class.\n\n"
content += generate_properties_markdown(properties, enumerations, classes)
content += "## Methods\n\n"
for method in methods:
method_name = method['name']
content += f"- [{method_name}](./Methods/{method_name}.md)\n"
# Escape just before returning
return escape_text_outside_code_blocks(content)
def generate_method_markdown(method, enumerations, classes):
method_name = method['name']
description = method.get('description', 'No description provided.')
description = correct_description(description)
params = method.get('params', [])
returns = method.get('returns', [])
example = method.get('example', '')
memberof = method.get('memberof', '')
content = f"# {method_name}\n\n{description}\n\n"
# Syntax
param_list = ', '.join([param['name'] for param in params]) if params else ''
content += f"## Syntax\n\n```javascript\nexpression.{method_name}({param_list});\n```\n\n"
if memberof:
content += f"`expression` - A variable that represents a [{memberof}](../{memberof}.md) class.\n\n"
# Parameters
content += "## Parameters\n\n"
if params:
content += "| **Name** | **Required/Optional** | **Data type** | **Default** | **Description** |\n"
content += "| ------------- | ------------- | ------------- | ------------- | ------------- |\n"
for param in params:
param_name = param.get('name', 'Unnamed')
param_types = param.get('type', {}).get('names', []) if param.get('type') else []
param_types_md = generate_data_types_markdown(param_types, enumerations, classes)
param_desc = remove_line_breaks(correct_description(param.get('description', 'No description provided.')))
param_required = "Required" if not param.get('optional') else "Optional"
param_default = correct_default_value(param.get('defaultvalue', ''), enumerations, classes)
content += f"| {param_name} | {param_required} | {param_types_md} | {param_default} | {param_desc} |\n"
else:
content += "This method doesn't have any parameters.\n"
# Returns
content += "\n## Returns\n\n"
if returns:
return_type_list = returns[0].get('type', {}).get('names', [])
return_type_md = generate_data_types_markdown(return_type_list, enumerations, classes)
content += return_type_md
else:
content += "This method doesn't return any data."
# Example
if example:
# Separate comment and code, remove JS comments
if '```js' in example:
comment, code = example.split('```js', 1)
comment = remove_js_comments(comment)
content += f"\n\n## Example\n\n{comment}\n\n```javascript\n{code.strip()}\n"
else:
# If there's no triple-backtick structure, just show it as code
cleaned_example = remove_js_comments(example)
content += f"\n\n## Example\n\n```javascript\n{cleaned_example}\n```\n"
return escape_text_outside_code_blocks(content)
def generate_properties_markdown(properties, enumerations, classes, root='../'):
if properties is None:
return ''
content = "## Properties\n\n"
content += "| Name | Type | Description |\n"
content += "| ---- | ---- | ----------- |\n"
for prop in properties:
prop_name = prop['name']
prop_description = prop.get('description', 'No description provided.')
prop_description = remove_line_breaks(correct_description(prop_description))
prop_types = prop['type']['names'] if prop.get('type') else []
param_types_md = generate_data_types_markdown(prop_types, enumerations, classes, root)
content += f"| {prop_name} | {param_types_md} | {prop_description} |\n"
# Escape outside code blocks
return escape_text_outside_code_blocks(content)
def generate_enumeration_markdown(enumeration, enumerations, classes):
enum_name = enumeration['name']
description = enumeration.get('description', 'No description provided.')
description = correct_description(description)
example = enumeration.get('example', '')
content = f"# {enum_name}\n\n{description}\n\n"
ptype = enumeration['type']['parsedType']
if ptype['type'] == 'TypeUnion':
enum_empty = True # is empty enum
content += "## Type\n\nEnumeration\n\n"
content += "## Values\n\n"
# Each top-level name in the union
for raw_t in enumeration['type']['names']:
ts_t = convert_jsdoc_array_to_ts(raw_t)
# Attempt linking: we compare the raw type to enumerations/classes
if any(enum['name'] == raw_t for enum in enumerations):
content += f"- [{ts_t}](../Enumeration/{raw_t}.md)\n"
enum_empty = False
elif raw_t in classes:
content += f"- [{ts_t}](../{raw_t}/{raw_t}.md)\n"
enum_empty = False
elif ts_t.find('Api') == -1:
content += f"- {ts_t}\n"
enum_empty = False
if enum_empty == True:
return None
elif enumeration['properties'] is not None:
content += "## Type\n\nObject\n\n"
content += generate_properties_markdown(enumeration['properties'], enumerations, classes)
else:
content += "## Type\n\n"
# If it's not a union and has no properties, simply print the type(s).
types = enumeration['type']['names']
t_md = generate_data_types_markdown(types, enumerations, classes)
content += t_md + "\n\n"
# Example
if example:
if '```js' in example:
comment, code = example.split('```js', 1)
comment = remove_js_comments(comment)
content += f"\n\n## Example\n\n{comment}\n\n```javascript\n{code.strip()}\n"
else:
# If there's no triple-backtick structure
cleaned_example = remove_js_comments(example)
content += f"\n\n## Example\n\n```javascript\n{cleaned_example}\n```\n"
return escape_text_outside_code_blocks(content)
def process_doclets(data, output_dir, editor_name):
classes = {}
classes_props = {}
enumerations = []
editor_dir = os.path.join(output_dir, editor_name)
for doclet in data:
if doclet['kind'] == 'class':
class_name = doclet['name']
classes[class_name] = []
classes_props[class_name] = doclet.get('properties', None)
elif doclet['kind'] == 'function':
class_name = doclet.get('memberof')
if class_name:
if class_name not in classes:
classes[class_name] = []
classes[class_name].append(doclet)
elif doclet['kind'] == 'typedef':
enumerations.append(doclet)
# Process classes
for class_name, methods in classes.items():
class_dir = os.path.join(editor_dir, class_name)
methods_dir = os.path.join(class_dir, 'Methods')
os.makedirs(methods_dir, exist_ok=True)
# Write class file
class_content = generate_class_markdown(
class_name,
methods,
classes_props[class_name],
enumerations,
classes
)
write_markdown_file(os.path.join(class_dir, f"{class_name}.md"), class_content)
# Write method files
for method in methods:
method_file_path = os.path.join(methods_dir, f"{method['name']}.md")
method_content = generate_method_markdown(method, enumerations, classes)
write_markdown_file(method_file_path, method_content)
if not method.get('example', ''):
missing_examples.append(os.path.relpath(method_file_path, output_dir))
# Process enumerations
enum_dir = os.path.join(editor_dir, 'Enumeration')
os.makedirs(enum_dir, exist_ok=True)
for enum in enumerations:
enum_file_path = os.path.join(enum_dir, f"{enum['name']}.md")
enum_content = generate_enumeration_markdown(enum, enumerations, classes)
if enum_content is None:
continue
write_markdown_file(enum_file_path, enum_content)
if not enum.get('example', ''):
missing_examples.append(os.path.relpath(enum_file_path, output_dir))
def generate(output_dir):
print('Generating Markdown documentation...')
generate_docs_json.generate(output_dir + 'tmp_json', md=True)
for editor_name in editors:
input_file = os.path.join(output_dir + 'tmp_json', editor_name + ".json")
shutil.rmtree(output_dir + f'/{editor_name.title()}')
os.makedirs(output_dir + f'/{editor_name.title()}')
data = load_json(input_file)
process_doclets(data, output_dir, editor_name.title())
shutil.rmtree(output_dir + 'tmp_json')
print('Done')
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Generate documentation")
parser.add_argument(
"destination",
type=str,
help="Destination directory for the generated documentation",
nargs='?', # Indicates the argument is optional
default="../../../../office-js-api/" # Default value
)
args = parser.parse_args()
generate(args.destination)
print("START_MISSING_EXAMPLES")
print(",".join(missing_examples))
print("END_MISSING_EXAMPLES")

View File

@ -6,14 +6,14 @@ import re
# Configuration files
configs = [
"./config/events/common.json",
"./config/events/word.json",
"./config/events/cell.json",
"./config/events/slide.json",
"./config/events/forms.json"
"./config/plugins/common.json",
"./config/plugins/word.json",
"./config/plugins/cell.json",
"./config/plugins/slide.json",
"./config/plugins/forms.json"
]
root = '../../../../..'
root = '../../../..'
def generate(output_dir, md=False):
if not os.path.exists(output_dir):
@ -49,7 +49,7 @@ def generate(output_dir, md=False):
# Modify JSON data
for idx, doclet in enumerate(data):
if idx >= start_common_doclet_idx:
if idx == start_common_doclet_idx:
example_folder_name = 'common'
elif editor_name == 'forms':
example_folder_name = 'word'
@ -84,7 +84,7 @@ def generate(output_dir, md=False):
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=4)
print("Documentation generation for plugin events completed.")
print("Documentation generation for builder completed.")
def remove_builder_lines(text):
lines = text.splitlines() # Split text into lines

View File

@ -3,20 +3,17 @@ import json
import re
import shutil
import argparse
import generate_docs_methods_json
import generate_docs_plugins_json
# Configuration files
editors = {
"word": "text-document-api",
"cell": "spreadsheet-api",
"slide": "presentation-api",
"forms": "form-api"
}
editors = [
"word",
"cell",
"slide",
"forms"
]
missing_examples = []
used_enumerations = set()
cur_editor_name = None
def load_json(file_path):
with open(file_path, 'r', encoding='utf-8') as f:
@ -31,86 +28,25 @@ def remove_js_comments(text):
text = re.sub(r'/\*.*?\*/', '', text, flags=re.DOTALL) # multi-line
return text.strip()
def process_link_tags(text, root=''):
def correct_description(string):
"""
Finds patterns like {@link ...} and replaces them with Markdown links.
If the prefix 'global#' is found, a link to a typedef is generated,
otherwise, a link to a class method is created.
For a method, if an alias is not specified, the name is left in the format 'Class#Method'.
"""
reserved_links = {
'/docbuilder/global#ShapeType': f"{'../../../../../' if root == '' else '../../../../' if root == '../' else root}docs/office-api/usage-api/text-document-api/Enumeration/ShapeType.md",
'/plugin/config': 'https://api.onlyoffice.com/docs/plugin-and-macros/structure/configuration/',
'/docbuilder/basic': 'https://api.onlyoffice.com/docs/office-api/usage-api/text-document-api/'
}
def replace_link(match):
content = match.group(1).strip() # Example: "/docbuilder/global#ShapeType shape type" or "global#ErrorValue ErrorValue"
parts = content.split()
ref = parts[0]
label = parts[1] if len(parts) > 1 else None
if ref.startswith('/'):
# Handle reserved links using mapping
if ref in reserved_links:
url = reserved_links[ref]
display_text = label if label else ref
return f"[{display_text}]({url})"
else:
# If the link is not in the mapping, return the original construction
return match.group(0)
elif ref.startswith("global#"):
# Handle links to typedef (similar logic as before)
typedef_name = ref.split("#")[1]
used_enumerations.add(typedef_name)
display_text = label if label else typedef_name
return f"[{display_text}]({root}Enumeration/{typedef_name}.md)"
elif ref.startswith("https"):
display_text = label if label else ref # Keep the full notation, e.g., "Api#CreateSlide"
return f"[{display_text}]({ref})"
else:
# Handle links to class methods like ClassName#MethodName
try:
class_name, method_name = ref.split("#")
except ValueError:
return match.group(0)
display_text = label if label else ref # Keep the full notation, e.g., "Api#CreateSlide"
return f"[{display_text}]({root}{class_name}/Methods/{method_name}.md)"
return re.sub(r'{@link\s+([^}]+)}', replace_link, text)
def correct_description(string, root='', isInTable=False):
"""
Cleans or transforms specific tags in the doclet description:
- <b> => ** (bold text)
Cleans up or transforms certain tags in a doclet description:
- <b> => **
- <note>...</note> => 💡 ...
- {@link ...} is replaced with a Markdown link
- If the description is missing, returns a default value.
- All '\r' characters are replaced with '\n'.
- Provide a default if None.
"""
if string is None:
return 'No description provided.'
if False == isInTable:
# Line breaks
string = string.replace('\r', '\\\n')
# Replace <b> tags with Markdown bold formatting
string = re.sub(r'<b>', '-**', string)
else:
string = re.sub(r'<b>', '**', string)
# Replace <b> tags with markdown bold
string = re.sub(r'<b>', '**', string)
string = re.sub(r'</b>', '**', string)
# Replace <note> tags with an icon and text
# Convert <note>...</note> to a little icon + text
string = re.sub(r'<note>(.*?)</note>', r'💡 \1', string, flags=re.DOTALL)
# Process {@link ...} constructions
string = process_link_tags(string, root)
return string
def correct_default_value(value, enumerations, classes):
if value is None or value == '':
if value is None:
return ''
if value == True:
@ -162,24 +98,15 @@ def escape_text_outside_code_blocks(markdown: str) -> str:
# Even indices (0, 2, 4, ...) are outside code blocks,
# odd indices (1, 3, 5, ...) are actual code blocks.
for i in range(0, len(parts), 2):
text = (parts[i]
.replace('<', '&lt;')
.replace('>', '&gt;')
.replace('{', '&#123;')
.replace('}', '&#125;'))
parts[i] = escape_brackets_in_quotes(text)
# Only escape in parts outside code blocks
parts[i] = (parts[i]
.replace('<', '&lt;')
.replace('>', '&gt;')
.replace('{', '&#123;')
.replace('}', '&#125;')
)
return "".join(parts)
def escape_brackets_in_quotes(text: str) -> str:
return re.sub(
r"(['\"])(.*?)(?<!\\)\1",
lambda m: m.group(1)
+ m.group(2).replace('[', r'\[').replace(']', r'\]')
+ m.group(1),
text
)
def get_base_type(ts_type: str) -> str:
"""
Given a TypeScript-like type (e.g. "Drawing[][]"), return the
@ -191,147 +118,64 @@ def get_base_type(ts_type: str) -> str:
ts_type = ts_type[:-2]
return ts_type
def generate_data_types_markdown(types, enumerations, classes, root='../'):
def generate_data_types_markdown(types, enumerations, classes, root='../../'):
"""
1) Converts each type from JSDoc (e.g., Array.<T>) to T[].
2) Processes union types by splitting them using '|'.
3) Supports multidimensional arrays, e.g., (string|ApiRange|number)[].
4) If the base type matches the name of an enumeration or class, generates a link.
5) The final types are joined using " | ".
1) Convert each raw JSDoc type from Array.<T> to T[].
2) Split union types if needed (usually they're provided as separate
elements in 'types' already, but let's be safe).
3) For each type, extract the base type (e.g. "Drawing" from "Drawing[]").
4) If the base type matches an enumeration or class, link the entire
T[]-based string.
5) Join with " | ".
"""
# Convert each type from JSDoc format to TypeScript format (e.g., T[])
converted = [convert_jsdoc_array_to_ts(t) for t in types]
# Set of primitive types
primitive_types = {"string", "number", "boolean", "null", "undefined", "any", "object", "false", "true", "json", "function", "date", "{}"}
def is_primitive(type):
if (type.lower() in primitive_types or
(type.startswith('"') and type.endswith('"')) or
(type.startswith("'") and type.endswith("'")) or
type.replace('.', '', 1).isdigit() or
(type.startswith('-') and type[1:].replace('.', '', 1).isdigit())):
return True
return False
# Convert each raw type from JSDoc to TS
converted = [convert_jsdoc_array_to_ts(t) for t in types] # e.g. ["Drawing[]", "Foo[]", ...]
# For each converted type (like "Drawing[]"), see if the base is in enumerations or classes
def link_if_known(ts_type):
ts_type = ts_type.strip()
# Count the number of array dimensions, e.g., "[][]" has 2 dimensions
array_dims = 0
while ts_type.endswith("[]"):
array_dims += 1
ts_type = ts_type[:-2].strip()
base = get_base_type(ts_type) # e.g. "Drawing" from "Drawing[]"
# Process generic types, e.g., Object.<string, editorType>
if ".<" in ts_type and ts_type.endswith(">"):
import re
m = re.match(r'^(.*?)\.<(.*)>$', ts_type)
if m:
base_part = m.group(1).strip()
generic_args_str = m.group(2).strip()
# Process the base part of the type
found = False
for enum in enumerations:
if enum['name'] == base_part:
used_enumerations.add(base_part)
base_result = f"[{base_part}]({root}Enumeration/{base_part}.md)"
found = True
break
if not found:
if base_part in classes:
base_result = f"[{base_part}]({root}{base_part}/{base_part}.md)"
elif is_primitive(base_part):
base_result = base_part
elif cur_editor_name == "forms":
base_result = f"[{base_part}]({root}../text-document-api/{base_part}/{base_part}.md)"
else:
print(f"Unknown type encountered: {base_part}")
base_result = base_part
# Split the generic parameters by commas and process each recursively
generic_args = [link_if_known(x) for x in generic_args_str.split(",")]
result = base_result + ".&lt;" + ", ".join(generic_args) + "&gt;"
result += "[]" * array_dims
return result
# Check enumerations first
for enum in enumerations:
if enum['name'] == base:
# Replace the entire token with a link
return f"[{ts_type}]({root}Enumeration/{base}.md)"
# Process union types: if the type is enclosed in parentheses
if ts_type.startswith("(") and ts_type.endswith(")"):
inner = ts_type[1:-1].strip()
subtypes = [sub.strip() for sub in inner.split("|")]
if len(subtypes) == 1:
result = link_if_known(subtypes[0])
else:
processed = [link_if_known(subtype) for subtype in subtypes]
result = "(" + " | ".join(processed) + ")"
result += "[]" * array_dims
return result
# Check classes
if base in classes:
return f"[{ts_type}]({root}{base}/{base}.md)"
# If not a generic or union type process the base type
else:
base = ts_type
found = False
for enum in enumerations:
if enum['name'] == base:
used_enumerations.add(base)
result = f"[{base}]({root}Enumeration/{base}.md)"
found = True
break
if not found:
if base in classes:
result = f"[{base}]({root}{base}/{base}.md)"
elif is_primitive(base):
result = base
elif cur_editor_name == "forms":
result = f"[{base}]({root}../text-document-api/{base}/{base}.md)"
else:
print(f"Unknown type encountered: {base}")
result = base
result += "[]" * array_dims
return result
# Otherwise just return as-is
return ts_type
# Apply link_if_known to each converted type
# Build final list of possibly-linked types
linked = [link_if_known(ts_t) for ts_t in converted]
# Join results using " | "
param_types_md = r' | '.join(linked)
param_types_md = param_types_md.replace("|", r"\|")
# Join them with " | "
param_types_md = ' | '.join(linked)
# Escape remaining angle brackets for generics
# If there's still leftover angle brackets for generics, gently escape or link them
# e.g. "Object.<string, number>" => "Object.&lt;string, number&gt;"
# or do more specialized linking if you want to handle them deeper.
def replace_leftover_generics(match):
element = match.group(1).strip()
return f"&lt;{element}&gt;"
param_types_md = re.sub(r'<([^<>]+)>', replace_leftover_generics, param_types_md)
return param_types_md
def generate_class_markdown(class_name, methods, properties, enumerations, classes):
content = f"# {class_name}\n\nRepresents the {class_name} class.\n\n"
content += generate_properties_markdown(properties, enumerations, classes)
content += "\n## Methods\n\n"
content += "| Method | Returns | Description |\n"
content += "| ------ | ------- | ----------- |\n"
for method in sorted(methods, key=lambda m: m['name']):
content += "## Methods\n\n"
for method in methods:
method_name = method['name']
# Get the type of return values
returns = method.get('returns', [])
if returns:
return_type_list = returns[0].get('type', {}).get('names', [])
returns_markdown = generate_data_types_markdown(return_type_list, enumerations, classes, '../')
else:
returns_markdown = "None"
# Processing the method description
description = remove_line_breaks(correct_description(method.get('description', 'No description provided.'), '../', True))
# Form a link to the method document
method_link = f"[{method_name}](./{method_name}.md)"
content += f"| {method_link} | {returns_markdown} | {description} |\n"
content += f"- [{method_name}](./Methods/{method_name}.md)\n"
# Escape just before returning
return escape_text_outside_code_blocks(content)
def generate_method_markdown(method, enumerations, classes):
@ -342,7 +186,7 @@ def generate_method_markdown(method, enumerations, classes):
method_name = method['name']
description = method.get('description', 'No description provided.')
description = correct_description(description, '../')
description = correct_description(description)
params = method.get('params', [])
returns = method.get('returns', [])
memberof = method.get('memberof', '')
@ -353,10 +197,10 @@ def generate_method_markdown(method, enumerations, classes):
content = f"# {method_name}\n\n{description}\n\n"
# Syntax
param_list = ', '.join([param['name'] for param in params if '.' not in param['name']]) if params else ''
param_list = ', '.join([param['name'] for param in params]) if params else ''
content += f"## Syntax\n\n```javascript\nexpression.{method_name}({param_list});\n```\n\n"
if memberof:
content += f"`expression` - A variable that represents a [{memberof}](Methods.md) class.\n\n"
content += f"`expression` - A variable that represents a [{memberof}](../{memberof}.md) class.\n\n"
# Parameters
content += "## Parameters\n\n"
@ -367,7 +211,7 @@ def generate_method_markdown(method, enumerations, classes):
param_name = param.get('name', 'Unnamed')
param_types = param.get('type', {}).get('names', []) if param.get('type') else []
param_types_md = generate_data_types_markdown(param_types, enumerations, classes)
param_desc = remove_line_breaks(correct_description(param.get('description', 'No description provided.'), '../', True))
param_desc = remove_line_breaks(correct_description(param.get('description', 'No description provided.')))
param_required = "Required" if not param.get('optional') else "Optional"
param_default = correct_default_value(param.get('defaultvalue', ''), enumerations, classes)
@ -420,10 +264,10 @@ def generate_properties_markdown(properties, enumerations, classes, root='../'):
content += "| Name | Type | Description |\n"
content += "| ---- | ---- | ----------- |\n"
for prop in sorted(properties, key=lambda m: m['name']):
for prop in properties:
prop_name = prop['name']
prop_description = prop.get('description', 'No description provided.')
prop_description = remove_line_breaks(correct_description(prop_description, isInTable=True))
prop_description = remove_line_breaks(correct_description(prop_description))
prop_types = prop['type']['names'] if prop.get('type') else []
param_types_md = generate_data_types_markdown(prop_types, enumerations, classes, root)
content += f"| {prop_name} | {param_types_md} | {prop_description} |\n"
@ -437,13 +281,10 @@ def generate_enumeration_markdown(enumeration, enumerations, classes):
This version only works with `enumeration['examples']` (an array of strings),
ignoring any single `enumeration['examples']` field.
"""
enum_name = enumeration['name']
if enum_name not in used_enumerations:
return None
enum_name = enumeration['name']
description = enumeration.get('description', 'No description provided.')
description = correct_description(description, '../')
description = correct_description(description)
# Only use the 'examples' array
examples = enumeration.get('examples', [])
@ -468,7 +309,6 @@ def generate_enumeration_markdown(enumeration, enumerations, classes):
for raw_t in enumeration['type']['names']:
# Attempt linking
if any(enum['name'] == raw_t for enum in enumerations):
used_enumerations.add(raw_t)
content += f"- [{raw_t}](../Enumeration/{raw_t}.md)\n"
elif raw_t in classes:
content += f"- [{raw_t}](../{raw_t}/{raw_t}.md)\n"
@ -523,86 +363,55 @@ def generate_enumeration_markdown(enumeration, enumerations, classes):
return escape_text_outside_code_blocks(content)
def clean_methods_dir(methods_dir):
for root, dirs, files in os.walk(methods_dir, topdown=False):
for file in files:
if not file.endswith(('.json')):
os.remove(os.path.join(root, file))
for dir in dirs:
dir_path = os.path.join(root, dir)
# remove empty folder
if not os.listdir(dir_path):
os.rmdir(dir_path)
def clean_enum_files(editor_dir: str):
for root, _, files in os.walk(editor_dir, topdown=False):
for file in files:
if False == file.startswith('Event_') and False == file.endswith('.json'):
os.remove(os.path.join(root, file))
def process_doclets(data, output_dir, editor_name):
global cur_editor_name
cur_editor_name = editor_name
classes = {}
classes_props = {}
enumerations = []
editor_dir = os.path.join(output_dir, editors[editor_name])
methods_dir = os.path.join(output_dir, editors[editor_name], 'Methods')
clean_methods_dir(methods_dir)
os.makedirs(methods_dir, exist_ok=True)
editor_dir = os.path.join(output_dir, editor_name)
for doclet in data:
if doclet['kind'] == 'class':
class_name = doclet['name']
if class_name:
if class_name not in classes:
classes[class_name] = []
classes_props[class_name] = doclet.get('properties', None)
classes[class_name] = []
classes_props[class_name] = doclet.get('properties', None)
elif doclet['kind'] == 'function':
class_name = doclet.get('memberof')
if class_name:
if class_name not in classes:
classes[class_name] = []
classes[class_name] = []
classes[class_name].append(doclet)
elif doclet['kind'] == 'typedef':
enumerations.append(doclet)
# Process api methods
class_name = 'Api'
methods = classes[class_name]
# Write class file
class_content = generate_class_markdown(
class_name,
methods,
classes_props[class_name],
enumerations,
classes
)
write_markdown_file(os.path.join(methods_dir, f"Methods.md"), class_content)
# Process classes
for class_name, methods in classes.items():
class_dir = os.path.join(editor_dir, class_name)
methods_dir = os.path.join(class_dir, 'Methods')
os.makedirs(methods_dir, exist_ok=True)
# Write method files
for method in methods:
method_file_path = os.path.join(methods_dir, f"{method['name']}.md")
method_content = generate_method_markdown(method, enumerations, classes)
write_markdown_file(method_file_path, method_content)
# Write class file
class_content = generate_class_markdown(
class_name,
methods,
classes_props[class_name],
enumerations,
classes
)
write_markdown_file(os.path.join(class_dir, f"{class_name}.md"), class_content)
if not method.get('examples', ''):
missing_examples.append(os.path.relpath(method_file_path, output_dir))
# Write method files
for method in methods:
method_file_path = os.path.join(methods_dir, f"{method['name']}.md")
method_content = generate_method_markdown(method, enumerations, classes)
write_markdown_file(method_file_path, method_content)
if not method.get('examples', ''):
missing_examples.append(os.path.relpath(method_file_path, output_dir))
# Process enumerations
enum_dir = os.path.join(editor_dir, 'Enumeration')
clean_enum_files(enum_dir)
os.makedirs(enum_dir, exist_ok=True)
# idle run
prev_used_count = -1
while len(used_enumerations) != prev_used_count:
prev_used_count = len(used_enumerations)
for enum in [e for e in enumerations if e['name'] in used_enumerations]:
enum_content = generate_enumeration_markdown(enum, enumerations, classes)
for enum in enumerations:
enum_file_path = os.path.join(enum_dir, f"{enum['name']}.md")
enum_content = generate_enumeration_markdown(enum, enumerations, classes)
@ -619,13 +428,15 @@ def generate(output_dir):
if output_dir[-1] == '/':
output_dir = output_dir[:-1]
generate_docs_methods_json.generate(output_dir + '/tmp_json', md=True)
for editor_name, folder_name in editors.items():
generate_docs_plugins_json.generate(output_dir + '/tmp_json', md=True)
for editor_name in editors:
input_file = os.path.join(output_dir + '/tmp_json', editor_name + ".json")
shutil.rmtree(output_dir + f'/{editor_name.title()}', ignore_errors=True)
os.makedirs(output_dir + f'/{editor_name.title()}')
data = load_json(input_file)
used_enumerations.clear()
process_doclets(data, output_dir, editor_name)
process_doclets(data, output_dir, editor_name.title())
shutil.rmtree(output_dir + '/tmp_json')
print('Done')
@ -637,7 +448,7 @@ if __name__ == "__main__":
type=str,
help="Destination directory for the generated documentation",
nargs='?', # Indicates the argument is optional
default="../../../../../api.onlyoffice.com/site/docs/plugin-and-macros/interacting-with-editors/" # Default value
default="../../../../office-js-api/Plugins/" # Default value
)
args = parser.parse_args()
generate(args.destination)

View File

@ -1,16 +0,0 @@
{
"source": {
"include": ["../../../../../sdkjs/word/apiBuilder.js", "../../../../../sdkjs/slide/apiBuilder.js", "../../../../../sdkjs/cell/apiBuilder.js"]
},
"plugins": ["./correct_doclets.js"],
"opts": {
"destination": "./out",
"recurse": true,
"encoding": "utf8"
},
"templates": {
"json": {
"pretty": true
}
}
}

View File

@ -1,585 +0,0 @@
import os
import json
import re
import shutil
import argparse
import generate_docs_json
# Configuration files
editors = {
"word": "text-document-api",
"cell": "spreadsheet-api",
"slide": "presentation-api",
"forms": "form-api"
}
missing_examples = []
used_enumerations = set()
cur_editor_name = None
def load_json(file_path):
with open(file_path, 'r', encoding='utf-8') as f:
return json.load(f)
def write_markdown_file(file_path, content):
with open(file_path, 'w', encoding='utf-8') as md_file:
md_file.write(content)
def remove_js_comments(text):
text = re.sub(r'^\s*//.*$', '', text, flags=re.MULTILINE) # single-line
text = re.sub(r'/\*.*?\*/', '', text, flags=re.DOTALL) # multi-line
return text.strip()
def process_link_tags(text, root=''):
"""
Finds patterns like {@link ...} and replaces them with Markdown links.
If the prefix 'global#' is found, a link to a typedef is generated,
otherwise, a link to a class method is created.
For a method, if an alias is not specified, the name is left in the format 'Class#Method'.
"""
reserved_links = {
'/docbuilder/global#ShapeType': f"{'../../../../../../' if root == '' else '../../../../../' if root == '../' else root}docs/office-api/usage-api/text-document-api/Enumeration/ShapeType.md",
'/plugin/config': 'https://api.onlyoffice.com/docs/plugin-and-macros/structure/configuration/',
'/docbuilder/basic': 'https://api.onlyoffice.com/docs/office-api/usage-api/text-document-api/'
}
def replace_link(match):
content = match.group(1).strip() # Example: "/docbuilder/global#ShapeType shape type" or "global#ErrorValue ErrorValue"
parts = content.split()
ref = parts[0]
label = parts[1] if len(parts) > 1 else None
if ref.startswith('/'):
# Handle reserved links using mapping
if ref in reserved_links:
url = reserved_links[ref]
display_text = label if label else ref
return f"[{display_text}]({url})"
else:
# If the link is not in the mapping, return the original construction
return match.group(0)
elif ref.startswith("global#"):
# Handle links to typedef (similar logic as before)
typedef_name = ref.split("#")[1]
used_enumerations.add(typedef_name)
display_text = label if label else typedef_name
return f"[{display_text}]({root}Enumeration/{typedef_name}.md)"
else:
# Handle links to class methods like ClassName#MethodName
try:
class_name, method_name = ref.split("#")
except ValueError:
return match.group(0)
display_text = label if label else ref # Keep the full notation, e.g., "Api#CreateSlide"
return f"[{display_text}]({root}{class_name}/Methods/{method_name}.md)"
return re.sub(r'{@link\s+([^}]+)}', replace_link, text)
def correct_description(string, root='', isInTable=False):
"""
Cleans or transforms specific tags in the doclet description:
- <b> => ** (bold text)
- <note>...</note> => 💡 ...
- {@link ...} is replaced with a Markdown link
- If the description is missing, returns a default value.
- All '\r' characters are replaced with '\n'.
"""
if string is None:
return 'No description provided.'
if False == isInTable:
# Line breaks
string = string.replace('\r', '\\\n')
# Replace <b> tags with Markdown bold formatting
string = re.sub(r'<b>', '-**', string)
else:
string = re.sub(r'<b>', '**', string)
string = re.sub(r'</b>', '**', string)
# Replace <note> tags with an icon and text
string = re.sub(r'<note>(.*?)</note>', r'💡 \1', string, flags=re.DOTALL)
# Process {@link ...} constructions
string = process_link_tags(string, root)
return string
def correct_default_value(value, enumerations, classes):
if value is None or value == '':
return ''
if isinstance(value, bool):
value = "true" if value else "false"
else:
value = str(value)
return generate_data_types_markdown([value], enumerations, classes)
def remove_line_breaks(string):
return re.sub(r'[\r\n]+', ' ', string)
# Convert Array.<T> => T[] (including nested arrays).
def convert_jsdoc_array_to_ts(type_str: str) -> str:
"""
Recursively replaces 'Array.<T>' with 'T[]',
handling nested arrays like 'Array.<Array.<string>>' => 'string[][]'.
"""
pattern = re.compile(r'Array\.<([^>]+)>')
while True:
match = pattern.search(type_str)
if not match:
break
inner_type = match.group(1).strip()
# Recursively convert inner parts
inner_type = convert_jsdoc_array_to_ts(inner_type)
# Replace the outer Array.<...> with ...[]
type_str = (
type_str[:match.start()]
+ f"{inner_type}[]"
+ type_str[match.end():]
)
return type_str
def escape_text_outside_code_blocks(markdown: str) -> str:
"""
Splits content by fenced code blocks, escapes MDX-unsafe characters
(<, >, {, }) only in the text outside those code blocks.
"""
# A regex to capture fenced code blocks with ```
parts = re.split(r'(```.*?```)', markdown, flags=re.DOTALL)
# Even indices (0, 2, 4, ...) are outside code blocks,
# odd indices (1, 3, 5, ...) are actual code blocks.
for i in range(0, len(parts), 2):
text = (parts[i]
.replace('<', '&lt;')
.replace('>', '&gt;')
.replace('{', '&#123;')
.replace('}', '&#125;'))
parts[i] = escape_brackets_in_quotes(text)
return "".join(parts)
def escape_brackets_in_quotes(text: str) -> str:
return re.sub(
r"(['\"])(.*?)(?<!\\)\1",
lambda m: m.group(1)
+ m.group(2).replace('[', r'\[').replace(']', r'\]')
+ m.group(1),
text
)
def get_base_type(ts_type: str) -> str:
"""
Given a TypeScript-like type (e.g. "Drawing[][]"), return the
'base' portion by stripping trailing "[]". For "Drawing[][]",
returns "Drawing". For "Array.<Drawing>", you'd convert it first
to "Drawing[]" then return "Drawing".
"""
while ts_type.endswith('[]'):
ts_type = ts_type[:-2]
return ts_type
def generate_data_types_markdown(types, enumerations, classes, root='../../'):
"""
1) Converts each type from JSDoc (e.g., Array.<T>) to T[].
2) Processes union types by splitting them using '|'.
3) Supports multidimensional arrays, e.g., (string|ApiRange|number)[].
4) If the base type matches the name of an enumeration or class, generates a link.
5) The final types are joined using " | ".
"""
# Convert each type from JSDoc format to TypeScript format (e.g., T[])
converted = [convert_jsdoc_array_to_ts(t) for t in types]
# Set of primitive types
primitive_types = {"string", "number", "boolean", "null", "undefined", "any", "object", "false", "true", "json", "function", "date", "{}"}
def is_primitive(type):
if (type.lower() in primitive_types or
(type.startswith('"') and type.endswith('"')) or
(type.startswith("'") and type.endswith("'")) or
type.replace('.', '', 1).isdigit() or
(type.startswith('-') and type[1:].replace('.', '', 1).isdigit())):
return True
return False
def link_if_known(ts_type):
ts_type = ts_type.strip()
# Count the number of array dimensions, e.g., "[][]" has 2 dimensions
array_dims = 0
while ts_type.endswith("[]"):
array_dims += 1
ts_type = ts_type[:-2].strip()
# Process generic types, e.g., Object.<string, editorType>
if ".<" in ts_type and ts_type.endswith(">"):
import re
m = re.match(r'^(.*?)\.<(.*)>$', ts_type)
if m:
base_part = m.group(1).strip()
generic_args_str = m.group(2).strip()
# Process the base part of the type
found = False
for enum in enumerations:
if enum['name'] == base_part:
used_enumerations.add(base_part)
base_result = f"[{base_part}]({root}Enumeration/{base_part}.md)"
found = True
break
if not found:
if base_part in classes:
base_result = f"[{base_part}]({root}{base_part}/{base_part}.md)"
elif is_primitive(base_part):
base_result = base_part
elif cur_editor_name == "forms":
base_result = f"[{base_part}]({root}../text-document-api/{base_part}/{base_part}.md)"
else:
print(f"Unknown type encountered: {base_part}")
base_result = base_part
# Split the generic parameters by commas and process each recursively
generic_args = [link_if_known(x) for x in generic_args_str.split(",")]
result = base_result + ".&lt;" + ", ".join(generic_args) + "&gt;"
result += "[]" * array_dims
return result
# Process union types: if the type is enclosed in parentheses
if ts_type.startswith("(") and ts_type.endswith(")"):
inner = ts_type[1:-1].strip()
subtypes = [sub.strip() for sub in inner.split("|")]
if len(subtypes) == 1:
result = link_if_known(subtypes[0])
else:
processed = [link_if_known(subtype) for subtype in subtypes]
result = "(" + " | ".join(processed) + ")"
result += "[]" * array_dims
return result
# If not a generic or union type process the base type
else:
base = ts_type
found = False
for enum in enumerations:
if enum['name'] == base:
used_enumerations.add(base)
result = f"[{base}]({root}Enumeration/{base}.md)"
found = True
break
if not found:
if base in classes:
result = f"[{base}]({root}{base}/{base}.md)"
elif is_primitive(base):
result = base
elif cur_editor_name == "forms":
result = f"[{base}]({root}../text-document-api/{base}/{base}.md)"
else:
print(f"Unknown type encountered: {base}")
result = base
result += "[]" * array_dims
return result
# Apply link_if_known to each converted type
linked = [link_if_known(ts_t) for ts_t in converted]
# Join results using " | "
param_types_md = r' | '.join(linked)
param_types_md = param_types_md.replace("|", r"\|")
# Escape remaining angle brackets for generics
def replace_leftover_generics(match):
element = match.group(1).strip()
return f"&lt;{element}&gt;"
param_types_md = re.sub(r'<([^<>]+)>', replace_leftover_generics, param_types_md)
return param_types_md
def generate_class_markdown(class_name, methods, properties, enumerations, classes):
content = f"# {class_name}\n\nRepresents the {class_name} class.\n\n"
content += generate_properties_markdown(properties, enumerations, classes)
content += "\n## Methods\n\n"
content += "| Method | Returns | Description |\n"
content += "| ------ | ------- | ----------- |\n"
for method in sorted(methods, key=lambda m: m['name']):
method_name = method['name']
# Get the type of return values
returns = method.get('returns', [])
if returns:
return_type_list = returns[0].get('type', {}).get('names', [])
returns_markdown = generate_data_types_markdown(return_type_list, enumerations, classes, '../')
else:
returns_markdown = "None"
# Processing the method description
description = remove_line_breaks(correct_description(method.get('description', 'No description provided.'), '../', True))
# Form a link to the method document
method_link = f"[{method_name}](./Methods/{method_name}.md)"
content += f"| {method_link} | {returns_markdown} | {description} |\n"
return escape_text_outside_code_blocks(content)
def generate_method_markdown(method, enumerations, classes, example_editor_name):
method_name = method['name']
description = method.get('description', 'No description provided.')
description = correct_description(description, '../../')
params = method.get('params', [])
returns = method.get('returns', [])
example = method.get('example', '')
memberof = method.get('memberof', '')
content = f"# {method_name}\n\n{description}\n\n"
# Syntax
param_list = ', '.join([param['name'] for param in params if '.' not in param['name']]) if params else ''
content += f"## Syntax\n\n```javascript\nexpression.{method_name}({param_list});\n```\n\n"
if memberof:
content += f"`expression` - A variable that represents a [{memberof}](../{memberof}.md) class.\n\n"
# Parameters
content += "## Parameters\n\n"
if params:
content += "| **Name** | **Required/Optional** | **Data type** | **Default** | **Description** |\n"
content += "| ------------- | ------------- | ------------- | ------------- | ------------- |\n"
for param in params:
param_name = param.get('name', 'Unnamed')
param_types = param.get('type', {}).get('names', []) if param.get('type') else []
param_types_md = generate_data_types_markdown(param_types, enumerations, classes)
param_desc = remove_line_breaks(correct_description(param.get('description', 'No description provided.'), '../../', True))
param_required = "Required" if not param.get('optional') else "Optional"
param_default = correct_default_value(param.get('defaultvalue', ''), enumerations, classes)
content += f"| {param_name} | {param_required} | {param_types_md} | {param_default} | {param_desc} |\n"
else:
content += "This method doesn't have any parameters.\n"
# Returns
content += "\n## Returns\n\n"
if returns:
return_type_list = returns[0].get('type', {}).get('names', [])
return_type_md = generate_data_types_markdown(return_type_list, enumerations, classes)
content += return_type_md
else:
content += "This method doesn't return any data."
# Example
if example:
# Separate comment and code, remove JS comments
if '```js' in example:
comment, code = example.split('```js', 1)
comment = remove_js_comments(comment)
content += f"\n\n## Example\n\n{comment}\n\n```javascript {example_editor_name}\n{code.strip()}\n"
else:
# If there's no triple-backtick structure, just show it as code
cleaned_example = remove_js_comments(example)
content += f"\n\n## Example\n\n```javascript {example_editor_name}\n{cleaned_example}\n```\n"
return escape_text_outside_code_blocks(content)
def generate_properties_markdown(properties, enumerations, classes, root='../'):
if properties is None:
return ''
content = "## Properties\n\n"
content += "| Name | Type | Description |\n"
content += "| ---- | ---- | ----------- |\n"
for prop in sorted(properties, key=lambda m: m['name']):
prop_name = prop['name']
prop_description = prop.get('description', 'No description provided.')
prop_description = remove_line_breaks(correct_description(prop_description, root, True))
prop_types = prop['type']['names'] if prop.get('type') else []
param_types_md = generate_data_types_markdown(prop_types, enumerations, classes, root)
content += f"| {prop_name} | {param_types_md} | {prop_description} |\n"
# Escape outside code blocks
return escape_text_outside_code_blocks(content)
def generate_enumeration_markdown(enumeration, enumerations, classes, example_editor_name):
enum_name = enumeration['name']
if enum_name not in used_enumerations:
return None
description = enumeration.get('description', 'No description provided.')
description = correct_description(description, '../')
example = enumeration.get('example', '')
content = f"# {enum_name}\n\n{description}\n\n"
ptype = enumeration['type']['parsedType']
if ptype['type'] == 'TypeUnion':
enum_empty = True # is empty enum
content += "## Type\n\nEnumeration\n\n"
content += "## Values\n\n"
# Each top-level name in the union
for raw_t in enumeration['type']['names']:
ts_t = convert_jsdoc_array_to_ts(raw_t)
# Attempt linking: we compare the raw type to enumerations/classes
if any(enum['name'] == raw_t for enum in enumerations):
used_enumerations.add(raw_t)
content += f"- [{ts_t}](../Enumeration/{raw_t}.md)\n"
enum_empty = False
elif raw_t in classes:
content += f"- [{ts_t}](../{raw_t}/{raw_t}.md)\n"
enum_empty = False
elif ts_t.find('Api') == -1:
content += f"- {ts_t}\n"
enum_empty = False
if enum_empty == True:
return None
elif enumeration['properties'] is not None:
content += "## Type\n\nObject\n\n"
content += generate_properties_markdown(enumeration['properties'], enumerations, classes)
else:
content += "## Type\n\n"
# If it's not a union and has no properties, simply print the type(s).
types = enumeration['type']['names']
t_md = generate_data_types_markdown(types, enumerations, classes)
content += t_md + "\n\n"
# Example
if example:
if '```js' in example:
comment, code = example.split('```js', 1)
comment = remove_js_comments(comment)
content += f"\n\n## Example\n\n{comment}\n\n```javascript {example_editor_name}\n{code.strip()}\n"
else:
# If there's no triple-backtick structure
cleaned_example = remove_js_comments(example)
content += f"\n\n## Example\n\n```javascript {example_editor_name}\n{cleaned_example}\n```\n"
return escape_text_outside_code_blocks(content)
def process_doclets(data, output_dir, editor_name):
global cur_editor_name
cur_editor_name = editor_name
classes = {}
classes_props = {}
enumerations = []
editor_dir = os.path.join(output_dir, editors[editor_name])
example_editor_name = 'editor-'
if editor_name == 'word':
example_editor_name += 'docx'
elif editor_name == 'forms':
example_editor_name += 'pdf'
elif editor_name == 'slide':
example_editor_name += 'pptx'
elif editor_name == 'cell':
example_editor_name += 'xlsx'
for doclet in data:
if doclet['kind'] == 'class':
class_name = doclet['name']
if class_name:
if class_name not in classes:
classes[class_name] = []
classes_props[class_name] = doclet.get('properties', None)
elif doclet['kind'] == 'function':
class_name = doclet.get('memberof')
if class_name:
if class_name not in classes:
classes[class_name] = []
classes[class_name].append(doclet)
elif doclet['kind'] == 'typedef':
enumerations.append(doclet)
# Process classes
for class_name, methods in classes.items():
if (len(methods) == 0):
continue
class_dir = os.path.join(editor_dir, class_name)
methods_dir = os.path.join(class_dir, 'Methods')
os.makedirs(methods_dir, exist_ok=True)
# Write class file
class_content = generate_class_markdown(
class_name,
methods,
classes_props[class_name],
enumerations,
classes
)
write_markdown_file(os.path.join(class_dir, f"{class_name}.md"), class_content)
# Write method files
for method in methods:
method_file_path = os.path.join(methods_dir, f"{method['name']}.md")
method_content = generate_method_markdown(method, enumerations, classes, example_editor_name)
write_markdown_file(method_file_path, method_content)
if not method.get('example', ''):
missing_examples.append(os.path.relpath(method_file_path, output_dir))
# Process enumerations
enum_dir = os.path.join(editor_dir, 'Enumeration')
os.makedirs(enum_dir, exist_ok=True)
# idle run
prev_used_count = -1
while len(used_enumerations) != prev_used_count:
prev_used_count = len(used_enumerations)
for enum in [e for e in enumerations if e['name'] in used_enumerations]:
enum_content = generate_enumeration_markdown(enum, enumerations, classes, example_editor_name)
for enum in enumerations:
enum_file_path = os.path.join(enum_dir, f"{enum['name']}.md")
enum_content = generate_enumeration_markdown(enum, enumerations, classes, example_editor_name)
if enum_content is None:
continue
write_markdown_file(enum_file_path, enum_content)
if not enum.get('example', ''):
missing_examples.append(os.path.relpath(enum_file_path, output_dir))
def generate(output_dir):
print('Generating Markdown documentation...')
generate_docs_json.generate(output_dir + 'tmp_json', md=True)
for editor_name, folder_name in editors.items():
input_file = os.path.join(output_dir + '/tmp_json', editor_name + ".json")
editor_folder_path = os.path.join(output_dir, folder_name)
for folder_name in os.listdir(editor_folder_path):
folder_path_to_del = os.path.join(editor_folder_path, folder_name)
if os.path.isdir(folder_path_to_del):
shutil.rmtree(folder_path_to_del, ignore_errors=True)
data = load_json(input_file)
used_enumerations.clear()
process_doclets(data, output_dir, editor_name)
shutil.rmtree(output_dir + 'tmp_json')
print('Done')
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Generate documentation")
parser.add_argument(
"destination",
type=str,
help="Destination directory for the generated documentation",
nargs='?', # Indicates the argument is optional
default="../../../../../api.onlyoffice.com/site/docs/office-api/usage-api/" # Default value
)
args = parser.parse_args()
generate(args.destination)
print("START_MISSING_EXAMPLES")
print(",".join(missing_examples))
print("END_MISSING_EXAMPLES")

View File

@ -1,245 +0,0 @@
import os
import json
import re
import shutil
import argparse
import generate_docs_json
from datetime import datetime
# Configuration files
editors = [
"word",
"cell",
"slide",
"forms"
]
editors_names = {
"word": "Word",
"cell": "Spreadsheet",
"slide": "Presentation",
"forms": "Forms"
}
root = '../../../../..'
missing_examples = []
def load_json(file_path):
with open(file_path, 'r', encoding='utf-8') as f:
return json.load(f)
def read_file_content(file_path):
try:
with open(file_path, encoding='utf-8') as f:
return f.read()
except Exception as e:
missing_examples.append(file_path)
# print(f"Failed to open file {file_path}: {e}")
return ""
def extract_js_comments_as_text(text):
# Extract single-line comments (after //)
single_line_comments = re.findall(r'^\s*//(.*)$', text, flags=re.MULTILINE)
# Extract multi-line comments (between /* and */)
multi_line_comments = re.findall(r'/\*(.*?)\*/', text, flags=re.DOTALL)
# Combine all found comments into a single list
all_comments = single_line_comments + multi_line_comments
# Join comments into a single text, separated by a space
return " ".join(comment.strip() for comment in all_comments if comment.strip())
def extract_examples_blocks(content: str):
blocks = []
current_block = {"comments": [], "code": []}
in_comment_section = True # Collect comments until code appears
current_comment_group = [] # Accumulate lines of the current comment
for line in content.splitlines():
stripped = line.strip()
if not stripped:
# Empty line
if in_comment_section and current_comment_group:
# Finish the current comment group
comment_text = " ".join(current_comment_group)
current_block["comments"].append(comment_text)
current_comment_group = []
elif not in_comment_section:
# Empty line in the code keep it as is
current_block["code"].append(line)
continue
if stripped.startswith("//"):
if in_comment_section:
# Remove comment marker and extra spaces
current_comment_group.append(extract_js_comments_as_text(stripped))
else:
# Comment after code starts finish the current block and start a new one
blocks.append({
"comments": current_block["comments"],
"code": "\n".join(current_block["code"]).rstrip()
})
current_block = {"comments": [], "code": []}
in_comment_section = True
# Start a new comment group with the current line
current_comment_group = [stripped[2:].strip()]
else:
# Code line
if in_comment_section:
if current_comment_group:
comment_text = " ".join(current_comment_group)
current_block["comments"].append(comment_text)
current_comment_group = []
in_comment_section = False
current_block["code"].append(line)
# Finalize any remaining comment group
if in_comment_section and current_comment_group:
comment_text = " ".join(current_comment_group)
current_block["comments"].append(comment_text)
# Save the last block if it's not empty
if current_block["comments"] or current_block["code"]:
blocks.append({
"comments": current_block["comments"],
"code": "\n".join(current_block["code"]).rstrip()
})
return blocks
def extract_examples_blocks_temp(content: str):
lines = content.splitlines()
comment_blocks = []
current_group = []
first_code_index = None
for i, line in enumerate(lines):
stripped = line.strip()
if not stripped:
if current_group:
comment_blocks.append(" ".join(current_group))
current_group = []
continue
if stripped.startswith("//"):
current_group.append(stripped[2:].strip())
else:
if current_group:
comment_blocks.append(" ".join(current_group))
current_group = []
first_code_index = i
break
code_part = ""
if first_code_index is not None:
code_part = "\n".join(lines[first_code_index:]).rstrip()
return [{"comments": comment_blocks, "code": code_part}]
def create_entry(system_message, user_message, assistant_message, model):
entry = {
"created_at": datetime.now().isoformat(" "),
"messages": [
{"role": "system", "content": system_message},
{"role": "user", "content": user_message},
{"role": "assistant", "content": assistant_message}
],
"recommended": False,
"upvoted": True
}
if model is not "":
entry["model"] = model
return entry
def process_doclets(doclets, output_entries, editor_name, model):
system_message = f'You are an expert in API for library from OnlyOffice. The library provides functions for editing {editors_names[editor_name]} documents. Your functional capabilities: 1) Explanation of Onlyoffice JavaScript API classes and their methods and parameters. 2) Assistance in writing Onlyoffice JavaScript API examples upon user request. 3) Reviewing user examples, assisting in finding and fixing their mistakes.'
for doclet in doclets:
kind = doclet.get("kind", "").lower()
see = doclet.get("see", [])
# The "see" field must always be present
if not see:
continue
# Processing based on the "kind" value
if kind == "function":
method_name = doclet.get("name", "")
memberof = doclet.get("memberof", "")
# Functions must have both "name" (method_name) and "memberof" fields filled
if not (method_name and memberof):
continue
default_user_message = f"How do I use the method {method_name} of {memberof} class?"
elif kind == "class":
class_name = doclet.get("name", "")
default_user_message = f"How do I instantiate or work with the class {class_name}?"
elif kind == "typedef":
typedef_name = doclet.get("name", "")
default_user_message = f"How do I use the typedef {typedef_name}?"
else:
continue
# Read the content of the first file listed in the "see" field
content = read_file_content(f'{root}/{see[0]}')
if content == "":
continue
# now use only first block cause there is bad comments in examples
blocks = extract_examples_blocks_temp(content)
for block in blocks:
assistant_message = block['code']
# default entry
output_entries.append(create_entry(system_message, default_user_message, assistant_message, model))
# If the file content contains comments, create a separate entry for each one
for comment in block['comments']:
output_entries.append(create_entry(system_message, comment, assistant_message, model))
def generate(output_dir, model):
print('Generating documentation JSONL dataset...')
shutil.rmtree(output_dir, ignore_errors=True)
os.makedirs(output_dir)
generate_docs_json.generate(f'{output_dir}/tmp_json')
output_entries = []
output_filename = "dataset.jsonl"
for editor_name in editors:
input_file = os.path.join(f'{output_dir}/tmp_json', editor_name + ".json")
doclets = load_json(input_file)
process_doclets(doclets, output_entries, editor_name, model)
with open(f'{output_dir}/{output_filename}', "w", encoding="utf-8") as out_file:
for entry in output_entries:
out_file.write(json.dumps(entry, ensure_ascii=False) + "\n")
shutil.rmtree(f'{output_dir}/tmp_json')
print('Done')
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Generate documentation JSONL dataset")
parser.add_argument(
"destination",
type=str,
help="Destination directory for the generated documentation",
nargs='?', # Indicates the argument is optional
default="../../../../../office-js-api/dataset" # Default value
)
parser.add_argument(
"model",
type=str,
help="Type of model",
nargs='?', # Indicates the argument is optional
default="" # Default value
)
args = parser.parse_args()
generate(args.destination, args.model)
print("START_MISSING_EXAMPLES")
print(",".join(missing_examples))
print("END_MISSING_EXAMPLES")

View File

@ -1,16 +0,0 @@
{
"source": {
"include": ["../../../../../sdkjs/cell/plugin-events.js"]
},
"plugins": ["../correct_doclets.js"],
"opts": {
"destination": "./out",
"recurse": true,
"encoding": "utf8"
},
"templates": {
"json": {
"pretty": true
}
}
}

View File

@ -1,16 +0,0 @@
{
"source": {
"include": ["../../../../../sdkjs/common/base-plugin-events.js"]
},
"plugins": ["../correct_doclets.js"],
"opts": {
"destination": "./out",
"recurse": true,
"encoding": "utf8"
},
"templates": {
"json": {
"pretty": true
}
}
}

View File

@ -1,16 +0,0 @@
{
"source": {
"include": ["../../../../../sdkjs-forms/plugin-events.js"]
},
"plugins": ["../correct_doclets.js"],
"opts": {
"destination": "./out",
"recurse": true,
"encoding": "utf8"
},
"templates": {
"json": {
"pretty": true
}
}
}

View File

@ -1,16 +0,0 @@
{
"source": {
"include": ["../../../../../sdkjs/slide/plugin-events.js"]
},
"plugins": ["../correct_doclets.js"],
"opts": {
"destination": "./out",
"recurse": true,
"encoding": "utf8"
},
"templates": {
"json": {
"pretty": true
}
}
}

View File

@ -1,16 +0,0 @@
{
"source": {
"include": ["../../../../../sdkjs/word/plugin-events.js"]
},
"plugins": ["../correct_doclets.js"],
"opts": {
"destination": "./out",
"recurse": true,
"encoding": "utf8"
},
"templates": {
"json": {
"pretty": true
}
}
}

View File

@ -1,16 +0,0 @@
{
"source": {
"include": ["../../../../../sdkjs/cell/api_plugins.js"]
},
"plugins": ["../correct_doclets.js"],
"opts": {
"destination": "./out",
"recurse": true,
"encoding": "utf8"
},
"templates": {
"json": {
"pretty": true
}
}
}

View File

@ -1,16 +0,0 @@
{
"source": {
"include": ["../../../../../sdkjs/common/plugins/plugin_base_api.js" ,"../../../../../sdkjs/common/apiBase_plugins.js"]
},
"plugins": ["../correct_doclets.js"],
"opts": {
"destination": "./out",
"recurse": true,
"encoding": "utf8"
},
"templates": {
"json": {
"pretty": true
}
}
}

View File

@ -1,16 +0,0 @@
{
"source": {
"include": ["../../../../../sdkjs-forms/apiPlugins.js"]
},
"plugins": ["../correct_doclets.js"],
"opts": {
"destination": "./out",
"recurse": true,
"encoding": "utf8"
},
"templates": {
"json": {
"pretty": true
}
}
}

View File

@ -1,16 +0,0 @@
{
"source": {
"include": ["../../../../../sdkjs/slide/api_plugins.js"]
},
"plugins": ["../correct_doclets.js"],
"opts": {
"destination": "./out",
"recurse": true,
"encoding": "utf8"
},
"templates": {
"json": {
"pretty": true
}
}
}

View File

@ -1,16 +0,0 @@
{
"source": {
"include": ["../../../../../sdkjs/word/api_plugins.js", "../../../../../sdkjs-forms/apiPlugins.js"]
},
"plugins": ["../correct_doclets.js"],
"opts": {
"destination": "./out",
"recurse": true,
"encoding": "utf8"
},
"templates": {
"json": {
"pretty": true
}
}
}

View File

@ -1,398 +0,0 @@
#!/usr/bin/env python3
import os
import json
import re
import shutil
import argparse
import generate_docs_events_json
# Папки для каждого editor_name
editors = {
"word": "text-document-api",
"cell": "spreadsheet-api",
"slide": "presentation-api",
"forms": "form-api"
}
missing_examples = []
used_enumerations = set()
def load_json(path):
with open(path, 'r', encoding='utf-8') as f:
return json.load(f)
def write_markdown_file(path, content):
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, 'w', encoding='utf-8') as f:
f.write(content)
def remove_js_comments(text):
text = re.sub(r'^\s*//.*$', '', text, flags=re.MULTILINE)
text = re.sub(r'/\*.*?\*/', '', text, flags=re.DOTALL)
return text.strip()
def correct_description(string, root='', isInTable=False):
"""
Cleans or transforms specific tags in the doclet description:
- <b> => ** (bold text)
- <note>...</note> => 💡 ...
- {@link ...} is replaced with a Markdown link
- If the description is missing, returns a default value.
- All '\r' characters are replaced with '\n'.
"""
if string is None:
return 'No description provided.'
if False == isInTable:
# Line breaks
string = string.replace('\r', '\\\n')
# Replace <b> tags with Markdown bold formatting
string = re.sub(r'<b>', '-**', string)
else:
string = re.sub(r'<b>', '**', string)
string = re.sub(r'</b>', '**', string)
# Replace <note> tags with an icon and text
string = re.sub(r'<note>(.*?)</note>', r'💡 \1', string, flags=re.DOTALL)
# Process {@link ...} constructions
string = process_link_tags(string, root)
return string
def process_link_tags(text, root=''):
"""
Finds patterns like {@link ...} and replaces them with Markdown links.
If the prefix 'global#' is found, a link to a typedef is generated,
otherwise, a link to a class method is created.
For a method, if an alias is not specified, the name is left in the format 'Class#Method'.
"""
reserved_links = {
'/docbuilder/global#ShapeType': f"{'../../../../../../' if root == '' else '../../../../../' if root == '../' else root}docs/office-api/usage-api/text-document-api/Enumeration/ShapeType.md",
'/plugin/config': 'https://api.onlyoffice.com/docs/plugin-and-macros/structure/configuration/',
'/docbuilder/basic': 'https://api.onlyoffice.com/docs/office-api/usage-api/text-document-api/'
}
def replace_link(match):
content = match.group(1).strip() # Example: "/docbuilder/global#ShapeType shape type" or "global#ErrorValue ErrorValue"
parts = content.split()
ref = parts[0]
label = parts[1] if len(parts) > 1 else None
if ref.startswith('/'):
# Handle reserved links using mapping
if ref in reserved_links:
url = reserved_links[ref]
display_text = label if label else ref
return f"[{display_text}]({url})"
elif ref.startswith('/docs/plugins/'):
url = f"../../{ref.split('/docs/plugins/')[1]}.md"
display_text = label if label else ref
return f"[{display_text}]({url})"
else:
# If the link is not in the mapping, return the original construction
return match.group(0)
elif ref.startswith("global#"):
# Handle links to typedef (similar logic as before)
typedef_name = ref.split("#")[1]
used_enumerations.add(typedef_name)
display_text = label if label else typedef_name
return f"[{display_text}]({root}Enumeration/Event_{typedef_name}.md)"
else:
# Handle links to class methods like ClassName#MethodName
try:
class_name, method_name = ref.split("#")
except ValueError:
return match.group(0)
display_text = label if label else ref # Keep the full notation, e.g., "Api#CreateSlide"
return f"[{display_text}]({root}{class_name}/Methods/{method_name}.md)"
return re.sub(r'{@link\s+([^}]+)}', replace_link, text)
def remove_line_breaks(s):
return re.sub(r'[\r\n]+', ' ', s)
def convert_jsdoc_array_to_ts(type_str):
p = re.compile(r'Array\.<([^>]+)>')
while True:
m = p.search(type_str)
if not m:
break
inner = convert_jsdoc_array_to_ts(m.group(1).strip())
type_str = type_str[:m.start()] + inner + '[]' + type_str[m.end():]
return type_str
def generate_data_types_markdown(types, enumerations, root=''):
converted = [convert_jsdoc_array_to_ts(t) for t in types]
primitives = {"string", "number", "boolean", "null", "undefined", "any", "object", "false", "true", "json", "function", "date", "{}"}
result = []
enum_names = {e['name'] for e in enumerations}
for t in converted:
base = t.rstrip('[]')
dims = t[len(base):]
if base in enum_names:
used_enumerations.add(base)
link = f"[Event_{base}]({root}../Enumeration/Event_{base}.md)"
elif base in primitives or re.match(r"^['\"].*['\"]$", base) or re.match(r"^-?\d+(\.\d+)?$", base):
link = base
else:
link = base
result.append(link + dims)
return " | ".join(result)
def escape_text_outside_code_blocks(md):
parts = re.split(r'(```.*?```)', md, flags=re.DOTALL)
for i in range(0, len(parts), 2):
parts[i] = parts[i].replace('<', '&lt;').replace('>', '&gt;')
return "".join(parts)
def generate_event_markdown(event, enumerations):
name = event['name']
desc = correct_description(event.get('description', ''))
params = event.get('params', [])
md = f"# {name}\n\n{desc}\n\n"
# Parameters
md += "## Parameters\n\n"
if params:
md += "| **Name** | **Data type** | **Description** |\n"
md += "| --------- | ------------- | ----------- |\n"
for p in params:
t_md = generate_data_types_markdown(
p.get('type', {}).get('names', []),
enumerations
)
d = remove_line_breaks(correct_description(p.get('description', ''), isInTable=True))
md += f"| {p['name']} | {t_md} | {d} |\n"
md += "\n"
else:
md += "This event has no parameters.\n\n"
for ex in event.get('examples', []):
code = remove_js_comments(ex).strip()
md += f"```javascript\n{code}\n```\n\n"
return escape_text_outside_code_blocks(md)
def generate_enumeration_markdown(enumeration, enumerations):
"""
Generates Markdown documentation for a 'typedef' doclet.
This version only works with `enumeration['examples']` (an array of strings),
ignoring any single `enumeration['examples']` field.
"""
enum_name = enumeration['name']
if enum_name not in used_enumerations:
return None
description = enumeration.get('description', 'No description provided.')
description = correct_description(description, '../')
# Only use the 'examples' array
examples = enumeration.get('examples', [])
content = f"# Event_{enum_name}\n\n{description}\n\n"
parsed_type = enumeration['type'].get('parsedType')
if not parsed_type:
# If parsedType is missing, just list 'type.names' if available
type_names = enumeration['type'].get('names', [])
if type_names:
content += "## Type\n\n"
t_md = generate_data_types_markdown(type_names, enumerations)
content += t_md + "\n\n"
else:
ptype = parsed_type['type']
# 1) Handle TypeUnion
if ptype == 'TypeUnion':
content += "## Type\n\nEnumeration\n\n"
content += "## Values\n\n"
for raw_t in enumeration['type']['names']:
# Attempt linking
if any(enum['name'] == raw_t for enum in enumerations):
used_enumerations.add(raw_t)
content += f"- [{raw_t}](../Enumeration/Event_{raw_t}.md)\n"
else:
content += f"- {raw_t}\n"
# 2) Handle TypeApplication (e.g. Object.<string, string>)
elif ptype == 'TypeApplication':
content += "## Type\n\nObject\n\n"
type_names = enumeration['type'].get('names', [])
if type_names:
t_md = generate_data_types_markdown(type_names, enumerations)
content += f"**Type:** {t_md}\n\n"
# 3) If properties are present, treat it like an object
if enumeration.get('properties') is not None:
content += generate_properties_markdown(enumeration['properties'], enumerations)
# 4) If it's neither TypeUnion nor TypeApplication, just output the type names
if ptype not in ('TypeUnion', 'TypeApplication'):
type_names = enumeration['type'].get('names', [])
if type_names:
content += "## Type\n\n"
t_md = generate_data_types_markdown(type_names, enumerations)
content += t_md + "\n\n"
# Process examples array
if examples:
if len(examples) > 1:
content += "\n\n## Examples\n\n"
else:
content += "\n\n## Example\n\n"
for i, ex_line in enumerate(examples, start=1):
# Remove JS comments
cleaned_example = remove_js_comments(ex_line).strip()
# Attempt splitting if the user used ```js
if '```js' in cleaned_example:
comment, code = cleaned_example.split('```js', 1)
comment = comment.strip()
code = code.strip()
if len(examples) > 1:
content += f"**Example {i}:**\n\n{comment}\n\n"
content += f"```javascript\n{code}\n```\n"
else:
if len(examples) > 1:
content += f"**Example {i}:**\n\n{comment}\n\n"
# No special fences, just show as code
content += f"```javascript\n{cleaned_example}\n```\n"
return escape_text_outside_code_blocks(content)
def generate_events_summary(events):
"""
Create Events.md summary listing all events with their description.
"""
header = [
"# Events\n\n",
"| Event | Description |\n",
"| ----- | ----------- |\n"
]
lines = [
f"| [{ev['name']}](./{ev['name']}.md) | "
f"{remove_line_breaks(correct_description(ev.get('description', ''), isInTable=True))} |\n"
for ev in sorted(events, key=lambda e: e['name'])
]
return "".join(header + lines)
def generate_properties_markdown(properties, enumerations):
if properties is None:
return ''
content = "## Properties\n\n"
content += "| Name | Type | Description |\n"
content += "| ---- | ---- | ----------- |\n"
for prop in sorted(properties, key=lambda m: m['name']):
prop_name = prop['name']
prop_description = prop.get('description', 'No description provided.')
prop_description = remove_line_breaks(correct_description(prop_description, isInTable=True))
prop_types = prop['type']['names'] if prop.get('type') else []
param_types_md = generate_data_types_markdown(prop_types, enumerations)
content += f"| {prop_name} | {param_types_md} | {prop_description} |\n"
# Escape outside code blocks
return escape_text_outside_code_blocks(content)
def clean_editor_dir(editor_dir):
for root, dirs, files in os.walk(editor_dir, topdown=False):
for file in files:
if not file.endswith(('.json')):
os.remove(os.path.join(root, file))
for dir in dirs:
dir_path = os.path.join(root, dir)
# remove empty folder
if not os.listdir(dir_path):
os.rmdir(dir_path)
def clean_enum_files(editor_dir: str):
for root, _, files in os.walk(editor_dir, topdown=False):
for file in files:
if True == file.startswith('Event_') and False == file.endswith('.json'):
os.remove(os.path.join(root, file))
def process_events(data, editor_dir):
enumerations = []
events = []
for doclet in data:
kind = doclet.get('kind')
if kind == 'typedef':
enumerations.append(doclet)
elif kind == 'event':
events.append(doclet)
events_dir = f'{editor_dir}/Events'
clean_editor_dir(events_dir)
os.makedirs(events_dir, exist_ok=True)
used_enumerations.clear()
# пишем события
for ev in events:
path = os.path.join(events_dir, f"{ev['name']}.md")
write_markdown_file(path, generate_event_markdown(ev, enumerations))
if not ev.get('examples'):
missing_examples.append(os.path.relpath(path, events_dir))
# пишем перечисления, используемые событиями
enum_dir = os.path.join(editor_dir, 'Enumeration')
clean_enum_files(enum_dir)
os.makedirs(enum_dir, exist_ok=True)
prev = -1
while len(used_enumerations) != prev:
prev = len(used_enumerations)
for e in enumerations:
if e['name'] in used_enumerations:
generate_enumeration_markdown(e, enumerations)
for e in enumerations:
if e['name'] in used_enumerations:
path = os.path.join(enum_dir, f"Event_{e['name']}.md")
write_markdown_file(path, generate_enumeration_markdown(e, enumerations))
if not e.get('examples'):
missing_examples.append(os.path.relpath(path, editor_dir))
# events summary
write_markdown_file(os.path.join(events_dir, "Events.md"), generate_events_summary(events))
def generate_events(output_dir):
if output_dir.endswith('/'):
output_dir = output_dir[:-1]
tmp = os.path.join(output_dir, 'tmp_json')
generate_docs_events_json.generate(tmp, md=True)
for editor_name, folder in editors.items():
data = load_json(os.path.join(tmp, f"{editor_name}.json"))
process_events(data, os.path.join(output_dir, folder))
shutil.rmtree(tmp)
print("Done. Missing examples:", missing_examples)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Generate events documentation")
parser.add_argument(
"destination",
nargs="?",
default="../../../../../api.onlyoffice.com/site/docs/plugin-and-macros/interacting-with-editors/",
help="Output directory"
)
args = parser.parse_args()
generate_events(args.destination)

View File

@ -1,111 +0,0 @@
import os
import subprocess
import json
import argparse
import re
# Configuration files
configs = [
"./config/methods/common.json",
"./config/methods/word.json",
"./config/methods/cell.json",
"./config/methods/slide.json",
"./config/methods/forms.json"
]
root = '../../../../..'
def generate(output_dir, md=False):
if not os.path.exists(output_dir):
os.makedirs(output_dir)
# Generate JSON documentation
for config in configs:
editor_name = config.split('/')[-1].replace('.json', '')
output_file = os.path.join(output_dir, editor_name + ".json")
command = f"npx jsdoc -c {config} -X > {output_file}"
print(f"Generating {editor_name}.json: {command}")
subprocess.run(command, shell=True)
common_doclets_file = os.path.join(output_dir, 'common.json')
with open(common_doclets_file, 'r', encoding='utf-8') as f:
common_doclets_json = json.dumps(json.load(f))
os.remove(common_doclets_file)
# Append examples to JSON documentation
for config in configs:
if (config.find('common') != -1):
continue
editor_name = config.split('/')[-1].replace('.json', '')
example_folder_name = editor_name # name of folder with examples
output_file = os.path.join(output_dir, editor_name + ".json")
# Read the JSON file
with open(output_file, 'r', encoding='utf-8') as f:
data = json.load(f)
start_common_doclet_idx = len(data)
data += json.loads(common_doclets_json)
# Modify JSON data
for idx, doclet in enumerate(data):
if idx >= start_common_doclet_idx:
example_folder_name = 'common'
elif editor_name == 'forms':
example_folder_name = 'word'
if 'see' in doclet:
if doclet['see'] is not None:
doclet['see'][0] = doclet['see'][0].replace('{Editor}', example_folder_name.title())
file_path = f'{root}/' + doclet['see'][0]
if os.path.exists(file_path):
with open(file_path, 'r', encoding='utf-8') as see_file:
example_content = see_file.read()
# Extract the first line as a comment if it exists
lines = example_content.split('\n')
if lines[0].startswith('//'):
comment = lines[0] + '\n'
code_content = '\n'.join(lines[1:])
else:
comment = ''
code_content = example_content
doclet['examples'] = [remove_js_comments(comment) + code_content]
if md == False:
document_type = editor_name
if "forms" == document_type:
document_type = "pdf"
doclet['description'] = doclet['description'] + f'\n\n## Try it\n\n ```js document-builder={{"documentType": "{document_type}"}}\n{code_content}\n```'
# Write the modified JSON file back
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=4)
print("Documentation generation for plugin methods completed.")
def remove_builder_lines(text):
lines = text.splitlines() # Split text into lines
filtered_lines = [line for line in lines if not line.strip().startswith("builder.")]
return "\n".join(filtered_lines)
def remove_js_comments(text):
# Remove single-line comments, leaving text after //
text = re.sub(r'^\s*//\s?', '', text, flags=re.MULTILINE)
# Remove multi-line comments, leaving text after /*
text = re.sub(r'/\*\s*|\s*\*/', '', text, flags=re.DOTALL)
return text.strip()
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Generate documentation")
parser.add_argument(
"destination",
type=str,
help="Destination directory for the generated documentation",
nargs='?', # Indicates the argument is optional
default=f"{root}/office-js-api-declarations/office-js-api-plugins"
)
args = parser.parse_args()
generate(args.destination)

View File

@ -97,7 +97,7 @@ def get_projects(pro_json_path, platform):
records_src = data[module]
records = get_full_projects_list(data, records_src)
#print(records)
print(records)
for rec in records:
params = []
@ -133,7 +133,7 @@ def get_projects(pro_json_path, platform):
is_needed_platform_exist = False
for pl in platform_records:
if is_exist_in_array(params, pl):
is_needed_platform_exist = True
is_needed_platform_exist = True;
break
# if one config exists => all needed must exists
@ -144,7 +144,7 @@ def get_projects(pro_json_path, platform):
if is_exist_in_array(platform_records, item):
continue
is_needed_config_exist = True
break
break;
if is_needed_platform_exist:
if not is_exist_in_array(params, platform):
@ -164,18 +164,6 @@ def get_projects(pro_json_path, platform):
if is_append:
result.append(root_dir + record)
# delete duplicates
old_results = result
result = []
map_results = set()
for item in old_results:
proj = item.replace("\\", "/")
if proj in map_results:
continue
map_results.add(proj)
result.append(proj)
if is_log:
print(result)
return result

View File

@ -19,7 +19,6 @@
"core/PdfFile/PdfFile.pro",
"core/DjVuFile/DjVuFile.pro",
"core/XpsFile/XpsFile.pro",
"core/OFDFile/OFDFile.pro",
"core/HtmlFile2/HtmlFile2.pro",
"core/Fb2File/Fb2File.pro",
"core/EpubFile/CEpubFile.pro",
@ -93,7 +92,8 @@
"[win,linux]desktop-apps/win-linux/ASCDocumentEditor.pro",
"[win]desktop-apps/win-linux/extras/projicons/ProjIcons.pro",
"[win,!win_xp]desktop-apps/win-linux/extras/update-daemon/UpdateDaemon.pro"
"[win,!win_xp]desktop-apps/win-linux/extras/update-daemon/UpdateDaemon.pro",
"[win,!win_xp]desktop-apps/win-linux/extras/online-installer/OnlineInstaller.pro"
],
"mobile" : [

View File

@ -68,7 +68,6 @@ AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_HTMLR = AVS_OFFICESTUDIO_FILE_CROS
AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_HTMLRMenu = AVS_OFFICESTUDIO_FILE_CROSSPLATFORM + 0x0007
AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_HTMLRCanvas = AVS_OFFICESTUDIO_FILE_CROSSPLATFORM + 0x0008
AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDFA = AVS_OFFICESTUDIO_FILE_CROSSPLATFORM + 0x0009
AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_OFD = AVS_OFFICESTUDIO_FILE_CROSSPLATFORM + 0x000a
AVS_OFFICESTUDIO_FILE_IMAGE = 0x0400
AVS_OFFICESTUDIO_FILE_IMAGE_JPG = AVS_OFFICESTUDIO_FILE_IMAGE + 0x0001

View File

@ -1,5 +0,0 @@
qt_source*
qt_binary*
qt_build*
qt-*
gcc-linaro-*

View File

@ -1,103 +0,0 @@
#!/usr/bin/env python
import sys
import os
sys.path.append('../../../../scripts')
import base
def update_qmake_conf(arm_toolchain_bin):
replace_file = "./qt-everywhere-src-5.15.2/qtbase/mkspecs/linux-aarch64-gnu-g++/qmake.conf"
arm_toolchain_bin = os.path.abspath(arm_toolchain_bin)
replace_src = ""
replace_src += "# modifications to g++.conf\n"
replace_src += "QMAKE_CC = aarch64-linux-gnu-gcc\n"
replace_src += "QMAKE_CXX = aarch64-linux-gnu-g++\n"
replace_src += "QMAKE_LINK = aarch64-linux-gnu-g++\n"
replace_src += "QMAKE_LINK_SHLIB = aarch64-linux-gnu-g++\n"
replace_src += "\n"
replace_src += "# modifications to linux.conf\n"
replace_src += "QMAKE_AR = aarch64-linux-gnu-ar cqs\n"
replace_src += "QMAKE_OBJCOPY = aarch64-linux-gnu-objcopy\n"
replace_src += "QMAKE_NM = aarch64-linux-gnu-nm -P\n"
replace_src += "QMAKE_STRIP = aarch64-linux-gnu-strip\n"
replace_dst = ""
replace_dst += "# modifications to g++.conf\n"
replace_dst += "QMAKE_CC = " + arm_toolchain_bin + "/aarch64-linux-gnu-gcc\n"
replace_dst += "QMAKE_CXX = " + arm_toolchain_bin + "/aarch64-linux-gnu-g++\n"
replace_dst += "QMAKE_LINK = " + arm_toolchain_bin + "/aarch64-linux-gnu-g++\n"
replace_dst += "QMAKE_LINK_SHLIB = " + arm_toolchain_bin + "/aarch64-linux-gnu-g++\n"
replace_dst += "\n"
replace_dst += "# modifications to linux.conf\n"
replace_dst += "QMAKE_AR = " + arm_toolchain_bin + "/aarch64-linux-gnu-ar cqs\n"
replace_dst += "QMAKE_OBJCOPY = " + arm_toolchain_bin + "/aarch64-linux-gnu-objcopy\n"
replace_dst += "QMAKE_NM = " + arm_toolchain_bin + "/aarch64-linux-gnu-nm -P\n"
replace_dst += "QMAKE_STRIP = " + arm_toolchain_bin + "/aarch64-linux-gnu-strip\n"
base.replaceInFile(replace_file, replace_src, replace_dst)
def make(arm_toolchain_bin=""):
qt_build_path = os.path.dirname(os.path.abspath(__file__)) + "/qt_build/Qt-5.15.2/linux_arm64"
qt_params = ["-opensource",
"-confirm-license",
"-release",
"-shared",
"-accessibility",
"-prefix", "\"" + qt_build_path + "\"",
"-extprefix", "\"" + qt_build_path + "\"",
"-hostprefix", "\"" + qt_build_path + "\"",
"-c++std", "c++11",
"-qt-zlib",
"-qt-libpng",
"-qt-libjpeg",
"-qt-pcre",
"-no-sql-sqlite",
"-no-opengl",
"-nomake", "examples",
"-nomake", "tests",
"-skip", "qtlocation",
"-skip", "qtserialport",
"-skip", "qtsensors",
"-skip", "qtxmlpatterns",
"-skip", "qt3d",
"-skip", "qtwebview",
"-skip", "qtwebengine",
"-skip", "qtdeclarative",
"-xplatform", "linux-aarch64-gnu-g++", # be sure that aarch64 gnu compiler is installed
"-no-pch"]
qt_params_str = ""
for param in qt_params:
qt_params_str += (param + " ")
qt_url = "https://github.com/ONLYOFFICE-data/build_tools_data/raw/refs/heads/master/qt/qt-everywhere-src-5.15.2.tar.xz"
if not base.is_file("./qt_source_5.15.2.tar.xz"):
base.download(qt_url, "./qt_source_5.15.2.tar.xz")
if not base.is_dir("./qt-everywhere-src-5.15.2"):
base.cmd("tar", ["-xf", "./qt_source_5.15.2.tar.xz"])
# https://bugreports.qt.io/browse/QTBUG-93452
# for GCC 11 and Qt5/Qt6
additional_gcc_11 = "#ifdef __cplusplus\n#include <limits>\n#endif\n"
chanage_file = "./qt-everywhere-src-5.15.2/qtbase/src/corelib/global/qglobal.h"
filedata = base.readFile(chanage_file)
if filedata.find(additional_gcc_11) == -1:
filedata = additional_gcc_11 + filedata
base.writeFile(chanage_file, filedata)
if arm_toolchain_bin != "":
update_qmake_conf(arm_toolchain_bin)
base.cmd_in_dir("./qt-everywhere-src-5.15.2", "./configure " + qt_params_str)
base.cmd_in_dir("./qt-everywhere-src-5.15.2", "make -j4")
base.cmd_in_dir("./qt-everywhere-src-5.15.2", "make install")
if __name__ == "__main__":
arm_toolchain_path = "./gcc-linaro-5.4.1-2017.05-x86_64_aarch64-linux-gnu/bin"
if len(sys.argv) != 1:
arm_toolchain_path = sys.argv[1]
make(arm_toolchain_path)

View File

@ -1,16 +0,0 @@
#!/usr/bin/env python
import sys
import os
sys.path.append('../../../../scripts')
import base
def make():
arm_toolchain_url = 'https://releases.linaro.org/components/toolchain/binaries/5.4-2017.05/aarch64-linux-gnu/'
arm_toolchain_tar_filename = 'gcc-linaro-5.4.1-2017.05-x86_64_aarch64-linux-gnu.tar.xz'
base.cmd2('wget', [arm_toolchain_url + arm_toolchain_tar_filename])
base.cmd2('tar', ['-xf', arm_toolchain_tar_filename])
if __name__ == "__main__":
make()

View File

@ -1,22 +0,0 @@
#!/usr/bin/env python
import sys
import os
sys.path.append('../../../scripts')
import base
def make():
qt_build_path = os.path.dirname(os.path.abspath(__file__)) + "/qt_build/Qt-5.15.2"
qt_binary_url = "https://github.com/ONLYOFFICE-data/build_tools_data/raw/refs/heads/master/qt/qt_binary_linux_arm64.7z"
if not base.is_file("./qt_binary_linux_arm64.7z"):
base.download(qt_binary_url, "./qt_binary_linux_arm64.7z")
if not base.is_dir(qt_build_path):
os.makedirs(qt_build_path)
base.cmd("tar", ["-xf", "./qt_binary_linux_arm64.7z", "-C", qt_build_path])
if __name__ == "__main__":
make()

View File

@ -1,10 +0,0 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

View File

@ -1,5 +0,0 @@
{
"exclude": [
"qt-everywhere-src-5.15.2/**"
]
}

View File

@ -20,7 +20,7 @@ def get_branch_name(directory):
def install_qt():
# qt
if not base.is_file("./qt_source_5.9.9.tar.xz"):
base.download("https://github.com/ONLYOFFICE-data/build_tools_data/raw/refs/heads/master/qt/qt-everywhere-opensource-src-5.9.9.tar.xz", "./qt_source_5.9.9.tar.xz")
base.download("https://download.qt.io/new_archive/qt/5.9/5.9.9/single/qt-everywhere-opensource-src-5.9.9.tar.xz", "./qt_source_5.9.9.tar.xz")
if not base.is_dir("./qt-everywhere-opensource-src-5.9.9"):
base.cmd("tar", ["-xf", "./qt_source_5.9.9.tar.xz"])
@ -57,7 +57,7 @@ def install_qt():
return
def install_qt_prebuild():
url_amd64 = "https://github.com/ONLYOFFICE-data/build_tools_data/raw/refs/heads/master/qt/qt_binary_linux_amd64.7z"
url_amd64 = "https://s3.eu-west-1.amazonaws.com/static-doc.teamlab.eu.com/qt/5.9.9/linux_amd64/qt_binary.7z"
base.download(url_amd64, "./qt_amd64.7z")
base.extract("./qt_amd64.7z", "./qt_build")
base.create_dir("./qt_build/Qt-5.9.9")
@ -71,10 +71,7 @@ if not base.is_file("./node_js_setup_14.x"):
if not base.is_dir("./qt_build"):
print("install qt...")
if base.get_env("DO_NOT_USE_PREBUILD_QT") == "1":
install_qt()
else:
install_qt_prebuild()
install_qt_prebuild()
branch = get_branch_name("../..")

BIN
tools/linux/python3.tar.gz Normal file

Binary file not shown.

View File

@ -1,82 +0,0 @@
#!/usr/bin/env python
import sys
sys.path.append('../../../scripts')
import base
import os
import shutil
import fix_symlinks
def bash_chroot(command, sysroot):
base.cmd2('sudo -S chroot', [sysroot, '/bin/bash -c', '\"' + command + ' \"'])
def download_sysroot():
curr_dir = base.get_script_dir(__file__)
tmp_sysroot_ubuntu_dir = curr_dir + '/sysroot_ubuntu_1604'
if os.path.isdir(tmp_sysroot_ubuntu_dir):
shutil.rmtree(tmp_sysroot_ubuntu_dir)
# debootstrap for downloading sysroot
base.cmd2('sudo -S apt-get', ['install', 'debootstrap'])
archive_ubuntu_url = 'http://archive.ubuntu.com/ubuntu/'
base.cmd2('sudo -S debootstrap', ['--arch=amd64', 'xenial', tmp_sysroot_ubuntu_dir, archive_ubuntu_url])
# setup a new sources
base.cmd2('sudo -S cp', [curr_dir + '/sources.list', tmp_sysroot_ubuntu_dir + '/etc/apt/sources.list'])
bash_chroot('apt update -y', tmp_sysroot_ubuntu_dir)
bash_chroot('apt upgrade -y', tmp_sysroot_ubuntu_dir)
apt_libs = ["build-essential"]
apt_libs += ["libpthread-stubs0-dev"]
apt_libs += ["zlib1g-dev"]
apt_libs += ["curl"]
apt_libs += ["libc6-dev"]
apt_libs += ["glib-2.0-dev"]
apt_libs += ["libglu1-mesa-dev"]
apt_libs += ["libgtk-3-dev"]
apt_libs += ["libpulse-dev"]
apt_libs += ["libasound2-dev"]
apt_libs += ["libatspi2.0-dev"]
apt_libs += ["libcups2-dev"]
apt_libs += ["libdbus-1-dev"]
apt_libs += ["libicu-dev"]
apt_libs += ["libgstreamer1.0-dev"]
apt_libs += ["libgstreamer-plugins-base1.0-dev"]
apt_libs += ["libx11-xcb-dev"]
apt_libs += ["libxcb*"]
apt_libs += ["libxi-dev"]
apt_libs += ["libxrender-dev"]
apt_libs += ["libxss-dev"]
apt_libs += ["libxkbcommon-dev"]
apt_libs += ["libxkbcommon-x11-dev"]
apt_libs += ["libnotify-dev"]
apt_libs += ["gtk+-3.0-dev"]
apt_libs_str = ""
for apt_lib in apt_libs:
apt_libs_str += apt_lib + " "
bash_chroot('apt install -y ' + apt_libs_str, tmp_sysroot_ubuntu_dir)
# # downloading arm toolchain
arm_toolchain_url = 'https://releases.linaro.org/components/toolchain/binaries/5.4-2017.05/aarch64-linux-gnu/'
arm_toolchain_tar_filename = 'gcc-linaro-5.4.1-2017.05-x86_64_aarch64-linux-gnu.tar.xz'
arm_toolchain_output_dir = 'gcc-linaro-5.4.1-2017.05-x86_64_aarch64-linux-gnu'
base.cmd2('wget', [arm_toolchain_url + arm_toolchain_tar_filename])
base.cmd2('tar', ['-xf', arm_toolchain_tar_filename])
base.cmd2('sudo -S rsync', ['-avh', '--progress', curr_dir + '/' + arm_toolchain_output_dir + '/', tmp_sysroot_ubuntu_dir + '/usr/'])
shutil.rmtree(arm_toolchain_output_dir)
os.remove(arm_toolchain_tar_filename)
base.cmd2('sudo -S chmod', ['-R', 'o+rwx', tmp_sysroot_ubuntu_dir])
# fix symlinks
fix_symlinks.fix_symlinks(tmp_sysroot_ubuntu_dir)
return
if __name__ == '__main__':
download_sysroot()

View File

@ -1,4 +0,0 @@
set(CMAKE_C_FLAGS $ENV{CFLAGS})
set(CMAKE_CXX_FLAGS $ENV{CXXFLAGS})
set(CMAKE_C_LINKER_FLAGS $ENV{LDFLAGS})
set(CMAKE_CXX_LINKER_FLAGS $ENV{LDFLAGS})

View File

@ -1,45 +0,0 @@
import os
import sys
import uuid
# change symbolic link to relative paths
def fix_symlinks(top_dir='./sysroot_ubuntu_1604'):
for root, dirs, files in os.walk(top_dir):
for name in files:
path = os.path.join(root, name)
if not os.path.islink(path):
continue
try:
target = os.readlink(path)
except OSError as e:
print(f"Error reading link '{path}': {e}", file=sys.stderr)
continue
if not target.startswith('/'):
continue
new_target = top_dir + target
new_target_rel = os.path.relpath(new_target, os.path.dirname(path))
temp_name = f".tmp.{uuid.uuid4().hex}"
temp_path = os.path.join(root, temp_name)
try:
os.symlink(new_target_rel, temp_path)
except OSError as e:
print(f"Failed to create temporary symlink for '{path}': {e}", file=sys.stderr)
continue
try:
os.replace(temp_path, path)
print(f"Updated: {path} -> {new_target_rel}")
except OSError as e:
print(f"Failed to replace symlink '{path}': {e}", file=sys.stderr)
try:
os.unlink(temp_path)
except OSError:
pass
if __name__ == "__main__":
if len(sys.argv) > 1:
directory = sys.argv[1]
else:
directory = './sysroot_ubuntu_1604'
fix_symlinks(directory)

View File

@ -1,51 +0,0 @@
#deb cdrom:[Ubuntu 16.04.2 LTS _Xenial Xerus_ - Release amd64 (20170215.2)]/ xenial main restricted
# See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to
# newer versions of the distribution.
deb http://us.archive.ubuntu.com/ubuntu/ xenial main restricted
# deb-src http://us.archive.ubuntu.com/ubuntu/ xenial main restricted
## Major bug fix updates produced after the final release of the
## distribution.
deb http://us.archive.ubuntu.com/ubuntu/ xenial-updates main restricted
# deb-src http://us.archive.ubuntu.com/ubuntu/ xenial-updates main restricted
## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
## team. Also, please note that software in universe WILL NOT receive any
## review or updates from the Ubuntu security team.
deb http://us.archive.ubuntu.com/ubuntu/ xenial universe
# deb-src http://us.archive.ubuntu.com/ubuntu/ xenial universe
deb http://us.archive.ubuntu.com/ubuntu/ xenial-updates universe
# deb-src http://us.archive.ubuntu.com/ubuntu/ xenial-updates universe
## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
## team, and may not be under a free licence. Please satisfy yourself as to
## your rights to use the software. Also, please note that software in
## multiverse WILL NOT receive any review or updates from the Ubuntu
## security team.
deb http://us.archive.ubuntu.com/ubuntu/ xenial multiverse
# deb-src http://us.archive.ubuntu.com/ubuntu/ xenial multiverse
deb http://us.archive.ubuntu.com/ubuntu/ xenial-updates multiverse
# deb-src http://us.archive.ubuntu.com/ubuntu/ xenial-updates multiverse
## N.B. software from this repository may not have been tested as
## extensively as that contained in the main release, although it includes
## newer versions of some applications which may provide useful features.
## Also, please note that software in backports WILL NOT receive any review
## or updates from the Ubuntu security team.
deb http://us.archive.ubuntu.com/ubuntu/ xenial-backports main restricted universe multiverse
# deb-src http://us.archive.ubuntu.com/ubuntu/ xenial-backports main restricted universe multiverse
## Uncomment the following two lines to add software from Canonical's
## 'partner' repository.
## This software is not part of Ubuntu, but is offered by Canonical and the
## respective vendors as a service to Ubuntu users.
# deb http://archive.canonical.com/ubuntu xenial partner
# deb-src http://archive.canonical.com/ubuntu xenial partner
deb http://security.ubuntu.com/ubuntu xenial-security main restricted
# deb-src http://security.ubuntu.com/ubuntu xenial-security main restricted
deb http://security.ubuntu.com/ubuntu xenial-security universe
# deb-src http://security.ubuntu.com/ubuntu xenial-security universe
deb http://security.ubuntu.com/ubuntu xenial-security multiverse
# deb-src http://security.ubuntu.com/ubuntu xenial-security multiverse

View File

@ -1,5 +0,0 @@
tmp.bat
qt_source*
qt_binary*
qt_build*
qt-*

View File

@ -1,77 +0,0 @@
import sys
import os
sys.path.append('../../../scripts')
import base
def get_vs_path(version = "2019"):
vs_path = ""
programFilesDir = base.get_env("ProgramFiles")
if ("" != base.get_env("ProgramFiles(x86)")):
programFilesDir = base.get_env("ProgramFiles(x86)")
if ("2015" == version):
vs_path = programFilesDir + "/Microsoft Visual Studio 14.0/VC"
elif ("2019" == version):
if base.is_dir(programFilesDir + "/Microsoft Visual Studio/2019/Enterprise/VC/Auxiliary/Build"):
vs_path = programFilesDir + "/Microsoft Visual Studio/2019/Enterprise/VC/Auxiliary/Build"
elif base.is_dir(programFilesDir + "/Microsoft Visual Studio/2019/Professional/VC/Auxiliary/Build"):
vs_path = programFilesDir + "/Microsoft Visual Studio/2019/Professional/VC/Auxiliary/Build"
else:
vs_path = programFilesDir + "/Microsoft Visual Studio/2019/Community/VC/Auxiliary/Build"
return vs_path
def make():
qt_build_path = os.path.dirname(os.path.abspath(__file__)) + "/qt_build/Qt-5.15.2/win_arm64"
qt_params = ["-opensource",
"-confirm-license",
"-release",
"-shared",
"-accessibility",
"-prefix", "\"" + qt_build_path + "\"",
"-extprefix", "\"" + qt_build_path + "\"",
"-hostprefix", "\"" + qt_build_path + "\"",
"-c++std", "c++11",
"-qt-zlib",
"-qt-libpng",
"-qt-libjpeg",
"-qt-pcre",
"-no-sql-sqlite",
"-no-qml-debug",
"-nomake", "examples",
"-nomake", "tests",
"-skip", "qtlocation",
"-skip", "qtserialport",
"-skip", "qtsensors",
"-skip", "qtxmlpatterns",
"-skip", "qt3d",
"-skip", "qtwebview",
"-skip", "qtwebengine",
"-xplatform", "win32-arm64-msvc2017",
"-mp",
"-no-pch"]
qt_params_str = ""
for param in qt_params:
qt_params_str += (param + " ")
qt_url = "https://github.com/ONLYOFFICE-data/build_tools_data/raw/refs/heads/master/qt/qt-everywhere-src-5.15.2.tar.xz"
if not base.is_file("./qt_source_5.15.2.tar.xz"):
base.download(qt_url, "./qt_source_5.15.2.tar.xz")
if not base.is_dir("./qt-everywhere-src-5.15.2"):
base.cmd("tar", ["-xf", "./qt_source_5.15.2.tar.xz"])
vs_path = get_vs_path()
vcvarsall_host_arch = "x64"
qt_build_bat = []
qt_build_bat.append("call \"" + vs_path + "/vcvarsall.bat\" " + vcvarsall_host_arch) # for nmake
qt_build_bat.append("cd qt-everywhere-src-5.15.2")
qt_build_bat.append("call configure " + qt_params_str)
qt_build_bat.append("call nmake")
qt_build_bat.append("call nmake install")
base.run_as_bat(qt_build_bat)
if __name__ == "__main__":
make()

View File

@ -1,20 +0,0 @@
import sys
import os
sys.path.append('../../../scripts')
import base
def make():
qt_build_path = os.path.dirname(os.path.abspath(__file__)) + "/qt_build/Qt-5.15.2"
qt_binary_url = "https://github.com/ONLYOFFICE-data/build_tools_data/raw/refs/heads/master/qt/qt_binary_win_arm64.7z"
if not base.is_file("./qt_binary_win_arm64.7z"):
base.download(qt_binary_url, "./qt_binary_win_arm64.7z")
if not base.is_dir(qt_build_path):
os.makedirs(qt_build_path)
base.extract("./qt_binary_win_arm64.7z", qt_build_path)
if __name__ == "__main__":
base.configure_common_apps()
make()

Some files were not shown because too many files have changed in this diff Show More