diff --git a/Dockerfile b/Dockerfile index 0cd5a0a..eb8cb99 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,11 +4,17 @@ 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 python \ - python3 \ + apt-get -y install tar \ 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 && \ + tar -xzf /build_tools/tools/linux/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"] diff --git a/configure.py b/configure.py index 857b50f..eb95088 100755 --- a/configure.py +++ b/configure.py @@ -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', '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', '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("--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") diff --git a/defaults b/defaults index 7428cc6..1d71ba7 100644 --- a/defaults +++ b/defaults @@ -1,3 +1,3 @@ -sdkjs-plugin="photoeditor, macros, ocr, translator, thesaurus, youtube, highlightcode, zotero" -sdkjs-plugin-server="speech, zotero, mendeley, speechrecognition, drawio" +sdkjs-plugin="ai, photoeditor, ocr, translator, thesaurus, youtube, highlightcode" +sdkjs-plugin-server="speech, zotero, mendeley, speechrecognition" sdkjs-addons="sdkjs-forms" diff --git a/scripts/base.py b/scripts/base.py index b5ba96a..8f89fae 100644 --- a/scripts/base.py +++ b/scripts/base.py @@ -15,6 +15,7 @@ import stat import json __file__script__path__ = os.path.dirname( os.path.realpath(__file__)) +icu_ver = "74" # common functions -------------------------------------- def get_script_dir(file=""): @@ -736,6 +737,14 @@ 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): @@ -830,6 +839,9 @@ 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 @@ -854,6 +866,12 @@ 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) @@ -862,7 +880,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_version()) + copy_file(src_file, dir + "/lib" + lib + ".so." + qt_major) else: libFramework = lib libFramework = libFramework.replace("Qt5", "Qt") @@ -1269,12 +1287,13 @@ def mac_correct_rpath_binary(path, libs): 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.58", []) - mac_correct_rpath_library("icuuc.58", ["icudata.58"]) - mac_correct_rpath_library("UnicodeConverter", ["icuuc.58", "icudata.58"]) + 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("kernel", ["UnicodeConverter"]) mac_correct_rpath_library("kernel_network", ["UnicodeConverter", "kernel"]) mac_correct_rpath_library("graphics", ["UnicodeConverter", "kernel"]) @@ -1291,32 +1310,31 @@ def mac_correct_rpath_x2t(dir): mac_correct_rpath_library("HWPFile", ["UnicodeConverter", "kernel", "graphics"]) 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", "OFDFile", "DjVuFile", "HtmlFile2", "Fb2File", "EpubFile", "doctrenderer", "DocxRenderer", "IWorkFile", "HWPFile"]) + mac_correct_rpath_binary("./x2t", mac_icu_libs + ["UnicodeConverter", "kernel", "kernel_network", "graphics", "PdfFile", "XpsFile", "OFDFile", "DjVuFile", "HtmlFile2", "Fb2File", "EpubFile", "doctrenderer", "DocxRenderer", "IWorkFile", "HWPFile"]) if is_file("./allfontsgen"): 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"]) + mac_correct_rpath_binary("./allfontsgen", mac_icu_libs + ["UnicodeConverter", "kernel", "graphics"]) if is_file("./allthemesgen"): 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", "OFDFile", "DjVuFile", "DocxRenderer"]) + mac_correct_rpath_binary("./allthemesgen", mac_icu_libs + ["UnicodeConverter", "kernel", "graphics", "kernel_network", "doctrenderer", "PdfFile", "XpsFile", "OFDFile", "DjVuFile", "DocxRenderer"]) if is_file("./pluginsmanager"): 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"]) + mac_correct_rpath_binary("./pluginsmanager", mac_icu_libs + ["UnicodeConverter", "kernel", "kernel_network"]) if is_file("./vboxtester"): 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"]) + mac_correct_rpath_binary("./vboxtester", mac_icu_libs + ["UnicodeConverter", "kernel", "kernel_network"]) os.chdir(cur_dir) return def mac_add_loader_path_to_rpath(libs): - icu_libs = {"icudata.58", "icuuc.58"} for lib in libs: if config.check_option("config", "bundle_dylibs"): # icu libs are linked statically for frameworks - if lib in icu_libs: + if lib in mac_icu_libs: continue cmd("install_name_tool", ["-add_rpath", "@loader_path/../../..", lib + ".framework/" + lib], True) else: @@ -1327,9 +1345,10 @@ def mac_correct_rpath_docbuilder(dir): os.chdir(dir) cmd("chmod", ["-v", "+x", "./docbuilder"]) cmd("install_name_tool", ["-add_rpath", "@executable_path", "./docbuilder"], True) - mac_correct_rpath_binary("./docbuilder", ["icudata.58", "icuuc.58", "UnicodeConverter", "kernel", "kernel_network", "graphics", "PdfFile", "XpsFile", "OFDFile", "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", "OFDFile", "DjVuFile", "DocxRenderer"]) - mac_add_loader_path_to_rpath(["icuuc.58", "UnicodeConverter", "kernel", "kernel_network", "graphics", "doctrenderer", "PdfFile", "XpsFile", "OFDFile", "DjVuFile", "DocxRenderer", "docbuilder.c"]) + 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_add_loader_path_to_rpath(["icuuc." + icu_ver, "UnicodeConverter", "kernel", "kernel_network", "graphics", "doctrenderer", "PdfFile", "XpsFile", "OFDFile", "DjVuFile", "DocxRenderer", "docbuilder.c"]) os.chdir(cur_dir) return @@ -1375,7 +1394,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.58", "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." + icu_ver, "doctrenderer.so", "graphics.so", "kernel.so", "kernel_network.so", "UnicodeConverter.so", "PdfFile.so", "XpsFile.so", "OFDFile.so", "DjVuFile.so", "DocxRenderer.so"]) return def common_check_version(name, good_version, clean_func): @@ -1458,7 +1477,7 @@ 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, macros, highlightcode, doc2md" + plugins_list_config="photoeditor, highlightcode, doc2md" if ("" == plugins_list_config): return plugins_list = plugins_list_config.rsplit(", ") @@ -1713,7 +1732,7 @@ def convert_ios_framework_to_xcframework_folder(folder, libs): def change_elf_rpath(path, origin): # excludes --- - if (-1 != path.find("libicudata.so.58")): + if (-1 != path.find("libicudata.so." + icu_ver)): return # ------------ tools_dir = get_script_dir() + "/../tools/linux/elf/" @@ -1903,6 +1922,9 @@ def create_x2t_js_cache(dir, product, platform): cmd_in_dir_qemu(platform, dir, "./x2t", ["-create-js-snapshots"], True) return + if platform == "win_arm64": # copying sdkjs later + return + cmd_in_dir(dir, "./x2t", ["-create-js-snapshots"], True) return @@ -1910,3 +1932,25 @@ 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", root_dir + "/icudt" + icu_ver + "l.dat") + return + + src_dir = core_dir + "/Common/3dParty/icu/" + platform + "/build" + + if (0 == platform.find("win")): + copy_file(src_dir + "/icudt" + icu_ver + ".dll", dst_dir + "/icudt" + icu_ver + ".dll") + copy_file(src_dir + "/icuuc" + icu_ver + ".dll", dst_dir + "/icuuc" + icu_ver + ".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") + + return diff --git a/scripts/build_js.py b/scripts/build_js.py index 5405e73..ed3d6c6 100644 --- a/scripts/build_js.py +++ b/scripts/build_js.py @@ -65,10 +65,6 @@ 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") diff --git a/scripts/config.py b/scripts/config.py index d625638..6a80cda 100644 --- a/scripts/config.py +++ b/scripts/config.py @@ -24,7 +24,7 @@ def parse(): # all platforms global platforms - platforms = ["win_64", "win_32", "win_64_xp", "win_32_xp", + platforms = ["win_64", "win_32", "win_64_xp", "win_32_xp", "win_arm64", "linux_64", "linux_32", "linux_arm64", "mac_64", "mac_arm64", "ios", @@ -56,6 +56,10 @@ def parse(): if ("mac" == host_platform) and check_option("platform", "mac_arm64") and not base.is_os_arm(): if not check_option("platform", "mac_64"): options["platform"] = "mac_64 " + options["platform"] + + 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"): @@ -139,6 +143,9 @@ 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" diff --git a/scripts/core_common/make_common.py b/scripts/core_common/make_common.py index 8801094..f8e8384 100755 --- a/scripts/core_common/make_common.py +++ b/scripts/core_common/make_common.py @@ -21,6 +21,7 @@ import md import hunspell import glew import harfbuzz +import oo_brotli import hyphen import googletest import libvlc @@ -51,6 +52,7 @@ def make(): glew.make() hyphen.make() googletest.make() + oo_brotli.make() if config.check_option("build-libvlc", "1"): libvlc.make() diff --git a/scripts/core_common/modules/android/icu_android.py b/scripts/core_common/modules/android/icu_android.py index fb37b64..bfa06a1 100755 --- a/scripts/core_common/modules/android/icu_android.py +++ b/scripts/core_common/modules/android/icu_android.py @@ -57,14 +57,9 @@ cpp_flags = [ def fetch_icu(): if not base.is_dir(current_dir + "icu"): - base.cmd("git", ["clone", "--depth", "1", "--branch", "maint/maint-" + icu_major, "https://github.com/unicode-org/icu.git", current_dir + "icu2"]) + base.cmd("git", ["clone", "--depth", "1", "--branch", "release-" + major + "-" + minor, "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(): diff --git a/scripts/core_common/modules/boost.py b/scripts/core_common/modules/boost.py index f6dca55..42d9a65 100644 --- a/scripts/core_common/modules/boost.py +++ b/scripts/core_common/modules/boost.py @@ -85,8 +85,18 @@ 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_32") + correct_install_includes_win(base_dir, "win_arm64") if config.check_option("platform", "linux_64") and not base.is_dir("../build/linux_64"): addon_config = [] diff --git a/scripts/core_common/modules/cef.py b/scripts/core_common/modules/cef.py index 3067b71..0556086 100644 --- a/scripts/core_common/modules/cef.py +++ b/scripts/core_common/modules/cef.py @@ -13,13 +13,13 @@ def make(): old_cur = os.getcwd() os.chdir(base_dir) - platforms = ["win_64", "win_32", "win_64_xp", "win_32_xp", "linux_64", "linux_32", "mac_64", "mac_arm64"] + platforms = ["win_64", "win_32", "win_64_xp", "win_32_xp", "linux_64", "linux_32", "mac_64", "mac_arm64", "win_arm64"] for platform in platforms: if not config.check_option("platform", platform): continue - url = "http://d2ettrnqo7v976.cloudfront.net/cef/" + url = "https://github.com/ONLYOFFICE-data/build_tools_data/raw/refs/heads/master/cef/" archive_name = "./cef_binary.7z" if (-1 != platform.find("_xp")): diff --git a/scripts/core_common/modules/icu.py b/scripts/core_common/modules/icu.py index c3ae287..7657db6 100755 --- a/scripts/core_common/modules/icu.py +++ b/scripts/core_common/modules/icu.py @@ -12,10 +12,9 @@ import icu_android def fetch_icu(major, minor): if (base.is_dir("./icu2")): base.delete_dir_with_access_error("icu2") - base.cmd("git", ["clone", "--depth", "1", "--branch", "maint/maint-" + major, "https://github.com/unicode-org/icu.git", "./icu2"]) + base.cmd("git", ["clone", "--depth", "1", "--branch", "release-" + major + "-" + minor, "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(): @@ -36,15 +35,15 @@ def make(): old_cur = os.getcwd() os.chdir(base_dir) - base.check_module_version("3", clear_module) + base.check_module_version("6", clear_module) if (-1 != config.option("platform").find("android")): icu_android.make() os.chdir(base_dir) - icu_major = "58" - icu_minor = "3" + icu_major = "74" + icu_minor = "2" if not base.is_dir("icu"): fetch_icu(icu_major, icu_minor) @@ -58,36 +57,56 @@ 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") + for platform in need_platforms: if not config.check_option("platform", platform) and not config.check_option("platform", platform + "_xp"): continue + 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")) + + args = { + "win_32" : { + "msbuild_platfrom" : "Win32", + "vcvarsall_arch" : "x86", + "out_bin_dir" : "icu/bin/", + "out_lib_dir" : "icu/lib/" + }, + "win_64" : { + "msbuild_platfrom" : "X64", + "vcvarsall_arch" : "x64", + "out_bin_dir" : "icu/bin64/", + "out_lib_dir" : "icu/lib64/" + }, + "win_arm64" : { + "msbuild_platfrom" : "ARM64", + "vcvarsall_arch" : "x64_arm64", + "out_bin_dir" : "icu/binARM64/", + "out_lib_dir" : "icu/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 icu/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) - 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/") + base.copy_file(platform_args['out_bin_dir'] + "icudt" + icu_major + ".dll", platform + "/build/") + base.copy_file(platform_args['out_bin_dir'] + "icuuc" + icu_major + ".dll", platform + "/build/") + base.copy_file(platform_args['out_lib_dir'] + "icudt.lib", platform + "/build/") + base.copy_file(platform_args['out_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") diff --git a/scripts/core_common/modules/icu_mac.py b/scripts/core_common/modules/icu_mac.py index 9e9a3d7..b9ee8dd 100755 --- a/scripts/core_common/modules/icu_mac.py +++ b/scripts/core_common/modules/icu_mac.py @@ -5,37 +5,29 @@ sys.path.append('../..') import base import os -def change_icu_defs(current_dir, arch): - icudef_file = current_dir + "/icudefs.mk" - icudef_file_old = current_dir + "/icudefs.mk.back" +def change_icu_defs(arch): + old_env = dict(os.environ) param = "-arch x86_64" if arch == "arm64": - param = "-arch arm64 -isysroot " + base.find_mac_sdk() + param = "-arch arm64" + param += " -isysroot " + base.find_mac_sdk() param += " -mmacosx-version-min=10.12" - base.copy_file(icudef_file, icudef_file_old) + os.environ["CFLAGS"] = param + os.environ["CXXFLAGS"] = param + " --std=c++11" + os.environ["LDFLAGS"] = param - 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 =") + return old_env +def restore_icu_defs(old_env): + os.environ.clear() + os.environ.update(old_env) return -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" +icu_major = "74" +icu_minor = "2" current_dir_old = os.getcwd() current_dir = base.get_script_dir() + "/../../core/Common/3dParty/icu" @@ -46,29 +38,33 @@ 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") - base.cmd("../icu/source/runConfigureICU", ["MacOSX", - "--prefix=" + current_dir + "/mac_cross_64", "--enable-static", "CFLAGS=-Os CXXFLAGS=--std=c++11"]) + old_env = change_icu_defs("x86_64") - change_icu_defs(current_dir + "/mac_cross_64", "x86_64") + base.cmd("../icu/source/runConfigureICU", ["MacOSX", + "--prefix=" + current_dir + "/mac_cross_64", "--enable-static"]) base.cmd("make", ["-j4"]) base.cmd("make", ["install"], True) - restore_icu_defs(current_dir + "/mac_cross_64") + restore_icu_defs(old_env) os.chdir(current_dir) os.chdir(current_dir + "/icu/source") -base.cmd("./configure", ["--prefix=" + current_dir + "/mac_arm_64", - "--with-cross-build=" + current_dir + "/mac_cross_64", "--enable-static", "VERBOSE=1"]) +old_env = change_icu_defs("arm64") -change_icu_defs(current_dir + "/icu/source", "arm64") +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) base.cmd("make", ["-j4"]) base.cmd("make", ["install"]) -restore_icu_defs(current_dir + "/icu/source") +restore_icu_defs(old_env) os.chdir(current_dir) diff --git a/scripts/core_common/modules/oo_brotli.py b/scripts/core_common/modules/oo_brotli.py new file mode 100644 index 0000000..d672885 --- /dev/null +++ b/scripts/core_common/modules/oo_brotli.py @@ -0,0 +1,15 @@ +#!/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() diff --git a/scripts/core_common/modules/openssl.py b/scripts/core_common/modules/openssl.py index 3f3dd17..938a398 100644 --- a/scripts/core_common/modules/openssl.py +++ b/scripts/core_common/modules/openssl.py @@ -54,6 +54,14 @@ 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") diff --git a/scripts/core_common/modules/v8.py b/scripts/core_common/modules/v8.py index e02d107..f1fe806 100644 --- a/scripts/core_common/modules/v8.py +++ b/scripts/core_common/modules/v8.py @@ -26,6 +26,8 @@ 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"): diff --git a/scripts/core_common/modules/v8_89.py b/scripts/core_common/modules/v8_89.py index 2c920a4..f6c48bd 100644 --- a/scripts/core_common/modules/v8_89.py +++ b/scripts/core_common/modules/v8_89.py @@ -44,7 +44,13 @@ 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"): @@ -68,12 +74,21 @@ def make_args(args, platform, is_64=True, is_debug=False): return "--args=\"" + " ".join(args_copy) + "\"" -def ninja_windows_make(args, is_64=True, is_debug=False): +def ninja_windows_make(args, is_64=True, is_debug=False, is_arm=False): directory_out = "out.gn/" - directory_out += ("win_64/" if is_64 else "win_32/") + + if is_arm: + directory_out += "win_arm64/" + else: + directory_out += ("win_64/" if is_64 else "win_32/") + directory_out += ("debug" if is_debug else "release") - base.cmd2("gn", ["gen", directory_out, make_args(args, "windows", is_64, is_debug)]) + 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.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") @@ -83,7 +98,10 @@ def ninja_windows_make(args, is_64=True, is_debug=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") @@ -149,8 +167,19 @@ 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", "") @@ -187,6 +216,9 @@ 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")): diff --git a/scripts/deploy_builder.py b/scripts/deploy_builder.py index acfc02f..8231bc4 100644 --- a/scripts/deploy_builder.py +++ b/scripts/deploy_builder.py @@ -15,6 +15,7 @@ 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) @@ -57,17 +58,7 @@ def make(): # base.generate_check_linux_system(git_dir + "/build_tools", root_dir) # icu - 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") and not config.check_option("config", "bundle_dylibs")): - 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") + base.deploy_icu(core_dir, root_dir, platform) # doctrenderer if isWindowsXP: @@ -129,6 +120,18 @@ def make(): 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") + + if native_platform == "win_arm64": + base.delete_dir(root_dir + "/sdkjs") + base.copy_dir(root_dir_win64 + "/sdkjs", root_dir + "/sdkjs") + return + # delete unnecessary builder files def delete_files(files): for file in files: diff --git a/scripts/deploy_core.py b/scripts/deploy_core.py index 95d5fd4..f87398d 100644 --- a/scripts/deploy_core.py +++ b/scripts/deploy_core.py @@ -75,6 +75,11 @@ def make(): base.generate_doctrenderer_config(archive_dir + "/DoctRenderer.config", "./", "builder", "", "./dictionaries") base.create_x2t_js_cache(archive_dir, "core", platform) base.delete_file(archive_dir + "/DoctRenderer.config") + + # just copy sdkjs to avoid executing arm64 x2t on non-arm system + if native_platform == "win_arm64" : + base.delete_dir(archive_dir + "/sdkjs") + base.copy_dir(archive_dir + "/../../../win_64/" + branding + "/core/sdkjs", archive_dir + "/sdkjs") # dictionaries base.copy_dictionaries(git_dir + "/dictionaries", archive_dir + "/dictionaries", True, False) diff --git a/scripts/deploy_desktop.py b/scripts/deploy_desktop.py index 196e979..fab1531 100644 --- a/scripts/deploy_desktop.py +++ b/scripts/deploy_desktop.py @@ -82,18 +82,7 @@ def make(): # base.generate_check_linux_system(git_dir + "/build_tools", root_dir + "/converter") # icu - 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") and not config.check_option("config", "bundle_dylibs")): - 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") + base.deploy_icu(core_dir, root_dir + "/converter", platform) # doctrenderer if isWindowsXP: @@ -116,8 +105,6 @@ 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")): @@ -272,9 +259,14 @@ def make(): base.delete_file(root_dir + "/cef_sandbox.lib") base.delete_file(root_dir + "/libcef.lib") - isMacArmPlaformOnIntel = False - if (platform == "mac_arm64") and not base.is_os_arm(): - isMacArmPlaformOnIntel = True + 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" # all themes generate ---- base.copy_exe(core_build_dir + "/bin/" + platform_postfix, root_dir + "/converter", "allfontsgen") @@ -285,12 +277,12 @@ def make(): base.generate_plist(root_dir, "mac", max_depth=2) base.mac_correct_rpath_desktop(root_dir) - if isMacArmPlaformOnIntel: + if is_host_not_arm: sdkjs_dir = root_dir + "/editors/sdkjs" - 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:] + end_find_platform = sdkjs_dir.rfind("/" + platform + "/") + sdkjs_dir_64 = sdkjs_dir[0:end_find_platform] + "/" + host_platform + "/" + sdkjs_dir[end_find_platform+11:] base.delete_dir(sdkjs_dir) - base.copy_dir(sdkjs_dir_mac64, sdkjs_dir) + base.copy_dir(sdkjs_dir_64, sdkjs_dir) else: themes_params = [] if ("" != config.option("themesparams")): diff --git a/scripts/deploy_mobile.py b/scripts/deploy_mobile.py index 78be016..ae5ff71 100644 --- a/scripts/deploy_mobile.py +++ b/scripts/deploy_mobile.py @@ -73,22 +73,7 @@ def make(): base.copy_lib(core_build_dir + "/lib/" + platform_postfix, root_dir, "x2t") # icu - 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") + base.deploy_icu(core_dir, root_dir, platform) # js base.copy_dir(base_dir + "/js/" + branding + "/mobile/sdkjs", root_dir + "/sdkjs") diff --git a/scripts/deploy_server.py b/scripts/deploy_server.py index 88e4056..c9e31ce 100644 --- a/scripts/deploy_server.py +++ b/scripts/deploy_server.py @@ -94,17 +94,7 @@ def make(): base.generate_doctrenderer_config(converter_dir + "/DoctRenderer.config", "../../../", "server", "", "../../../dictionaries") # icu - 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") and not config.check_option("config", "bundle_dylibs")): - 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.deploy_icu(core_dir, converter_dir, platform) base.copy_v8_files(core_dir, converter_dir, platform) diff --git a/scripts/develop/build_lo_linux.py b/scripts/develop/build_lo_linux.py new file mode 100644 index 0000000..6540663 --- /dev/null +++ b/scripts/develop/build_lo_linux.py @@ -0,0 +1,104 @@ +# 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() diff --git a/scripts/develop/build_lo_windows.py b/scripts/develop/build_lo_windows.py new file mode 100644 index 0000000..064e34b --- /dev/null +++ b/scripts/develop/build_lo_windows.py @@ -0,0 +1,202 @@ +# Before starting, make sure that: +# 1. MVS 2022 is installed and the necessary individual components are in its installer +# � Windows Universal C Runtime +# � .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.) +# � C++ 20xx Redistributable MSMs (only required to build MSI installer) +# � 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() diff --git a/scripts/develop/run_server.py b/scripts/develop/run_server.py index c742888..8db3517 100644 --- a/scripts/develop/run_server.py +++ b/scripts/develop/run_server.py @@ -8,6 +8,13 @@ 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): @@ -21,11 +28,18 @@ 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: - 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']) + 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 else: base.print_info('Missing rabbitmqctl.bat') diff --git a/scripts/license_checker/config.json b/scripts/license_checker/config.json index 6eb9cb5..f6c0237 100644 --- a/scripts/license_checker/config.json +++ b/scripts/license_checker/config.json @@ -198,6 +198,11 @@ "editors-ios/Vendor/ThreadSafeMutable/ThreadSafeMutableDictionary.h", "editors-ios/Vendor/ThreadSafeMutable/ThreadSafeMutableDictionary.m" ] + }, + { + "dir": "editors-webview-ios", + "fileExtensions": [".swift", ".xcconfig"], + "licensePath": "header.license", } ] } \ No newline at end of file diff --git a/scripts/license_checker/header.license b/scripts/license_checker/header.license index a2faf53..6286700 100644 --- a/scripts/license_checker/header.license +++ b/scripts/license_checker/header.license @@ -1,5 +1,5 @@ /* - * (c) Copyright Ascensio System SIA 2010-2024 + * (c) Copyright Ascensio System SIA 2010-2025 * * 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) diff --git a/scripts/package_desktop.py b/scripts/package_desktop.py index 9545abc..8ec8d16 100644 --- a/scripts/package_desktop.py +++ b/scripts/package_desktop.py @@ -35,7 +35,7 @@ def s3_upload(files, dst): # def make_windows(): - global package_name, package_version, arch, xp, suffix + global package_name, package_version, arch, xp utils.set_cwd("desktop-apps\\win-linux\\package\\windows") package_name = branding.desktop_package_name @@ -47,7 +47,6 @@ 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") @@ -60,10 +59,22 @@ def make_windows(): utils.delete_files("data\\*.exe") make_prepare() - make_zip() - make_inno() - make_advinst() - make_online() + if not xp: + make_zip() + make_zip("commercial") + make_inno() + make_inno("commercial") + if branding.onlyoffice: + make_inno("standalone") + make_inno("update") + make_advinst() + make_advinst("commercial") + else: + make_zip("xp") + make_inno("xp") + # Disable build online installer + # if common.platform == "windows_x86_xp": + # make_online() utils.set_cwd(common.workspace_dir) return @@ -83,101 +94,82 @@ def make_prepare(): utils.set_summary("desktop prepare", ret) return -def make_zip(): - zip_file = "%s-%s-%s.zip" % (package_name, package_version, suffix) +def make_zip(edition = "opensource"): + if edition == "commercial": zip_file = "%s-Commercial-%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) args = [ "-Version", package_version, - "-Arch", arch + "-Arch", arch, + "-Target", edition ] - if xp: - args += ["-Target", "xp"] # if common.sign: # args += ["-Sign"] - utils.log_h2("desktop zip build") + utils.log_h2("desktop zip " + edition + " build") ret = utils.ps1("make_zip.ps1", args, verbose=True) - utils.set_summary("desktop zip build", ret) + utils.set_summary("desktop zip " + edition + " build", ret) if common.deploy and ret: - utils.log_h2("desktop zip deploy") + utils.log_h2("desktop zip " + edition + " deploy") ret = s3_upload([zip_file], "desktop/win/generic/") - utils.set_summary("desktop zip deploy", ret) + utils.set_summary("desktop zip " + edition + " deploy", ret) return -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) +def make_inno(edition = "opensource"): + if edition == "commercial": inno_file = "%s-Commercial-%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) args = [ "-Version", package_version, - "-Arch", arch + "-Arch", arch, + "-Target", edition ] if common.sign: args += ["-Sign"] - utils.log_h2("desktop inno build") if xp: - 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) + args += ["-TimestampServer", "http://timestamp.comodoca.com/authenticode"] - 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 update_wrapper and not xp: - utils.log_h2("desktop inno update build") - 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 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(): - 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 - ] - if common.sign: - args += ["-Sign"] - - utils.log_h2("desktop advinst build") - ret = utils.ps1("make_advinst.ps1", args, verbose=True) - utils.set_summary("desktop advinst 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 common.deploy and ret: - utils.log_h2("desktop advinst deploy") + utils.log_h2("desktop inno " + edition + " deploy") + ret = s3_upload([inno_file], "desktop/win/inno/") + utils.set_summary("desktop inno " + edition + " deploy", ret) + return + +def make_advinst(edition = "opensource"): + if edition == "commercial": advinst_file = "%s-Commercial-%s-%s.msi" + else: advinst_file = "%s-%s-%s.msi" + advinst_file = advinst_file % (package_name, package_version, arch) + args = [ + "-Version", package_version, + "-Arch", arch, + "-Target", edition + ] + if common.sign: + args += ["-Sign"] + + utils.log_h2("desktop advinst " + edition + " build") + ret = utils.ps1("make_advinst.ps1", args, verbose=True) + utils.set_summary("desktop advinst " + edition + " build", ret) + + if common.deploy and ret: + utils.log_h2("desktop advinst " + edition + " deploy") ret = s3_upload([advinst_file], "desktop/win/advinst/") - utils.set_summary("desktop advinst deploy", ret) + utils.set_summary("desktop advinst " + edition + " deploy", ret) return def make_online(): - if not common.platform in ["windows_x86_xp"]: - return - online_file = "%s-%s-%s.exe" % ("OnlineInstaller", package_version, suffix) + online_file = utils.glob_file("OnlineInstaller-" + package_version + "*.exe") + utils.log_h2("desktop online installer build") ret = utils.is_file(online_file) utils.set_summary("desktop online installer build", ret) @@ -333,20 +325,23 @@ def make_sparkle_updates(): def make_linux(): utils.set_cwd("desktop-apps/win-linux/package/linux") - 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) + 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) - 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) + 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) utils.set_cwd(common.workspace_dir) return diff --git a/scripts/qmake.py b/scripts/qmake.py index 4b34fad..886b925 100644 --- a/scripts/qmake.py +++ b/scripts/qmake.py @@ -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"): + 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"): return False return True @@ -91,6 +91,7 @@ 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"): @@ -116,12 +117,17 @@ def make(platform, project, qmake_config_addon="", is_no_errors=False): if ("" != qmake_addon_string): qmake_addon_string = " " + qmake_addon_string + vcvarsall_arch = ("x86" if base.platform_is_32(platform) else "x64") + 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\" " + ("x86" if base.platform_is_32(platform) else "x64")) + qmake_bat.append("call \"" + config.option("vs-path") + "/vcvarsall.bat\" " + vcvarsall_arch) 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 " + file_pro + config_params_string + qmake_addon_string) + qmake_bat.append("call \"" + qmake_app + "\" -nocache " + qmake_env_addon + 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)) diff --git a/scripts/sdkjs_common/jsdoc/config/plugins/events/cell.json b/scripts/sdkjs_common/jsdoc/config/plugins/events/cell.json deleted file mode 100644 index c3d5583..0000000 --- a/scripts/sdkjs_common/jsdoc/config/plugins/events/cell.json +++ /dev/null @@ -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 - } - } -} diff --git a/scripts/sdkjs_common/jsdoc/config/plugins/events/common.json b/scripts/sdkjs_common/jsdoc/config/plugins/events/common.json deleted file mode 100644 index 30fcb8a..0000000 --- a/scripts/sdkjs_common/jsdoc/config/plugins/events/common.json +++ /dev/null @@ -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 - } - } -} \ No newline at end of file diff --git a/scripts/sdkjs_common/jsdoc/config/plugins/events/slide.json b/scripts/sdkjs_common/jsdoc/config/plugins/events/slide.json deleted file mode 100644 index 5847639..0000000 --- a/scripts/sdkjs_common/jsdoc/config/plugins/events/slide.json +++ /dev/null @@ -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 - } - } -} diff --git a/scripts/sdkjs_common/jsdoc/config/plugins/events/word.json b/scripts/sdkjs_common/jsdoc/config/plugins/events/word.json deleted file mode 100644 index f684434..0000000 --- a/scripts/sdkjs_common/jsdoc/config/plugins/events/word.json +++ /dev/null @@ -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 - } - } -} \ No newline at end of file diff --git a/scripts/sdkjs_common/jsdoc/config/plugins/methods/correct_doclets.js b/scripts/sdkjs_common/jsdoc/config/plugins/methods/correct_doclets.js deleted file mode 100644 index bea3873..0000000 --- a/scripts/sdkjs_common/jsdoc/config/plugins/methods/correct_doclets.js +++ /dev/null @@ -1,85 +0,0 @@ -exports.handlers = { - processingComplete: function(e) { - const filteredDoclets = []; - - function checkNullProps(oDoclet) { - for (let key of Object.keys(oDoclet)) { - if (oDoclet[key] == null) { - delete oDoclet[key]; - } - if (typeof(oDoclet[key]) == "object") { - checkNullProps(oDoclet[key]); - } - } - } - - for (let i = 0; i < e.doclets.length; i++) { - const doclet = e.doclets[i]; - if (true == doclet.undocumented || doclet.kind == 'package') { - continue; - } - - const filteredDoclet = { - comment: doclet.comment, - - meta: doclet.meta ? { - lineno: doclet.meta.lineno, - columnno: doclet.meta.columnno - } : doclet.meta, - - kind: doclet.kind, - since: doclet.since, - name: doclet.name, - type: doclet.type ? { - names: doclet.type.names, - parsedType: doclet.type.parsedType - } : doclet.type, - - description: doclet.description, - memberof: doclet.memberof, - - properties: doclet.properties ? doclet.properties.map(property => ({ - type: property.type ? { - names: property.type.names, - parsedType: property.type.parsedType - } : property.type, - - name: property.name, - description: property.description, - optional: property.optional, - defaultvalue: property.defaultvalue - })) : doclet.properties, - - longname: doclet.longname, - scope: doclet.scope, - alias: doclet.alias, - - params: doclet.params ? doclet.params.map(param => ({ - type: param.type ? { - names: param.type.names, - parsedType: param.type.parsedType - } : param.type, - - name: param.name, - description: param.description, - optional: param.optional, - defaultvalue: param.defaultvalue - })) : doclet.params, - - returns: doclet.returns ? doclet.returns.map(returnObj => ({ - type: { - names: returnObj.type.names, - parsedType: returnObj.type.parsedType - } - })) : doclet.returns, - see: doclet.see - }; - - checkNullProps(filteredDoclet) - - filteredDoclets.push(filteredDoclet); - } - - e.doclets.splice(0, e.doclets.length, ...filteredDoclets); - } -}; \ No newline at end of file diff --git a/scripts/sdkjs_common/jsdoc/generate_docs_plugins_events_json.py b/scripts/sdkjs_common/jsdoc/generate_docs_plugins_events_json.py deleted file mode 100644 index 71b12b9..0000000 --- a/scripts/sdkjs_common/jsdoc/generate_docs_plugins_events_json.py +++ /dev/null @@ -1,110 +0,0 @@ -import os -import subprocess -import json -import argparse -import re - -# Configuration files -configs = [ - "./config/plugins/events/common.json", - "./config/plugins/events/word.json", - "./config/plugins/events/cell.json", - "./config/plugins/events/slide.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 builder 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/events" - ) - args = parser.parse_args() - generate(args.destination) diff --git a/scripts/sdkjs_common/jsdoc/generate_docs_plugins_events_md_site.py b/scripts/sdkjs_common/jsdoc/generate_docs_plugins_events_md_site.py deleted file mode 100644 index 37f4f6a..0000000 --- a/scripts/sdkjs_common/jsdoc/generate_docs_plugins_events_md_site.py +++ /dev/null @@ -1,356 +0,0 @@ -#!/usr/bin/env python3 -import os -import json -import re -import shutil -import argparse -import generate_docs_plugins_events_json - -# Папки для каждого editor_name -editors = { - "word": "text-document-api", - "cell": "spreadsheet-api", - "slide": "presentation-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=''): - """ - Cleans or transforms specific tags in the doclet description: - - => ** (bold text) - - ... => 💡 ... - - {@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.' - - # Line breaks - string = string.replace('\r', '\\\n') - - # Replace tags with Markdown bold formatting - string = re.sub(r'', '-**', string) - string = re.sub(r'', '**', string) - - # Replace tags with an icon and text - string = re.sub(r'(.*?)', 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/manifest/', - '/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('/plugins/methods/'): - url = f'../../{ref.split('/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/{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", "true", "false"} - 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"[{base}]({root}Enumeration/{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('<', '<').replace('>', '>') - 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', ''))) - 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"# {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/{raw_t}.md)\n" - else: - content += f"- {raw_t}\n" - - # 2) Handle TypeApplication (e.g. Object.) - 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_properties_markdown(properties, enumerations, 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)) - prop_types = prop['type']['names'] if prop.get('type') else [] - param_types_md = generate_data_types_markdown(prop_types, enumerations, root) - content += f"| {prop_name} | {param_types_md} | {prop_description} |\n" - - # Escape outside code blocks - return escape_text_outside_code_blocks(content) - -def process_events(data, events_root): - enumerations = [] - events = [] - - for doclet in data: - kind = doclet.get('kind') - if kind == 'typedef': - enumerations.append(doclet) - elif kind == 'event': - events.append(doclet) - - os.makedirs(events_root, exist_ok=True) - used_enumerations.clear() - - # пишем события - for ev in events: - path = os.path.join(events_root, 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_root)) - - # пишем перечисления, используемые событиями - enum_dir = os.path.join(events_root, 'Enumeration') - 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"{e['name']}.md") - write_markdown_file(path, generate_enumeration_markdown(e, enumerations)) - if not e.get('examples'): - missing_examples.append(os.path.relpath(path, events_root)) - - -def generate_events(output_dir): - if output_dir.endswith('/'): - output_dir = output_dir[:-1] - tmp = os.path.join(output_dir, 'tmp_json') - - shutil.rmtree(output_dir, ignore_errors=True) - generate_docs_plugins_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/events/", - help="Output directory" - ) - args = parser.parse_args() - generate_events(args.destination) \ No newline at end of file diff --git a/scripts/sdkjs_common/jsdoc/plugins/generate_docs_events_md.py b/scripts/sdkjs_common/jsdoc/plugins/generate_docs_events_md.py index 350e676..12e0299 100644 --- a/scripts/sdkjs_common/jsdoc/plugins/generate_docs_events_md.py +++ b/scripts/sdkjs_common/jsdoc/plugins/generate_docs_events_md.py @@ -91,7 +91,7 @@ def process_link_tags(text, root=''): 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' + url = f"../../{ref.split('/docs/plugins/')[1]}.md" display_text = label if label else ref return f"[{display_text}]({url})" else: @@ -275,6 +275,22 @@ def generate_enumeration_markdown(enumeration, enumerations): 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 '' @@ -352,6 +368,8 @@ def process_events(data, editor_dir): 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('/'): diff --git a/sln.json b/sln.json index 15dc71c..3fd4408 100644 --- a/sln.json +++ b/sln.json @@ -93,8 +93,7 @@ "[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_xp]desktop-apps/win-linux/extras/online-installer/OnlineInstaller.pro" + "[win,!win_xp]desktop-apps/win-linux/extras/update-daemon/UpdateDaemon.pro" ], "mobile" : [ diff --git a/tools/linux/arm/cross_arm64/.gitignore b/tools/linux/arm/cross_arm64/.gitignore new file mode 100644 index 0000000..d8eeaf0 --- /dev/null +++ b/tools/linux/arm/cross_arm64/.gitignore @@ -0,0 +1,5 @@ +qt_source* +qt_binary* +qt_build* +qt-* +gcc-linaro-* \ No newline at end of file diff --git a/tools/linux/arm/cross_arm64/build_qt.py b/tools/linux/arm/cross_arm64/build_qt.py new file mode 100644 index 0000000..e76cf60 --- /dev/null +++ b/tools/linux/arm/cross_arm64/build_qt.py @@ -0,0 +1,103 @@ +#!/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 \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) diff --git a/tools/linux/arm/cross_arm64/download_arm_toolchain.py b/tools/linux/arm/cross_arm64/download_arm_toolchain.py new file mode 100644 index 0000000..ef5fa31 --- /dev/null +++ b/tools/linux/arm/cross_arm64/download_arm_toolchain.py @@ -0,0 +1,16 @@ +#!/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() \ No newline at end of file diff --git a/tools/linux/arm/cross_arm64/fetch_qt.py b/tools/linux/arm/cross_arm64/fetch_qt.py new file mode 100644 index 0000000..1b1f2ff --- /dev/null +++ b/tools/linux/arm/cross_arm64/fetch_qt.py @@ -0,0 +1,22 @@ +#!/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() \ No newline at end of file diff --git a/tools/linux/arm/cross_arm64/pyrightconfig.json b/tools/linux/arm/cross_arm64/pyrightconfig.json new file mode 100644 index 0000000..4094cf8 --- /dev/null +++ b/tools/linux/arm/cross_arm64/pyrightconfig.json @@ -0,0 +1,5 @@ +{ + "exclude": [ + "qt-everywhere-src-5.15.2/**" + ] +} \ No newline at end of file diff --git a/tools/win/arm64/.gitignore b/tools/win/arm64/.gitignore new file mode 100644 index 0000000..0260ec9 --- /dev/null +++ b/tools/win/arm64/.gitignore @@ -0,0 +1,5 @@ +tmp.bat +qt_source* +qt_binary* +qt_build* +qt-* diff --git a/tools/win/arm64/build_qt.py b/tools/win/arm64/build_qt.py new file mode 100644 index 0000000..467b1d7 --- /dev/null +++ b/tools/win/arm64/build_qt.py @@ -0,0 +1,77 @@ +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() \ No newline at end of file diff --git a/tools/win/arm64/fetch_qt.py b/tools/win/arm64/fetch_qt.py new file mode 100644 index 0000000..e3b7994 --- /dev/null +++ b/tools/win/arm64/fetch_qt.py @@ -0,0 +1,20 @@ +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() \ No newline at end of file diff --git a/tools/win/arm64/pyrightconfig.json b/tools/win/arm64/pyrightconfig.json new file mode 100644 index 0000000..4094cf8 --- /dev/null +++ b/tools/win/arm64/pyrightconfig.json @@ -0,0 +1,5 @@ +{ + "exclude": [ + "qt-everywhere-src-5.15.2/**" + ] +} \ No newline at end of file diff --git a/version b/version index 8e055f7..93c8cbd 100644 --- a/version +++ b/version @@ -1 +1 @@ -9.0.3 \ No newline at end of file +9.0.4 \ No newline at end of file