From d673aa77a55422edc0364b2d23032f311e285a23 Mon Sep 17 00:00:00 2001 From: Mooneer Salem Date: Fri, 26 Jan 2024 23:51:56 -0800 Subject: [PATCH 1/6] Add framework for kicking off autoupdater + initial Windows support. --- src/main.cpp | 6 +++++ src/os/CMakeLists.txt | 44 ++++++++++++++++++++++++++++++++++- src/os/no_autoupdate.cpp | 35 ++++++++++++++++++++++++++++ src/os/os_interface.h | 10 ++++++++ src/os/windows_autoupdate.cpp | 37 +++++++++++++++++++++++++++++ 5 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 src/os/no_autoupdate.cpp create mode 100644 src/os/windows_autoupdate.cpp diff --git a/src/main.cpp b/src/main.cpp index d57c3e8ee..89fbfc551 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -215,6 +215,9 @@ bool MainApp::OnCmdLineParsed(wxCmdLineParser& parser) //------------------------------------------------------------------------- bool MainApp::OnInit() { + // Initialize autoupdate. + initializeAutoUpdate(); + // Initialize locale. m_locale.Init(); @@ -252,6 +255,9 @@ bool MainApp::OnInit() //------------------------------------------------------------------------- int MainApp::OnExit() { + // Cleanup autoupdate. + cleanupAutoUpdate(); + return 0; } diff --git a/src/os/CMakeLists.txt b/src/os/CMakeLists.txt index b6133bfcb..bfc3e0883 100644 --- a/src/os/CMakeLists.txt +++ b/src/os/CMakeLists.txt @@ -4,8 +4,50 @@ else(APPLE) set(OS_WRAP_FILES osx_stubs.cpp) endif(APPLE) +if(WIN32) + # Auto-update functionality requires winsparkle, so build the DLL for it. + if(CMAKE_CROSSCOMPILING) + set(WINSPARKLE_CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}) + endif() + + # Build winsparkle library + include(ExternalProject) + ExternalProject_Add(build_winsparkle + SOURCE_DIR winsparkle_src + SOURCE_SUBDIR cmake + BINARY_DIR winsparkle_build + GIT_REPOSITORY https://github.com/vslavik/winsparkle.git + GIT_TAG master + CMAKE_ARGS ${WINSPARKLE_CMAKE_ARGS} + INSTALL_COMMAND "" + ) + + ExternalProject_Get_Property(build_winsparkle BINARY_DIR) + ExternalProject_Get_Property(build_winsparkle SOURCE_DIR) + add_library(winsparkle SHARED IMPORTED) + + set_target_properties(winsparkle PROPERTIES + IMPORTED_LOCATION "${BINARY_DIR}/bin/WinSparkle${CMAKE_SHARED_LIBRARY_SUFFIX}" + IMPORTED_IMPLIB "${BINARY_DIR}/lib/libWinSparkle${CMAKE_IMPORT_LIBRARY_SUFFIX}" + ) + + set(WINSPARKLE_INCLUDE_DIRS ${SOURCE_DIR}/include) + include_directories(${WINSPARKLE_INCLUDE_DIRS}) + + # Add SW update related hooks. + list(APPEND OS_WRAP_FILES windows_autoupdate.cpp) + set(AUTOUPDATE_LIBRARY winsparkle) + add_dependencies(winsparkle build_winsparkle) +elseif(APPLE) + # TBD: Sparkle support for updates on macOS. + list(APPEND OS_WRAP_FILES no_autoupdate.cpp) +else() + list(APPEND OS_WRAP_FILES no_autoupdate.cpp) +endif() + add_library(fdv_os_wrapper STATIC ${OS_WRAP_FILES} ) -target_include_directories(fdv_os_wrapper PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/..) \ No newline at end of file +target_include_directories(fdv_os_wrapper PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/..) +target_link_libraries(fdv_os_wrapper PRIVATE ${AUTOUPDATE_LIBRARY}) diff --git a/src/os/no_autoupdate.cpp b/src/os/no_autoupdate.cpp new file mode 100644 index 000000000..5edac5020 --- /dev/null +++ b/src/os/no_autoupdate.cpp @@ -0,0 +1,35 @@ +//========================================================================== +// Name: no_autoupdate.cpp +// +// Purpose: Provides C wrapper to platform-specific autoupdate interface. +// Created: Jan. 26, 2024 +// Authors: Mooneer Salem +// +// License: +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General License version 2.1, +// as published by the Free Software Foundation. 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 License +// along with this program; if not, see . +// +//========================================================================== + +#include "os_interface.h" + +// Autoupdate: initialize autoupdater. +void initializeAutoUpdate() +{ + // none; not currently supported except on specific platforms. +} + +// Autoupdate: cleanup autoupdater. +void cleanupAutoUpdate() +{ + // none; not currently supported except on specific platforms. +} diff --git a/src/os/os_interface.h b/src/os/os_interface.h index 375501877..52190abcf 100644 --- a/src/os/os_interface.h +++ b/src/os/os_interface.h @@ -43,4 +43,14 @@ extern "C" void ResetMainWindowColorSpace(); // This can be either "windows", "linux", "macos" or "other". std::string GetOperatingSystemString(); +// Autoupdate: initialize autoupdater. +void initializeAutoUpdate(); + +// Autoupdate: cleanup autoupdater. +void cleanupAutoUpdate(); + +// Autoupdate: URL to appcast file containing update data. +// Shared between Windows and macOS. +#define FREEDV_APPCAST_URL "https://k6aq.net/freedv-update/appcast.xml" + #endif // __OS_INTERFACE__ diff --git a/src/os/windows_autoupdate.cpp b/src/os/windows_autoupdate.cpp new file mode 100644 index 000000000..ba689ecad --- /dev/null +++ b/src/os/windows_autoupdate.cpp @@ -0,0 +1,37 @@ +//========================================================================== +// Name: windows_autoupdate.cpp +// +// Purpose: Provides C wrapper to platform-specific autoupdate interface. +// Created: Jan. 26, 2024 +// Authors: Mooneer Salem +// +// License: +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General License version 2.1, +// as published by the Free Software Foundation. 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 License +// along with this program; if not, see . +// +//========================================================================== + +#include "os_interface.h" +#include + +// Autoupdate: initialize autoupdater. +void initializeAutoUpdate() +{ + win_sparkle_set_appcast_url(FREEDV_APPCAST_URL); + win_sparkle_init(); +} + +// Autoupdate: cleanup autoupdater. +void cleanupAutoUpdate() +{ + win_sparkle_cleanup(); +} From 0f0bfe38955cbfe3ef444617fbcdcf8c20abe201 Mon Sep 17 00:00:00 2001 From: Mooneer Salem Date: Sat, 27 Jan 2024 00:26:27 -0800 Subject: [PATCH 2/6] Add WinSparkle DLL files to installer. --- cmake/GetDependencies.cmake.in | 9 ++++++++- src/os/CMakeLists.txt | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/cmake/GetDependencies.cmake.in b/cmake/GetDependencies.cmake.in index a8e61090a..4aaf757ee 100644 --- a/cmake/GetDependencies.cmake.in +++ b/cmake/GetDependencies.cmake.in @@ -21,7 +21,7 @@ endif() set(FREEDV_USING_LLVM_MINGW @FREEDV_USING_LLVM_MINGW@) set(FREEDV_PACKAGE_SEARCH_PATHS @FREEDV_PACKAGE_SEARCH_PATHS@) -list(APPEND FREEDV_PACKAGE_SEARCH_PATHS ${CMAKE_BINARY_DIR}/external/dist/bin) +list(APPEND FREEDV_PACKAGE_SEARCH_PATHS ${CMAKE_BINARY_DIR}/external/dist/bin ${CMAKE_BINARY_DIR}/external/dist/lib) set(CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM windows+pe) set(CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL objdump) @@ -60,6 +60,10 @@ endfunction() freedv_get_dependencies(_deps ${FREEDV_EXE}) +# Ensure that WebView2Loader.dll gets included as that's needed by WinSparkle +# (but not detected by the dependency scan). +list(APPEND _deps WebView2Loader.dll) + message("Found Win32 dependencies: ${_deps}") # Filter libraries known to be provided by Windows @@ -89,6 +93,8 @@ set( _windlls OLEACC.dll msvcrt.dll bcrypt.dll + WININET.dll + CRYPT32.dll # The below are additional DLLs required when compiled # using the LLVM version of MinGW. @@ -106,6 +112,7 @@ set( _windlls api-ms-win-crt-heap-l1-1-0.dll api-ms-win-crt-convert-l1-1-0.dll api-ms-win-crt-multibyte-l1-1-0.dll + api-ms-win-crt-conio-l1-1-0.dll ) list(REMOVE_ITEM _deps ${_windlls}) diff --git a/src/os/CMakeLists.txt b/src/os/CMakeLists.txt index bfc3e0883..667c58390 100644 --- a/src/os/CMakeLists.txt +++ b/src/os/CMakeLists.txt @@ -16,10 +16,10 @@ if(WIN32) SOURCE_DIR winsparkle_src SOURCE_SUBDIR cmake BINARY_DIR winsparkle_build + INSTALL_DIR ${CMAKE_BINARY_DIR}/external/dist GIT_REPOSITORY https://github.com/vslavik/winsparkle.git GIT_TAG master - CMAKE_ARGS ${WINSPARKLE_CMAKE_ARGS} - INSTALL_COMMAND "" + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/external/dist ${WINSPARKLE_CMAKE_ARGS} ) ExternalProject_Get_Property(build_winsparkle BINARY_DIR) From 49cc317cfb920a95fa1984cbf69b018a210fbb76 Mon Sep 17 00:00:00 2001 From: Mooneer Salem Date: Sat, 27 Jan 2024 03:01:10 -0800 Subject: [PATCH 3/6] Add support for macOS. --- src/CMakeLists.txt | 7 +++-- src/info.plist.in | 4 ++- src/os/CMakeLists.txt | 44 ++++++++++++++++++++++------- src/os/macos_autoupdate.mm | 58 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 14 deletions(-) create mode 100644 src/os/macos_autoupdate.mm diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cd55fcfb6..f49b3125d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,7 +10,7 @@ set(FREEDV_SOURCES freedv_interface.cpp ) -set(FREEDV_LINK_LIBS_OSX +list(APPEND FREEDV_LINK_LIBS_OSX "-framework AVFoundation" ) @@ -35,7 +35,7 @@ if(APPLE) BUNDLE True MACOSX_BUNDLE_GUI_IDENTIFIER org.freedv.freedv MACOSX_BUNDLE_BUNDLE_NAME FreeDV - MACOSX_BNUDLE_COPYRIGHT "Copyright (c) 2021 FreeDV" + MACOSX_BNUDLE_COPYRIGHT "Copyright (c) 2024 FreeDV" MACOSX_BUNDLE_BUNDLE_VERSION "${FreeDV_VERSION}" MACOSX_BUNDLE_BUNDLE_SHORT_VERSION_STRING "${FreeDV_VERSION}" MACOSX_BUNDLE_BUNDLE_LONG_VERSION_STRING "${FreeDV_VERSION}" @@ -76,6 +76,7 @@ endif(FREEDV_STATIC_DEPS) # Link other dependencies if(APPLE) +target_link_options(FreeDV PRIVATE -F ${CMAKE_CURRENT_BINARY_DIR}/os/sparkle_src) target_link_libraries(FreeDV ${FREEDV_LINK_LIBS} ${FREEDV_LINK_LIBS_OSX}) elseif(WIN32) target_link_libraries(freedv ${FREEDV_LINK_LIBS} ws2_32) @@ -130,7 +131,7 @@ if(APPLE) TARGET FreeDV POST_BUILD COMMAND rm -rf dist_tmp FreeDV.dmg || true - COMMAND DYLD_LIBRARY_PATH=${CODEC2_BUILD_DIR}/src:${LPCNET_BUILD_DIR}/src:${portaudio_BINARY_DIR}:${samplerate_BINARY_DIR}/src:${DYLD_LIBRARY_PATH} ${CMAKE_SOURCE_DIR}/macdylibbundler/dylibbundler ARGS -od -b -x FreeDV.app/Contents/MacOS/FreeDV -d FreeDV.app/Contents/libs -p @loader_path/../libs/ -i /usr/lib -s ${LPCNET_BUILD_DIR}/src -s ${CODEC2_BUILD_DIR}/src -s ${CMAKE_BINARY_DIR}/LPCNet_build/src -s ${CMAKE_BINARY_DIR}/codec2_build/src -s ${portaudio_BINARY_DIR} -s ${samplerate_BINARY_DIR}/src + COMMAND DYLD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/src/os/sparkle_src:${CODEC2_BUILD_DIR}/src:${LPCNET_BUILD_DIR}/src:${portaudio_BINARY_DIR}:${samplerate_BINARY_DIR}/src:${DYLD_LIBRARY_PATH} ${CMAKE_SOURCE_DIR}/macdylibbundler/dylibbundler ARGS -od -b -x FreeDV.app/Contents/MacOS/FreeDV -d FreeDV.app/Contents/libs -p @loader_path/../libs/ -i /usr/lib -s ${LPCNET_BUILD_DIR}/src -s ${CODEC2_BUILD_DIR}/src -s ${CMAKE_BINARY_DIR}/LPCNet_build/src -s ${CMAKE_BINARY_DIR}/codec2_build/src -s ${portaudio_BINARY_DIR} -s ${samplerate_BINARY_DIR}/src -f -s ${CMAKE_BINARY_DIR}/src/os/sparkle_src/Sparkle.framework/Versions/Current COMMAND cp ARGS ${CMAKE_CURRENT_SOURCE_DIR}/freedv.icns FreeDV.app/Contents/Resources COMMAND codesign --force --options runtime --timestamp --entitlements ${CMAKE_CURRENT_SOURCE_DIR}/entitlements.plist --sign - ${CMAKE_CURRENT_BINARY_DIR}/FreeDV.app COMMAND mkdir dist_tmp diff --git a/src/info.plist.in b/src/info.plist.in index 8ff97e1a4..c5cda3669 100644 --- a/src/info.plist.in +++ b/src/info.plist.in @@ -38,5 +38,7 @@ NSApplication NSRequiresAquaSystemAppearance <@DARK_MODE_DISABLE@ /> + SUFeedURL + https://k6aq.net/freedv-update/appcast.xml - \ No newline at end of file + diff --git a/src/os/CMakeLists.txt b/src/os/CMakeLists.txt index 667c58390..6ac7b1cc4 100644 --- a/src/os/CMakeLists.txt +++ b/src/os/CMakeLists.txt @@ -1,9 +1,25 @@ +# General OS specific hooks if(APPLE) set(OS_WRAP_FILES osx_interface.mm) else(APPLE) set(OS_WRAP_FILES osx_stubs.cpp) endif(APPLE) +# Autoupdate handling +if(WIN32) + list(APPEND OS_WRAP_FILES windows_autoupdate.cpp) +elseif(APPLE) + list(APPEND OS_WRAP_FILES macos_autoupdate.mm) +else() + list(APPEND OS_WRAP_FILES no_autoupdate.cpp) +endif() + +add_library(fdv_os_wrapper STATIC + ${OS_WRAP_FILES} +) + +include(ExternalProject) + if(WIN32) # Auto-update functionality requires winsparkle, so build the DLL for it. if(CMAKE_CROSSCOMPILING) @@ -11,7 +27,6 @@ if(WIN32) endif() # Build winsparkle library - include(ExternalProject) ExternalProject_Add(build_winsparkle SOURCE_DIR winsparkle_src SOURCE_SUBDIR cmake @@ -35,19 +50,28 @@ if(WIN32) include_directories(${WINSPARKLE_INCLUDE_DIRS}) # Add SW update related hooks. - list(APPEND OS_WRAP_FILES windows_autoupdate.cpp) set(AUTOUPDATE_LIBRARY winsparkle) add_dependencies(winsparkle build_winsparkle) elseif(APPLE) - # TBD: Sparkle support for updates on macOS. - list(APPEND OS_WRAP_FILES no_autoupdate.cpp) -else() - list(APPEND OS_WRAP_FILES no_autoupdate.cpp) -endif() + # Download Sparkle + ExternalProject_Add(build_sparkle + URL https://github.com/sparkle-project/Sparkle/releases/download/2.5.2/Sparkle-2.5.2.tar.xz + SOURCE_DIR sparkle_src + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + UPDATE_COMMAND "" # Skip annoying updates for every build + INSTALL_COMMAND "" + ) + ExternalProject_Get_Property(build_sparkle SOURCE_DIR) + add_library(sparkle SHARED IMPORTED) -add_library(fdv_os_wrapper STATIC - ${OS_WRAP_FILES} -) + set(AUTOUPDATE_LIBRARY "-framework Sparkle") + + # Ensure that the compile step can find Sparkle.framework. + target_compile_options(fdv_os_wrapper PRIVATE -F ${SOURCE_DIR}) + target_link_directories(fdv_os_wrapper PRIVATE ${SOURCE_DIR}) + add_dependencies(fdv_os_wrapper build_sparkle) +endif() target_include_directories(fdv_os_wrapper PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/..) target_link_libraries(fdv_os_wrapper PRIVATE ${AUTOUPDATE_LIBRARY}) diff --git a/src/os/macos_autoupdate.mm b/src/os/macos_autoupdate.mm new file mode 100644 index 000000000..5d44a04e9 --- /dev/null +++ b/src/os/macos_autoupdate.mm @@ -0,0 +1,58 @@ +//========================================================================== +// Name: macos_autoupdate.mm +// +// Purpose: Provides C wrapper to platform-specific autoupdate interface. +// Created: Jan. 27, 2024 +// Authors: Mooneer Salem +// +// License: +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General License version 2.1, +// as published by the Free Software Foundation. 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 License +// along with this program; if not, see . +// +//========================================================================== + +#include +#include "os_interface.h" +#import + +@interface AppUpdaterDelegate : NSObject + +@property (nonatomic) SPUStandardUpdaterController *updaterController; + +@end + +@implementation AppUpdaterDelegate + +- (void)updaterDidNotFindUpdate:(nonnull SPUUpdater *)updater + error:(nonnull NSError *)error +{ + NSString* str = [error localizedDescription]; + fprintf(stderr, "update error: %s\n", str.UTF8String); + fprintf(stderr, "description: %s\n", error.userInfo.description.UTF8String); +} + +@end + +static AppUpdaterDelegate* _updaterDelegate; + +// Autoupdate: initialize autoupdater. +void initializeAutoUpdate() +{ + _updaterDelegate = [[AppUpdaterDelegate alloc] init]; + _updaterDelegate.updaterController = [[SPUStandardUpdaterController alloc] initWithStartingUpdater:YES updaterDelegate:_updaterDelegate userDriverDelegate:nil]; +} + +// Autoupdate: cleanup autoupdater. +void cleanupAutoUpdate() +{ + [_updaterDelegate release]; +} From 78310bbda39c81197db21603e6843f5878a55c29 Mon Sep 17 00:00:00 2001 From: Mooneer Salem Date: Sat, 27 Jan 2024 19:15:01 -0800 Subject: [PATCH 4/6] Temporary change to debug failing GitHub action. --- .github/workflows/cmake-windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cmake-windows.yml b/.github/workflows/cmake-windows.yml index 995429068..00f84370a 100644 --- a/.github/workflows/cmake-windows.yml +++ b/.github/workflows/cmake-windows.yml @@ -46,4 +46,4 @@ jobs: working-directory: ${{github.workspace}}/build_windows run: | export PATH=${{github.workspace}}/llvm-mingw-20230320-ucrt-ubuntu-18.04-x86_64/bin:$PATH - make -j6 package + make package From 4c18ece4c99f46fc85e2acd6b9950c8378ba8862 Mon Sep 17 00:00:00 2001 From: Mooneer Salem Date: Sat, 27 Jan 2024 20:04:41 -0800 Subject: [PATCH 5/6] Install gettext package as part of Windows build. --- .github/workflows/cmake-windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cmake-windows.yml b/.github/workflows/cmake-windows.yml index 00f84370a..5a3fef966 100644 --- a/.github/workflows/cmake-windows.yml +++ b/.github/workflows/cmake-windows.yml @@ -23,7 +23,7 @@ jobs: - name: Install required packages shell: bash working-directory: ${{github.workspace}} - run: sudo apt-get install nsis + run: sudo apt-get install nsis gettext - name: Download MinGW LLVM shell: bash From 6e0d9819b13989f0283a911ee65c198d6d3d599f Mon Sep 17 00:00:00 2001 From: Mooneer Salem Date: Sat, 27 Jan 2024 20:57:21 -0800 Subject: [PATCH 6/6] Revert "Temporary change to debug failing GitHub action." This reverts commit 78310bbda39c81197db21603e6843f5878a55c29. --- .github/workflows/cmake-windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cmake-windows.yml b/.github/workflows/cmake-windows.yml index 5a3fef966..1479c8863 100644 --- a/.github/workflows/cmake-windows.yml +++ b/.github/workflows/cmake-windows.yml @@ -46,4 +46,4 @@ jobs: working-directory: ${{github.workspace}}/build_windows run: | export PATH=${{github.workspace}}/llvm-mingw-20230320-ucrt-ubuntu-18.04-x86_64/bin:$PATH - make package + make -j6 package