diff --git a/build.py b/build.py index f08cba548fb0eb227e21cd7c2036f2cbf3dc0c2f..d05a7298408dd3713f2962793e8e48b369de12ba 100755 --- a/build.py +++ b/build.py @@ -305,6 +305,12 @@ def run_dependencies(args): 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 environment defined in 'guix/manifest.scm'...") + execute_script(['mkdir -p ~/.config/guix/profiles', + ('guix time-machine --channels=guix/channels.scm -- ' + 'package --manifest=guix/manifest.scm ' + '--profile=$HOME/.config/guix/profiles/jami')]) else: print("Not yet implemented for current distribution (%s). Please continue with the --install instruction. Note: You may need to install some dependencies manually." % @@ -398,8 +404,28 @@ def run_install(args): install_args += ("-q", args.qtver) install_args += ("-Q", args.qt) - print(f'info: Invoking scripts/install.sh with arguments: {install_args}') - return subprocess.run(["./scripts/install.sh"] + install_args, env=environ, check=True) + command = ['bash', '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"]}'] + # Note: we must expose /gnu/store because /etc/ssl/certs + # contains certs that are symlinks to store items. + command = ['guix', 'time-machine', '-C', 'guix/channels.scm', '--', + 'environment', '--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): @@ -525,13 +551,25 @@ def execute_script(script, settings=None, fail=True): 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 = [ ANDROID_DISTRIBUTION_NAME, OSX_DISTRIBUTION_NAME, IOS_DISTRIBUTION_NAME, - WIN32_DISTRIBUTION_NAME + WIN32_DISTRIBUTION_NAME, 'guix' ] + APT_BASED_DISTROS + DNF_BASED_DISTROS + PACMAN_BASED_DISTROS \ + ZYPPER_BASED_DISTROS + FLATPAK_BASED_RUNTIMES @@ -551,6 +589,7 @@ def validate_args(parsed_args): # The Qt client support will be added incrementally. if parsed_args.qt is not None: supported_qt_distros = [ + 'guix', WIN32_DISTRIBUTION_NAME ] + APT_BASED_DISTROS + DNF_BASED_DISTROS + PACMAN_BASED_DISTROS @@ -619,7 +658,7 @@ def parse_args(): parsed_args = ap.parse_args() - if (parsed_args.distribution is not None): + if parsed_args.distribution: parsed_args.distribution = parsed_args.distribution.lower() else: parsed_args.distribution = dist @@ -642,6 +681,8 @@ def choose_distribution(): 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 @@ -669,7 +710,23 @@ def main(): run_uninstall(parsed_args) elif parsed_args.run: - run_run(parsed_args) + if (parsed_args.distribution == 'guix' + and 'GUIX_ENVIRONMENT' not in os.environ): + if parsed_args.qt is not None: + print('FIXME: Qt fails loading QML modules due to ' + 'https://issues.guix.gnu.org/47655') + # Relaunch this script, this time in a pure Guix environment. + guix_args = ['time-machine', '--channels=guix/channels.scm', + '--', 'environment', '--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 environment 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) diff --git a/guix/channels.scm b/guix/channels.scm new file mode 100644 index 0000000000000000000000000000000000000000..b31ce8dbc293237b5b6ef9e868a6e16d0082bd9e --- /dev/null +++ b/guix/channels.scm @@ -0,0 +1,8 @@ +(list (channel + (inherit %default-guix-channel) + ;; Use the staging branch for now, as it includes more debug + ;; symbols and fixes a propagation conflict between + ;; gdk-pixbuf+svg and gdk-pixbuf. + (branch "staging") + (commit + "42231bc15df441d6426dec57283aca9ae7a03fcf"))) diff --git a/guix/manifest.scm b/guix/manifest.scm new file mode 100644 index 0000000000000000000000000000000000000000..7e66817555c8a3737c1cba0190e18044590a30a3 --- /dev/null +++ b/guix/manifest.scm @@ -0,0 +1,142 @@ +;;; To use with the GNU Guix package manager. +;;; Available at https://guix.gnu.org/. +;;; +;;; Commentary: +;;; +;;; A full-blown development environment that can be used to build the +;;; whole project. It includes both the GNOME as well as the Qt +;;; libraries, so that both clients can be built. The sensitive +;;; (i.e., patched) dependencies are consciously omitted from this +;;; list so that the bundled libraries are the ones used, which is +;;; usually what is desired for development purposes. + +;;; The make-jami.py script makes use of it to build Jami in a Linux +;;; container with the dependencies below when Guix is detected (and +;;; no /etc/os-release file exists) or when explicitly specified, +;;; e.g.: +;;; +;;; $ ./make-jami.py --distribution=guix --install +;;; +;;; It can also be invoked directly to spawn a development environment, like so: +;;; +;;; $ guix environment --pure --manifest=guix/manifest.scm + +(specifications->manifest + (list + ;; Minimal requirements of the daemon contrib build system. + "coreutils" + "gcc-toolchain" + "git-minimal" + "grep" + "gzip" + "make" + "nss-certs" + "pkg-config" + "python" + "sed" + "tar" + "wget" + "xz" + + ;; For the daemon and its contribs. + "alsa-lib" + "autoconf" + "automake" + "bash" + "bzip2" + "cmake" + "dbus" + ;; Bundled because broken with GCC 7 upstream (unmaintained). When + ;; attempting to use it, it would cause confusing errors such as + ;; "ld: ../src/.libs/libring.a(libupnpcontrol_la-upnp_context.o): in + ;; function `jami::upnp::UPnPContext::updateMappingList(bool)': + ;; upnp_context.cpp:(.text+0xa4be): undefined reference to + ;; `std::__cxx11::basic_ostringstream<char, std::char_traits<char>, + ;; std::allocator<char> >::basic_ostringstream()' + ;;"dbus-c++" ;for dbusxx-xml2cpp + "diffutils" + "doxygen" + "eudev" ;udev library + "expat" + "findutils" + "gawk" + "gettext" + "gnutls" + ;;"ffmpeg" ;bundled because patched + "gmp" + "gsm" + "gtk-doc" + "http-parser" + "jsoncpp" + "libarchive" + "libnatpmp" + "libupnp" + "libsecp256k1" + "libtool" + "libva" ;vaapi + "libvdpau" + "libx264" + "nasm" + "nettle" + "openssl" + "opus" + "patch" + "pcre" + "perl" + ;;"pjproject" ;bundled because patched + "pulseaudio" + "speex" + "speexdsp" + "which" + "yaml-cpp" + "yasm" + + ;; For libringclient (LRC) and the Qt client. + "qtbase" + "qtbase:debug" + + ;; Shared by the GNOME and Qt clients. + "qrencode" + + ;; Shared by the LRC, GNOME and Qt clients. + "network-manager" ;libnm + + ;; For the GNOME client (client-gnome) + "adwaita-icon-theme" + "hicolor-icon-theme" + "clutter" + "clutter-gtk" + "glib:bin" ;for glib-compile-resources + "gtk+" + "gtk+:debug" + "libcanberra" + "libindicator" + "libnotify" + "sqlite" + "webkitgtk" + + ;; For the Qt client. + "qtsvg" + "qtsvg:debug" + "qttools" + "qtwebengine" + "qtwebengine:debug" + "qtwebchannel" + "qtwebchannel:debug" + "qtmultimedia" + "qtmultimedia:debug" + "qtdeclarative" + "qtdeclarative:debug" + "qtgraphicaleffects" + "qtgraphicaleffects:debug" + "qtquickcontrols" + "qtquickcontrols:debug" + "qtquickcontrols2" + "qtquickcontrols2:debug" + + ;; For tests and debugging. + "cppunit" + "file" + "gdb" + "ltrace" + "strace"))