Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add autoupdate functionality for Windows and macOS #674

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
2 changes: 1 addition & 1 deletion .github/workflows/cmake-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 8 additions & 1 deletion cmake/GetDependencies.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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})

Expand Down
7 changes: 4 additions & 3 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ set(FREEDV_SOURCES
freedv_interface.cpp
)

set(FREEDV_LINK_LIBS_OSX
list(APPEND FREEDV_LINK_LIBS_OSX
"-framework AVFoundation"
)

Expand All @@ -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}"
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion src/info.plist.in
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,7 @@
<string>NSApplication</string>
<key>NSRequiresAquaSystemAppearance</key>
<@DARK_MODE_DISABLE@ />
<key>SUFeedURL</key>
<string>https://k6aq.net/freedv-update/appcast.xml</string>
</dict>
</plist>
</plist>
6 changes: 6 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,9 @@ bool MainApp::OnCmdLineParsed(wxCmdLineParser& parser)
//-------------------------------------------------------------------------
bool MainApp::OnInit()
{
// Initialize autoupdate.
initializeAutoUpdate();

// Initialize locale.
m_locale.Init();

Expand Down Expand Up @@ -252,6 +255,9 @@ bool MainApp::OnInit()
//-------------------------------------------------------------------------
int MainApp::OnExit()
{
// Cleanup autoupdate.
cleanupAutoUpdate();

return 0;
}

Expand Down
68 changes: 67 additions & 1 deletion src/os/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,77 @@
# 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}
)

target_include_directories(fdv_os_wrapper PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/..)
include(ExternalProject)

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
ExternalProject_Add(build_winsparkle
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 -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/external/dist ${WINSPARKLE_CMAKE_ARGS}
)

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.
set(AUTOUPDATE_LIBRARY winsparkle)
add_dependencies(winsparkle build_winsparkle)
elseif(APPLE)
# 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)

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})
58 changes: 58 additions & 0 deletions src/os/macos_autoupdate.mm
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
//
//==========================================================================

#include <cstdio>
#include "os_interface.h"
#import <Sparkle/Sparkle.h>

@interface AppUpdaterDelegate : NSObject <SPUUpdaterDelegate>

@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];
}
35 changes: 35 additions & 0 deletions src/os/no_autoupdate.cpp
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
//
//==========================================================================

#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.
}
10 changes: 10 additions & 0 deletions src/os/os_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__
37 changes: 37 additions & 0 deletions src/os/windows_autoupdate.cpp
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
//
//==========================================================================

#include "os_interface.h"
#include <winsparkle.h>

// Autoupdate: initialize autoupdater.
void initializeAutoUpdate()
{
win_sparkle_set_appcast_url(FREEDV_APPCAST_URL);
win_sparkle_init();
}

// Autoupdate: cleanup autoupdater.
void cleanupAutoUpdate()
{
win_sparkle_cleanup();
}
Loading