Use vcpkg to manage openssl dep instead of choco (#7471)

* Brighter red

* Move openssl to vcpkg.exe

* Revert "Move openssl to vcpkg.exe"

This reverts commit 36f39d916f3cc2c8ce779442bd964bd6af7edd69.

* Add missing copyright

* Fix copyright dates

* Remove openssl from choco

* Install openssl using vcpkg

* Add deps for vcpkg

* Add missing vcpkg manifest

* Revert "Add deps for vcpkg"

This reverts commit c266d29c2cec4474a181b89c2f759b62ed67db10.

* Make vcpkg Windows only

* Improve comment about vcpkg

* Remove unused var

* Add caching for vcpkg

* Reorg launch.json

* Remove static env var for openssl on Windows

* Add openssl dep to vcpkg

* Update ChangeLog

* Add OpenSSL include dir

* Remove pointless choco cache

* Remove vcpkg downloads

* Remove wixtoolset for CI already installed on GitHub runners

* Use `Remove-Item` instead of `rmdir`

* Move cmake and ninja out of choco

* Revert "Move cmake and ninja out of choco (winget not supported on GitHub runner)"

This reverts commit a65c02d275e58705b8cd86fac72629284191d737.

* Move cmake and ninja to winget and don't use choco on CI

* Remove winget action

* Use scoop on CI and winget locally

* Use `seanmiddleditch/gha-setup-ninja` for Ninja

* Improve comments

* Install Ninja before deps

* Use system vcpkg if installed

* Revert "Use system vcpkg if installed"

This reverts commit 4ddee1c66e8cace458c047285a70d2f98cf9d82c.

* Add comment about why we're using local vcpkg

* Fixed comment about VC++

* Improve config comments

* Delete dead code

* Improve comment about vcpkg/buildtrees
This commit is contained in:
Nick Bolton
2024-09-04 16:52:37 +01:00
committed by GitHub
parent 0eadaec2d8
commit 94d9baca2d
38 changed files with 706 additions and 239 deletions

View File

@ -66,11 +66,13 @@ jobs:
with:
submodules: "recursive"
- name: Cache Chocolatey packages
- name: Cache vcpkg dirs
uses: actions/cache@v4
with:
path: ${{ runner.temp }}/choco
key: choco-${{ hashFiles('Chocolatey.config') }}
path: |
vcpkg
vcpkg_installed
key: vcpkg-${{ runner.os }}-${{ hashFiles('vcpkg.json', 'vcpkg-configuration.json') }}
- name: Cache deps dir
uses: actions/cache@v4
@ -78,11 +80,24 @@ jobs:
path: ./deps
key: ${{ runner.os }}-deps-${{ hashFiles('config.yaml') }}
# This effectively runs `vcvarsall.bat`, etc. It's not actually installing
# VC++ as that's already pre-installed on the Windows runner.
- name: Setup VC++ environment
uses: ilammy/msvc-dev-cmd@v1
# Install Ninja with an action instead of using Chocolatey, as it's more
# reliable and faster. The Ninja install action is pretty good as it
# downloads directly from the `ninja-build` GitHub project releases.
- name: Install Ninja
uses: seanmiddleditch/gha-setup-ninja@master
- name: Install dependencies
run: python ./scripts/install_deps.py
- name: Setup VC++ environment
uses: ilammy/msvc-dev-cmd@v1
# The vcpkg downloads dir can be quite large (over 2GB) which bloats the cache.
# For the most part, we don't need it so it probably safe to discard it.
- name: Cleanup vcpkg downloads
run: Remove-Item -Path vcpkg/downloads -Recurse -Force
- name: Configure
run: cmake -B build --preset=windows-release

2
.gitignore vendored
View File

@ -3,6 +3,8 @@
/dist
/deps
/tmp
/vcpkg
/vcpkg_installed
/scripts/**/*.pyc
aqtinstall.log
Brewfile.lock.json

95
.vscode/launch.json vendored
View File

@ -2,7 +2,7 @@
"version": "0.2.0",
"configurations": [
{
"name": "gui unix",
"name": "unix - gui",
"type": "lldb",
"cwd": "${workspaceRoot}",
"request": "launch",
@ -10,7 +10,45 @@
"preLaunchTask": "kill-build"
},
{
"name": "gui windows",
"name": "unix - unittests",
"type": "lldb",
"cwd": "${workspaceRoot}",
"request": "launch",
"program": "${workspaceFolder}/build/bin/unittests",
"preLaunchTask": "build"
},
{
"name": "unix - integtests",
"type": "lldb",
"cwd": "${workspaceRoot}",
"request": "launch",
"program": "${workspaceFolder}/build/bin/integtests",
"preLaunchTask": "build"
},
{
"name": "unix - server",
"type": "lldb",
"cwd": "${workspaceRoot}",
"request": "launch",
"program": "${workspaceFolder}/build/bin/synergys",
"preLaunchTask": "kill-build"
},
{
"name": "unix - client",
"type": "lldb",
"cwd": "${workspaceRoot}",
"request": "launch",
"program": "${workspaceFolder}/build/bin/synergyc",
"preLaunchTask": "kill-build"
},
{
"name": "unix - attach",
"type": "lldb",
"request": "attach",
"pid": "${command:pickProcess}"
},
{
"name": "windows - gui",
"type": "cppvsdbg",
"cwd": "${workspaceRoot}",
"request": "launch",
@ -19,15 +57,7 @@
"preLaunchTask": "kill-build"
},
{
"name": "unittests unix",
"type": "lldb",
"cwd": "${workspaceRoot}",
"request": "launch",
"program": "${workspaceFolder}/build/bin/unittests",
"preLaunchTask": "build"
},
{
"name": "unittests windows",
"name": "windows - unittests",
"type": "cppvsdbg",
"cwd": "${workspaceRoot}",
"request": "launch",
@ -36,15 +66,7 @@
"preLaunchTask": "build"
},
{
"name": "integtests unix",
"type": "lldb",
"cwd": "${workspaceRoot}",
"request": "launch",
"program": "${workspaceFolder}/build/bin/integtests",
"preLaunchTask": "build"
},
{
"name": "integtests windows",
"name": "windows - integtests",
"type": "cppvsdbg",
"cwd": "${workspaceRoot}",
"request": "launch",
@ -53,15 +75,7 @@
"preLaunchTask": "build"
},
{
"name": "server unix",
"type": "lldb",
"cwd": "${workspaceRoot}",
"request": "launch",
"program": "${workspaceFolder}/build/bin/synergys",
"preLaunchTask": "kill-build"
},
{
"name": "server windows",
"name": "windows - server",
"type": "cppvsdbg",
"cwd": "${workspaceRoot}",
"request": "launch",
@ -70,15 +84,7 @@
"preLaunchTask": "kill-build"
},
{
"name": "client unix",
"type": "lldb",
"cwd": "${workspaceRoot}",
"request": "launch",
"program": "${workspaceFolder}/build/bin/synergyc",
"preLaunchTask": "kill-build"
},
{
"name": "client windows",
"name": "windows - client",
"type": "cppvsdbg",
"cwd": "${workspaceRoot}",
"request": "launch",
@ -87,7 +93,7 @@
"preLaunchTask": "kill-build"
},
{
"name": "daemon windows",
"name": "windows - daemon",
"type": "cppvsdbg",
"cwd": "${workspaceRoot}",
"request": "launch",
@ -97,16 +103,17 @@
"preLaunchTask": "build"
},
{
"name": "windows attach",
"name": "windows - attach",
"type": "cppvsdbg",
"request": "attach",
"processId": "${command:pickProcess}"
},
{
"name": "unix attach",
"type": "lldb",
"request": "attach",
"pid": "${command:pickProcess}"
"name": "install_deps.py",
"type": "debugpy",
"request": "launch",
"program": "scripts/install_deps.py",
"console": "integratedTerminal"
}
]
}

