NSIS CPack generator forcibly overwrites $INSTDIR to $DOCUMENTS for per-user JustMe installs

Hiya

I’ve run into an issue with using the NSIS generator for CPack where it’s not possible to change the default install location for per-user JustMe installs. Specifically, if you wanted to change the default per-user install location $INSTDIR to something like $LOCALAPPDATA\@CPACK_PACKAGE_INSTALL_DIRECTORY@ by setting set(CPACK_NSIS_INSTALL_ROOT "$LOCALAPPDATA") or something similar, CMake will automatically forcibly overwrite it and change $INSTDIR to $DOCUMENTS\@CPACK_PACKAGE_INSTALL_DIRECTORY@. This appears to be enforced by the default NSIS.template.in provided with CPack for some reason in the default NSIS.template.in:

;--------------------------------
; determine admin versus local install
; Is install for "AllUsers" or "JustMe"?
; Default to "JustMe" - set to "AllUsers" if admin or on Win9x
; This function is used for the very first "custom page" of the installer.
; This custom page does not show up visibly, but it executes prior to the
; first visible page and sets up $INSTDIR properly...
; Choose different default installation folder based on SV_ALLUSERS...
; "Program Files" for AllUsers, "My Documents" for JustMe...

Function .onInit

  ;...

inst:
  ; Reads components status for registry
  !insertmacro SectionList "InitSection"

  ; check to see if /D has been used to change
  ; the install directory by comparing it to the
  ; install directory that is expected to be the
  ; default
  StrCpy $IS_DEFAULT_INSTALLDIR 0
  StrCmp "$INSTDIR" "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" 0 +2
    StrCpy $IS_DEFAULT_INSTALLDIR 1

  StrCpy $SV_ALLUSERS "JustMe"
  ; if default install dir then change the default
  ; if it is installed for JustMe
  StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2
    StrCpy $INSTDIR "$DOCUMENTS\@CPACK_PACKAGE_INSTALL_DIRECTORY@"

  ;...

  done:
  StrCmp $SV_ALLUSERS "AllUsers" 0 +3
    StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2
      StrCpy $INSTDIR "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@"

  ;...

FunctionEnd

By my interpretation, this actually reads like a design mistake, seemingly assuming that @CPACK_NSIS_INSTALL_ROOT@ is always the default directory for an AllUsers installation (e.g., C:/Program Files), ignoring the case where AllUsers installations may be disabled (i.e., JustMe is enforced). In this case, the install directory is always forcibly changed to $Documents, no matter what @CPACK_NSIS_INSTALL_ROOT@ is actually set to (including if it’s a local user directory), with no way to change the default install location.

As a result, it’s impossible to modify the install location to something sensible like Users/<user>/AppData/Local/<Application>, as CPack will hard enforce the default of <user>/Documents/<Application>, which is frankly a poor location to install a program. It’s very strange that CPACK_NSIS_INSTALL_ROOT is even an option at all if CPack will always override and ignore it by default for per-user installs. Further, this behavior is entirely undocumented in the CMake/CPack documentation, and is actually in effect contradictory to the existing explanation of CPACK_NSIS_INSTALL_ROOT if considering both the AllUsers and JustMe cases, as the JustMe case will always ignore CPACK_NSIS_INSTALL_ROOT:

CPACK_NSIS_INSTALL_ROOT

The default installation directory presented to the end user by the NSIS installer is under this root dir. The full directory presented to the end user is: ${CPACK_NSIS_INSTALL_ROOT}/${CPACK_PACKAGE_INSTALL_DIRECTORY}

I think the documentation for CPACK_NSIS_INSTALL_ROOT ought to specify it is only relevant for AllUsers install scopes and an additional variable should exist for handling the JustMe install scope (or at the very least, it should default to $LOCALAPPDATA instead of $DOCUMENTS). Additionally, by my reading it seems strange that the default behavior is to manually override the install directory to $DOCUMENTS and then manually change it back to CPACK_NSIS_INSTALL_ROOT if the scope is AllUsers rather than just deciding the install path based on the scope directly.

Am I missing something? And do people have workarounds for this for user-only installers?