diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index f0e025c..b60cc19 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -1,9 +1,9 @@ -cmake_minimum_required (VERSION 3.5) +cmake_minimum_required (VERSION 3.15) # This directive is ignored for non OSX environments set (CMAKE_OSX_DEPLOYMENT_TARGET "10.12" CACHE STRING "Minimum OS X deployment version") -project (outliner C CXX) # Your project name +project (Noo C CXX) # Your project name if (NOT LIB_PLATFORM) message("No LIB_PLATFORM is set, defaulting to works/sevana/platform/libraries") @@ -12,8 +12,8 @@ endif() include (${LIB_PLATFORM}/platform_libs.cmake) -# C++ 11 standard -set (CMAKE_CXX_STANDARD 11) +# C++ 20 standard +set (CMAKE_CXX_STANDARD 20) set (CMAKE_CXX_STANDARD_REQUIRED ON) # Find includes in corresponding build directories @@ -30,11 +30,11 @@ set (CMAKE_AUTOUIC ON) set (APP_SKIP_BUILD_NUMBER OFF CACHE BOOL "Skip Litt build number increase.") # App version is expected as APP_VERSION variable -if (NOT APP_VERSION) - message(FATAL "Requires APP_VERSION to be set") -endif() +#if (NOT APP_VERSION) +# message(FATAL "Requires APP_VERSION to be set") +#endif() -add_definitions(-DAPP_VERSION="\"${APP_VERSION}\"") +#add_definitions(-DAPP_VERSION="\"${APP_VERSION}\"") # This will find the Qt5 files. You will need a QT5_DIR env variable find_package (Qt5Core REQUIRED) @@ -232,8 +232,8 @@ if (TARGET_OSX) endif() # This will create you executable -set (EXE_NAME Litt) -set (PRODUCT_NAME Litt) +set (EXE_NAME noo) +set (PRODUCT_NAME Noo) add_executable(${EXE_NAME} ${ADDITIONAL_EXE_OPTIONS} @@ -261,13 +261,13 @@ target_include_directories(${EXE_NAME} SYSTEM BEFORE PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/fervor ) -message("App version: ${APP_VERSION}") +# message("App version: ${APP_VERSION}") if (TARGET_OSX) set_source_files_properties( ${MACOS_ICON_PATH} PROPERTIES MACOSX_PACKAGE_LOCATION Resources ) set_target_properties( ${EXE_NAME} PROPERTIES MACOSX_BUNDLE_ICON_FILE ${MACOS_ICON_FILENAME} ) set_target_properties( ${EXE_NAME} PROPERTIES OUTPUT_NAME ${PRODUCT_NAME}) set_target_properties( ${EXE_NAME} PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME ${PRODUCT_NAME} ) - set_target_properties( ${EXE_NAME} PROPERTIES MACOSX_BUNDLE_SHORT_VERSION_STRING "${APP_VERSION}") + # set_target_properties( ${EXE_NAME} PROPERTIES MACOSX_BUNDLE_SHORT_VERSION_STRING "${APP_VERSION}") set_target_properties( ${EXE_NAME} PROPERTIES MACOSX_BUNDLE_LONG_VERSION_STRING "${APP_VERSION}") set_target_properties( ${EXE_NAME} PROPERTIES MACOSX_BUNDLE TRUE diff --git a/client/build-number/build_number.h b/client/build-number/build_number.h index 9cb8094..a70dc32 100644 --- a/client/build-number/build_number.h +++ b/client/build-number/build_number.h @@ -1,2 +1,2 @@ // Auto generated file ! Please do not edit ! -#define APP_BUILD_NUMBER 235 \ No newline at end of file +#define APP_BUILD_NUMBER 249 \ No newline at end of file diff --git a/client/icons/app/README.md b/client/icons/app/README.md new file mode 100644 index 0000000..61a345b --- /dev/null +++ b/client/icons/app/README.md @@ -0,0 +1,2 @@ +ToDo: check this icon https://iconscout.com/icon/artificial-noosphere-2532340 + diff --git a/scripts/appimage_dir.tar.gz b/scripts/appimage_dir.tar.gz new file mode 100644 index 0000000..a378510 Binary files /dev/null and b/scripts/appimage_dir.tar.gz differ diff --git a/scripts/build_linux.sh b/scripts/build_linux.sh new file mode 100755 index 0000000..dbbaa32 --- /dev/null +++ b/scripts/build_linux.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# I use this script on two different hosts so there are logic to find proper Qt installation + +export QT_HOME=/home/$USER/qt/5.12.10/gcc_64 +if [ ! -d "$QT_HOME" ] ; then + export QT_HOME=/home/$USER/qt5/5.12.12/gcc_64 +fi + +# Build .appimage +/usr/bin/python3 build_outliner.py + diff --git a/scripts/build_outliner.py b/scripts/build_outliner.py new file mode 100755 index 0000000..e0e29bf --- /dev/null +++ b/scripts/build_outliner.py @@ -0,0 +1,116 @@ +#!/usr/bin/python3 + +import typing +import platform +import os +import shutil +import glob +from pathlib import Path +import multiprocessing +import build_utils + +EXIT_OK = 0 +EXIT_ERROR = 1 + +# Check if Qt is specified +if not 'QT_HOME' in os.environ: + print('Qt location must be set in QT_HOME environment variable.') + exit(1) + +# Prepare build directory +build_dir = Path('build') +if build_dir.exists(): + shutil.rmtree(build_dir) +os.mkdir(build_dir) + +app_source = Path('../client').resolve() +version_suffix = build_utils.get_version(app_source / 'config.h', 'APP_VERSION_SUFFIX') +version_minor = build_utils.get_version(app_source / 'config.h', 'APP_VERSION_MINOR') +version_major = build_utils.get_version(app_source / 'config.h', 'APP_VERSION_MAJOR') + +if version_major is None or version_minor is None or version_suffix is None: + print('App version is not found, exiting.') + exit(EXIT_OK) + +app_version = f'{version_major}.{version_minor}.{version_suffix}' +print (f'Found Noo version: {app_version}') + +# Go to build directory +os.chdir(build_dir) + +if platform.system() == 'Linux': + print('Linux detected') + print('Configure...') + + qt_home = Path(os.environ['QT_HOME']).resolve() + cmake_params = { + 'Qt5Core_DIR': qt_home / 'lib/cmake/Qt5Core', + 'Qt5Widgets_DIR': qt_home / 'lib/cmake/Qt5Widgets', + 'Qt5DBus_DIR': qt_home / 'lib/cmake/Qt5DBus', + 'Qt5Gui_DIR': qt_home / 'lib/cmake/Qt5Gui', + 'Qt5LinguistTools_DIR': qt_home / 'lib/cmake/Qt5LinguistTools', + 'Qt5PrintSupport_DIR': qt_home / 'lib/cmake/Qt5PrintSupport', + 'Qt5OpenGL_DIR': qt_home / 'lib/cmake/Qt5OpenGL', + 'Qt5Network_DIR': qt_home / 'lib/cmake/Qt5Network' + } + + cmake_cmd = 'cmake ' + for k,v in cmake_params.items(): + cmake_cmd = f'{cmake_cmd} -D{k}={v} ' + cmake_cmd = f'{cmake_cmd} ../../client' + print(f'cmake command line: {cmake_cmd}') + + retcode = os.system(f'{cmake_cmd} ../../client') + if retcode != 0: + print(f'cmake call failed with code {retcode}') + exit(retcode) + + print('Build...') + retcode = os.system('make -j4') + if retcode != 0: + print(f'make call failed with code {retcode}') + exit(retcode) + + # Build appimage + print('Assembling app...') + os.chdir('..') + + # Remove possible old image + if os.path.exists('appimage_dir'): + shutil.rmtree('appimage_dir') + + # Expand image template + retcode = os.system('tar -xvzf appimage_dir.tar.gz') + if retcode != 0: + print(f'Failed to expand template directory, code {retcode}') + exit(retcode) + + # Copy binary file + shutil.copy('build/noo', 'appimage_dir/usr/bin') + + deploy_options = [ + '-always-overwrite', + '-verbose=2', + '-appimage', + '-qmake=' + os.environ['QT_HOME'] + '/bin/qmake', + '-unsupported-allow-new-glibc', + #'-no-translations', + '-extra-plugins=iconengines,platformthemes/libqgtk3.so' + ] + + desktop_path = 'appimage_dir/usr/share/applications/noo.desktop' + cmd_deploy = f'./linuxdeployqt {desktop_path} {" ".join(deploy_options)}' + retcode = os.system(cmd_deploy) + if retcode != 0: + print(f'linuxdeployqt failed with code {retcode}') + print(cmd_deploy) + exit(retcode) + + releases_dir = Path('releases') + if not releases_dir.exists(): + os.mkdir(releases_dir) + for f in os.listdir(): + if f.endswith('x86_64.AppImage') and f.startswith('Noo'): + shutil.move(f, releases_dir / f'noo-{app_version}-x86_64.AppImage') + + exit(0) diff --git a/scripts/build_utils.py b/scripts/build_utils.py new file mode 100644 index 0000000..5b421dc --- /dev/null +++ b/scripts/build_utils.py @@ -0,0 +1,170 @@ +#!/usr/bin/python3 + +import os +import sys +import multiprocessing +import shutil +import platform +import re +import glob +import typing +import codecs + +# from PyInquirer import prompt, print_json + + +AR_TEMP_DIR = "ar_temp_dir" + +def show_menu(message, lst): + print() + # Print selection menu + for l in range(len(lst)): + print(f'{l}) {lst[l]}') + + return lst[int(input(message))] + + +def ask_password(message): + return input(message) + + +# Replace substring in a file +def inplace_change(filename, old_string, new_string): + # Safely read the input filename using 'with' + with open(filename) as f: + s = f.read() + if old_string not in s: + print('"{old_string}" not found in {filename}.'.format(**locals())) + return + + # Safely write the changed content, if found in the file + with open(filename, 'w') as f: + print('Changing "{old_string}" to "{new_string}" in {filename}'.format(**locals())) + s = s.replace(old_string, new_string) + f.write(s) + + +# Architecture used for VS2019 architecture parameters +def make_build(path: str, profile: str, params: dict, merge_libs :bool, generator: str=None, architecture: str = None): + cmdline = "cmake " + if generator is not None: + cmdline += f'-G "{generator}"' + if architecture is not None: + cmdline += f' -A {architecture}' + + for key in params: + cmdline += f" -D {key}={params[key]}" + + cmdline += f" -D CMAKE_BUILD_TYPE={profile}" + cmdline += f" {path}" + print(f"Cmake configure call: {cmdline}") + + retcode = os.system(cmdline) + + if retcode != 0: + return retcode + + if platform.system() == "Windows": + cmdline = "cmake --build . --config %s -j%d" % (profile, multiprocessing.cpu_count()) + else: + cmdline = f"cmake --build . -j{multiprocessing.cpu_count()}" + + retcode = os.system(cmdline) + if retcode != 0: + return retcode + + return 0 + + +def get_version(path, name): + with codecs.open(path, mode='r', encoding='utf-8') as f: + t = f.read() + + pattern = r"#define " + name + r"[\s]+(?P[\d]+)" + m = re.search(pattern=pattern, string=t, flags=re.MULTILINE) + if m is not None: + return m.group("number") + else: + return None + + +def make_chdir(path): + # Prepare build directory + if os.path.exists(path): + shutil.rmtree(path) + os.mkdir(path) + os.chdir(path) + + +def upload_to_builds(path): + # Build command line + if platform.system().lower() == "windows": + cmdline = f"pscp.exe {path} uploader@f.sevana.biz:/var/www/f.sevana.biz/public_html/" + else: + cmdline = f"scp -o \"StrictHostKeyChecking no\" {path} uploader@f.sevana.biz:/var/www/f.sevana.biz/public_html/" + + # Upload + retcode = os.system(cmdline) + + # Print results + if retcode == 0: + print (f"https://f.sevana.biz/{os.path.basename(path)}") + else: + print ("Failed to upload. Return code: %d" % retcode) + + +def merge_static_libs(main_lib, build_dir, use_android_ndk: bool): + # Find all static libraries + print ("Looking for additional static libraries to merge...") + files = glob.glob("**/*.a", recursive=True) + print (files) + + if platform.system() in ["Linux", "Darwin"]: + print ("Merging with binutils...") + + if use_android_ndk: + if platform.system() == "Darwin": + toolchain_prefix = "darwin-x86_64" + else: + toolchain_prefix = "linux-x86_64" + + ar_command = f"{path_android_ndk}/toolchains/llvm/prebuilt/{toolchain_prefix}/bin/aarch64-linux-android-ar" + else: + ar_command = "ar" + + # Extract all object files + os.system("mkdir %s" % AR_TEMP_DIR) + os.chdir(AR_TEMP_DIR) + for libname in files: + cmdline_extract = f"{ar_command} -x {os.path.join('..', libname)}" + retcode = os.system(cmdline_extract) + if retcode != 0: + print(f"Failed: {cmdline_extract}") + sys.exit(1) + + # Extract object files from main library + cmdline_extract = f"{ar_command} -x {os.path.join('..', main_lib)}" + retcode = os.system(cmdline_extract) + if retcode != 0: + print(f"Failed: {cmdline_extract}") + sys.exit(1) + + cmdline = f"{ar_command} -qc {os.path.basename(main_lib)} *.o" + retcode = os.system(cmdline) + if retcode != 0: + print(f"Failed: {cmdline}") + sys.exit(1) + + # Replace original library with a new one + os.chdir("..") + os.remove(main_lib) + shutil.move(os.path.join(AR_TEMP_DIR, os.path.basename(main_lib)), main_lib) + # os.system("strip %s" % main_lib) + shutil.rmtree(AR_TEMP_DIR) + +if 'ANDROID_NDK_HOME' in os.environ: + path_android_ndk = os.environ['ANDROID_NDK_HOME'] +else: + path_android_ndk = None + +# "~/Library/Android/sdk/ndk/21.0.6113669" diff --git a/scripts/linuxdeployqt b/scripts/linuxdeployqt new file mode 100755 index 0000000..2d65297 Binary files /dev/null and b/scripts/linuxdeployqt differ