View File

@ -1,6 +1,6 @@
# Synergy -- mouse and keyboard sharing utility
# Copyright (C) 2012-2024 Symless Ltd.
# Copyright (C) 2009-2012 Nick Bolton
# Copyright (C) 2024 Symless Ltd.
# Copyright (C) 2009 Nick Bolton
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License

View File

@ -25,9 +25,6 @@
"CMAKE_C_COMPILER": "cl.exe",
"CMAKE_CXX_COMPILER": "cl.exe"
},
"environment": {
"SYNERGY_STATIC_OPENSSL": "ON"
},
"architecture": {
"value": "x64",
"strategy": "external"

View File

@ -12,6 +12,7 @@ Enhancements:
- #7465 Also cut `+` char for `SHORT_VERSION` var used on upload
- #7467 Load server or client args from `synergy-config.toml`
- #7469 Option to link against local `libportal` and other subprojects
- #7471 Use `vcpkg` to manage `openssl` dep instead of `choco`
# 1.15.1

View File

@ -2,9 +2,6 @@
<!-- install with: choco install Chocolatey.config -y -->
<packages>
<package id="cmake" />
<package id="ninja" />
<package id="openssl" />
<package id="wixtoolset" />
<package id="visualstudio2022buildtools"
packageParameters="--includeRecommended --add Microsoft.VisualStudio.Workload.MSBuildTools --add Microsoft.VisualStudio.Workload.VCTools " />

View File

@ -433,11 +433,31 @@ macro(configure_windows_libs)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/res/win/version.rc.in
${CMAKE_BINARY_DIR}/src/version.rc @ONLY)
find_openssl_dir_win32(OPENSSL_PATH)
add_definitions(-DOPENSSL_PATH="${OPENSSL_PATH}")
configure_windows_openssl()
endmacro()
macro(configure_windows_openssl)
# Strangely, vcpkg doesn't seem to put openssl.exe in the `vcpkg_installed` dir,
# so we have to fish it out of the `vcpkg/buildtrees` dir.
set(OPENSSL_EXE_DIR
${CMAKE_SOURCE_DIR}/vcpkg/buildtrees/openssl/x64-windows-rel/apps)
set(OPENSSL_ROOT_DIR ${CMAKE_SOURCE_DIR}/vcpkg_installed/x64-windows)
if(EXISTS ${OPENSSL_EXE_DIR})
message(STATUS "OpenSSL exe dir: ${OPENSSL_EXE_DIR}")
add_definitions(-DOPENSSL_EXE_DIR="${OPENSSL_EXE_DIR}")
else()
message(FATAL_ERROR "OpenSSL exe dir not found: ${OPENSSL_EXE_DIR}")
endif()
if(EXISTS ${OPENSSL_ROOT_DIR})
message(STATUS "OpenSSL root dir: ${OPENSSL_ROOT_DIR}")
else()
message(FATAL_ERROR "OpenSSL root dir not found: ${OPENSSL_ROOT_DIR}")
endif()
endmacro()
macro(configure_qt)
find_package(
@ -453,11 +473,13 @@ macro(configure_openssl)
# Apple has to use static libraries because "Use of the Apple-provided OpenSSL
# libraries by apps is strongly discouraged."
# https://developer.apple.com/library/archive/documentation/Security/Conceptual/cryptoservices/SecureNetworkCommunicationAPIs/SecureNetworkCommunicationAPIs.html
if(APPLE OR DEFINED ENV{SYNERGY_STATIC_OPENSSL})
# TODO: How about bundling the OpenSSL .dylib files with the app so they can be updated?
if(APPLE)
set(OPENSSL_USE_STATIC_LIBS TRUE)
endif()
find_package(OpenSSL REQUIRED)
include_directories(${OPENSSL_INCLUDE_DIR})
endmacro()
macro(configure_gtest)
@ -561,39 +583,6 @@ macro(configure_python)
endif()
endmacro()
#
# Find the OpenSSL directory on Windows based on the location of the first
# `openssl` binary found.
#
function(find_openssl_dir_win32 result)
execute_process(
COMMAND where openssl
OUTPUT_VARIABLE OPENSSL_PATH
OUTPUT_STRIP_TRAILING_WHITESPACE)
# It's possible that there are multiple OpenSSL installations on the system,
# which is the case on GitHub runners. For now we'll pick the first one, but
# that's probably not very robust. Maybe our choco config could install to a
# specific location?
string(REGEX REPLACE "\r?\n" ";" OPENSSL_PATH_LIST ${OPENSSL_PATH})
message(STATUS "Found OpenSSL binaries at: ${OPENSSL_PATH_LIST}")
list(GET OPENSSL_PATH_LIST 0 OPENSSL_FIRST_PATH)
message(VERBOSE "First OpenSSL binary: ${OPENSSL_FIRST_PATH}")
get_filename_component(OPENSSL_BIN_DIR ${OPENSSL_FIRST_PATH} DIRECTORY)
message(VERBOSE "OpenSSL bin dir: ${OPENSSL_BIN_DIR}")
get_filename_component(OPENSSL_DIR ${OPENSSL_BIN_DIR} DIRECTORY)
message(VERBOSE "OpenSSL install root dir: ${OPENSSL_DIR}")
set(${result}
${OPENSSL_DIR}
PARENT_SCOPE)
endfunction()
macro(configure_wintoast)
# WinToast is a pretty niche library, and there doesn't seem to be an installable package,
# so we rely on building from source.

View File

@ -1,16 +1,20 @@
config:
windows:
dependencies:
command: choco install Chocolatey.config -y
# We only run `choco` when not in CI env because it's pretty unreliable and slow.
# The Chocolatey mirror cannot be 100% reliable (according to docs) so it will often fail
# with an error `503 (Service Unavailable: Back-end server is at capacity)` which causes
# the nightly CI to fail intermittently.
command-elevated: if not defined CI (choco install Chocolatey.config -y)
# We only run `winget` when not in CI env; it's not available on the GitHub Windows runner.
# It's simpler to solve dependencies like Ninja with a GitHub workflow action, and cmake is
# already installed on the Windows runner.
command: if not defined CI (winget install ninja-build.ninja cmake)
qt:
version: 6.7
mirror: https://qt.mirror.constant.com/
base-dir: ./deps/qt
ci:
edit-config: Chocolatey.config
skip-packages:
- cmake
- visualstudio2022buildtools
mac:
dependencies:

View File

@ -59,6 +59,7 @@
"synergyd",
"synergys",
"Valgrind",
"vcpkg",
"Volker",
"winget"
],

