Skip to content

Commit

Permalink
build: implement packaging steps for the Windows build
Browse files Browse the repository at this point in the history
Implement a `pkg-windows` target that ultimately results in `Status.zip` being
written to `pkg/`.

Note: this commit does not introduce code signing for the Windows build since
that piece is still a work in progress.

`pkg-windows` creates a portable folder in `tmp/windows/dist` with the help of
[`windeployqt`][windeployqt], which copies the needed portions of Qt into the
folder.

Since DLL resolution is relatively inflexible, a launcher `Status.exe` is
created at the top-level of the folder; the launcher opens `bin/Status.exe`
while adding the portable folder's `bin/` to the `PATH`, allowing
`bin/Status.exe` to resolve the DLLs in that folder.

A few additional tools need to be installed (e.g. with [scoop][scoop]) and
availble in `PATH`:
* 7-zip
* dos2unix (provides unix2dos)
* findutils
* go
* rcedit
* wget

The above list builds on the tools list in PR status-im#521, and the other requirements
and instructions in that PR's description still apply.

**Why not build an installer?**

When starting work on packaging for the Windows build, my initial plan was to
build an installer, and for that purpose I researched the [WiX Toolset][wix],
the [Qt Installer Framework][qtif], and some other options.

I found that building an installer is a bit complex. I then recalled, from
personal experience, that [Cmder][cmder]'s [Mini download][mini] is
installer-less. You simply unzip the download and place the `cmder_mini` folder
wherever you prefer. Such an approach was also recommended to me in one of the
Nim language's community chats.

In addition to being simpler, the installer-less approach also gives
installation of Status Desktop a lower profile than an installer-application
would since nothing is written to the Windows registry, added to the *Add or
remove programs* list, etc. I think that's a benefit given the privacy-security
focus of Status, but others may feel differently so please provide feedback on
this point!

[windeployqt]: https://doc.qt.io/qt-5/windows-deployment.html
[scoop]: https://scoop.sh/
[wix]: https://wixtoolset.org/
[qtif]: https://doc.qt.io/qtinstallerframework/index.html
[cmder]: https://cmder.net/
[mini]: https://github.com/cmderdev/cmder/releases/download/v1.3.15/cmder_mini.zip
  • Loading branch information
michaelsbradleyjr committed Jul 17, 2020
1 parent 449b8c0 commit 29e74b6
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 16 deletions.
93 changes: 83 additions & 10 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@ BUILD_SYSTEM_DIR := vendor/nimbus-build-system
bottles \
bottles-dummy \
bottles-macos \
check-pkg-target-linux \
check-pkg-target-macos \
check-pkg-target-windows \
clean \
deps \
nim_status_client \
nim_windows_launcher \
pkg \
pkg-linux \
pkg-macos \
Expand Down Expand Up @@ -70,13 +74,31 @@ ifeq ($(detected_OS),Darwin)
else ifeq ($(detected_OS),Windows)
BOTTLES_TARGET := bottles-dummy
PKG_TARGET := pkg-windows
QRCODEGEN_MAKE_PARAMS := CC=gcc
RUN_TARGET := run-windows
VCINSTALLDIR ?= C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\BuildTools\\VC\\
export VCINSTALLDIR
else
BOTTLES_TARGET := bottles-dummy
PKG_TARGET := pkg-linux
RUN_TARGET := run-linux-or-macos
endif

check-pkg-target-linux:
ifneq ($(detected_OS),Linux)
$(error The pkg-linux target must be run on Linux)
endif

check-pkg-target-macos:
ifneq ($(detected_OS),Darwin)
$(error The pkg-macos target must be run on macOS)
endif

check-pkg-target-windows:
ifneq ($(detected_OS),Windows)
$(error The pkg-windows target must be run on Windows)
endif

bottles: $(BOTTLES_TARGET)

bottles-dummy: ;
Expand Down Expand Up @@ -142,7 +164,6 @@ else
DOTHERSIDE_BUILD_CMD := cmake --build . --config Release $(HANDLE_OUTPUT)
NIM_PARAMS += -L:$(DOTHERSIDE)
NIM_EXTRA_PARAMS := --passL:"-lsetupapi -lhid"
QRCODEGEN_MAKE_PARAMS := CC=gcc
endif

# TODO: control debug/release builds with a Make var
Expand Down Expand Up @@ -206,6 +227,7 @@ STATUS_CLIENT_APPIMAGE ?= pkg/NimStatusClient-x86_64.AppImage

