From ba867b0636309b9999a5704be5f7de8f57dbd50b Mon Sep 17 00:00:00 2001 From: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com> Date: Sun, 26 Feb 2023 20:32:34 -0500 Subject: [PATCH] macos: support unified build This patch adds a parameter arch to specify architecture to build. This parameter could be arm64, x86_64 or unified. Change-Id: I2907e03410e0c01b8505afbe283da04b8d0291b6 --- .gitmodules | 4 + 3rdparty/libqrencode | 1 + CMakeLists.txt | 27 ++-- build.py | 3 + extras/build/cmake/modules/FindLibJami.cmake | 6 + extras/scripts/build_daemon_macos.sh | 145 +++++++++++++++++++ extras/scripts/build_qrencode.sh | 61 ++++++++ extras/scripts/install.sh | 130 ++++++++++------- src/libclient/CMakeLists.txt | 3 +- 9 files changed, 315 insertions(+), 65 deletions(-) create mode 160000 3rdparty/libqrencode create mode 100755 extras/scripts/build_daemon_macos.sh create mode 100755 extras/scripts/build_qrencode.sh diff --git a/.gitmodules b/.gitmodules index 43fa67200..62876e832 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,6 +2,10 @@ path = 3rdparty/qrencode-win32 url = https://github.com/BlueDragon747/qrencode-win32.git ignore = dirty +[submodule "3rdparty/libqrencode"] + url = https://github.com/fukuchi/libqrencode.git + ignore = dirty + path = 3rdparty/libqrencode [submodule "3rdparty/SortFilterProxyModel"] path = 3rdparty/SortFilterProxyModel url = https://github.com/atraczyk/SortFilterProxyModel.git diff --git a/3rdparty/libqrencode b/3rdparty/libqrencode new file mode 160000 index 000000000..715e29fd4 --- /dev/null +++ b/3rdparty/libqrencode @@ -0,0 +1 @@ +Subproject commit 715e29fd4cd71b6e452ae0f4e36d917b43122ce8 diff --git a/CMakeLists.txt b/CMakeLists.txt index d0fdd65be..2ceb76668 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -158,17 +158,6 @@ execute_process( WORKING_DIRECTORY ${APP_SRC_DIR}) set(QML_RESOURCES ${APP_SRC_DIR}/resources.qrc) -if (APPLE) - include(FetchContent) - FetchContent_Declare( - libqrencode - GIT_REPOSITORY https://github.com/fukuchi/libqrencode.git - GIT_TAG v4.1.1) - FetchContent_Populate(libqrencode) - add_subdirectory(${libqrencode_SOURCE_DIR} ${libqrencode_BINARY_DIR}) - include_directories(${libqrencode_SOURCE_DIR}) -endif() - # library compatibility (boost, libnotify, etc.) add_definitions(-DQT_NO_KEYWORDS) @@ -299,6 +288,7 @@ set(LIBJAMI_CONTRIB_DIR "${DAEMON_DIR}/contrib") find_path(AVUTIL_INCLUDE_DIR libavutil/avutil.h PATHS ${LIBJAMI_CONTRIB_DIR}/native/ffmpeg + ${LIBJAMI_CONTRIB_DIR}/apple-darwin/include/ ${LIBJAMI_CONTRIB_DIR}/build/ffmpeg/Build/win32/x64/include) include_directories(${AVUTIL_INCLUDE_DIR}) @@ -443,6 +433,8 @@ else() # APPLE ${myApp_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) + INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/3rdparty/libqrencode/include) + LINK_DIRECTORIES(${PROJECT_SOURCE_DIR}/3rdparty/libqrencode/lib) if(ENABLE_SPARKLE) message("Sparkle auto-update enabled") set(sparkle_dir "${PACKAGING_DIR}/update/sparkle") @@ -723,6 +715,19 @@ else() endif(ENABLE_SPARKLE) target_sources(${PROJECT_NAME} PRIVATE ${resources}) target_link_libraries(${PROJECT_NAME} PRIVATE ${libs}) + FILE(GLOB CONTRIB ${LIBJAMI_CONTRIB_DIR}/apple-darwin/lib/*.a) + + target_link_libraries(${PROJECT_NAME} PRIVATE ${CONTRIB}) + find_package(Iconv REQUIRED) + target_link_libraries(${PROJECT_NAME} PRIVATE Iconv::Iconv) + target_link_libraries(${PROJECT_NAME} PRIVATE + "-framework AVFoundation" + "-framework CoreAudio -framework CoreMedia -framework CoreVideo" + "-framework VideoToolbox -framework AudioUnit" + "-framework Security" + compression + resolv + ) # translations if(Qt${QT_VERSION_MAJOR}LinguistTools_FOUND) diff --git a/build.py b/build.py index 4ed2468ca..c1edd9c63 100755 --- a/build.py +++ b/build.py @@ -367,6 +367,8 @@ def run_install(args): install_args.append('-W') if args.no_webengine: install_args.append('-w') + if args.arch: + install_args += ('-a', args.arch) if args.distribution == OSX_DISTRIBUTION_NAME: # The `universal_newlines` parameter has been renamed to `text` in @@ -597,6 +599,7 @@ def parse_args(): ap.add_argument('--no-webengine', dest='no_webengine', default=False, action='store_true', help='Do not use Qt WebEngine.') + ap.add_argument('--arch') dist = choose_distribution() diff --git a/extras/build/cmake/modules/FindLibJami.cmake b/extras/build/cmake/modules/FindLibJami.cmake index 8b9313714..5cce45fc0 100644 --- a/extras/build/cmake/modules/FindLibJami.cmake +++ b/extras/build/cmake/modules/FindLibJami.cmake @@ -39,6 +39,8 @@ else() set(LIBJAMI_INCLUDE_DIRS ${RING_BUILD_DIR}/jami) elseif(EXISTS ${CMAKE_INSTALL_PREFIX}/include/jami/jami.h) set(LIBJAMI_INCLUDE_DIRS ${CMAKE_INSTALL_PREFIX}/include/jami) + elseif(EXISTS ${CMAKE_INSTALL_PREFIX}/daemon/include/jami/jami.h) + set(LIBJAMI_INCLUDE_DIRS ${CMAKE_INSTALL_PREFIX}/daemon/include/jami) else() message(STATUS "Jami daemon headers not found! Set -DLIBJAMI_BUILD_DIR or -DCMAKE_INSTALL_PREFIX") @@ -55,6 +57,7 @@ if(WITH_DAEMON_SUBMODULE) find_library(LIBJAMI_LIB NAMES jami ring PATHS ${DAEMON_DIR}/src/.libs PATHS ${CMAKE_INSTALL_PREFIX}/lib + PATHS ${CMAKE_INSTALL_PREFIX}/daemon/lib PATHS ${CMAKE_INSTALL_PREFIX}/libexec PATHS ${CMAKE_INSTALL_PREFIX}/bin NO_DEFAULT_PATH) @@ -64,6 +67,7 @@ else() PATHS ${LIBJAMI_BUILD_DIR}/.libs PATHS ${RING_BUILD_DIR}/.libs PATHS ${CMAKE_INSTALL_PREFIX}/lib + PATHS ${CMAKE_INSTALL_PREFIX}/daemon/lib PATHS ${CMAKE_INSTALL_PREFIX}/libexec PATHS ${CMAKE_INSTALL_PREFIX}/bin NO_DEFAULT_PATH) @@ -83,6 +87,7 @@ if(NOT LIBJAMI_LIB) PATHS ${DAEMON_DIR}/src/.libs PATHS ${CMAKE_INSTALL_PREFIX} PATHS ${CMAKE_INSTALL_PREFIX}/lib + PATHS ${CMAKE_INSTALL_PREFIX}/daemon/lib PATHS ${CMAKE_INSTALL_PREFIX}/libexec NO_DEFAULT_PATH) else() @@ -92,6 +97,7 @@ if(NOT LIBJAMI_LIB) PATHS ${RING_BUILD_DIR}/.libs PATHS ${CMAKE_INSTALL_PREFIX} PATHS ${CMAKE_INSTALL_PREFIX}/lib + PATHS ${CMAKE_INSTALL_PREFIX}/daemon/lib PATHS ${CMAKE_INSTALL_PREFIX}/libexec NO_DEFAULT_PATH) diff --git a/extras/scripts/build_daemon_macos.sh b/extras/scripts/build_daemon_macos.sh new file mode 100755 index 000000000..5e65db83f --- /dev/null +++ b/extras/scripts/build_daemon_macos.sh @@ -0,0 +1,145 @@ +#!/usr/bin/env bash + +# Flags: + +# -a: architecture to build. Accepted values arm64, x86_64, unified +# -d: debug +set -e + +arch='' +debug= +while getopts "a:d:" OPT; do + case "$OPT" in + a) + arch="${OPTARG}" + ;; + d) + debug=true + ;; + \?) + exit 1 + ;; + esac +done + +if [[ "$arch" == 'unified' ]]; then + echo "unified build" + ARCHS=("arm64" "x86_64") +elif [[ "$arch" == '' ]]; then + ARCHS=("arm64") +else + ARCHS=("$arch") +fi + +TOP="$(pwd)" +INSTALL="${TOP}/install" +OS_VER=$(uname -r) + +DAEMON=${TOP}/daemon +cd "$DAEMON" + +FAT_CONTRIB_DIR=$DAEMON/contrib/apple-darwin +mkdir -p "$FAT_CONTRIB_DIR" +# build contrib for every arch +for ARCH in "${ARCHS[@]}"; do + HOST="${ARCH}-apple-darwin${OS_VER}" + mkdir -p contrib/native-"${ARCH}" + ( + cd contrib/native-"${ARCH}" + ../bootstrap --host="$HOST" + + echo "Building contrib for $ARCH" + # force to build every contrib + for dir in "$DAEMON"/contrib/src/*/; do + PKG=$(basename -- "$dir") + if [ "$PKG" != "dbus-cpp" ] && [ "$PKG" != "natpmp" ] && + [ "$PKG" != "portaudio" ] && [ "$PKG" != "pthreads" ] && + [ "$PKG" != "lttng-ust" ] && [ "$PKG" != "openssl" ] && + [ "$PKG" != "media-sdk" ] && [ "$PKG" != "jack" ] && + [ "$PKG" != "onnx" ] && [ "$PKG" != "opencv" ] && + [ "$PKG" != "opencv_contrib" ] && [ "$PKG" != "uuid" ] && + [ "$PKG" != "webrtc-audio-processing" ] && [ "$PKG" != "liburcu" ]; then + make -j"$NPROC" ."$PKG" + fi + done + ) +done + +# make fat libs for contrib +mkdir -p "$FAT_CONTRIB_DIR"/lib +if ((${#ARCHS[@]} == "2")); then + echo "Making fat lib for ${ARCHS[0]} and ${ARCHS[1]}" + LIBFILES="$DAEMON/contrib/${ARCHS[0]}-apple-darwin$OS_VER/lib/*".a + for f in $LIBFILES; do + # filter out arch from file name + arch0=${ARCHS[0]} + if [ "$arch0" = "arm64" ]; then + arch0="aarch64" + fi + # file name for first arch + libfile0=${f##*/} + # file name without arch + libfile="${libfile0//"-$arch0"/}" + # replace arch0 with ARCHS[1] to get file name for second arch + libfile1="${libfile0//$arch0/${ARCHS[1]}}" + echo "Processing $libfile from $libfile0 and $libfile1 $ lib..." + lipo -create "$DAEMON/contrib/${ARCHS[0]}-apple-darwin$OS_VER/lib/$libfile0" \ + "$DAEMON/contrib/${ARCHS[1]}-apple-darwin$OS_VER/lib/$libfile1" \ + -output "$FAT_CONTRIB_DIR/lib/$libfile" + done +else + echo "No need for fat lib" + rsync -ar --delete "$DAEMON/contrib/${ARCHS[0]}-apple-darwin$OS_VER/lib/"*.a "$FAT_CONTRIB_DIR/lib" +fi + +rsync -ar --delete "$DAEMON/contrib/${ARCHS[0]}-apple-darwin$OS_VER/include"* "$FAT_CONTRIB_DIR/" + +# build deamon for every arch +for ARCH in "${ARCHS[@]}"; do + echo "$ARCH" + cd "$DAEMON" + HOST="${ARCH}-apple-darwin" + CONFIGURE_FLAGS=" --without-dbus --host=${HOST} -with-contrib=$DAEMON/contrib/${ARCH}-apple-darwin${OS_VER} --prefix=${INSTALL}/daemon/$ARCH" + + if [ "${debug}" = "true" ]; then + CONFIGURE_FLAGS+=" --enable-debug" + fi + + echo "$CONFIGURE_FLAGS" + ./autogen.sh || exit + + # We need to copy this file or else it's just an empty file + rsync -a "$DAEMON"/src/buildinfo.cpp ./src/buildinfo.cpp + mkdir -p "build-macos-${ARCH}" + cd "build-macos-${ARCH}" + + "$DAEMON"/configure $CONFIGURE_FLAGS ARCH="$ARCH" || exit 1 + + echo "$CONFIGURE_FLAGS" + + rsync -a "$DAEMON"/src/buildinfo.cpp ./src/buildinfo.cpp + + make -j"$NPROC" || exit 1 + make install || exit 1 + cd "$DAEMON" +done + +# make fat lib for daemon +FAT_INSTALL_DIR="${INSTALL}/daemon/" +FAT_INSTALL_DIR_LIB="${FAT_INSTALL_DIR}/lib/" +mkdir -p "${FAT_INSTALL_DIR_LIB}" + +if + ((${#ARCHS[@]} == "2")) + echo "Creating daemon fat lib" +then + #daemon + lipo -create "${INSTALL}/daemon/${ARCHS[0]}/lib/libjami.a" \ + "${INSTALL}/daemon/${ARCHS[1]}/lib/libjami.a" \ + -output "${FAT_INSTALL_DIR_LIB}/libjami.a" +else + echo "No need for daemon fat lib" + rsync -ar --delete "${INSTALL}/daemon/${ARCHS[0]}/lib/libjami.a" "${FAT_INSTALL_DIR_LIB}" +fi + +rsync -ar --delete "${INSTALL}/daemon/${ARCHS[0]}/include/"* "$FAT_INSTALL_DIR/include" diff --git a/extras/scripts/build_qrencode.sh b/extras/scripts/build_qrencode.sh new file mode 100755 index 000000000..f63844ec7 --- /dev/null +++ b/extras/scripts/build_qrencode.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash + +# Flags: + +# -a: architecture to build. Accepted values arm64, x86_64, unified + +arch='' +while getopts "a:" OPT; do + case "$OPT" in + a) + arch="${OPTARG}" + ;; + \?) + exit 1 + ;; + esac +done + +if [[ "$arch" == 'unified' ]]; then + ARCHS=("arm64" "x86_64") +elif [[ "$arch" == '' ]]; then + ARCHS=("arm64") +else + ARCHS=("$arch") +fi + +TOP="$(pwd)" +QRENCODEDIR="${TOP}/3rdparty/libqrencode" +if [ -z "$NPROC" ]; then + NPROC=$(sysctl -n hw.ncpu || echo -n 1) +fi + +for ARCH in "${ARCHS[@]}"; do + cd "$QRENCODEDIR" || exit 1 + BUILDDIR="$ARCH-libqrencode" + mkdir "$BUILDDIR" + make clean + ./autogen.sh + ./configure --host="$ARCH" --without-png --prefix="${QRENCODEDIR}/${BUILDDIR}" CFLAGS=" -arch $ARCH $CFLAGS" + make -j"$NPROC" + make install +done +mkdir -p "$QRENCODEDIR"/lib +mkdir -p "$QRENCODEDIR"/include + +if ((${#ARCHS[@]} == "2")); then + echo "Making fat lib for ${ARCHS[0]} and ${ARCHS[1]}" + LIBFILES="$QRENCODEDIR/${ARCHS[0]}-libqrencode/lib/*.a" + for f in $LIBFILES; do + libFile=${f##*/} + echo "$libFile" + lipo -create "$QRENCODEDIR/${ARCHS[0]}-libqrencode/lib/$libFile" \ + "$QRENCODEDIR/${ARCHS[1]}-libqrencode/lib/$libFile" \ + -output "${QRENCODEDIR}/lib/$libFile" + done +else + echo "No need for fat lib" + rsync -ar --delete "$QRENCODEDIR/${ARCHS[0]}-libqrencode/lib/"*.a "${QRENCODEDIR}/lib/" +fi + +rsync -ar --delete "$QRENCODEDIR/${ARCHS[0]}-libqrencode/include/"* "${QRENCODEDIR}/include/" diff --git a/extras/scripts/install.sh b/extras/scripts/install.sh index 78bb551d6..bff747b8c 100755 --- a/extras/scripts/install.sh +++ b/extras/scripts/install.sh @@ -28,6 +28,7 @@ export OSTYPE # -u: disable use of privileges (sudo) during install # -W: disable libwrap and shared library # -w: do not use Qt WebEngine + # -a: arch to build set -ex @@ -42,8 +43,9 @@ proc='1' priv_install=true enable_libwrap=true enable_webengine=true +arch='' -while getopts gsc:dQ:P:p:uWw OPT; do +while getopts gsc:dQ:P:p:uWw:a: OPT; do case "$OPT" in g) global='true' @@ -72,6 +74,9 @@ while getopts gsc:dQ:P:p:uWw OPT; do w) enable_webengine='false' ;; + a) + arch="${OPTARG}" + ;; \?) exit 1 ;; @@ -102,64 +107,68 @@ 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"} +if [[ "$OSTYPE" == "darwin"* ]]; then + sh "${TOP}"/extras/scripts/build_daemon_macos.sh -a "$arch" -d "$debug" 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; + 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 - sys_qtver=${sys_qtver#*Qt version} - sys_qtver=${sys_qtver%\ in\ *} + BUILD_TYPE="Release" + if [ "${debug}" = "true" ]; then + BUILD_TYPE="Debug" + CONFIGURE_FLAGS+=" --enable-debug" + fi - installed_qtver=$(echo "$sys_qtver" | cut -d'.' -f 2) - required_qtver=$(echo $QT_MIN_VER | cut -d'.' -f 2) + # Build the daemon itself. + test -f configure || ./autogen.sh - if [[ $installed_qtver -ge $required_qtver ]] ; then - # Set qtpath to empty in order to use system's Qt. - qtpath="" + if [ "${global}" = "true" ]; then + ./configure ${CONFIGURE_FLAGS} ${prefix:+"--prefix=$prefix"} else - echo "No valid Qt found"; exit 1; + ./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 fi @@ -172,6 +181,21 @@ client_cmake_flags=(-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" -DCMAKE_PREFIX_PATH="${qtpath}" -DENABLE_LIBWRAP="${enable_libwrap}" -DWITH_WEBENGINE="${enable_webengine}") +if [[ "$OSTYPE" == "darwin"* ]]; then + #detect arch for macos + CMAKE_OSX_ARCHITECTURES="arm64" + if [[ "$arch" == 'unified' ]]; then + CMAKE_OSX_ARCHITECTURES="x86_64;arm64" + elif [[ "$arch" != '' ]]; then + CMAKE_OSX_ARCHITECTURES="$arch" + fi + client_cmake_flags+=(-DCMAKE_OSX_ARCHITECTURES="${CMAKE_OSX_ARCHITECTURES}") + # build qrencode + ( + cd ${TOP} + ./extras/scripts/build_qrencode.sh -a "$arch" + ) +fi if [ "${global}" = "true" ]; then client_cmake_flags+=(${prefix:+"-DCMAKE_INSTALL_PREFIX=$prefix"} diff --git a/src/libclient/CMakeLists.txt b/src/libclient/CMakeLists.txt index bebe1edc3..5956e43e1 100644 --- a/src/libclient/CMakeLists.txt +++ b/src/libclient/CMakeLists.txt @@ -333,6 +333,7 @@ set(LIBJAMI_CONTRIB_DIR find_path(AVUTIL_INCLUDE_DIR libavutil/avutil.h PATHS ${LIBJAMI_CONTRIB_DIR}/native/ffmpeg + ${LIBJAMI_CONTRIB_DIR}/apple-darwin/include/ ${LIBJAMI_CONTRIB_DIR}/build/ffmpeg/Build/win32/x64/include) include_directories(${AVUTIL_INCLUDE_DIR}) if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") @@ -345,7 +346,7 @@ endif() find_library(AVUTIL_LIBRARY avutil HINTS ${LIBJAMI_CONTRIB_DIR}/${CC_MACHINE}/lib - ${LIBJAMI_CONTRIB_DIR}/x86_64-apple-darwin${CMAKE_HOST_SYSTEM_VERSION}/lib) + ${LIBJAMI_CONTRIB_DIR}/apple-darwin/lib) if(ENABLE_LIBWRAP) list(APPEND LIBCLIENT_HEADERS directrenderer.h) -- GitLab