View File

@ -18,6 +18,6 @@
<?define QtPath="@QT_PATH@"?>
<?define QtBinPath="$(var.QtPath)\bin"?>
<?define QtPluginsPath="$(var.QtPath)\plugins"?>
<?define OpenSSLPath="@OPENSSL_PATH@"?>
<?define OpenSSLBinPath="$(var.OpenSSLPath)\bin"?>
<?define OpenSslExeDir="@OPENSSL_EXE_DIR@"?>
<?define OpenSslDllDir="@OPENSSL_ROOT_DIR@/bin"?>
</Include>

View File

@ -90,11 +90,11 @@
</File>
<File Source="$(var.BinPath)/syntool.exe"/>
<?if $(var.Platform) = x64 ?>
<File Source="$(var.OpenSSLBinPath)/libssl-3-x64.dll"/>
<File Source="$(var.OpenSSLBinPath)/libcrypto-3-x64.dll"/>
<File Source="$(var.OpenSslDllDir)/libssl-3-x64.dll"/>
<File Source="$(var.OpenSslDllDir)/libcrypto-3-x64.dll"/>
<?else ?>
<File Source="$(var.OpenSSLBinPath)/libssl-3.dll"/>
<File Source="$(var.OpenSSLBinPath)/libcrypto-3.dll"/>
<File Source="$(var.OpenSslDllDir)/libssl-3.dll"/>
<File Source="$(var.OpenSslDllDir)/libcrypto-3.dll"/>
<?endif ?>
</Component>
<Component Guid="BAC8149B-6287-45BF-9C27-43D71ED40214" Id="Gui">
@ -140,13 +140,13 @@
<ComponentGroup Directory="OpenSSLDir" Id="OpenSSLComponents">
<Component Guid="92648F77-65A6-4B16-AC59-A1F37BD341B1" Id="OpenSSL">
<?if $(var.Platform) = x64 ?>
<File Id="OpenSSLDll1" Source="$(var.OpenSSLBinPath)/libcrypto-3-x64.dll"/>
<File Id="OpenSSLDll2" Source="$(var.OpenSSLBinPath)/libssl-3-x64.dll"/>
<File Id="OpenSSLDll1" Source="$(var.OpenSslDllDir)/libcrypto-3-x64.dll"/>
<File Id="OpenSSLDll2" Source="$(var.OpenSslDllDir)/libssl-3-x64.dll"/>
<?else ?>
<File Id="OpenSSLDll1" Source="$(var.OpenSSLBinPath)/libcrypto-3.dll"/>
<File Id="OpenSSLDll2" Source="$(var.OpenSSLBinPath)/libssl-3.dll"/>
<File Id="OpenSSLDll1" Source="$(var.OpenSslDllDir)/libcrypto-3.dll"/>
<File Id="OpenSSLDll2" Source="$(var.OpenSslDllDir)/libssl-3.dll"/>
<?endif ?>
<File Source="$(var.OpenSSLBinPath)/openssl.exe"/>
<File Source="$(var.OpenSslExeDir)/openssl.exe"/>
<File Source="$(var.ResPath)/openssl/synergy.conf"/>
</Component>
</ComponentGroup>