$(STATUS_CLIENT_APPIMAGE): nim_status_client $(APPIMAGE_TOOL) nim-status.desktop
rm -rf pkg/*.AppImage
rm -rf tmp/linux/dist
mkdir -p tmp/linux/dist/usr/bin
mkdir -p tmp/linux/dist/usr/lib
mkdir -p tmp/linux/dist/usr/qml
Expand Down Expand Up @@ -285,18 +307,69 @@ ifdef MACOS_CODESIGN_IDENT
scripts/sign-macos-pkg.sh $(STATUS_CLIENT_DMG) $(MACOS_CODESIGN_IDENT)
endif

STATUS_CLIENT_EXE ?= pkg/Status.exe

# not implemented yet
# $(STATUS_CLIENT_EXE): nim_status_client
NIM_WINDOWS_PREBUILT_DLLS ?= tmp/windows/tools/pcre.dll

$(NIM_WINDOWS_PREBUILT_DLLS):
echo -e "\e[92mFetching:\e[39m prebuilt DLLs from nim-lang.org"
rm -rf tmp/windows
mkdir -p tmp/windows/tools
cd tmp/windows/tools && \
wget https://nim-lang.org/download/dlls.zip && \
unzip dlls.zip

nim_windows_launcher: | deps
$(ENV_SCRIPT) nim c -d:debug --outdir:./bin --passL:"-static-libgcc -Wl,-Bstatic,--whole-archive -lwinpthread -Wl,--no-whole-archive" src/nim_windows_launcher.nim

STATUS_CLIENT_ZIP ?= pkg/Status.zip

$(STATUS_CLIENT_ZIP): nim_status_client nim_windows_launcher $(NIM_WINDOWS_PREBUILT_DLLS)
rm -rf pkg/*.zip
rm -rf tmp/windows/dist
mkdir -p tmp/windows/dist/Status/bin
mkdir -p tmp/windows/dist/Status/resources
mkdir -p tmp/windows/dist/Status/vendor
cp windows-install.txt tmp/windows/dist/Status/INSTALL.txt
unix2dos -k tmp/windows/dist/Status/INSTALL.txt
# cp LICENSE tmp/windows/dist/Status/LICENSE.txt
# unix2dos -k tmp/windows/dist/Status/LICENSE.txt
cp status.ico tmp/windows/dist/Status/resources/
cp status.svg tmp/windows/dist/Status/resources/
cp resources.rcc tmp/windows/dist/Status/resources/
cp bin/nim_status_client.exe tmp/windows/dist/Status/bin/Status.exe
mv bin/nim_windows_launcher.exe tmp/windows/dist/Status/Status.exe
rcedit \
tmp/windows/dist/Status/bin/Status.exe \
--set-icon tmp/windows/dist/Status/resources/status.ico
rcedit \
tmp/windows/dist/Status/Status.exe \
--set-icon tmp/windows/dist/Status/resources/status.ico
cp $(DOTHERSIDE) tmp/windows/dist/Status/bin/
cp tmp/windows/tools/*.dll tmp/windows/dist/Status/bin/
cp "$(shell which libgcc_s_seh-1.dll)" tmp/windows/dist/Status/bin/
cp "$(shell which libwinpthread-1.dll)" tmp/windows/dist/Status/bin/

echo -e $(BUILD_MSG) "deployable folder"
windeployqt \
--compiler-runtime \
--qmldir ui \
--release \
tmp/windows/dist/Status/bin/DOtherSide.dll
mv tmp/windows/dist/Status/bin/vc_redist.x64.exe tmp/windows/dist/Status/vendor/
# implement code signing of applicable files in deployable folder

echo -e $(BUILD_MSG) "zip"
mkdir -p pkg
cd tmp/windows/dist/Status && \
7z a ../../../../pkg/Status.zip *
# can the final .zip file be code signed as well?

pkg: $(PKG_TARGET)

pkg-linux: $(STATUS_CLIENT_APPIMAGE)
pkg-linux: check-pkg-target-linux $(STATUS_CLIENT_APPIMAGE)

pkg-macos: $(STATUS_CLIENT_DMG)
pkg-macos: check-pkg-target-macos $(STATUS_CLIENT_DMG)

pkg-windows: $(STATUS_CLIENT_EXE)
pkg-windows: check-pkg-target-windows $(STATUS_CLIENT_ZIP)

clean: | clean-common
rm -rf bin/* node_modules pkg/* tmp/* $(STATUSGO)
Expand All @@ -312,10 +385,10 @@ run-linux-or-macos:
LD_LIBRARY_PATH="$(QT5_LIBDIR)" \
./bin/nim_status_client

run-windows:
run-windows: $(NIM_WINDOWS_PREBUILT_DLLS)
echo -e "\e[92mRunning:\e[39m bin/nim_status_client.exe"
NIM_STATUS_CLIENT_DEV="$(NIM_STATUS_CLIENT_DEV)" \
PATH="$(shell pwd)"/"$(shell dirname "$(DOTHERSIDE)")":"$(PATH)" \
PATH="$(shell pwd)"/"$(shell dirname "$(DOTHERSIDE)")":"$(shell pwd)"/"$(shell dirname "$(NIM_WINDOWS_PREBUILT_DLLS)")":"$(PATH)" \
./bin/nim_status_client.exe

endif # "variables.mk" was not included
1 change: 1 addition & 0 deletions config.nims
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ if defined(macosx):
# set the minimum supported macOS version to 10.13
switch("passC", "-mmacosx-version-min=10.13")
elif defined(windows):
--app:gui
--tlsEmulation:off
switch("passL", "-Wl,-as-needed")
else:
Expand Down
22 changes: 16 additions & 6 deletions src/nim_status_client.nim
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,19 @@ proc mainProc() =
initializeOpenGL()

let app = newQApplication("Nim Status Client")
QResource.registerResource(app.applicationDirPath & "/../resources.rcc")

app.icon(app.applicationDirPath & "/../status.svg")
let resources =
if defined(windows) and getEnv("NIM_STATUS_CLIENT_DEV").string == "":
"/../resources/resources.rcc"
else:
"/../resources.rcc"
QResource.registerResource(app.applicationDirPath & resources)

let statusSvg =
if defined(windows) and getEnv("NIM_STATUS_CLIENT_DEV").string == "":
"/../resources/status.svg"
else:
"/../status.svg"
app.icon(app.applicationDirPath & statusSvg)

let engine = newQQmlApplicationEngine()
let signalController = signals.newController(app)
Expand All @@ -54,7 +64,7 @@ proc mainProc() =
profile.init(args.account)
wallet.init()
chat.init()


var login = login.newController(status)
var onboarding = onboarding.newController(status)
Expand Down Expand Up @@ -84,7 +94,7 @@ proc mainProc() =
node.init()
login.init()
onboarding.init()

initControllers()

# Handle node.stopped signal when user has logged out
Expand All @@ -100,7 +110,7 @@ proc mainProc() =
# node.reset()
# wallet.reset()
# profile.reset()

# 2. Re-init controllers that don't require a running node
initControllers()

Expand Down
17 changes: 17 additions & 0 deletions src/nim_windows_launcher.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from os import getCurrentDir, joinPath
from winlean import Handle, shellExecuteW

const NULL: Handle = 0
let cwd = getCurrentDir()
let workDir_str = joinPath(cwd, "bin")
let exePath_str = joinPath(workDir_str, "Status.exe")
let open_str = "open"
let params_str = ""
let workDir = newWideCString(workDir_str)
let exePath = newWideCString(exePath_str)
let open = newWideCString(open_str)
let params = newWideCString(params_str)
# SW_SHOW (5): activates window and displays it in its current size and position
const showCmd: int32 = 5

discard shellExecuteW(NULL, open, exePath, params, workDir, showCmd)
42 changes: 42 additions & 0 deletions windows-install.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
REQUIREMENTS
============

This application requires 64-bit Windows 7 or newer.

INSTALLING
==========

After unzipping Status.zip, the Status folder can be placed wherever you prefer
(and have permissions) on your computer.

RUNNING
=======

Double-click Status.exe in the Status folder to launch the application.

If you see an error complaining about a DLL file, you should open
vc_redist.x64.exe in the Status\vendor folder to install the Microsoft Visual
C++ Redistributable. This is usually necessary only on versions of Windows
older than Windows 10. Then retry launching the application.

You may wish to right-click Status.exe and "Send to > Desktop (create shortcut)".
The application can then be launched by double-clicking the shortcut on your
desktop.

Status.exe persists settings and encrypted data in your %LOCALAPPDATA%\Status
folder.

UPGRADING
=========

To upgrade this application download the latest Status.zip, delete this Status
folder and the older Status.zip, unzip the newer one, and then place the new
Status folder in your preferred location.

If you place the new Status folder in a different location than the old one
then you should recreate any shortcuts you created for Status.exe.

UNINSTALLING
============

Delete this Status folder and delete your %LOCALAPPDATA%\Status folder.

0 comments on commit 29e74b6

Please sign in to comment.