diff --git a/.gitignore b/.gitignore index 80cf8f117b17a8d04f327de92f3bf5b8c60c8614..f4a63d6d8e22c714a03563eb4b9be823fdff3d59 100644 --- a/.gitignore +++ b/.gitignore @@ -19,12 +19,16 @@ changelog.html obj/ build/ build-local/ -install-local/ +build-global/ +install/ *.vcxproj *.vcxproj.filters *qmlcache.qrc .deploy.stamp +*.log +*.pid + # auto-gen files src/app/resources.qrc src/app/qml.qrc diff --git a/INSTALL.md b/INSTALL.md index 1ea9a4712dcc820a6b7b5a9bc3d823b7fa5dc583..b47cdc02c989640e895bd8718e3eea91738c1caf 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1,8 +1,8 @@ # Build instructions -There is basically two ways to build `client-qt`: +There are essentially two ways to build `client-qt`: -- Use `build.py` script which will build all Jami (daemon/client lib/client-qt) +- Use `build.py` script which will build all of Jami (daemon and client) - Build only this client. ## Disclaimer @@ -55,14 +55,14 @@ Then, you can build the project ### With build.py -```bash -git clone https://review.jami.net/jami-project -``` - -Jami installer uses **python3 (minimum v3.6)**. If it's not installed, please install it: +The build.py Jami installer uses **python3 (minimum v3.6)**. If it's not installed, +please install it. Then run the following to initialize and update +the submodules to set them at the top of their latest commit (ideal +for getting the latest development versions; otherwise, you can use +`git submodule update --init` then checkout specific commits for each +submodule). ```bash -cd jami-project/ ./build.py --init ``` @@ -71,21 +71,24 @@ Then you will need to install dependencies: - For GNU/Linux ```bash -./build.py --dependencies --qt # needs sudo +./build.py --dependencies # needs sudo ``` -Then, you can build daemon and the client with: +Then, you can build daemon and the client using: ```bash -./build.py --install --qt +./build.py --install ``` -And you will have the daemon in `daemon/bin/jamid` and the client in `client-qt/build-local/jami`. You also can run it with +If you use a Qt version that is not system-wide installed, you need to +specify its path using the `--qt` flag, e.g. +`./build.py --install --qt=/home/<username>/Qt/6.2.1/gcc_64`. -If you use a Qt version that is not wide-system installed you need to specify its path after the `--qt` flag, i. e., `./build.py --install --qt /home/<username>/Qt/6.2.1/gcc_64 +Now you will have the daemon in `daemon/bin/jamid` and the client in +`build/bin/jami`. You can now run Jami using ```bash -./build.py --run --qt +./build.py --run ``` Notes: @@ -122,7 +125,7 @@ cmake can take some options: e.g. (with Qt version from https://jami.net) ``` -cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=jami-project/install/client-qt -DCMAKE_PREFIX_PATH=/usr/lib/libqt-jami +cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=../install -DCMAKE_PREFIX_PATH=/usr/lib/libqt-jami ``` After the build has finished, you are finally ready to launch jami in your build directory. @@ -208,9 +211,8 @@ Only 64-bit MSVC build can be compiled. ```bash python build.py --install - cd client-qt - python build.py init - python build.py --qtver <your qt version> + python extras\scripts\build-windows.py init + python extras\scripts\build-windows.py --qtver <your qt version> ``` - Then you should be able to use the Visual Studio Solution file in client-qt folder **(Configuration = Release, Platform = x64)** @@ -221,15 +223,15 @@ Only 64-bit MSVC build can be compiled. **Daemon** -- Make sure that dependencies is built by make-ring.py -- On MSVC folder (jami-project\daemon\MSVC): +- Make sure that dependencies is built by build.py +- On MSVC folder (daemon\MSVC): ```sh cmake -DCMAKE_CONFIGURATION_TYPES="ReleaseLib_win32" -DCMAKE_VS_PLATFORM_NAME="x64" -G "Visual Studio 16 2019" -A x64 -T '$(DefaultPlatformToolset)' .. python winmake.py -b daemon ``` -- This will generate a `.lib` file in the path of ring-project\daemon\MSVC\x64\ReleaseLib_win32\bin +- This will generate a `.lib` file in the path of daemon\MSVC\x64\ReleaseLib_win32\bin > Note: each dependencies contrib for daemon can also be updated individually <br> > For example: @@ -240,15 +242,14 @@ Only 64-bit MSVC build can be compiled. **Jami** -- Make sure that daemon, is built first +- Make sure that daemon is built first. Then, ```bash - cd client-qt - python build.py init - python build.py + python extras\scripts\build-windows.py init + python extras\scripts\build-windows.py ``` -Note: if your qt version is different than 6.2.3, you need to use `python build.py --qtver <your qt version>`. +Note: if your qt version is different than 6.2.3, you need to use `python extras\scripts\build-windows.py --qtver <your qt version>`. ## Building On MacOS @@ -272,33 +273,31 @@ Then, you can build the project **Build with build.py** ```bash -git clone https://review.jami.net/jami-project - cd jami-project ./build.py --init -./build.py --dependencies --qt -./build.py --install --qt +./build.py --dependencies +./build.py --install ``` If you use a Qt version that is installed in a different than standard location you need to specify its path ```bash -./build.py --install --qt QT_ROOT_DIRECTORY=your_qt_directory +QT_ROOT_DIRECTORY=your_qt_directory ./build.py --install ``` -Built client could be find in `client-qt/build-local/Jami` +Built client could be find in `build/Jami` ## Packaging On Native Windows - To be able to generate a msi package, first download and install [Wixtoolset](https://wixtoolset.org/releases/). - In Visual Studio, download WiX Toolset Visual Studio Extension. -- Build client-qt project first, then the JamiInstaller project, msi package should be stored in jami-project\client-qt\JamiInstaller\bin\Release +- Build client-qt project first, then the JamiInstaller project, msi package should be stored in JamiInstaller\bin\Release ## Testing for Client-qt on Windows - We currently use [GoogleTest](https://github.com/google/googletest) and [Qt Quick Test](https://doc.qt.io/qt-5/qtquicktest-index.html#introduction) in our product. To build and run tests, you could use the following command. ``` - python build.py [runtests, pack] + python extras\scripts\build-windows.py [runtests, pack] ``` - Note that, for tests, the path of local storage files for jami will be changed based on following environment variables. @@ -309,11 +308,11 @@ Built client could be find in `client-qt/build-local/Jami` %JAMI_CACHE_HOME% = %TEMP% + '\\jami_test\\.cache' ``` -- These environment variables will be temporarily set when using make-client.py to run tests. +- These environment variables will be temporarily set when using build-windows.py to run tests. ## Debugging -Compile the client with `BUILD=Debug` and compile LibRingClient with -`-DCMAKE_BUILD_TYPE=Debug` +Compile the client with with `-DCMAKE_BUILD_TYPE=Debug`. -Then, if you want to enable logging when running `jami` launch it with `-d` or `--debug` +Then, if you want to enable logging when running `jami`, launch it +with `-d` or `--debug`. diff --git a/build.py b/build.py new file mode 100755 index 0000000000000000000000000000000000000000..d7617e522b2b7bcbf8fdb81743df9cc60f8dba31 --- /dev/null +++ b/build.py @@ -0,0 +1,696 @@ +#!/usr/bin/env python3 +# build.py --- Convenience script for building and running Jami + +# Copyright (C) 2016-2022 Savoir-faire Linux Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import argparse +import contextlib +import multiprocessing +import os +import platform +import shlex +import shutil +import subprocess +import sys +import time + +OSX_DISTRIBUTION_NAME = "osx" +WIN32_DISTRIBUTION_NAME = "win32" + +# vs vars +win_sdk_default = '10.0.16299.0' +win_toolset_default = '142' + +APT_BASED_DISTROS = [ + 'debian', + 'linuxmint', + 'raspbian', + 'trisquel', + 'ubuntu', +] + +DNF_BASED_DISTROS = [ + 'fedora', 'rhel', +] + +PACMAN_BASED_DISTROS = [ + 'arch', 'parabola', +] + +ZYPPER_BASED_DISTROS = [ + 'opensuse-leap', +] + +FLATPAK_BASED_RUNTIMES = [ + 'org.gnome.Platform', +] + +APT_INSTALL_SCRIPT = [ + 'apt-get update', + 'apt-get install %(packages)s' +] + +BREW_UNLINK_SCRIPT = [ + 'brew unlink %(packages)s' +] + +BREW_INSTALL_SCRIPT = [ + 'brew update', + 'brew install %(packages)s', + 'brew link --force --overwrite %(packages)s' +] + +RPM_INSTALL_SCRIPT = [ + 'dnf update', + 'dnf install %(packages)s' +] + +PACMAN_INSTALL_SCRIPT = [ + 'pacman -Sy', + 'pacman -S --asdeps --needed %(packages)s' +] + +ZYPPER_INSTALL_SCRIPT = [ + 'zypper update', + 'zypper install %(packages)s' +] + +ZYPPER_DEPENDENCIES = [ + # build system + 'autoconf', 'autoconf-archive', 'automake', 'cmake', 'make', 'patch', 'gcc-c++', + 'libtool', 'which', 'pandoc','nasm', 'doxygen', 'graphviz', + # contrib dependencies + 'curl', 'gzip', 'bzip2', + # daemon + 'speexdsp-devel', 'speex-devel', 'libdbus-c++-devel', 'jsoncpp-devel', 'yaml-cpp-devel', + 'yasm', 'libuuid-devel', 'libnettle-devel', 'libopus-devel', 'libexpat-devel', + 'libgnutls-devel', 'msgpack-devel', 'libavcodec-devel', 'libavdevice-devel', 'pcre-devel', + 'alsa-devel', 'libpulse-devel', 'libudev-devel', 'libva-devel', 'libvdpau-devel', + 'libopenssl-devel', 'libavutil-devel', +] + +ZYPPER_CLIENT_DEPENDENCIES = [ + # lrc + 'qt6-core-devel', 'qt6-dbus-devel', 'qt6-linguist-devel', + # client-qt + 'qt6-svg-devel', 'qt6-multimedia-devel', 'qt6-declarative-devel', + 'qt6-quickcontrols2-devel', + 'qrencode-devel', 'NetworkManager-devel' +] + +ZYPPER_QT_WEBENGINE = [ + 'qt6-webenginecore-devel', + 'qt6-webenginequick-devel', + 'qt6-webenginewidgets-devel' +] + +DNF_DEPENDENCIES = [ + 'autoconf', 'autoconf-archive', 'automake', 'cmake', 'make', 'speexdsp-devel', 'pulseaudio-libs-devel', + 'libtool', 'dbus-devel', 'expat-devel', 'pcre-devel', 'doxygen', 'graphviz', + 'yaml-cpp-devel', 'boost-devel', 'dbus-c++-devel', 'dbus-devel', + 'libXext-devel', 'libXfixes-devel', 'yasm', + 'speex-devel', 'chrpath', 'check', 'astyle', 'uuid-c++-devel', 'gettext-devel', + 'gcc-c++', 'which', 'alsa-lib-devel', 'systemd-devel', 'libuuid-devel', + 'uuid-devel', 'gnutls-devel', 'nettle-devel', 'opus-devel', 'speexdsp-devel', + 'yaml-cpp-devel', 'swig', 'jsoncpp-devel', + 'patch', 'libva-devel', 'openssl-devel', 'libvdpau-devel', 'msgpack-devel', + 'sqlite-devel', 'openssl-static', 'pandoc', 'nasm', + 'bzip2' +] + +DNF_CLIENT_DEPENDENCIES = [ + 'libnotify-devel', + 'qt6-qtbase-devel', + 'qt6-qtsvg-devel', 'qt6-qtmultimedia-devel', 'qt6-qtdeclarative-devel', + 'qrencode-devel', 'NetworkManager-libnm-devel' +] + +DNF_QT_WEBENGINE = [ 'qt6-qtwebengine-devel' ] + +APT_DEPENDENCIES = [ + 'autoconf', 'autoconf-archive', 'autopoint', 'automake', 'cmake', 'make', 'dbus', 'doxygen', 'graphviz', + 'g++', 'gettext', 'libasound2-dev', 'libavcodec-dev', + 'libavdevice-dev', 'libavformat-dev', 'libboost-dev', + 'libcppunit-dev', 'libdbus-1-dev', + 'libdbus-c++-dev', 'libebook1.2-dev', 'libexpat1-dev', 'libgnutls28-dev', + 'libgtk-3-dev', 'libjack-dev', + 'libopus-dev', 'libpcre3-dev', 'libpulse-dev', 'libssl-dev', + 'libspeex-dev', 'libspeexdsp-dev', 'libswscale-dev', 'libtool', + 'libudev-dev', 'libyaml-cpp-dev', 'sip-tester', 'swig', + 'uuid-dev', 'yasm', 'libjsoncpp-dev', 'libva-dev', 'libvdpau-dev', 'libmsgpack-dev', + 'pandoc', 'nasm', 'dpkg-dev' +] + +APT_CLIENT_DEPENDENCIES = [ + 'qt6-base-dev', 'qt6-tools-dev', 'qt6-tools-dev-tools', + 'qt6-l10n-tools', 'libnotify-dev', 'libqt6sql6-sqlite', + 'libqt6core5compat6-dev', 'libqt6networkauth6-dev', + 'qt6-multimedia-dev', 'libqt6svg6-dev', 'qt6-declarative-dev', + 'qml6-module-qt-labs-qmlmodels', + 'qml6-module-qt5compat-graphicaleffects', + 'qml6-module-qtqml-workerscript', + 'qml6-module-qtmultimedia', + 'qml6-module-qtquick', 'qml6-module-qtquick-controls', + 'qml6-module-qtquick-dialogs', 'qml6-module-qtquick-layouts', + 'qml6-module-qtquick-shapes', 'qml6-module-qtquick-window', + 'qml6-module-qtquick-templates', 'qml6-module-qt-labs-platform', + 'libqrencode-dev', 'libnm-dev' +] + +APT_QT_WEBENGINE = [ + 'libqt6webengine6-data', 'libqt6webenginecore6-bin', + 'qt6-webengine-dev', 'qt6-webengine-dev-tools', + 'qml6-module-qtwebengine', 'qml6-module-qtwebchannel' ] + +PACMAN_DEPENDENCIES = [ + 'autoconf', 'autoconf-archive', 'gettext', 'cmake', 'dbus', 'doxygen', 'graphviz', + 'gcc', 'ffmpeg', 'boost', 'cppunit', 'libdbus', 'dbus-c++', 'libe-book', 'expat', + 'jack', 'opus', 'pcre', 'libpulse', 'speex', 'speexdsp', 'libtool', 'yaml-cpp', + 'swig', 'yasm', 'make', 'patch', 'pkg-config', + 'automake', 'libva', 'libvdpau', 'openssl', 'pandoc', 'nasm' +] + +PACMAN_CLIENT_DEPENDENCIES = [ + # lrc + 'qt6-base', + # client-qt + 'qt6-declarative', 'qt6-5compat', 'qt6-multimedia', + 'qt6-networkauth', 'qt6-shadertools', + 'qt6-svg', 'qt6-tools', + 'qrencode', 'libnm' +] + +PACMAN_QT_WEBENGINE = [ 'qt6-webengine' ] + +OSX_DEPENDENCIES = [ + 'autoconf', 'cmake', 'gettext', 'pkg-config', 'qt6', + 'libtool', 'yasm', 'nasm', 'automake' +] + +OSX_DEPENDENCIES_UNLINK = [ + 'autoconf*', 'cmake*', 'gettext*', 'pkg-config*', 'qt*', 'qt@6.*', + 'libtool*', 'yasm*', 'nasm*', 'automake*', 'gnutls*', 'nettle*', 'msgpack*' +] + +UNINSTALL_DAEMON_SCRIPT = [ + 'make -C daemon uninstall' +] + +ASSUME_YES_FLAG = ' -y' +ASSUME_YES_FLAG_PACMAN = ' --noconfirm' + +def run_powershell_cmd(cmd): + p = subprocess.Popen(["powershell.exe", cmd], stdout=sys.stdout) + p.communicate() + p.wait() + return + + +def run_dependencies(args): + if args.distribution == WIN32_DISTRIBUTION_NAME: + run_powershell_cmd( + 'Set-ExecutionPolicy Unrestricted; .\\extras\\scripts\\install-deps-windows.ps1') + + elif args.distribution in APT_BASED_DISTROS: + if args.assume_yes: + for i, _ in enumerate(APT_INSTALL_SCRIPT): + APT_INSTALL_SCRIPT[i] += ASSUME_YES_FLAG + execute_script( + APT_INSTALL_SCRIPT, + {"packages": ' '.join(map(shlex.quote, APT_DEPENDENCIES))}) + if not args.no_webengine: + APT_CLIENT_DEPENDENCIES.extend(APT_QT_WEBENGINE) + execute_script( + APT_INSTALL_SCRIPT, + {"packages": ' '.join(map(shlex.quote, APT_CLIENT_DEPENDENCIES))}) + + elif args.distribution in DNF_BASED_DISTROS: + if args.assume_yes: + for i, _ in enumerate(DNF_INSTALL_SCRIPT): + DNF_INSTALL_SCRIPT[i] += ASSUME_YES_FLAG + execute_script( + RPM_INSTALL_SCRIPT, + {"packages": ' '.join(map(shlex.quote, DNF_DEPENDENCIES))}) + if not args.no_webengine: + DNF_CLIENT_DEPENDENCIES.extend(DNF_QT_WEBENGINE) + execute_script( + RPM_INSTALL_SCRIPT, + {"packages": ' '.join(map(shlex.quote, DNF_CLIENT_DEPENDENCIES))}) + + elif args.distribution in PACMAN_BASED_DISTROS: + if args.assume_yes: + for i, _ in enumerate(PACMAN_INSTALL_SCRIPT): + PACMAN_INSTALL_SCRIPT[i] += ASSUME_YES_FLAG_PACMAN + execute_script( + PACMAN_INSTALL_SCRIPT, + {"packages": ' '.join(map(shlex.quote, PACMAN_DEPENDENCIES))}) + if not args.no_webengine: + PACMAN_CLIENT_DEPENDENCIES.extend(PACMAN_QT_WEBENGINE) + execute_script( + PACMAN_INSTALL_SCRIPT, + {"packages": ' '.join(map(shlex.quote, PACMAN_CLIENT_DEPENDENCIES))}) + + elif args.distribution in ZYPPER_BASED_DISTROS: + if args.assume_yes: + for i, _ in enumerate(ZYPPER_INSTALL_SCRIPT): + ZYPPER_INSTALL_SCRIPT[i] += ASSUME_YES_FLAG + execute_script( + ZYPPER_INSTALL_SCRIPT, + {"packages": ' '.join(map(shlex.quote, ZYPPER_DEPENDENCIES))}) + if not args.no_webengine: + ZYPPER_CLIENT_DEPENDENCIES.extend(ZYPPER_QT_WEBENGINE) + execute_script( + ZYPPER_INSTALL_SCRIPT, + {"packages": ' '.join(map(shlex.quote, ZYPPER_CLIENT_DEPENDENCIES))}) + + elif args.distribution == OSX_DISTRIBUTION_NAME: + execute_script( + BREW_UNLINK_SCRIPT, + {"packages": ' '.join(map(shlex.quote, OSX_DEPENDENCIES_UNLINK))}, + False + ) + execute_script( + BREW_INSTALL_SCRIPT, + {"packages": ' '.join(map(shlex.quote, OSX_DEPENDENCIES))}, + False + ) + + elif args.distribution == WIN32_DISTRIBUTION_NAME: + print("The win32 version does not install dependencies with this script.\nPlease continue with the --install instruction.") + sys.exit(1) + elif args.distribution == 'guix': + print("Building the profile defined in 'guix/manifest.scm'...") + execute_script(['guix shell --manifest=guix/manifest.scm -- true']) + + else: + print("Not yet implemented for current distribution (%s). Please continue with the --install instruction. Note: You may need to install some dependencies manually." % + args.distribution) + sys.exit(1) + + +def run_init(): + # Extract modules path from '.gitmodules' file + module_names = [] + with open('.gitmodules') as fd: + for line in fd.readlines(): + if line.startswith('[submodule "'): + module_names.append(line[line.find('"')+1:line.rfind('"')]) + + subprocess.run(["git", "submodule", "update", "--init"], check=True) + subprocess.run(["git", "submodule", "foreach", + "git checkout master && git pull"], check=True) + + for name in module_names: + hooks_dir = f'.git/modules/{name}/hooks' + if not os.path.exists(hooks_dir): + os.makedirs(hooks_dir) + copy_file("./extras/scripts/commit-msg", f'{hooks_dir}/commit-msg') + + module_names_to_format = ['daemon'] + for name in module_names_to_format: + hooks_dir = f'.git/modules/{name}/hooks' + execute_script(['./extras/scripts/format.sh --install %(path)s'], + {"path": hooks_dir}) + + subprocess.run(["git", "submodule", "update", "--recursive", "--init"], + check=True) + + +def copy_file(src, dest): + print(f'Copying: {src} to {dest}') + try: + shutil.copy2(src, dest) + # e.g. src and dest are the same file + except shutil.Error as e: + print(f'Error: {e}') + # e.g. source or destination doesn't exist + except IOError as e: + print(f'Error: {e.strerror}') + + +@contextlib.contextmanager +def cwd(path): + owd = os.getcwd() + os.chdir(path) + try: + yield + finally: + os.chdir(owd) + + +def run_install(args): + # Platforms with special compilation scripts + if args.distribution == WIN32_DISTRIBUTION_NAME: + winmake = 'daemon/compat/msvc/winmake.py' + with cwd(os.path.dirname(winmake)): + execute_script( + f'python {winmake} -iv -t {args.toolset} -s {args.sdk} -b daemon') + build_windows = 'extras/scripts/build-windows.py' + execute_script(f'python {build_windows} init') + execute_script(f'python {build_windows}') + return True + + # Unix-like platforms + environ = os.environ.copy() + + install_args = ['-p', str(multiprocessing.cpu_count())] + if args.static: + install_args.append('-s') + if args.global_install: + install_args.append('-g') + if args.prefix: + install_args += ('-P', args.prefix) + if not args.priv_install: + install_args.append('-u') + if args.debug: + install_args.append('-d') + if args.no_libwrap: + install_args.append('-W') + if args.no_webengine: + install_args.append('-w') + + if args.distribution == OSX_DISTRIBUTION_NAME: + # The `universal_newlines` parameter has been renamed to `text` in + # Python 3.7+ and triggering automatical binary to text conversion is + # what it actually does + proc = subprocess.run(["brew", "--prefix", "qt6"], + stdout=subprocess.PIPE, check=True, + universal_newlines=True) + + environ['CMAKE_PREFIX_PATH'] = proc.stdout.rstrip("\n") + environ['CONFIGURE_FLAGS'] = '--without-dbus' + if not args.qt: + raise Exception('provide the Qt path using --qt=/qt/install/prefix') + install_args += ("-Q", args.qt) + else: + if args.distribution in ZYPPER_BASED_DISTROS: + # fix jsoncpp pkg-config bug, remove when jsoncpp package bumped + environ['JSONCPP_LIBS'] = "-ljsoncpp" + if args.qt: + install_args += ("-Q", args.qt) + + command = ['extras/scripts/install.sh'] + install_args + + if args.distribution == 'guix': + if args.global_install: + print('error: global install is not supported when using Guix.') + sys.exit(1) + # Run the build in an isolated container. + share_tarballs_args = [] + if 'TARBALLS' in os.environ: + share_tarballs_args = ['--preserve=TARBALLS', + f'--share={os.environ["TARBALLS"]}'] + else: + print('info: consider setting the TARBALLS environment variable ' + 'to a stable writable location to avoid loosing ' + 'cached tarballs') + # Note: we must expose /gnu/store because /etc/ssl/certs + # contains certs that are symlinks to store items. + command = ['guix', 'shell', '--manifest=guix/manifest.scm', + '--expose=/gnu/store', '--expose=/etc/ssl/certs', + '--expose=/usr/bin/env', + '--container', '--network'] + share_tarballs_args \ + + ['--'] + command + + print(f'info: Building/installing using the command: {" ".join(command)}') + return subprocess.run(command, env=environ, check=True) + + +def run_uninstall(args): + execute_script(UNINSTALL_DAEMON_SCRIPT) + + BUILD_DIR = 'build-global' if args.global_install else 'build' + + if (os.path.exists(BUILD_DIR)): + UNINSTALL_CLIENT_SCRIPT = [ + f'make -C {BUILD_DIR} uninstall', + f'rm -rf {BUILD_DIR}' + ] + execute_script(UNINSTALL_CLIENT_SCRIPT) + + +def run_clean(): + execute_script(['git clean -xfd', + 'git submodule foreach git clean -xfd']) + + +def run_run(args): + run_env = os.environ + try: + if args.no_libwrap: + jamid_log = open("daemon.log", 'a') + jamid_log.write('=== Starting daemon (%s) ===' % + time.strftime("%d/%m/%Y %H:%M:%S")) + jamid_process = subprocess.Popen( + ["./install/libexec/jamid", "-c", "-d"], + stdout=jamid_log, + stderr=jamid_log) + + with open('daemon.pid', 'w') as f: + f.write(str(jamid_process.pid)+'\n') + + client_log = open('jami.log', 'a') + client_log.write('=== Starting client (%s) ===' % + time.strftime("%d/%m/%Y %H:%M:%S")) + client_process = subprocess.Popen(["./install/bin/jami", "-d"], + stdout=client_log, + stderr=client_log, + env=run_env) + + with open('jami.pid', 'w') as f: + f.write(str(client_process.pid)+'\n') + + if args.debug and args.no_libwrap: + subprocess.call(['gdb', './install/libexec/jamid']) + + if not args.background: + if args.no_libwrap: + jamid_process.wait() + client_process.wait() + + except KeyboardInterrupt: + print("\nCaught KeyboardInterrupt...") + + finally: + if args.background == False: + try: + # Only kill the processes if they are running, as they + # could have been closed by the user. + print("Killing processes...") + if args.no_libwrap: + jamid_log.close() + if jamid_process.poll() is None: + jamid_process.kill() + client_log.close() + if client_process.poll() is None: + client_process.kill() + except UnboundLocalError: + # Its okay! We crashed before we could start a process + # or open a file. All that matters is that we close + # files and kill processes in the right order. + pass + return True + + +def run_stop(args): + STOP_SCRIPT = ['xargs kill < jami.pid', + 'xargs kill < daemon.pid'] + execute_script(STOP_SCRIPT) + + +def execute_script(script, settings=None, fail=True): + if settings is None: + settings = {} + for line in script: + line = line % settings + rv = os.system(line) + if rv and fail: + print('Error executing script! Exit code: %s' % + rv, file=sys.stderr) + sys.exit(1) + + +def has_guix(): + """Check whether the 'guix' command is available.""" + with open(os.devnull, 'w') as f: + try: + subprocess.run(["sh", "-c", "command -v guix"], + check=True, stdout=f) + except subprocess.CalledProcessError: + return False + else: + return True + + +def validate_args(parsed_args): + """Validate the args values, exit if error is found""" + + # Filter unsupported distributions. + supported_distros = \ + [ OSX_DISTRIBUTION_NAME, WIN32_DISTRIBUTION_NAME, 'guix'] + \ + APT_BASED_DISTROS + DNF_BASED_DISTROS + PACMAN_BASED_DISTROS \ + + ZYPPER_BASED_DISTROS + FLATPAK_BASED_RUNTIMES + + if (parsed_args.distribution == 'no-check' + or 'JAMI_BUILD_NO_CHECK' in os.environ): + return + + if parsed_args.distribution not in supported_distros: + print(f'WARNING: Distribution \'{parsed_args.distribution}\' is not ' + f'supported. Choose one of: {", ".join(supported_distros)}. ' + 'Alternatively, you may force execution of this script ' + 'by providing the \'--distribution=no-check\' argument or by ' + 'exporting the JAMI_BUILD_NO_CHECK environment variable.', + file=sys.stderr) + sys.exit(1) + + # On Windows, version 10 or later is needed to build Jami. + if parsed_args.distribution == WIN32_DISTRIBUTION_NAME: + if hasattr(sys, 'getwindowsversion') and sys.getwindowsversion()[0] < 10: + print('Windows 10 or later is needed to build Jami') + sys.exit(1) + + +def parse_args(): + ap = argparse.ArgumentParser(description="Jami build tool") + + ga = ap.add_mutually_exclusive_group(required=True) + ga.add_argument( + '--init', action='store_true', + help='Init Jami repository') + ga.add_argument( + '--dependencies', action='store_true', + help='Install Jami build dependencies') + ga.add_argument( + '--install', action='store_true', + help='Build and install Jami') + ga.add_argument( + '--clean', action='store_true', + help='Call "git clean" on every repository of the project' + ) + ga.add_argument( + '--uninstall', action='store_true', + help='Uninstall Jami') + ga.add_argument( + '--run', action='store_true', + help='Run the Jami daemon and client') + ga.add_argument( + '--stop', action='store_true', + help='Stop the Jami processes') + + ap.add_argument('--distribution') + ap.add_argument('--prefix') + ap.add_argument('--static', default=False, action='store_true') + ap.add_argument('--global-install', default=False, action='store_true') + ap.add_argument('--debug', default=False, action='store_true', + help='Build with debug support; run in GDB') + ap.add_argument('--background', default=False, action='store_true') + ap.add_argument('--no-priv-install', dest='priv_install', + default=True, action='store_false') + ap.add_argument('--qt', type=str, + help='Use the Qt path supplied') + ap.add_argument('--no-libwrap', dest='no_libwrap', + default=False, action='store_true', + help='Disable libwrap. Also set --disable-shared option to daemon configure') + ap.add_argument('-y', '--assume-yes', default=False, action='store_true', + help='Assume yes (do not prompt user) for dependency installations through the system package manager') + ap.add_argument('--no-webengine', dest='no_webengine', + default=False, action='store_true', + help='Do not use Qt WebEngine.') + + dist = choose_distribution() + + if dist == WIN32_DISTRIBUTION_NAME: + ap.add_argument('--toolset', default=win_toolset_default, type=str, + help='Windows use only, specify Visual Studio toolset version') + ap.add_argument('--sdk', default=win_sdk_default, type=str, + help='Windows use only, specify Windows SDK version') + + parsed_args = ap.parse_args() + + if parsed_args.distribution: + parsed_args.distribution = parsed_args.distribution.lower() + else: + parsed_args.distribution = dist + + validate_args(parsed_args) + + return parsed_args + + +def choose_distribution(): + system = platform.system().lower() + + if system == "linux" or system == "linux2": + if os.path.isfile("/etc/arch-release"): + return "arch" + try: + with open("/etc/os-release") as f: + for line in f: + k, v = line.split("=") + if k.strip() == 'ID': + return v.strip().replace('"', '').split(' ')[0] + except FileNotFoundError: + if has_guix(): + return 'guix' + return 'Unknown' + elif system == "darwin": + return OSX_DISTRIBUTION_NAME + elif system == "windows": + return WIN32_DISTRIBUTION_NAME + + return 'Unknown' + + +def main(): + parsed_args = parse_args() + + if parsed_args.dependencies: + run_dependencies(parsed_args) + + elif parsed_args.init: + run_init() + elif parsed_args.clean: + run_clean() + + elif parsed_args.install: + run_install(parsed_args) + + elif parsed_args.uninstall: + run_uninstall(parsed_args) + + elif parsed_args.run: + if (parsed_args.distribution == 'guix' + and 'GUIX_ENVIRONMENT' not in os.environ): + # Relaunch this script, this time in a pure Guix environment. + guix_args = ['shell', '--pure', + # to allow pulseaudio to connect to an existing server + "-E", "XAUTHORITY", "-E", "XDG_RUNTIME_DIR", + '--manifest=guix/manifest.scm', '--'] + args = sys.argv + ['--distribution=guix'] + print('Running in a guix shell spawned with: guix {}' + .format(str.join(' ', guix_args + args))) + os.execlp('guix', 'guix', *(guix_args + args)) + else: + run_run(parsed_args) + + elif parsed_args.stop: + run_stop(parsed_args) + + +if __name__ == "__main__": + main() diff --git a/extras/scripts/commit-msg b/extras/scripts/commit-msg new file mode 100755 index 0000000000000000000000000000000000000000..81edbe8c91aeaa3816d47cc127319f271414506c --- /dev/null +++ b/extras/scripts/commit-msg @@ -0,0 +1,181 @@ +#!/bin/sh +# From Gerrit Code Review 2.11.3 +# +# Part of Gerrit Code Review (http://code.google.com/p/gerrit/) +# +# Copyright (C) 2009 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +unset GREP_OPTIONS + +CHANGE_ID_AFTER="Bug|Issue" +MSG="$1" + +# Check for, and add if missing, a unique Change-Id +# +add_ChangeId() { + clean_message=`sed -e ' + /^diff --git .*/{ + s/// + q + } + /^Signed-off-by:/d + /^#/d + ' "$MSG" | git stripspace` + if test -z "$clean_message" + then + return + fi + + if test "false" = "`git config --bool --get gerrit.createChangeId`" + then + return + fi + + # Does Change-Id: already exist? if so, exit (no change). + if grep -i '^Change-Id:' "$MSG" >/dev/null + then + return + fi + + id=`_gen_ChangeId` + T="$MSG.tmp.$$" + AWK=awk + if [ -x /usr/xpg4/bin/awk ]; then + # Solaris AWK is just too broken + AWK=/usr/xpg4/bin/awk + fi + + # How this works: + # - parse the commit message as (textLine+ blankLine*)* + # - assume textLine+ to be a footer until proven otherwise + # - exception: the first block is not footer (as it is the title) + # - read textLine+ into a variable + # - then count blankLines + # - once the next textLine appears, print textLine+ blankLine* as these + # aren't footer + # - in END, the last textLine+ block is available for footer parsing + $AWK ' + BEGIN { + # while we start with the assumption that textLine+ + # is a footer, the first block is not. + isFooter = 0 + footerComment = 0 + blankLines = 0 + } + + # Skip lines starting with "#" without any spaces before it. + /^#/ { next } + + # Skip the line starting with the diff command and everything after it, + # up to the end of the file, assuming it is only patch data. + # If more than one line before the diff was empty, strip all but one. + /^diff --git / { + blankLines = 0 + while (getline) { } + next + } + + # Count blank lines outside footer comments + /^$/ && (footerComment == 0) { + blankLines++ + next + } + + # Catch footer comment + /^\[[a-zA-Z0-9-]+:/ && (isFooter == 1) { + footerComment = 1 + } + + /]$/ && (footerComment == 1) { + footerComment = 2 + } + + # We have a non-blank line after blank lines. Handle this. + (blankLines > 0) { + print lines + for (i = 0; i < blankLines; i++) { + print "" + } + + lines = "" + blankLines = 0 + isFooter = 1 + footerComment = 0 + } + + # Detect that the current block is not the footer + (footerComment == 0) && (!/^\[?[a-zA-Z0-9-]+:/ || /^[a-zA-Z0-9-]+:\/\//) { + isFooter = 0 + } + + { + # We need this information about the current last comment line + if (footerComment == 2) { + footerComment = 0 + } + if (lines != "") { + lines = lines "\n"; + } + lines = lines $0 + } + + # Footer handling: + # If the last block is considered a footer, splice in the Change-Id at the + # right place. + # Look for the right place to inject Change-Id by considering + # CHANGE_ID_AFTER. Keys listed in it (case insensitive) come first, + # then Change-Id, then everything else (eg. Signed-off-by:). + # + # Otherwise just print the last block, a new line and the Change-Id as a + # block of its own. + END { + unprinted = 1 + if (isFooter == 0) { + print lines "\n" + lines = "" + } + changeIdAfter = "^(" tolower("'"$CHANGE_ID_AFTER"'") "):" + numlines = split(lines, footer, "\n") + for (line = 1; line <= numlines; line++) { + if (unprinted && match(tolower(footer[line]), changeIdAfter) != 1) { + unprinted = 0 + print "Change-Id: I'"$id"'" + } + print footer[line] + } + if (unprinted) { + print "Change-Id: I'"$id"'" + } + }' "$MSG" > "$T" && mv "$T" "$MSG" || rm -f "$T" +} +_gen_ChangeIdInput() { + echo "tree `git write-tree`" + if parent=`git rev-parse "HEAD^0" 2>/dev/null` + then + echo "parent $parent" + fi + echo "author `git var GIT_AUTHOR_IDENT`" + echo "committer `git var GIT_COMMITTER_IDENT`" + echo + printf '%s' "$clean_message" +} +_gen_ChangeId() { + _gen_ChangeIdInput | + git hash-object -t commit --stdin +} + + +add_ChangeId diff --git a/extras/scripts/format.sh b/extras/scripts/format.sh new file mode 100755 index 0000000000000000000000000000000000000000..dfbe1d878b4b03323a0f9a7ae88170123eae5b18 --- /dev/null +++ b/extras/scripts/format.sh @@ -0,0 +1,103 @@ +#!/usr/bin/env bash +# format.sh --- set up clang-format for source files + +# Copyright (C) 2020-2022 Savoir-faire Linux Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +set -e + +command_exists () +{ + type "$1" &> /dev/null ; +} + +CFVERSION="9" +CLANGFORMAT="" +if command_exists clang-format-${CFVERSION}; then + CLANGFORMAT=clang-format-${CFVERSION} +else + if command_exists clang-format; then + CLANGFORMAT=clang-format + fi +fi + +if ! command -v $CLANGFORMAT &> /dev/null; then + echo "Required version of clang-format not found" + exit 1 +fi + +format_file() +{ + if [ -f "${1}" ]; then + $CLANGFORMAT -i -style=file "${1}" || true + fi +} + +format_files() +{ + for file in $1; do + echo -ne "Formatting: ${file}\\033[0K\\r" + format_file "${file}" + done +} + +exit_if_no_files() +{ + echo No files to format + exit 0 +} + +install_hook() +{ + hooks_path=$1 + if [ ! -d "$hooks_path" ]; then + echo "$hooks_path" path does not exist + exit 1 + fi + echo Installing pre-commit hook in "$hooks_path" + echo "$(realpath $0)" > "$hooks_path"/pre-commit + chmod +x "$hooks_path"/pre-commit +} + +display_help() +{ + echo "Usage: $0 [OPTION...] -- Clang format source files with a .clang-format file" >&2 + echo + echo " --all format all files instead of only committed ones" + echo " --install <path> install a pre-commit hook to run this script" + echo +} + +if [ "$1" == "--help" ]; then + display_help + exit 0 +fi + +case "${1}" in + --all ) + files=$(find src -regex '.*\.\(cpp\|hpp\|cc\|cxx\|h\)$') || true + echo Formatting all source files... + format_files "$files" + ;; + --install ) + install_hook "${2}" + ;; + * ) + files=$(git diff-index --cached --name-only HEAD | grep -iE '\.(cpp|cxx|cc|h|hpp)$') || exit_if_no_files + echo Formatting committed source files... + format_files "$files" + ;; +esac diff --git a/extras/scripts/install-deps-windows.ps1 b/extras/scripts/install-deps-windows.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..6955b613cc7a19a3b0b0c1b15fc108c99ed83a00 --- /dev/null +++ b/extras/scripts/install-deps-windows.ps1 @@ -0,0 +1,236 @@ +# Copyright (C) 2019-2022 Savoir-faire Linux Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +<# + This script should install dependencies required for building the Jami + Qt client on windows. + + Required components not installed: + - Visual Studio + - build toolchains + - SDKs + - WiX + WiX Visual Studio extension + - Qt + Qt Visual Studio extension +#> + +write-host "Installing jami-qt build dependencies for windows…" -ForegroundColor Green + +Set-ExecutionPolicy Bypass -Scope Process -Force + +$global:installed_packages = $null +Function choco_check_package([String] $package, [String] $version = "") { + # Query a package listing once + if ($null -eq $global:installed_packages) { + write-host "Getting installed package list from Chocolatey…" -ForegroundColor DarkCyan + $global:installed_packages = choco list -lo + } + # Check installed packages + $result = $global:installed_packages | Where-object { + $_.ToLower().StartsWith($package.ToLower()) + } + if ($null -eq $result) { + # We don't have the package + write-host $package "not found." -ForegroundColor Yellow + return $false + } + if ("" -eq $version) { + # We have the package and don't care what version it is + write-host $package "found." -ForegroundColor Cyan + return $true + } + # We now check the results for a package of the specified version + $parts = $result.Split(' ') + Foreach ($part in $parts) { + if ($part -eq $version) { + # We have the package of the specified version + write-host $package $version "found." -ForegroundColor Cyan + return $true + } + } + # We don't have the package of the specified version + write-host $package $version "not found." -ForegroundColor Yellow + return $false +} + +Function install_chocolatey { + # Install Chocolatey if not installed already + if (!(Test-Path "$($env:ProgramData)\chocolatey\choco.exe")) { + Invoke-Expression ((New-Object System.Net.WebClient).DownloadString("https://chocolatey.org/install.ps1")) + if ( $LASTEXITCODE -eq 0 ) { + write-host "Chocolatey installation succeeded" -ForegroundColor Green + } + else { + write-host "Chocolatey installation failed" -ForegroundColor Red + exit $LASTEXITCODE + } + } + else { + write-host "Chocolatey already installed" -ForegroundColor DarkGreen + } +} + +Function choco_install_package([String] $package, [String] $version = "") { + $package_installed = choco_check_package $package $version + if ($true -eq $package_installed) { + return + } + if ("" -ne $version) { + write-host "Installing" $package "@" $version + choco install -fy --allow-downgrade $package --version $version --acceptlicense + } + else { + write-host "Installing" $package + choco install -fy --allow-downgrade $package --acceptlicense + } + if ( $LASTEXITCODE -ne 0 ) { + write-host "Choco Packages Installation Failed" -ForegroundColor Red + exit 1 + } +} +Function install_choco_packages($packages) { + Foreach ($i in $packages) { + choco_install_package $i.pkg $i.ver + } + write-host "Choco Packages Installation Succeeded" -ForegroundColor Green +} + +Function download_file_to_temp($download_name, $url, $output_name) { + write-host "Downloading $download_name" -ForegroundColor DarkCyan + $output = $env:TEMP + "\$output_name" + (New-Object System.Net.WebClient).DownloadFile($url, $output) + if ( $LASTEXITCODE -eq 0 ) { + write-host "Download $download_name Succeeded" -ForegroundColor Green + } + else { + write-host "Download $download_name Failed" -ForegroundColor Red + exit $LASTEXITCODE + } +} + +Function unzip_file_from_temp($unzip_name, $zip_file_name, $unzip_file_output_name) { + write-host "Unzipping $unzip_name" -ForegroundColor DarkCyan + $zip_path = $env:TEMP + "\$zip_file_name" + $unzip_path = $env:TEMP + "\$unzip_file_output_name" + Invoke-Expression("unzip -o $zip_path -d '$unzip_path'") | Out-Null + if ( $LASTEXITCODE -eq 0 ) { + write-host "Unzip $unzip_name Succeeded" -ForegroundColor Green + } + else { + write-host "Unzip $unzip_name Failed" -ForegroundColor Red + exit $LASTEXITCODE + } +} + +Function run_batch($batch_cmd, $task_name) { + write-host $task_name -ForegroundColor DarkCyan + Start-Process "cmd.exe" $batch_cmd -Wait -NoNewWindow | Out-Null + if ( $LASTEXITCODE -eq 0 ) { + write-host "$task_name Succeeded" -ForegroundColor Green + } + else { + write-host "$task_name Failed" -ForegroundColor Red + exit $LASTEXITCODE + } +} + +Function move_file_from_temp_to_msys64($file_name, $task_name) { + write-host $task_name -ForegroundColor DarkCyan + $file_path = $env:TEMP + "\$file_name" + Move-item -Path $file_path -Destination $msys2_path -Force + if ($LASTEXITCODE -eq 0) { + write-host "$task_name Succeeded" -ForegroundColor Green + } + else { + write-host "$task_name Failed" -ForegroundColor Red + exit $LASTEXITCODE + } +} + +Function install_msys2_packages($packages) { + Foreach ($i in $packages) { + Invoke-Expression ("pacman -Q '$i'") | out-null + if ($LASTEXITCODE -eq 0) { + write-host $i "already installed" -ForegroundColor Cyan + continue + } + Invoke-Expression ("pacman -S '$i' --noconfirm") + if ($LASTEXITCODE -ne 0) { + write-host "Pacman Packages Installation Failed" -ForegroundColor Red + exit 1 + } + } + write-host "Pacman Packages Installation Succeeded" -ForegroundColor Green +} + +# Web installed msys2_64 bit to install make, gcc, perl, diffutils +$msys_packages = @("make", "gcc", "perl", "diffutils") + +# Install 7zip, unzip, wget --version 1.19.4, cmake, git --version 2.10.2, pandoc, strawberryperl, msys2 +$choco_packages = @( + [pscustomobject]@{pkg = "wget"; ver = "1.19.4" } + [pscustomobject]@{pkg = "git.install"; ver = "2.10.2" } + [pscustomobject]@{pkg = "7zip"; ver = "" } + [pscustomobject]@{pkg = "unzip"; ver = "" } + [pscustomobject]@{pkg = "cmake"; ver = "" } + [pscustomobject]@{pkg = "pandoc"; ver = "" } + [pscustomobject]@{pkg = "strawberryperl"; ver = "" } + [pscustomobject]@{pkg = "msys2"; ver = "" } +) + +install_chocolatey + +# Check for an existing msys2 install +# Note that choco installs msys2 in C:/tools/ +if (!(Test-Path -Path "C:\msys64")) { + $Env:Path += ";C:\tools\msys64\usr\bin" + $msys2_path = "C:\tools\msys64\usr\bin" + if ((Test-Path -Path "C:\tools\msys64")) { + write-host "MSYS2 64 already installed" -ForegroundColor Green + } + else { + $choco_packages.Add([pscustomobject]@{pkg = "msys2"; ver = "" }) + } +} +else { + write-host "MSYS2 64 already installed" -ForegroundColor Green + $Env:Path += ";C:\msys64\usr\bin" + $msys2_path = "C:\msys64\usr\bin" +} + +install_choco_packages $choco_packages +install_msys2_packages $msys_packages + +# Install VSNASM +download_file_to_temp 'VSNASM' "https://github.com/ShiftMediaProject/VSNASM/releases/download/0.5/VSNASM.zip" 'VSNASM.zip' +unzip_file_from_temp 'VSNASM' 'VSNASM.zip' 'VSNASM_UNZIP' +$batch_path = "/c set ISINSTANCE=1 &&" + $env:TEMP + "\VSNASM_UNZIP\install_script.bat" +run_batch $batch_path "Install VSNASM" + +# Install VSYASM +download_file_to_temp 'VSYASM' "https://github.com/ShiftMediaProject/VSYASM/releases/download/0.4/VSYASM.zip" 'VSYASM.zip' +unzip_file_from_temp 'VSYASM' 'VSYASM.zip' 'VSYASM_UNZIP' +$batch_path = "/c set ISINSTANCE=1 &&" + $env:TEMP + "\VSYASM_UNZIP\install_script.bat" +run_batch $batch_path "Install VSYASM" + +# Install yasm.exe (win64) +download_file_to_temp 'yasm.exe (win64)' "http://www.tortall.net/projects/yasm/releases/yasm-1.3.0-win64.exe" 'yasm.exe' +move_file_from_temp_to_msys64 'yasm.exe' 'Move yasm.exe (win64) to msys64 folder' + +# Install gas-preprocessor.pl +download_file_to_temp 'gas-preprocessor.pl' "https://github.com/FFmpeg/gas-preprocessor/blob/master/gas-preprocessor.pl" 'gas-preprocessor.pl' +move_file_from_temp_to_msys64 'gas-preprocessor.pl' 'Move gas-preprocessor.pl to msys64 folder' + +write-host "Done" -ForegroundColor Green diff --git a/extras/scripts/install.sh b/extras/scripts/install.sh new file mode 100755 index 0000000000000000000000000000000000000000..5c351318d0642d40b36c2377e19af45f22c9a27f --- /dev/null +++ b/extras/scripts/install.sh @@ -0,0 +1,187 @@ +#!/usr/bin/env bash +# install.sh --- build and install Jami daemon and client + +# Copyright (C) 2016-2022 Savoir-faire Linux Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +# Build and install to a local prefix under this repository. +export OSTYPE + +# Flags: + + # -g: install globally instead for all users + # -s: link everything statically, no D-Bus communication. More likely to work! + # -p: number of processors to use + # -u: disable use of privileges (sudo) during install + # -W: disable libwrap and shared library + # -w: do not use Qt WebEngine + +set -ex + +# Qt_MIN_VER required for client-qt +QT_MIN_VER="6.2" + +debug= +global=false +static='' +qtpath='' +proc='1' +priv_install=true +enable_libwrap=true +enable_webengine=true + +while getopts gsc:dQ:P:p:uWw OPT; do + case "$OPT" in + g) + global='true' + ;; + s) + static='-DENABLE_STATIC=true' + ;; + d) + debug=true + ;; + Q) + qtpath="${OPTARG}" + ;; + P) + prefix="${OPTARG}" + ;; + p) + proc="${OPTARG}" + ;; + u) + priv_install='false' + ;; + W) + enable_libwrap='false' + ;; + w) + enable_webengine='false' + ;; + \?) + exit 1 + ;; + esac +done + +# $1: global-install? +# $2: private-install? +make_install() { + if [ "$1" = "true" ] && [ "$2" != "false" ]; then + sudo make install + # Or else the next non-sudo install will fail, because this generates some + # root owned files like install_manifest.txt under the build directory. + sudo chown -R "$USER" . + else + make install + fi +} + +TOP="$(pwd)" +INSTALL_DIR="${TOP}/install" # local install directory + +if [ "${global}" = "true" ]; then + BUILD_DIR="build-global" +else + BUILD_DIR="build" +fi + +# jamid +DAEMON="${TOP}/daemon" +cd "$DAEMON" + +# Build the contribs. +mkdir -p contrib/native +( + cd contrib/native + ../bootstrap ${prefix:+"--prefix=$prefix"} + make -j"${proc}" +) + +if [[ "${enable_libwrap}" != "true" ]]; then + # Disable shared if requested + if [[ "$OSTYPE" != "darwin"* ]]; then + CONFIGURE_FLAGS+=" --disable-shared" + fi +fi + +BUILD_TYPE="Release" +if [ "${debug}" = "true" ]; then + BUILD_TYPE="Debug" + CONFIGURE_FLAGS+=" --enable-debug" +fi + +# Build the daemon itself. +test -f configure || ./autogen.sh + +if [ "${global}" = "true" ]; then + ./configure ${CONFIGURE_FLAGS} ${prefix:+"--prefix=$prefix"} +else + ./configure ${CONFIGURE_FLAGS} --prefix="${INSTALL_DIR}" +fi +make -j"${proc}" V=1 +make_install "${global}" "${priv_install}" + +# Verify system's version if no path provided. +if [ -z "$qtpath" ]; then + sys_qtver="" + if command -v qmake6 &> /dev/null; then + sys_qtver=$(qmake6 -v) + elif command -v qmake-qt6 &> /dev/null; then + sys_qtver=$(qmake-qt6 -v) # Fedora + elif command -v qmake &> /dev/null; then + sys_qtver=$(qmake -v) + else + echo "No valid Qt found"; exit 1; + fi + + sys_qtver=${sys_qtver#*Qt version} + sys_qtver=${sys_qtver%\ in\ *} + + installed_qtver=$(echo "$sys_qtver" | cut -d'.' -f 2) + required_qtver=$(echo $QT_MIN_VER | cut -d'.' -f 2) + + if [[ $installed_qtver -ge $required_qtver ]] ; then + # Set qtpath to empty in order to use system's Qt. + qtpath="" + else + echo "No valid Qt found"; exit 1; + fi +fi + +# client +cd "${TOP}" +mkdir -p "${BUILD_DIR}" +cd "${BUILD_DIR}" + +client_cmake_flags=(-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" + -DCMAKE_PREFIX_PATH="${qtpath}" + -DENABLE_LIBWRAP="${enable_libwrap}" + -DWITH_WEBENGINE="${enable_webengine}") + +if [ "${global}" = "true" ]; then + client_cmake_flags+=(${prefix:+"-DCMAKE_INSTALL_PREFIX=$prefix"} + $static) +else + client_cmake_flags+=(-DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" + -DLIBJAMI_BUILD_DIR="${DAEMON}/src") +fi + +echo "info: Configuring $client client with flags: ${client_cmake_flags[*]}" +cmake .. "${client_cmake_flags[@]}" +make -j"${proc}" V=1 +make_install "${global}" "${priv_install}"