View File

@ -1,5 +1,20 @@
#!/usr/bin/env python3
# Synergy -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package 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, see <http://www.gnu.org/licenses/>.
import lib.env as env
env.ensure_in_venv(__file__)
@ -70,7 +85,7 @@ def print_verbose(context, message):
def ensure_admin():
if not windows.is_admin():
windows.relaunch_as_admin(__file__)
windows.run_elevated(__file__)
sys.exit()

View File

@ -1,5 +1,20 @@
#!/usr/bin/env python3
# Synergy -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package 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, see <http://www.gnu.org/licenses/>.
import lib.env as env
env.ensure_in_venv(__file__)

View File

@ -1,5 +1,20 @@
#!/usr/bin/env python3
# Synergy -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package 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, see <http://www.gnu.org/licenses/>.
import os, sys, argparse, traceback
import lib.env as env
import lib.cmd_utils as cmd_utils
@ -17,65 +32,49 @@ def main():
print("CI environment detected")
args = parse_args(is_ci)
if args.lock_file:
env.persist_lock_file(args.lock_file)
env.ensure_dependencies()
env.ensure_in_venv(__file__, auto_create=True)
env.install_requirements()
colors = env.import_colors()
if args.only_python:
print()
print(colors.SUCCESS_TEXT + " Only Python dependencies installed")
return
error = False
try:
run(args)
except Exception:
traceback.print_exc()
error = True
print()
if error:
print(f"{colors.ERROR_TEXT} Failed to install dependencies")
else:
print(f"{colors.SUCCESS_TEXT} Dependencies installed")
# On Windows and macOS, we set env vars for cmake, but for them to be picked up,
# either the shell needs to be restarted or the env vars need to be re-sourced.
# Restarting the shell is easier for most people.
if not env.is_linux():
print(
f"{colors.WARNING_TEXT} You may need to restart your terminal "
"or IDE to use new env vars"
)
# Useful on Windows, when elevated, Python is opened in a new window and closes
# immediately after the script finishes. This keeps the script window open so that
# the user can see the output.
if args.pause_on_exit:
print()
input("Press enter to continue...")
if error:
sys.exit(1)
finally:
if env.is_windows() and args.pause_on_exit:
# Allow the rest of the install to continue while sitting at the pause.
if args.lock_file:
env.remove_lock_file(args.lock_file)
# Useful on Windows, when elevated, Python is opened in a new window and closes
# immediately after the script finishes. This keeps the script window open so that
# the user can see the output.
print()
input("Press enter to continue...")
def parse_args(is_ci):
parser = argparse.ArgumentParser()
parser.add_argument(
"--pause-on-exit", action="store_true", help="Useful on Windows"
)
parser.add_argument(
"--ci-env",
action="store_true",
help="Useful for faking CI env (defaults to true in CI env)",
default=is_ci,
)
parser.add_argument(
"--lock-file",
type=str,
help="Create a file to indicate script is running",
)
parser.add_argument(
"--only-python", action="store_true", help="Only install Python dependencies"
)
parser.add_argument(
"--skip-python",
action="store_true",
help="Do not install Python dependencies",
)
parser.add_argument(
"--skip-system",
action="store_true",
@ -97,18 +96,84 @@ def parse_args(is_ci):
nargs="+",
help="Specify which Meson subprojects to use instead of system dependencies",
)
if env.is_windows():
parser.add_argument(
"--skip-vcpkg",
action="store_true",
help="Windows only: Do not install vcpkg dependencies",
)
parser.add_argument(
"--skip-elevated",
action="store_true",
help="Windows only: Do not run elevated command",
)
parser.add_argument(
"--only-elevated",
action="store_true",
help="Windows only: Only run elevated command",
)
parser.add_argument(
"--pause-on-exit",
action="store_true",
help="Windows only: Useful to prevent elevated window from closing",
)
return parser.parse_args()
def run(args):
env.ensure_dependencies()
env.ensure_in_venv(__file__, auto_create=True)
if not args.skip_python:
env.install_requirements()
colors = env.import_colors()
if args.only_python:
print()
print(colors.SUCCESS_TEXT + " Only Python dependencies installed")
return
try:
install(args)
print()
print(f"\n{colors.SUCCESS_TEXT} Dependencies installed")
# On Windows and macOS, we set env vars for cmake, but for them to be picked up,
# either the shell needs to be restarted or the env vars need to be re-sourced.
# Restarting the shell is easier for most people.
if not env.is_linux():
print(
f"{colors.WARNING_TEXT} You may need to restart your terminal "
"or IDE to use new env vars"
)
except Exception:
traceback.print_exc()
print()
print(f"\n{colors.ERROR_TEXT} Failed to install dependencies")
sys.exit(1)
def install(args):
if not args.skip_system:
deps = Dependencies(args)
deps.install()
if args.subproject:
deps = SubprojectDependencies(args.subproject)
deps.install()
return
if not args.skip_system:
deps = Dependencies(args.ci_env)
deps.install()
# Only install vcpkg dependencies on Windows, since on other OS it's not needed (yet).
# We probably won't ever need this on macOS and Linux since brew and apt/dnf/etc do a
# good job of providing dependencies. Where they don't, we can use Meson.
if env.is_windows() and not args.skip_vcpkg:
import lib.vcpkg as vcpkg
vcpkg.install()
if not args.skip_meson:
run_meson(args.meson_install, args.meson_no_system)
@ -132,11 +197,12 @@ def run_meson(install, no_system_list):
class Dependencies:
def __init__(self, ci_env):
def __init__(self, args):
from lib.config import Config
self.config = Config()
self.ci_env = ci_env
self.args = args
self.ci_env = args.ci_env
def install(self):
"""Installs dependencies for the current platform."""
@ -154,9 +220,16 @@ class Dependencies:
"""Installs dependencies on Windows."""
import lib.windows as windows
if not windows.is_admin():
windows.relaunch_as_admin(__file__)
sys.exit()
if not self.args.skip_elevated:
if not windows.is_admin():
windows.run_elevated(__file__, "--only-elevated --skip-python")
elif self.args.only_elevated:
# The choco command should run from the elevated command.
choco = windows.WindowsChoco()
choco.ensure_choco_installed()
command_elevated = self.config.get_os_deps_command("command-elevated")
cmd_utils.run(command_elevated, shell=True, print_cmd=True)
sys.exit(0)
qt = qt_utils.WindowsQt(*self.config.get_qt_config())
qt.install()
@ -166,14 +239,9 @@ class Dependencies:
else:
windows.set_env_var(cmake_prefix_env_var, qt.get_install_dir())
choco = windows.WindowsChoco()
if self.ci_env:
choco.config_ci_cache()
edit_config, skip_packages = self.config.get_windows_ci_config()
choco.remove_from_config(edit_config, skip_packages)
command = self.config.get_os_deps_command()
choco.install(command, self.ci_env)
cmd_utils.run(command, shell=True, print_cmd=True)
def mac(self):
"""Installs dependencies on macOS."""

View File

@ -1,5 +1,20 @@
import os, base64
# Synergy -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package 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, see <http://www.gnu.org/licenses/>.
temp_path = "tmp/certificate"

View File

@ -1,3 +1,18 @@
# Synergy -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package 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, see <http://www.gnu.org/licenses/>.
import subprocess
import sys
import lib.env as env

View File

@ -1,9 +1,24 @@
# Synergy -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package 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, see <http://www.gnu.org/licenses/>.
import colorama # type: ignore
from colorama import Fore # type: ignore
colorama.init()
SUCCESS_TEXT = f"{Fore.LIGHTGREEN_EX}Success:{Fore.RESET}"
ERROR_TEXT = f"{Fore.RED}Error:{Fore.RESET}"
ERROR_TEXT = f"{Fore.LIGHTRED_EX}Error:{Fore.RESET}"
WARNING_TEXT = f"{Fore.LIGHTYELLOW_EX}Warning:{Fore.RESET}"
HINT_TEXT = f"{Fore.LIGHTBLUE_EX}Hint:{Fore.RESET}"

View File

@ -1,3 +1,18 @@
# Synergy -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package 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, see <http://www.gnu.org/licenses/>.
import yaml
import lib.env as env
import lib.cmd_utils as cmd_utils

View File

@ -1,3 +1,18 @@
# Synergy -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package 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, see <http://www.gnu.org/licenses/>.
import os, sys, subprocess
import lib.cmd_utils as cmd_utils
@ -233,3 +248,23 @@ def import_colors():
import lib.colors as colors
return colors
def persist_lock_file(path):
"""
Persists a lock file and ensures the directory part of the path exists.
"""
dir_path = os.path.dirname(path)
if not os.path.exists(dir_path):
os.makedirs(dir_path, exist_ok=True)
with open(path, "w") as f:
f.write(str(os.getpid()))
def remove_lock_file(path):
"""
Removes a lock file if it exists.
"""
if os.path.exists(path):
os.remove(path)

View File

@ -1,3 +1,18 @@
# Synergy -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package 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, see <http://www.gnu.org/licenses/>.
import glob, os, shutil, sys
import lib.env as env
import lib.colors as colors

View File

@ -1,3 +1,18 @@
# Synergy -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package 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, see <http://www.gnu.org/licenses/>.
import os, fnmatch

View File

@ -1,3 +1,18 @@
# Synergy -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package 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, see <http://www.gnu.org/licenses/>.
import os
github_env_key = "GITHUB_ENV"

View File

@ -1,3 +1,18 @@
# Synergy -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package 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, see <http://www.gnu.org/licenses/>.
import os, shutil, glob, sys
import lib.cmd_utils as cmd_utils
import lib.env as env

View File

@ -1,3 +1,18 @@
# Synergy -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package 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, see <http://www.gnu.org/licenses/>.
import dmgbuild # type: ignore
import os, time, json, shutil
import lib.cmd_utils as cmd_utils

View File

@ -1,3 +1,18 @@
# Synergy -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package 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, see <http://www.gnu.org/licenses/>.
import lib.cmd_utils as cmd_utils
import lib.env as env
import os

View File

@ -1,3 +1,18 @@
# Synergy -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package 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, see <http://www.gnu.org/licenses/>.
import os
import lib.cmd_utils as cmd_utils
import lib.env as env

63
scripts/lib/vcpkg.py Normal file
View File

@ -0,0 +1,63 @@
# Synergy -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package 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, see <http://www.gnu.org/licenses/>.
import os
import git # type: ignore
import lib.env as env
import lib.cmd_utils as cmd_utils
GIT_REPO = "https://github.com/microsoft/vcpkg.git"
def install():
vcpkg_bin = ensure_vcpkg()
cmd_utils.run([vcpkg_bin, "install"], print_cmd=True)
# Install a local vcpkg even if it's already installed system-wide, so that we can cache the
# vcpkg dirs in the CI env. We also depend on the local `vcpkg/buildtrees` dir when bundling
# the `openssl.exe` binary on Windows (that said, we could also use cmake to search for it).
def ensure_vcpkg():
if not os.path.exists("vcpkg"):
get_vcpkg()
else:
print("Updating vcpkg...")
repo = git.Repo("vcpkg")
repo.remotes.origin.pull()
if env.is_windows():
vcpkg_bin = "vcpkg/vcpkg.exe"
else:
vcpkg_bin = "vcpkg/vcpkg"
if not os.path.exists(vcpkg_bin):
raise RuntimeError(f"Path not found: {vcpkg_bin}")
return vcpkg_bin
def get_vcpkg():
print("Downloading vcpkg...")
git.Repo.clone_from(GIT_REPO, "vcpkg")
os.chdir("vcpkg")
try:
if env.is_windows():
cmd_utils.run("bootstrap-vcpkg.bat", shell=True, print_cmd=True)
else:
cmd_utils.run("./bootstrap-vcpkg.sh", shell=True, print_cmd=True)
finally:
os.chdir("..")

View File

@ -1,24 +1,73 @@
# Synergy -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package 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, see <http://www.gnu.org/licenses/>.
import ctypes, sys, os, shutil
import xml.etree.ElementTree as ET
import lib.cmd_utils as cmd_utils
import lib.env as env
from lib.certificate import Certificate
msbuild_cmd = "msbuild"
signtool_cmd = "signtool"
certutil_cmd = "certutil"
runner_temp_env_var = "RUNNER_TEMP"
dist_dir = "dist"
build_dir = "build"
wix_solution_file = f"{build_dir}/installer/Synergy.sln"
installer_file = f"{build_dir}/installer/bin/Release/Synergy.msi"
LOCK_FILE = "tmp/elevated.lock"
MSBUILD_CMD = "msbuild"
SIGNTOOL_CMD = "signtool"
CERTUTIL_CMD = "certutil"
RUNNER_TEMP_ENV = "RUNNER_TEMP"
DIST_DIR = "dist"
BUILD_DIR = "build"
WIX_FILE = f"{BUILD_DIR}/installer/Synergy.sln"
MSI_FILE = f"{BUILD_DIR}/installer/bin/Release/Synergy.msi"
def relaunch_as_admin(script):
args = " ".join(sys.argv[1:])
command = f"{script} --pause-on-exit {args}"
print(f"Re-launching script as admin: {command}")
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, command, None, 1)
def run_elevated(script, args=None, use_sys_argv=True):
if not args and use_sys_argv:
args = " ".join(sys.argv[1:])
env.persist_lock_file(LOCK_FILE)
command = f"{script} --pause-on-exit --lock-file {LOCK_FILE} {args}"
print(f"Running script with elevated privileges: {command}")
WINDOW_HANDLE = None
OPERATION = "runas"
DIRECTORY = None
SHOW_CMD = 1
instance = ctypes.windll.shell32.ShellExecuteW(
WINDOW_HANDLE, OPERATION, sys.executable, command, DIRECTORY, SHOW_CMD
)
ERROR_ACCESS_DENIED = 5
if instance == ERROR_ACCESS_DENIED:
raise RuntimeError(
f"Failed to run script with elevated privileges, access denied (code {instance})"
)
ERROR_MAX = 32
if instance <= ERROR_MAX:
raise RuntimeError(
f"Failed to run script with elevated privileges, error code: {instance}"
)
print("Script is running with elevated privileges")
with open(LOCK_FILE, "r") as f:
pid = f.read()
print(f"Waiting for elevated process to exit: {pid}")
while os.path.exists(LOCK_FILE):
# Intentionally wait forever, since this code should not run where a developer
# has no control, such as in a CI environment.
pass
def is_admin():
@ -76,11 +125,11 @@ def build_msi(filename_base):
configuration = "Release"
platform = "x64"
assert_vs_cmd(msbuild_cmd)
assert_vs_cmd(MSBUILD_CMD)
cmd_utils.run(
[
msbuild_cmd,
wix_solution_file,
MSBUILD_CMD,
WIX_FILE,
f"/p:Configuration={configuration}",
f"/p:Platform={platform}",
],
@ -89,17 +138,17 @@ def build_msi(filename_base):
)
path = get_package_path(filename_base)
print(f"Copying MSI installer to {dist_dir}")
os.makedirs(dist_dir, exist_ok=True)
shutil.copy(installer_file, path)
print(f"Copying MSI installer to {DIST_DIR}")
os.makedirs(DIST_DIR, exist_ok=True)
shutil.copy(MSI_FILE, path)
def get_package_path(filename_base):
return f"{dist_dir}/{filename_base}.msi"
return f"{DIST_DIR}/{filename_base}.msi"
def sign_binaries(cert_base64, cert_password):
exe_pattern = f"{build_dir}/bin/*.exe"
exe_pattern = f"{BUILD_DIR}/bin/*.exe"
run_codesign(exe_pattern, cert_base64, cert_password)
@ -114,12 +163,12 @@ def run_codesign(path, cert_base64, cert_password):
with Certificate(cert_base64, "pfx") as cert_path:
print("Signing MSI installer...")
assert_vs_cmd(signtool_cmd)
assert_vs_cmd(SIGNTOOL_CMD)
# WARNING: contains private key password, never print this command
cmd_utils.run(
[
signtool_cmd,
SIGNTOOL_CMD,
"sign",
"/f",
cert_path,
@ -137,58 +186,15 @@ def run_codesign(path, cert_base64, cert_password):
class WindowsChoco:
"""Chocolatey for Windows."""
def install(self, command, ci_env):
"""Installs packages using Chocolatey."""
if ci_env:
# don't show noisy choco progress bars in ci env
cmd_utils.run(
f"{command} --no-progress",
shell=True,
print_cmd=True,
)
else:
self.ensure_choco_installed()
cmd_utils.run(
command,
shell=True,
print_cmd=True,
)
def config_ci_cache(self):
"""Configures Chocolatey cache for CI."""
runner_temp = os.environ.get(runner_temp_env_var)
if runner_temp:
# sets the choco cache dir, which should match the dir in the ci cache action.
key_arg = '--name="cacheLocation"'
value_arg = f'--value="{runner_temp}/choco"'
cmd_utils.run(
["choco", "config", "set", key_arg, value_arg],
print_cmd=True,
)
else:
print(f"Warning: CI environment variable {runner_temp_env_var} not set")
def remove_from_config(self, choco_config_file, remove_packages):
"""Removes a package from the Chocolatey configuration."""
tree = ET.parse(choco_config_file)
root = tree.getroot()
for remove in remove_packages:
for package in root.findall("package"):
if package.get("id") == remove:
root.remove(package)
print(f"Removed package from choco config: {remove}")
tree.write(choco_config_file)
def ensure_choco_installed(self):
if cmd_utils.has_command("choco"):
return
if not cmd_utils.has_command("winget"):
print("The winget command was not found", file=sys.stderr)
print(
"The winget command was not found, please install Chocolatey manually",
file=sys.stderr,
)
sys.exit(1)
print("The choco command was not found, installing Chocolatey...")

View File

@ -1,5 +1,20 @@
#!/usr/bin/env python3
# Synergy -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package 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, see <http://www.gnu.org/licenses/>.
import lib.env as env
env.ensure_in_venv(__file__)

View File

@ -1,5 +1,20 @@
#!/usr/bin/env python3
# Synergy -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package 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, see <http://www.gnu.org/licenses/>.
import lib.env as env
env.ensure_in_venv(__file__)

View File

@ -1,5 +1,20 @@
#!/usr/bin/env python3
# Synergy -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package 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, see <http://www.gnu.org/licenses/>.
import lib.env as env
env.ensure_in_venv(__file__)

View File

@ -12,4 +12,5 @@ dependencies = [
"aqtinstall; sys_platform == 'win32' or sys_platform == 'darwin'",
"colorama",
"meson",
"gitpython",
]

View File

@ -1,5 +1,20 @@
#!/usr/bin/env python3
# Synergy -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package 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, see <http://www.gnu.org/licenses/>.
import lib.env as env
env.ensure_in_venv(__file__)

View File

@ -51,7 +51,7 @@ QString openSslWindowsDir() {
// in production, openssl is deployed with the app.
// in development, we can use the openssl path available at compile-time.
if (!openSslDir.exists()) {
openSslDir = QDir(OPENSSL_PATH);
openSslDir = QDir(OPENSSL_EXE_DIR);
}
// if the path still isn't found, something is seriously wrong.

View File

@ -22,10 +22,12 @@ if(ADD_HEADERS_TO_SOURCES)
endif()
add_library(net STATIC ${sources})
target_link_libraries(
net
PUBLIC OpenSSL::SSL
PUBLIC ${OPENSSL_LIBRARIES}
PRIVATE mt io)
if(WIN32)
target_link_libraries(net PRIVATE Crypt32 ws2_32)
endif()

14
vcpkg-configuration.json Normal file
View File

@ -0,0 +1,14 @@
{
"default-registry": {
"kind": "git",
"baseline": "4e08971f3ddc13018ca858a692efe92d3b6b9fce",
"repository": "https://github.com/microsoft/vcpkg"
},
"registries": [
{
"kind": "artifact",
"location": "https://github.com/microsoft/vcpkg-ce-catalog/archive/refs/heads/main.zip",
"name": "microsoft"
}
]
}

10
vcpkg.json Normal file
View File

@ -0,0 +1,10 @@
{
"dependencies": [
{
"name": "openssl",
"features": [
"tools"
]
}
]
}