From 3d94fe6f5328b2de442b3cdaf35793ceaba74d18 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 7 Nov 2026 09:10:31 +0000 Subject: [PATCH 01/17] [BUILD] Import shared build infrastructure from OpenMS@501f790 unchanged Verbatim copies of the files from OpenMS/OpenMS develop (501f790) that the standalone GUI build, its tests, docs, packaging and CI are adapted from. They stay in OpenMS as well, so they are copied without history. The following commits trim and adapt them; keeping this import separate makes those changes reviewable as diffs against the originals. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_0149aXma24dXL4j67seUsJyp --- .clang-format | 80 + .gitattributes | 21 + .github/actions/build/action.yml | 344 +++ .github/actions/cherry-pick/action.yml | 24 + .github/actions/dependencies/action.yml | 163 ++ .github/actions/rsync/action.yml | 115 + .github/actions/version/action.yml | 87 + .github/workflows/release.yml | 742 +++++ .github/workflows/test.yml | 70 + .github/workflows/update_version_numbers.yml | 99 + .gitignore | 282 ++ AUTHORS | 143 + CITATION.cff | 177 ++ CMakeLists.txt | 879 ++++++ CMakePresets.json | 477 +++ CODE_OF_CONDUCT.md | 73 + CONTRIBUTING.md | 50 + LICENSE | 29 + LICENSE.md | 29 + License.txt | 52 + PULL_REQUEST_TEMPLATE.md | 33 + cmake/AddressSanitizer.cmake | 60 + cmake/Coverage.cmake | 30 + cmake/MacOSX/DS_store | Bin 0 -> 12292 bytes cmake/MacOSX/DS_store_new | Bin 0 -> 10244 bytes cmake/MacOSX/README.md | 118 + cmake/MacOSX/TOPP-shell.command | 15 + cmake/MacOSX/TOPP_bash_profile | 37 + cmake/MacOSX/background.odg | Bin 0 -> 35089 bytes cmake/MacOSX/background.png | Bin 0 -> 46959 bytes cmake/MacOSX/fix_dependencies.rb | 576 ++++ cmake/MacOSX/notarize.sh | 202 ++ cmake/MacOSX/openms_logo_corner_small.png | Bin 0 -> 8610 bytes .../MacOSX/openms_logo_corner_transparent.png | Bin 0 -> 22120 bytes .../MacOSX/openms_logo_large_transparent.png | Bin 0 -> 14066 bytes .../MacOSX/openms_logo_small_transparent.png | Bin 0 -> 6513 bytes cmake/MacOSX/setIcon.sh.in | 39 + cmake/MacOSX/setup_applescript.scpt.in | 89 + cmake/MacOSX/sign_bins_and_libs.rb | 130 + cmake/Modules/CPack.distribution.dist.in | 9 + cmake/Modules/CheckLibArchitecture.cmake | 75 + cmake/Modules/GetGitRevisionDescription.cmake | 264 ++ .../GetGitRevisionDescription.cmake.in | 38 + cmake/OpenMSConfig.cmake.in | 281 ++ cmake/OpenMSPackageDescriptionFile.txt | 7 + cmake/OpenMSPackageResourceReadme.txt | 3 + cmake/OpenMSPackageResourceWelcomeFile.txt | 6 + cmake/Windows/Contrib/Inetc/afxres.h | 2 + cmake/Windows/Contrib/Inetc/api.h | 83 + cmake/Windows/Contrib/Inetc/crt.cpp | 105 + cmake/Windows/Contrib/Inetc/inetc.cpp | 1731 +++++++++++ cmake/Windows/Contrib/Inetc/inetc.rc | 199 ++ cmake/Windows/Contrib/Inetc/inetc.sln | 42 + cmake/Windows/Contrib/Inetc/inetc.vcxproj | 441 +++ .../Contrib/Inetc/inetc.vcxproj.filters | 52 + cmake/Windows/Contrib/Inetc/nsis_tchar.h | 229 ++ cmake/Windows/Contrib/Inetc/pluginapi.c | 294 ++ cmake/Windows/Contrib/Inetc/pluginapi.h | 104 + cmake/Windows/Contrib/Inetc/resource.h | 47 + .../Docs/Advanced Uninstall Log/Readme.txt | 121 + cmake/Windows/Docs/Inetc/Readme.htm | 153 + cmake/Windows/Docs/Inetc/wiki.txt | 161 ++ .../Uninstall_Log_Default_UI.nsi | 170 ++ .../Uninstall_Log_Modern_UI.nsi | 178 ++ cmake/Windows/Examples/Inetc/Example.nsi | 54 + cmake/Windows/Examples/Inetc/auth_dlg.nsi | 32 + cmake/Windows/Examples/Inetc/ftp_auth.nsi | 32 + cmake/Windows/Examples/Inetc/head.nsi | 30 + cmake/Windows/Examples/Inetc/headers.nsi | 32 + cmake/Windows/Examples/Inetc/headers.php | 7 + cmake/Windows/Examples/Inetc/https.nsi | 27 + cmake/Windows/Examples/Inetc/inetc_local.nsi | 81 + cmake/Windows/Examples/Inetc/post.nsi | 31 + cmake/Windows/Examples/Inetc/post.php | 13 + cmake/Windows/Examples/Inetc/post_file.nsi | 31 + cmake/Windows/Examples/Inetc/post_file.php | 10 + cmake/Windows/Examples/Inetc/post_form.html | 18 + cmake/Windows/Examples/Inetc/put.nsi | 31 + cmake/Windows/Examples/Inetc/put.php | 19 + cmake/Windows/Examples/Inetc/recursive.nsi | 65 + cmake/Windows/Examples/Inetc/redirect.nsi | 31 + cmake/Windows/Examples/Inetc/redirect.php | 6 + cmake/Windows/Examples/Inetc/timeout.nsi | 32 + cmake/Windows/Examples/Inetc/tostack.nsi | 32 + cmake/Windows/Examples/Inetc/translate.nsi | 33 + cmake/Windows/FolderList.exe | Bin 0 -> 49152 bytes cmake/Windows/Include/AdvUninstLog.nsh | 437 +++ cmake/Windows/Include/AdvUninstLog2.nsh | 418 +++ cmake/Windows/Include/EnvVarUpdate.nsh | 350 +++ .../Include/IncludeScript_FileLogging.nsh | 140 + cmake/Windows/Include/IncludeScript_Misc.nsh | 90 + cmake/Windows/Include/LogicLib.nsh | 792 +++++ cmake/Windows/Include/NsisMultiUser.nsh | 1154 ++++++++ cmake/Windows/Include/NsisMultiUserLang.nsh | 2038 +++++++++++++ cmake/Windows/Include/StdUtils.nsh | 501 ++++ cmake/Windows/Include/UAC.nsh | 299 ++ cmake/Windows/NSIS.template.in | 756 +++++ cmake/Windows/NSIS_Readme.txt | 6 + cmake/Windows/OpenMS.ico | Bin 0 -> 50534 bytes cmake/Windows/Plugins/amd64-unicode/INetC.dll | Bin 0 -> 27136 bytes cmake/Windows/Plugins/x86-ansi/INetC.dll | Bin 0 -> 22016 bytes cmake/Windows/Plugins/x86-ansi/StdUtils.dll | Bin 0 -> 95744 bytes cmake/Windows/Plugins/x86-ansi/UAC.dll | Bin 0 -> 14848 bytes cmake/Windows/Plugins/x86-unicode/INetC.dll | Bin 0 -> 25088 bytes .../Windows/Plugins/x86-unicode/StdUtils.dll | Bin 0 -> 102400 bytes cmake/Windows/Plugins/x86-unicode/UAC.dll | Bin 0 -> 14848 bytes cmake/Windows/ReleaseNotes.txt | 27 + cmake/Windows/ToolchainCommon.cmake | 115 + cmake/Windows/UAC_License.txt | 14 + cmake/Windows/VSWhere.cmake | 144 + cmake/Windows/images/OpenMS_splash.bmp | Bin 0 -> 94458 bytes cmake/Windows/images/example_header.png | Bin 0 -> 46526 bytes cmake/Windows/images/example_wizard.png | Bin 0 -> 47620 bytes cmake/Windows/images/header-uninstall.bmp | Bin 0 -> 9744 bytes cmake/Windows/images/header.bmp | Bin 0 -> 9744 bytes cmake/Windows/images/wizard-uninstall.bmp | Bin 0 -> 52576 bytes cmake/Windows/images/wizard.bmp | Bin 0 -> 52576 bytes cmake/Windows/install.exe | Bin 0 -> 41713 bytes cmake/add_library_macros.cmake | 316 ++ cmake/build_system_macros.cmake | 51 + cmake/compiler_flags.cmake | 220 ++ cmake/cpack_clean_runpath.cmake | 85 + cmake/cpack_deb_t64_dependencies.cmake | 275 ++ cmake/doc_macros.cmake | 27 + cmake/export_macros.cmake | 98 + cmake/find_installed_openms.cmake | 82 + cmake/install_macros.cmake | 430 +++ cmake/messages.cmake | 104 + cmake/mimalloc.cmake | 97 + cmake/min_compiler_versions.cmake | 108 + cmake/multithreading.cmake | 76 + cmake/package_components.cmake | 99 + cmake/package_deb.cmake | 112 + cmake/package_dragndrop_dmg.cmake | 134 + cmake/package_general.cmake | 222 ++ cmake/package_mac_productbuild.cmake | 185 ++ cmake/package_nsis.cmake | 128 + cmake/package_rpm.cmake | 56 + cmake/setup_lib_find_paths.cmake | 31 + cmake/stl_debug.cmake | 22 + cmake/third_party_licenses.cmake | 561 ++++ .../third_party_licenses/Qt/GPL-3.0-only.txt | 674 +++++ .../third_party_licenses/Qt/LGPL-3.0-only.txt | 165 ++ cmake/third_party_licenses/Qt/README.txt.in | 14 + .../homebrew/boost/LICENSE_1_0.txt | 23 + cmake/third_party_notices.cmake | 319 ++ cmake/topp_tool_macros.cmake | 154 + doc/CMakeLists.txt | 380 +++ doc/code_examples/CMakeLists.txt | 47 + doc/code_examples/executables.cmake | 64 + doc/doxygen/Doxyfile.in | 2572 +++++++++++++++++ .../common/OpenMS_75x55_transparent.png | Bin 0 -> 6220 bytes doc/doxygen/common/csi.min.js | 1 + doc/doxygen/common/customdoxygen.css | 1596 ++++++++++ doc/doxygen/common/favicon.ico | Bin 0 -> 1150 bytes doc/doxygen/common/footer.html | 21 + doc/doxygen/common/header.html | 69 + doc/doxygen/common/selectversion.js | 84 + doc/doxygen/common/style_ini.css | 144 + doc/doxygen/doxygen-awesome-css/LICENSE | 21 + doc/doxygen/doxygen-awesome-css/README.md | 90 + doc/doxygen/doxygen-awesome-css/custom.css | 4 + .../doxygen-awesome-darkmode-toggle.js | 157 + .../doxygen-awesome-fragment-copy-button.js | 85 + .../doxygen-awesome-paragraph-link.js | 51 + .../doxygen-awesome-css/doxygen-awesome.css | 2137 ++++++++++++++ .../doxygen-awesome-css/logo.drawio.svg | 1 + src/testframework/CMakeLists.txt | 69 + .../include/OpenMS/CONCEPT/ClassTest.h | 1096 +++++++ .../include/OpenMS/CONCEPT/ClassTestUtils.h | 352 +++ .../OpenMS/CONCEPT/FuzzyStringComparator.h | 353 +++ .../include/OpenMS/CONCEPT/MacrosTest.h | 59 + .../source/CONCEPT/ClassTest.cpp | 692 +++++ .../source/CONCEPT/FuzzyStringComparator.cpp | 1031 +++++++ src/tests/CMakeLists.txt | 413 +++ src/tests/class_tests/CMakeLists.txt | 66 + .../class_tests/source/OpenMSTestSupport.cpp | 72 + src/tests/external/CMakeLists.txt | 219 ++ src/tests/external/TestExternalCodeGUI.cpp | 23 + src/tests/topp/FuzzyDiff.ini | 26 + src/tests/topp/check_ini.cmake | 7 + src/tests/topp/check_tool_registry.cmake | 92 + ...dowsOS_OpenMS_file_associations_modify.reg | Bin 0 -> 3172 bytes tools/ci/deps-macos.sh | 90 + tools/ci/deps-ubuntu.sh | 62 + tools/ci/deps-windows.sh | 35 + tools/update_version_numbers.sh | 101 + 187 files changed, 35238 insertions(+) create mode 100644 .clang-format create mode 100644 .gitattributes create mode 100644 .github/actions/build/action.yml create mode 100644 .github/actions/cherry-pick/action.yml create mode 100644 .github/actions/dependencies/action.yml create mode 100644 .github/actions/rsync/action.yml create mode 100644 .github/actions/version/action.yml create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/test.yml create mode 100644 .github/workflows/update_version_numbers.yml create mode 100644 .gitignore create mode 100644 AUTHORS create mode 100644 CITATION.cff create mode 100644 CMakeLists.txt create mode 100644 CMakePresets.json create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 LICENSE.md create mode 100644 License.txt create mode 100644 PULL_REQUEST_TEMPLATE.md create mode 100644 cmake/AddressSanitizer.cmake create mode 100644 cmake/Coverage.cmake create mode 100644 cmake/MacOSX/DS_store create mode 100644 cmake/MacOSX/DS_store_new create mode 100644 cmake/MacOSX/README.md create mode 100755 cmake/MacOSX/TOPP-shell.command create mode 100644 cmake/MacOSX/TOPP_bash_profile create mode 100644 cmake/MacOSX/background.odg create mode 100644 cmake/MacOSX/background.png create mode 100755 cmake/MacOSX/fix_dependencies.rb create mode 100755 cmake/MacOSX/notarize.sh create mode 100644 cmake/MacOSX/openms_logo_corner_small.png create mode 100644 cmake/MacOSX/openms_logo_corner_transparent.png create mode 100644 cmake/MacOSX/openms_logo_large_transparent.png create mode 100644 cmake/MacOSX/openms_logo_small_transparent.png create mode 100644 cmake/MacOSX/setIcon.sh.in create mode 100644 cmake/MacOSX/setup_applescript.scpt.in create mode 100755 cmake/MacOSX/sign_bins_and_libs.rb create mode 100644 cmake/Modules/CPack.distribution.dist.in create mode 100644 cmake/Modules/CheckLibArchitecture.cmake create mode 100644 cmake/Modules/GetGitRevisionDescription.cmake create mode 100644 cmake/Modules/GetGitRevisionDescription.cmake.in create mode 100644 cmake/OpenMSConfig.cmake.in create mode 100644 cmake/OpenMSPackageDescriptionFile.txt create mode 100644 cmake/OpenMSPackageResourceReadme.txt create mode 100644 cmake/OpenMSPackageResourceWelcomeFile.txt create mode 100644 cmake/Windows/Contrib/Inetc/afxres.h create mode 100644 cmake/Windows/Contrib/Inetc/api.h create mode 100644 cmake/Windows/Contrib/Inetc/crt.cpp create mode 100644 cmake/Windows/Contrib/Inetc/inetc.cpp create mode 100755 cmake/Windows/Contrib/Inetc/inetc.rc create mode 100755 cmake/Windows/Contrib/Inetc/inetc.sln create mode 100755 cmake/Windows/Contrib/Inetc/inetc.vcxproj create mode 100755 cmake/Windows/Contrib/Inetc/inetc.vcxproj.filters create mode 100644 cmake/Windows/Contrib/Inetc/nsis_tchar.h create mode 100755 cmake/Windows/Contrib/Inetc/pluginapi.c create mode 100644 cmake/Windows/Contrib/Inetc/pluginapi.h create mode 100644 cmake/Windows/Contrib/Inetc/resource.h create mode 100644 cmake/Windows/Docs/Advanced Uninstall Log/Readme.txt create mode 100755 cmake/Windows/Docs/Inetc/Readme.htm create mode 100644 cmake/Windows/Docs/Inetc/wiki.txt create mode 100644 cmake/Windows/Examples/Advanced Uninstall Log/Uninstall_Log_Default_UI.nsi create mode 100644 cmake/Windows/Examples/Advanced Uninstall Log/Uninstall_Log_Modern_UI.nsi create mode 100755 cmake/Windows/Examples/Inetc/Example.nsi create mode 100755 cmake/Windows/Examples/Inetc/auth_dlg.nsi create mode 100755 cmake/Windows/Examples/Inetc/ftp_auth.nsi create mode 100755 cmake/Windows/Examples/Inetc/head.nsi create mode 100755 cmake/Windows/Examples/Inetc/headers.nsi create mode 100755 cmake/Windows/Examples/Inetc/headers.php create mode 100755 cmake/Windows/Examples/Inetc/https.nsi create mode 100755 cmake/Windows/Examples/Inetc/inetc_local.nsi create mode 100755 cmake/Windows/Examples/Inetc/post.nsi create mode 100755 cmake/Windows/Examples/Inetc/post.php create mode 100755 cmake/Windows/Examples/Inetc/post_file.nsi create mode 100755 cmake/Windows/Examples/Inetc/post_file.php create mode 100755 cmake/Windows/Examples/Inetc/post_form.html create mode 100755 cmake/Windows/Examples/Inetc/put.nsi create mode 100755 cmake/Windows/Examples/Inetc/put.php create mode 100755 cmake/Windows/Examples/Inetc/recursive.nsi create mode 100755 cmake/Windows/Examples/Inetc/redirect.nsi create mode 100755 cmake/Windows/Examples/Inetc/redirect.php create mode 100755 cmake/Windows/Examples/Inetc/timeout.nsi create mode 100755 cmake/Windows/Examples/Inetc/tostack.nsi create mode 100755 cmake/Windows/Examples/Inetc/translate.nsi create mode 100644 cmake/Windows/FolderList.exe create mode 100644 cmake/Windows/Include/AdvUninstLog.nsh create mode 100644 cmake/Windows/Include/AdvUninstLog2.nsh create mode 100644 cmake/Windows/Include/EnvVarUpdate.nsh create mode 100644 cmake/Windows/Include/IncludeScript_FileLogging.nsh create mode 100644 cmake/Windows/Include/IncludeScript_Misc.nsh create mode 100644 cmake/Windows/Include/LogicLib.nsh create mode 100644 cmake/Windows/Include/NsisMultiUser.nsh create mode 100644 cmake/Windows/Include/NsisMultiUserLang.nsh create mode 100644 cmake/Windows/Include/StdUtils.nsh create mode 100644 cmake/Windows/Include/UAC.nsh create mode 100644 cmake/Windows/NSIS.template.in create mode 100644 cmake/Windows/NSIS_Readme.txt create mode 100644 cmake/Windows/OpenMS.ico create mode 100755 cmake/Windows/Plugins/amd64-unicode/INetC.dll create mode 100755 cmake/Windows/Plugins/x86-ansi/INetC.dll create mode 100644 cmake/Windows/Plugins/x86-ansi/StdUtils.dll create mode 100755 cmake/Windows/Plugins/x86-ansi/UAC.dll create mode 100755 cmake/Windows/Plugins/x86-unicode/INetC.dll create mode 100644 cmake/Windows/Plugins/x86-unicode/StdUtils.dll create mode 100755 cmake/Windows/Plugins/x86-unicode/UAC.dll create mode 100644 cmake/Windows/ReleaseNotes.txt create mode 100644 cmake/Windows/ToolchainCommon.cmake create mode 100644 cmake/Windows/UAC_License.txt create mode 100644 cmake/Windows/VSWhere.cmake create mode 100644 cmake/Windows/images/OpenMS_splash.bmp create mode 100644 cmake/Windows/images/example_header.png create mode 100644 cmake/Windows/images/example_wizard.png create mode 100644 cmake/Windows/images/header-uninstall.bmp create mode 100644 cmake/Windows/images/header.bmp create mode 100644 cmake/Windows/images/wizard-uninstall.bmp create mode 100644 cmake/Windows/images/wizard.bmp create mode 100644 cmake/Windows/install.exe create mode 100644 cmake/add_library_macros.cmake create mode 100644 cmake/build_system_macros.cmake create mode 100644 cmake/compiler_flags.cmake create mode 100644 cmake/cpack_clean_runpath.cmake create mode 100644 cmake/cpack_deb_t64_dependencies.cmake create mode 100644 cmake/doc_macros.cmake create mode 100644 cmake/export_macros.cmake create mode 100644 cmake/find_installed_openms.cmake create mode 100644 cmake/install_macros.cmake create mode 100644 cmake/messages.cmake create mode 100644 cmake/mimalloc.cmake create mode 100644 cmake/min_compiler_versions.cmake create mode 100644 cmake/multithreading.cmake create mode 100644 cmake/package_components.cmake create mode 100644 cmake/package_deb.cmake create mode 100644 cmake/package_dragndrop_dmg.cmake create mode 100644 cmake/package_general.cmake create mode 100644 cmake/package_mac_productbuild.cmake create mode 100644 cmake/package_nsis.cmake create mode 100644 cmake/package_rpm.cmake create mode 100644 cmake/setup_lib_find_paths.cmake create mode 100644 cmake/stl_debug.cmake create mode 100644 cmake/third_party_licenses.cmake create mode 100644 cmake/third_party_licenses/Qt/GPL-3.0-only.txt create mode 100644 cmake/third_party_licenses/Qt/LGPL-3.0-only.txt create mode 100644 cmake/third_party_licenses/Qt/README.txt.in create mode 100644 cmake/third_party_licenses/homebrew/boost/LICENSE_1_0.txt create mode 100644 cmake/third_party_notices.cmake create mode 100644 cmake/topp_tool_macros.cmake create mode 100644 doc/CMakeLists.txt create mode 100644 doc/code_examples/CMakeLists.txt create mode 100644 doc/code_examples/executables.cmake create mode 100644 doc/doxygen/Doxyfile.in create mode 100644 doc/doxygen/common/OpenMS_75x55_transparent.png create mode 100644 doc/doxygen/common/csi.min.js create mode 100644 doc/doxygen/common/customdoxygen.css create mode 100644 doc/doxygen/common/favicon.ico create mode 100644 doc/doxygen/common/footer.html create mode 100644 doc/doxygen/common/header.html create mode 100644 doc/doxygen/common/selectversion.js create mode 100755 doc/doxygen/common/style_ini.css create mode 100644 doc/doxygen/doxygen-awesome-css/LICENSE create mode 100644 doc/doxygen/doxygen-awesome-css/README.md create mode 100644 doc/doxygen/doxygen-awesome-css/custom.css create mode 100644 doc/doxygen/doxygen-awesome-css/doxygen-awesome-darkmode-toggle.js create mode 100644 doc/doxygen/doxygen-awesome-css/doxygen-awesome-fragment-copy-button.js create mode 100644 doc/doxygen/doxygen-awesome-css/doxygen-awesome-paragraph-link.js create mode 100644 doc/doxygen/doxygen-awesome-css/doxygen-awesome.css create mode 100644 doc/doxygen/doxygen-awesome-css/logo.drawio.svg create mode 100644 src/testframework/CMakeLists.txt create mode 100644 src/testframework/include/OpenMS/CONCEPT/ClassTest.h create mode 100644 src/testframework/include/OpenMS/CONCEPT/ClassTestUtils.h create mode 100644 src/testframework/include/OpenMS/CONCEPT/FuzzyStringComparator.h create mode 100644 src/testframework/include/OpenMS/CONCEPT/MacrosTest.h create mode 100644 src/testframework/source/CONCEPT/ClassTest.cpp create mode 100644 src/testframework/source/CONCEPT/FuzzyStringComparator.cpp create mode 100644 src/tests/CMakeLists.txt create mode 100644 src/tests/class_tests/CMakeLists.txt create mode 100644 src/tests/class_tests/source/OpenMSTestSupport.cpp create mode 100644 src/tests/external/CMakeLists.txt create mode 100644 src/tests/external/TestExternalCodeGUI.cpp create mode 100644 src/tests/topp/FuzzyDiff.ini create mode 100644 src/tests/topp/check_ini.cmake create mode 100644 src/tests/topp/check_tool_registry.cmake create mode 100644 tools/MSWindowsOS_OpenMS_file_associations_modify.reg create mode 100755 tools/ci/deps-macos.sh create mode 100755 tools/ci/deps-ubuntu.sh create mode 100755 tools/ci/deps-windows.sh create mode 100755 tools/update_version_numbers.sh diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..b3a9c21c7 --- /dev/null +++ b/.clang-format @@ -0,0 +1,80 @@ +--- +BasedOnStyle: LLVM +AccessModifierOffset: '-2' +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: 'false' +AlignConsecutiveDeclarations: 'false' +AlignEscapedNewlines: Left +AlignOperands: 'true' +AlignTrailingComments: 'true' +AllowAllArgumentsOnNextLine: 'true' +AllowAllConstructorInitializersOnNextLine: 'false' +AllowAllParametersOfDeclarationOnNextLine: 'false' +AllowShortBlocksOnASingleLine: 'true' +AllowShortCaseLabelsOnASingleLine: 'false' +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: Always +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: 'false' +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: 'false' +AlwaysBreakTemplateDeclarations: 'Yes' +BinPackArguments: 'true' +BinPackParameters: 'false' +BreakBeforeBinaryOperators: All +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: 'true' +BreakConstructorInitializers: AfterColon +BreakInheritanceList: AfterColon +BreakStringLiterals: 'true' +ColumnLimit: '150' +CompactNamespaces: 'false' +ConstructorInitializerAllOnOneLineOrOnePerLine: 'true' +ContinuationIndentWidth: '2' +DerivePointerAlignment: 'false' +DisableFormat: 'false' +FixNamespaceComments: 'true' +IncludeBlocks: Regroup +IndentCaseLabels: 'true' +IndentPPDirectives: BeforeHash +IndentWidth: '2' +IndentWrappedFunctionNames: 'false' +KeepEmptyLinesAtTheStartOfBlocks: 'true' +Language: Cpp +MaxEmptyLinesToKeep: '2' +NamespaceIndentation: Inner +PointerAlignment: Left +SortIncludes: 'true' +SortUsingDeclarations: 'true' +SpaceAfterLogicalNot: 'true' +SpaceAfterTemplateKeyword: 'false' +SpaceBeforeAssignmentOperators: 'true' +SpaceBeforeCpp11BracedList: 'true' +SpaceBeforeCtorInitializerColon: 'false' +SpaceBeforeInheritanceColon: 'true' +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: 'true' +SpaceInEmptyParentheses: 'false' +SpacesBeforeTrailingComments: '1' +SpacesInAngles: 'false' +SpacesInCStyleCastParentheses: 'false' +SpacesInContainerLiterals: 'false' +SpacesInParentheses: 'false' +SpacesInSquareBrackets: 'false' +Standard: Cpp11 +TabWidth: '2' +UseTab: Never + +... diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..c10a334e0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,21 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +# Force UNIX line endings, so you can use the same repo e.g., on Win and WSL +* text=auto eol=lf +# batch files specifically need to have CRLF (win endings) +*.{cmd,[cC][mM][dD]} text eol=crlf +*.{bat,[bB][aA][tT]} text eol=crlf + +# Denote all files that are truly binary and should not be modified. +# Images +*.png binary +*.jpg binary +# XML files with potential byte-counting indices that will lose function +# if the windows CR byte is added +*.mzML binary +*.mzXML binary + +.github/workflows/*.lock.yml linguist-generated=true merge=ours + +# git archive fills in the commit and its release tag, so that a build from an archive (the +# Release workflow's source tarball, GitHub's source archives) knows its version (CMakeLists.txt). +.git_archival.txt export-subst diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml new file mode 100644 index 000000000..8815f7ac2 --- /dev/null +++ b/.github/actions/build/action.yml @@ -0,0 +1,344 @@ +name: "Build OpenMS" +description: "Action for automating the OpenMS build process" +inputs: + compiler: + description: "The name of the compiler to use" + required: true + preset: + description: >- + The CMake preset to configure, build and test with. By default the CI + preset of the runner (linux-x64-ci, macos-arm64-ci, windows-x64-ci, ...). + A build with another preset gets its own compiler and vcpkg caches, so it + neither evicts the default build's objects nor races it for the cache. + required: false + default: "" + run_tests: + description: "Whether to run the test suite after the build (ctest --preset)" + required: false + default: "true" + configure_only: + description: >- + Stop after configuring: the dependencies are installed and vcpkg builds + whatever its binary cache lacks, but OpenMS itself is not built and no + compiler cache is saved. A job that only warms the vcpkg cache of a preset + whose dependencies take hours to build from source. + required: false + default: "false" + macosx_deployment_target: + description: >- + The oldest macOS the binaries run on (-mmacosx-version-min). Keep it at the + runner's macOS: the Homebrew libraries the package bundles are built for that + version, so a lower value makes a package that installs on an older macOS and + then fails to load. + default: "15.0" + ssh_key: + description: "SSH private key for the rsync cache archive" + required: false + ssh_host: + description: "SSH host for the rsync cache archive" + required: false + ssh_port: + description: "SSH port for the rsync cache archive" + required: false + ssh_user: + description: "SSH user for the rsync cache archive" + required: false +outputs: + version: + description: "The discovered compiler version number" + value: ${{ steps.compiler.outputs.ver }} + preset: + description: "The resolved CMake preset name" + value: ${{ steps.preset.outputs.name }} +runs: + using: "composite" + steps: + + ############################################################################ + # NOTE: x64 is hardcoded. No support for 32bit. + - name: Emulate a Visual Studio shell (Windows) + if: ${{ runner.os == 'Windows' }} + uses: egor-tensin/vs-shell@v2 + with: { arch: x64 } + + ############################################################################ + # A build with a preset of its own gets caches of its own (see the preset + # input): the suffix goes into the compiler cache keys below and, through the + # job environment, into the vcpkg cache key of the dependencies action. The + # environment rather than an input because the vcpkg cache is uploaded by the + # post step of the cache action, and in a post step an input of a composite + # action evaluates to its default: the first Debug SDK job uploaded its + # dependencies into the default build's cache. A job that sets the variable + # itself (release.yml does for the Debug SDK jobs) keeps its value. + - name: Compute the Cache Key Suffix + id: cache-suffix + env: + preset: ${{ inputs.preset }} + shell: bash + run: | + suffix=${OPENMS_CACHE_KEY_SUFFIX:-${preset:+-$preset}} + echo "suffix=$suffix" >> "$GITHUB_OUTPUT" + echo "OPENMS_CACHE_KEY_SUFFIX=$suffix" >> "$GITHUB_ENV" + + ############################################################################ + - name: Install Dependencies + id: deps + uses: ./.github/actions/dependencies + with: + compiler: ${{ inputs.compiler }} + ssh_key: ${{ inputs.ssh_key }} + ssh_host: ${{ inputs.ssh_host }} + ssh_port: ${{ inputs.ssh_port }} + ssh_user: ${{ inputs.ssh_user }} + + ############################################################################ + - name: Compute the Compiler Version + id: compiler + env: + compiler: ${{ inputs.compiler }} + shell: bash + run: | + case ${compiler:-gcc} in + clang*) + ver=$(clang -dumpversion) + name=$(type -p clang++) + cc_name=$(type -p clang) + ;; + + cl*) + ver=$(cl.exe 2>&1 | + grep -E 'Version [0-9.]+' | + sed -E 's/^.* Version ([0-9.]+) .*$/\1/') + name=$compiler + cc_name=$compiler + ;; + + gcc | g++) + ver=$(gcc -dumpversion) + name=$(type -p g++) + cc_name=$(type -p gcc) + ;; + + xcode) + ver=$(clang -dumpversion) + name=$(xcrun -f clang++) + cc_name=$(xcrun -f clang) + ;; + + *) + ver="0.0" + name=$compiler + cc_name=$compiler + ;; + esac + + major=$(cut -d. -f1 <<<"$ver") + + { + echo "ver=$ver" + echo "major=$major" + echo "name=$name" + } >>"$GITHUB_OUTPUT" + + { + # All remaining steps should use this compiler. + echo "CXX=$name" + echo "CC=$cc_name" + } >>"$GITHUB_ENV" + + ############################################################################ + # These are variables that don't need to be set for normal + # (non-CI) builds. + - name: Set CI-specific Environment Variables + shell: bash + run: | + { + # During building and testing several Qt apps are run. This + # is needed so they can start without having a graphical + # environment: + echo "QT_QPA_PLATFORM=offscreen" + + } >>"$GITHUB_ENV" + + ############################################################################ + # This is only really needed so we can set cache keys. + - name: Extract the PR Number or Branch Name + id: pr + shell: bash + run: echo "name=${{ github.event.pull_request && github.event.number || github.ref_name }}" >>$GITHUB_OUTPUT + + ############################################################################ + # NOTE: restore/save are deliberately split instead of using the combined + # actions/cache action. The combined action only writes the cache in its + # post step when the *primary* key missed, so a static key (as used here + # before) is written exactly once and then frozen forever -- every later + # run restored a stale cache and recompiled everything from scratch. + # Making the primary key unique per run guarantees a miss, so the save step + # below always uploads a freshly populated cache, while the restore-keys + # ladder still finds the most recent cache by prefix. + # (not for a configure-only run, which compiles nothing) + - name: Try to Fetch Existing Build Cache + id: ccache-restore + if: ${{ inputs.configure_only != 'true' }} + uses: actions/cache/restore@v5 + with: + path: .ccache + key: ${{ runner.os }}-${{ runner.arch }}-${{ inputs.compiler }}-${{ steps.compiler.outputs.major }}${{ steps.cache-suffix.outputs.suffix }}-ccache-${{ steps.pr.outputs.name }}-${{ github.run_id }}-${{ github.run_attempt }} + + # Restoring: from the current branch/PR, otherwise from develop, otherwise the newest + # other cache that is still in scope -- not "any branch", see below. + # + # develop, not nightly, deliberately. GitHub scopes caches by ref: a run may restore only + # from its own ref, its base branch and the default branch. nightly is a sibling of + # develop (the default branch) -- its commit is an ancestor, but that does not matter, the + # scope is the ref -- so a cache written by a push to nightly is unreachable from a pull + # request and falling back to it would never match. develop is the default branch, so its + # cache is the only one every pull request can read, and the daily workflow_dispatch on + # develop keeps it fresh now that saving works at all. + restore-keys: | + ${{ runner.os }}-${{ runner.arch }}-${{ inputs.compiler }}-${{ steps.compiler.outputs.major }}${{ steps.cache-suffix.outputs.suffix }}-ccache-${{ steps.pr.outputs.name }}- + ${{ runner.os }}-${{ runner.arch }}-${{ inputs.compiler }}-${{ steps.compiler.outputs.major }}${{ steps.cache-suffix.outputs.suffix }}-ccache-develop- + ${{ runner.os }}-${{ runner.arch }}-${{ inputs.compiler }}-${{ steps.compiler.outputs.major }}${{ steps.cache-suffix.outputs.suffix }}-ccache- + + ############################################################################ + - name: Configure Build Caching + id: ccache-configure + shell: bash + env: + # A full build produces ~1900 objects. MSVC objects (built with + # /bigobj) are considerably larger than the gcc/clang ones, and 1G was + # not enough to hold a whole build -- the cache evicted itself while it + # was still being filled, so it could never warm up. Kept platform + # specific because the total GitHub Actions cache budget is 10 GB per + # repository and it has to cover the ccache of the five build jobs plus + # the Thermo asset caches of the wheel workflow. The vcpkg binary + # caches do not count against it: they live on the rsync archive + # (.github/actions/dependencies). + maxsize: ${{ runner.os == 'Windows' && '2G' || '1G' }} + run: | + mkdir -p "$GITHUB_WORKSPACE/.ccache" + + { + echo "CCACHE_COMPRESS=true" + echo "CCACHE_COMPRESSLEVEL=6" + echo "CCACHE_DIR=$GITHUB_WORKSPACE/.ccache" + echo "CCACHE_MAXSIZE=$maxsize" + echo "CMAKE_C_COMPILER_LAUNCHER=ccache" + echo "CMAKE_CXX_COMPILER_LAUNCHER=ccache" + + } >>"$GITHUB_ENV" + + ############################################################################ + # Reset the hit/miss counters (not the cached objects) so the statistics + # printed after the build describe this run only. + - name: Reset ccache Statistics + id: ccache-reset + shell: bash + run: | + ccache --version + ccache --zero-stats + + ############################################################################ + # The preset input, or else the CI preset of the runner. + - name: Resolve CMake presets + id: preset + shell: bash + env: + preset: ${{ inputs.preset }} + run: | + if [[ -n "$preset" ]]; then + echo "name=$preset" >> "$GITHUB_OUTPUT" + exit 0 + fi + case "$RUNNER_OS-$RUNNER_ARCH" in + Linux-X64) preset=linux-x64-ci ;; + Linux-ARM64) preset=linux-arm64-ci ;; + macOS-ARM64) preset=macos-arm64-ci ;; + Windows-X64) preset=windows-x64-ci ;; + *) + echo >&2 "ERROR: no CI preset mapped for $RUNNER_OS-$RUNNER_ARCH" + exit 1 + ;; + esac + echo "name=$preset" >> "$GITHUB_OUTPUT" + + ############################################################################ + # The actual commands to build OpenMS. + - name: Build + id: build + shell: bash + env: + # Official variables that need to be set to build OpenMS: + CMAKE_PREFIX_PATH: ${{ steps.deps.outputs.cmake_prefix }} + SEARCH_ENGINES_DIRECTORY: ${{ github.workspace }}/_thirdparty + # Also sets LSMinimumSystemVersion of the GUI apps (src/openms_gui/add_mac_bundle.cmake) + # and the installer's minimum macOS (cmake/package_mac_productbuild.cmake). + MACOSX_DEPLOYMENT_TARGET: "${{ inputs.macosx_deployment_target }}" + # -DPYOPENMS is not passed since pyOpenMS is not built in this workflow. + + run: | + set -ex + + cmake --preset "${{ steps.preset.outputs.name }}" \ + -DCMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH" \ + -DCMAKE_INSTALL_PREFIX="$GITHUB_WORKSPACE/install" \ + + if [[ "${{ inputs.configure_only }}" != "true" ]]; then + cmake --build --preset "${{ steps.preset.outputs.name }}" --verbose + fi + + - name: Verify public headers + if: ${{ runner.os == 'Linux' && runner.arch == 'X64' && inputs.configure_only != 'true' }} + shell: bash + run: cmake --build --preset "${{ steps.preset.outputs.name }}" --target all_verify_interface_header_sets --parallel 2 + + ############################################################################ + # Hit rate and cache size for this run. Without this there is no way to + # tell from a build log whether compiler caching is working at all. + # + # continue-on-error because this is a diagnostic and must never decide the + # fate of the job. Steps without an `if` carry an implicit success(), so a + # failure here would skip "Test" entirely and report a red job that never + # ran the suite. That is not hypothetical: --verbose needs ccache >= 4.4, + # so an older ccache on some runner image would silently swallow the tests. + - name: Report ccache Statistics + if: ${{ !cancelled() && steps.ccache-configure.outcome == 'success' && steps.ccache-reset.outcome == 'success' }} + continue-on-error: true + shell: bash + run: ccache --show-stats --verbose + + ############################################################################ + - name: Test + if: ${{ inputs.run_tests == 'true' && inputs.configure_only != 'true' }} + shell: bash + run: ctest --preset "${{ steps.preset.outputs.name }}" + + ############################################################################ + # Saved on every event, including pull requests. A cache written by a pull + # request run is scoped to that pull request, so it only speeds up later + # runs of the same one -- but that is precisely the loop developers iterate + # in. + # + # Only saved when the build SUCCEEDED, which is what makes this safe. The + # save key shares its prefix with the restore-keys ladder, and that ladder + # takes the most *recent* match, so whatever this step uploads becomes what + # every later run on this branch restores. Uploading after a failed build + # would therefore pin a partial cache -- and when the restore itself had + # missed (a new compiler major, or a new pull request before develop has a + # cache) that pinned entry is practically empty and permanently shadows the + # develop and any-branch rungs below it, leaving the branch cold for good. + # Requiring the build to have succeeded guarantees the cache is complete; + # on failure nothing is written and the previous good entry stays newest. + # + # Test failures still save: the build was complete by then, so the cache is + # too, and a red test says nothing about the objects. + # Not after a configure-only run: the cache would be empty, and under the + # primary key of this run it would shadow the one a full build of the same + # run saves afterwards, which could then not be saved under that key again. + - name: Save Build Cache + if: ${{ !cancelled() && steps.build.outcome == 'success' && inputs.configure_only != 'true' }} + uses: actions/cache/save@v5 + with: + path: .ccache + # Reuse the restore step's primary key so the two can never drift apart. + key: ${{ steps.ccache-restore.outputs.cache-primary-key }} diff --git a/.github/actions/cherry-pick/action.yml b/.github/actions/cherry-pick/action.yml new file mode 100644 index 000000000..1239687e6 --- /dev/null +++ b/.github/actions/cherry-pick/action.yml @@ -0,0 +1,24 @@ +name: Cherry-pick a merged PR onto a branch +description: Cherry-pick a merged PR's commit onto a branch and open a backport PR. + +inputs: + pr-number: + description: "Merged source PR whose squash commit to cherry-pick" + required: true + target-branch: + description: "Branch to cherry-pick onto (the current release branch)" + required: true + +runs: + using: composite + steps: + - name: Cherry-pick and open backport PR + uses: korthout/backport-action@v3.4.1 + with: + source_pr_number: ${{ inputs.pr-number }} + target_branches: ${{ inputs.target-branch }} + github_token: ${{ github.token }} + merge_commits: fail # Enforces squash + experimental: '{"conflict_resolution": "draft_commit_conflicts"}' # always open a PR; draft + instructions on conflict + add_labels: backport + add_author_as_assignee: true \ No newline at end of file diff --git a/.github/actions/dependencies/action.yml b/.github/actions/dependencies/action.yml new file mode 100644 index 000000000..3f82f8fa9 --- /dev/null +++ b/.github/actions/dependencies/action.yml @@ -0,0 +1,163 @@ +name: "Install OpenMS Dependencies" +description: "Central action for all dependency management" +inputs: + compiler: + description: "The name of the compiler to use" + required: true + ssh_key: + description: "SSH private key for the rsync cache archive" + required: false + ssh_host: + description: "SSH host for the rsync cache archive" + required: false + ssh_port: + description: "SSH port for the rsync cache archive" + required: false + ssh_user: + description: "SSH user for the rsync cache archive" + required: false +outputs: + cmake_prefix: + description: "Path to add to CMAKE_PREFIX" + value: ${{ steps.combine.outputs.cmake_prefix }} +runs: + using: "composite" + steps: + - name: Add THIRDPARTY + shell: bash + run: | + # initialize THIRDPARTY + git submodule update --init THIRDPARTY + + # add third-party binaries to PATH + # use flat THIRDPARTY structure + mkdir -p _thirdparty + + tp_folder=${{ runner.os }} + if [ "$tp_folder" = "macOS" ]; then + tp_folder=MacOS + fi + + # Copy the correct architecture + cp -R "THIRDPARTY/$tp_folder/$(uname -m)"/* _thirdparty/ + + # Copy architecture independent tools + cp -R THIRDPARTY/All/* _thirdparty/ + + # add third-party binaries to PATH + for thirdpartytool in '${{ github.workspace }}/_thirdparty'/*; do + if [ "${{ runner.os }}" = "Windows" ]; then + echo "${thirdpartytool//\//\\}" >> "$GITHUB_PATH" + else + echo "${thirdpartytool}" >> "$GITHUB_PATH" + fi + done + + - name: Install Qt (Windows) + if: runner.os == 'Windows' + uses: jurplel/install-qt-action@v4 + with: + version: '6.8.3' ## Qt 6.8.3 ships no msvc2026 build; the win64_msvc2022_64 binaries are + ## ABI-compatible with the VS2026 (v145) toolchain (shared v14x ABI). + arch: 'win64_msvc2022_64' + cache: 'false' + archives: 'qtsvg qtimageformats qtbase' + + - name: "Dependencies: Windows" + id: deps-windows + if: runner.os == 'Windows' + shell: bash + run: | + bash tools/ci/deps-windows.sh + echo "C:\Program Files (x86)\NSIS" >> $GITHUB_PATH + echo "cmake_prefix=" >>"$GITHUB_OUTPUT" + + - name: "Dependencies: Linux" + id: deps-linux + if: runner.os == 'Linux' + shell: bash + run: | + bash tools/ci/deps-ubuntu.sh + + if [[ "${{ inputs.compiler }}" == clang* ]]; then + major_ver=$(clang -dumpversion | cut -d. -f1) + sudo apt-get -qq install -y "libomp-${major_ver}-dev" "llvm-${major_ver}" + for tool in /usr/bin/llvm-*-${major_ver}; do + base=$(basename "$tool" "-${major_ver}") + sudo ln -sf "$tool" "/usr/local/bin/${base}" + done + fi + + echo "cmake_prefix=" >>$GITHUB_OUTPUT + + - name: "Dependencies: macOS" + id: deps-macos + if: runner.os == 'macOS' + env: + # We need to add this, otherwise brew "helpfully" updates all + # of the GitHub preinstalled packages, which can cause issues: + HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1 + shell: bash + run: | + bash tools/ci/deps-macos.sh + + brew_path=$(brew --prefix) + echo "$brew_path/bin" >>"$GITHUB_PATH" + echo "$(brew --prefix flex)/bin" >> "$GITHUB_PATH" + echo "$(brew --prefix bison)/bin" >> "$GITHUB_PATH" + echo "cmake_prefix=$brew_path" >>"$GITHUB_OUTPUT" + + - name: Combine Outputs + id: combine + shell: bash + run: | + cmake_prefix_s="" + cmake_prefix_a=( + "${{ steps.conda-setup.outputs.cmake_prefix}}" + "${{ steps.deps-windows.outputs.cmake_prefix}}" + "${{ steps.deps-linux.outputs.cmake_prefix}}" + "${{ steps.deps-macos.outputs.cmake_prefix}}" + ) + + for path in "${cmake_prefix_a[@]}"; do + if [ -n "$path" ]; then + if [ -n "$cmake_prefix_s" ]; then + cmake_prefix_s="${cmake_prefix_s};" + fi + cmake_prefix_s="${cmake_prefix_s}${path}" + fi + done + + echo "cmake_prefix=${cmake_prefix_s}" >> "$GITHUB_OUTPUT" + + # The key takes a suffix from the environment variable OPENMS_CACHE_KEY_SUFFIX + # (the build action sets it from its preset): a build whose dependencies differ + # from the default build's (another triplet) uses a cache of its own instead of + # overwriting the default build's. Not an input: the cache is uploaded by the + # post step of this action, and there an input of a composite action evaluates + # to its default, while the job environment keeps its value. + - uses: OpenMS/ci-tools/actions/rsync-cache@b0622a9a8ecfe12fa6e896795f45fddad12faa6c + with: + name: vcpkg-cache + path: ${{ github.workspace }}/.vcpkg-cache + key: ${{ runner.os }}-${{ runner.arch }}-${{ inputs.compiler }}${{ env.OPENMS_CACHE_KEY_SUFFIX }}-vcpkg-${{ hashFiles('vcpkg.json', 'vcpkg-configuration.json') }} + ssh_key: ${{ inputs.ssh_key }} + ssh_host: ${{ inputs.ssh_host }} + ssh_port: ${{ inputs.ssh_port }} + ssh_user: ${{ inputs.ssh_user }} + + - name: Init vcpkg submodule + shell: bash + run: | + git submodule update --init vcpkg + + - name: Point vcpkg at the Local Binary Cache + shell: bash + run: | + mkdir -p "${{ github.workspace }}/.vcpkg-cache" + echo "VCPKG_BINARY_SOURCES=clear;files,${{ github.workspace }}/.vcpkg-cache,readwrite" >> "$GITHUB_ENV" + + - name: Setup vcpkg + uses: lukka/run-vcpkg@v11 + with: + doNotCache: true diff --git a/.github/actions/rsync/action.yml b/.github/actions/rsync/action.yml new file mode 100644 index 000000000..087d37b7e --- /dev/null +++ b/.github/actions/rsync/action.yml @@ -0,0 +1,115 @@ +name: "Prepare for rsync" +description: "Prepare the environment for running rsync" + +inputs: + key: + description: "The text of the SSH key, or empty if there is no ssh key available" + required: false + user: + description: "The SSH user" + required: false + host: + description: "The SSH host name or IP address" + required: false + port: + description: "The port number that SSH is running on" + required: false + src: + description: "The source directory, file, glob to upload" + required: true + dst: + description: "The remote directory to upload into" + required: true + mkpath: + description: "Should rsync create the destination directory?" + required: false + latest: + description: "If set, create a 'latest' symlink to the given location" + required: false + latest_dst: + description: "The remote location to store the latest symlink. Defaults to the parent of dst." + required: false + +outputs: + have_key: + description: "Set to 'true' if a SSH key is present and rsync can be called" + value: ${{ steps.ssh-key.outputs.have_key }} + +runs: + using: "composite" + steps: + + - name: "Prepare for rsync" + id: ssh-key + shell: bash + env: + SSH_KEY_TEXT: ${{ inputs.key }} + SSH_PORT: ${{ inputs.port }} + run: | + output=$HOME/.ssh/private.key + + if [[ -n "$SSH_KEY_TEXT" ]]; then + mkdir -p "$(dirname "$output")" + cat <<<"$SSH_KEY_TEXT" >"$output" + chmod 0600 "$output" + + { + echo "have_key=true" + echo "ssh=ssh -i $output -p $SSH_PORT -o StrictHostKeyChecking=accept-new" + } >>"$GITHUB_OUTPUT" + else + { + echo "have_key=false" + echo "ssh=echo" + } >>"$GITHUB_OUTPUT" + fi + + - name: "Upload via rsync" + if: steps.ssh-key.outputs.have_key == 'true' + shell: bash + env: + SSH_CMD: ${{ steps.ssh-key.outputs.ssh }} + SSH_USER: ${{ inputs.user }} + SSH_HOST: ${{ inputs.host }} + SRC_DIR: ${{ inputs.src }} + DST_DIR: ${{ inputs.dst }} + MKPATH: ${{ inputs.mkpath }} + LATEST: ${{ inputs.latest }} + LATEST_DST: ${{ inputs.latest_dst }} + run: | + if [[ -z "${SSH_USER:-}" ]] || [[ -z "${SSH_HOST:-}" ]]; then + echo >&2 "ERROR: missing user or host input!" + exit 1 + fi + + rsync_options=( + "--progress" + "-avz" + "-e" "$SSH_CMD" + ) + + if [[ "${MKPATH:-false}" == "true" ]]; then + rsync_options+=("--mkpath") + fi + + # Allow globing on the src directory: + # shellcheck disable=SC2086 + rsync \ + "${rsync_options[@]}" \ + $SRC_DIR \ + "${SSH_USER}@${SSH_HOST}:${DST_DIR}" + + if [[ -n "${LATEST:-}" ]]; then + ln -s "$LATEST" latest + + if [[ -z "${LATEST_DST:-}" ]]; then + LATEST_DST=$(dirname "$DST_DIR") + fi + + rsync \ + "${rsync_options[@]}" \ + "latest" \ + "${SSH_USER}@${SSH_HOST}:${LATEST_DST}" + + rm latest + fi diff --git a/.github/actions/version/action.yml b/.github/actions/version/action.yml new file mode 100644 index 000000000..929274029 --- /dev/null +++ b/.github/actions/version/action.yml @@ -0,0 +1,87 @@ +name: "Parse a Version Number from a Tag or Input" +description: "Extract a version number from a Git tag for the OpenMS release process" + +inputs: + version: + description: "If set, parse this version number instead of `GITHUB_REF_NAME`" + required: false + fallback: + description: "Text to use when this version is not a release. Defaults to nightly." + required: false + +outputs: + has_version: + description: "Set to 'true' if a valid version number was found" + value: ${{ steps.version.outputs.has_version }} + version: + description: "The discovered version number" + value: ${{ steps.version.outputs.version }} + type: + description: "The word 'release' or the fallback" + value: ${{ steps.version.outputs.type }} + name: + description: "Release name followed by version number" + value: ${{ steps.version.outputs.name }} + major: + description: "The major version number or 0" + value: ${{ steps.version.outputs.major }} + minor: + description: "The minor version number or 0" + value: ${{ steps.version.outputs.minor }} + patch: + description: "The patch version number or 0" + value: ${{ steps.version.outputs.patch }} + +runs: + using: "composite" + steps: + + - name: "Parse Version Number" + id: version + shell: bash + env: + VERSION_ALT: ${{ inputs.version }} + VERSION_FALLBACK: ${{ inputs.fallback }} + run: | + VERSION=$GITHUB_REF_NAME + + if [[ -n "${VERSION_ALT:-}" ]]; then + if [[ "$VERSION_ALT" =~ ^v ]]; then + VERSION=$VERSION_ALT + else + VERSION="v${VERSION_ALT}" + fi + fi + + if [[ "$VERSION" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then + major="${BASH_REMATCH[1]}" + minor="${BASH_REMATCH[2]}" + patch="${BASH_REMATCH[3]}" + has_version=true + type=release + elif [[ "$VERSION" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)-?(.+)$ ]]; then + major="${BASH_REMATCH[1]}" + minor="${BASH_REMATCH[2]}" + patch="${BASH_REMATCH[3]}" + has_version=false # Not an official release + type="${BASH_REMATCH[4]}" # Stuff like "rc2" + else + major="$(date +%Y)" + minor="$(date +%m)" + patch="$(date +%d)" + has_version=false + type=${VERSION_FALLBACK:-nightly} + fi + + { + version="${major}.${minor}.${patch}" + + echo "has_version=$has_version" + echo "major=$major" + echo "minor=$minor" + echo "patch=$patch" + echo "version=$version" + echo "type=$type" + echo "name=${type}-${version}" + + } >>"$GITHUB_OUTPUT" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..e21ca3576 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,742 @@ +name: "Release" + +on: + workflow_dispatch: + inputs: + deploy: + description: >- + Upload the installers, SDKs and documentation to the archive server and + publish a tagged release. Off, the workflow only builds and keeps its + artifacts on the run: a dry run of the release workflow on any branch. + type: boolean + default: true + push: + tags: + - 'v[0-9]*' + +jobs: + build-and-test: + name: "Build, Test, and Package" + strategy: + fail-fast: false + matrix: + include: + # Only one entry per operating system allowed. + - os: windows-2025 + compiler: cl.exe + - os: macos-15 + compiler: xcode + - os: ubuntu-24.04 + compiler: g++ + - os: ubuntu-24.04-arm + compiler: g++ + runs-on: ${{ matrix.os }} + outputs: + has_version: ${{ steps.version.outputs.has_version }} + version: ${{ steps.version.outputs.version }} + version_name: ${{ steps.version.outputs.name }} + version_type: ${{ steps.version.outputs.type }} + source_tarball: ${{ steps.source-name.outputs.tarball }} + + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + + # Some steps should only run for a single element of the build + # matrix. This step computes which runner that is going to be. + - name: Compute Solo Runner + id: solo + shell: bash + run: | + if [[ "$RUNNER_OS" == "Linux" ]] && [[ "$RUNNER_ARCH" == "X64" ]]; then + echo "solo=true" >>"$GITHUB_OUTPUT" + else + echo "solo=false" >>"$GITHUB_OUTPUT" + fi + + - name: Build OpenMS + id: build-openms + uses: ./.github/actions/build + with: + compiler: ${{ matrix.compiler }} + ssh_key: ${{ secrets.ARCHIVE_RRSYNC_SSH }} + ssh_host: ${{ secrets.ARCHIVE_RRSYNC_HOST }} + ssh_port: ${{ secrets.ARCHIVE_RRSYNC_PORT }} + ssh_user: ${{ secrets.ARCHIVE_RRSYNC_USER }} + + - name: Parse the Version Number + id: version + uses: ./.github/actions/version + + # A release's tarball carries the plain version, the file name the + # Bioconda recipe downloads (OpenMS-.tar.gz); any other build + # is named after its type, e.g. OpenMS-nightly-.tar.gz. + - name: Name the Source Tarball + id: source-name + shell: bash + env: + HAS_VERSION: ${{ steps.version.outputs.has_version }} + VERSION: ${{ steps.version.outputs.version }} + VERSION_NAME: ${{ steps.version.outputs.name }} + run: | + if [[ "$HAS_VERSION" == "true" ]]; then + echo "tarball=OpenMS-${VERSION}.tar.gz" >>"$GITHUB_OUTPUT" + else + echo "tarball=OpenMS-${VERSION_NAME}.tar.gz" >>"$GITHUB_OUTPUT" + fi + + - name: Compute Package Type + id: package-info + shell: bash + run: | + # Why can't CMake do this? + if [[ "$RUNNER_OS" == "Linux" ]]; then + echo "type=deb" >>"$GITHUB_OUTPUT" + elif [[ "$RUNNER_OS" == "macOS" ]]; then + echo "type=pkg" >>"$GITHUB_OUTPUT" + elif [[ "$RUNNER_OS" == "Windows" ]]; then + echo "type=nsis" >>"$GITHUB_OUTPUT" + else + echo >&2 "ERROR: unrecognized RUNNER_OS=$RUNNER_OS" + exit 1 + fi + + - name: Import Apple Developer Certificates + id: apple-certs + if: runner.os == 'macOS' + env: + APPLE_CERTIFICATE: ${{ secrets.APPLE_DEVELOPER_ID_APPLICATION_CERT }} + APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_DEVELOPER_ID_APPLICATION_PASSWORD }} + INSTALLER_CERTIFICATE: ${{ secrets.APPLE_DEVELOPER_ID_INSTALLER_CERT }} + INSTALLER_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_DEVELOPER_ID_INSTALLER_PASSWORD }} + KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + run: | + if [[ -n "$APPLE_CERTIFICATE" ]]; then + echo $APPLE_CERTIFICATE | base64 --decode > certificate.p12 + echo $INSTALLER_CERTIFICATE | base64 --decode > installer_certificate.p12 + security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain + security list-keychains -d user -s build.keychain + security default-keychain -s build.keychain + security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain + security set-keychain-settings -t 3600 -u build.keychain + security import certificate.p12 -k build.keychain -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign -T /usr/bin/productbuild + security import installer_certificate.p12 -k build.keychain -P "$INSTALLER_CERTIFICATE_PASSWORD" -T /usr/bin/codesign -T /usr/bin/productsign -T /usr/bin/productbuild + security set-key-partition-list -S apple-tool:,apple:,codesign:,productsign:,productbuild: -s -k "$KEYCHAIN_PASSWORD" build.keychain + + echo "=== Available signing identities ===" + security find-identity -v -p codesigning build.keychain + echo "has_cert=true" >>"$GITHUB_OUTPUT" + else + echo "has_cert=false" >>"$GITHUB_OUTPUT" + fi + + - name: Package + shell: bash + env: + PACKAGE_TYPE: ${{ steps.package-info.outputs.type }} + HAVE_APPLE_CERT: ${{ runner.os == 'macOS' && steps.apple-certs.outputs.has_cert }} + SIGNING_IDENTITY: "Developer ID Application: OpenMS Inc. (C64UCGJ5PL)" + SIGNING_EMAIL: "apple@openms.de" + CPACK_PRODUCTBUILD_IDENTITY_NAME: "Developer ID Installer: OpenMS Inc. (C64UCGJ5PL)" + PRESET: ${{ steps.build-openms.outputs.preset }} + run: | + cd "build/$PRESET" || exit 1 + + cmake_options=( + "-DPACKAGE_TYPE=$PACKAGE_TYPE" + "-DSEARCH_ENGINES_DIRECTORY=$GITHUB_WORKSPACE/_thirdparty" + ) + + if [[ -n "$HAVE_APPLE_CERT" ]] && [[ "$HAVE_APPLE_CERT" == "true" ]]; then + cmake_options+=( + "-DSIGNING_IDENTITY=$SIGNING_IDENTITY" + "-DSIGNING_EMAIL=$SIGNING_EMAIL" + "-DCPACK_PRODUCTBUILD_IDENTITY_NAME=$CPACK_PRODUCTBUILD_IDENTITY_NAME" + ) + fi + + # makensis.exe opens every staged file (including the Doxygen HTML + # docs) through the plain Win32 file APIs, which are bound by + # MAX_PATH (260 chars). Deeply-mangled template filenames in the + # docs (e.g. GridSearch's nested Looper struct) combined with + # CPack's default staging path under this already-long build + # directory push some files past that limit and abort the NSIS + # build. Stage the CPack package build in a short, fixed directory + # on Windows instead, so the full staged path stays well under + # MAX_PATH; the resulting installer is moved back next to the + # other build output below so later steps don't need to know. + WIN_CPACK_STAGE_DIR="C:/cpk" + if [[ "$RUNNER_OS" == "Windows" ]]; then + rm -rf "/c/cpk" + mkdir -p "/c/cpk" + cmake_options+=("-DCPACK_PACKAGE_DIRECTORY=$WIN_CPACK_STAGE_DIR") + fi + + cmake "${cmake_options[@]}" ../.. + + if ! ninja dist; then + if [[ "$RUNNER_OS" == "Windows" ]]; then + cat /c/cpk/_CPack_Packages/win64/NSIS/NSISOutput.log + fi + + exit 1 + fi + + if [[ "$RUNNER_OS" == "Windows" ]]; then + mv /c/cpk/*.exe . + fi + + # Notarize macOS packages for Gatekeeper approval + # This step submits the signed package to Apple for notarization and staples the ticket + - name: Notarize macOS Package + if: runner.os == 'macOS' && steps.apple-certs.outputs.has_cert == 'true' + shell: bash + env: + APPLE_APP_SPECIFIC_NOTARIZATION_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_NOTARIZATION_PASSWORD }} + TEAM_ID: "C64UCGJ5PL" + PRESET: ${{ steps.build-openms.outputs.preset }} + run: | + echo "=== Starting macOS package notarization ===" + cd "build/$PRESET" + + # Find the generated .pkg file + PKG_FILE=$(ls -1 *.pkg 2>/dev/null | head -1) + if [[ -z "$PKG_FILE" ]]; then + echo "Error: No .pkg file found in build directory" + ls -la + exit 1 + fi + + echo "Found package: $PKG_FILE" + + # Run notarization script + $GITHUB_WORKSPACE/cmake/MacOSX/notarize.sh \ + "$PKG_FILE" \ + "de.openms" \ + "apple@openms.de" \ + "APPLE_APP_SPECIFIC_NOTARIZATION_PASSWORD" \ + "$TEAM_ID" \ + "$GITHUB_WORKSPACE/build/$PRESET" + + echo "=== Notarization complete ===" + + # Verify the notarization + echo "=== Verifying package signing and notarization ===" + pkgutil --check-signature "$PKG_FILE" || echo "Warning: pkgutil verification returned non-zero" + spctl -a -vvv -t install "$PKG_FILE" || echo "Warning: spctl assessment returned non-zero" + + - name: Upload Packages as Artifacts + uses: actions/upload-artifact@v7 + with: + name: ${{ format('installer-{0}-{1}-{2}', steps.version.outputs.name, runner.os, runner.arch) }} + path: | + ${{ github.workspace }}/build/${{ steps.build-openms.outputs.preset }}/*.exe + ${{ github.workspace }}/build/${{ steps.build-openms.outputs.preset }}/*.deb + ${{ github.workspace }}/build/${{ steps.build-openms.outputs.preset }}/*.pkg + + # The developer SDK (libraries, headers, CMake package, shared data and the + # bundled dependencies) is installed from the tree the installer was just + # packaged from, then checked by building src/tests/external against the + # extracted archive. See tools/ci/package_sdk.sh. + - name: Install SDK Packaging Tools + if: runner.os == 'Linux' + shell: bash + run: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends patchelf + + - name: Package the Developer SDK + shell: bash + env: + PRESET: ${{ steps.build-openms.outputs.preset }} + VERSION: ${{ steps.version.outputs.version }} + run: | + bash tools/ci/package_sdk.sh "build/$PRESET" "$VERSION" "$RUNNER_TEMP/sdk" + + - name: Upload the Developer SDK as an Artifact + uses: actions/upload-artifact@v7 + with: + name: ${{ format('sdk-{0}-{1}-{2}', steps.version.outputs.name, runner.os, runner.arch) }} + if-no-files-found: error + path: | + ${{ runner.temp }}/sdk/*.tar.gz + ${{ runner.temp }}/sdk/*.zip + + # Zip the documentation first, since there are :: which make the + # upload action choke. + - name: Zip Documentation + if: steps.solo.outputs.solo == 'true' + uses: thedoctor0/zip-release@0.7.6 + with: + type: 'zip' + directory: ${{ github.workspace }}/build/${{ steps.build-openms.outputs.preset }}/doc + exclusions: '/CMakeFiles/* /doxygen/* /code_examples/*' + filename: 'documentation.zip' + + - name: Upload Documentation as artifacts + if: steps.solo.outputs.solo == 'true' + uses: actions/upload-artifact@v7 + with: + name: documentation + path: | + ${{ github.workspace }}/build/${{ steps.build-openms.outputs.preset }}/doc/documentation.zip + + - name: Create a tarball of the Source Code + if: steps.solo.outputs.solo == 'true' + env: + TARBALL: ${{ steps.source-name.outputs.tarball }} + run: | + # git archive packs the files of the commit and nothing else from the + # workspace, where the build leaves build/, its caches (.ccache, + # .vcpkg-cache), the third-party tools (_thirdparty) and test output. + # It also fills in .git_archival.txt (export-subst): the tarball has no + # .git, so CMake takes the commit from there, and for the tag v + # the plain version. + # Left out are .github and the submodules THIRDPARTY and vcpkg, which git + # archive would add as empty directories. vcpkg.json, + # vcpkg-configuration.json and vcpkg-overlays/ (overlay ports and + # triplets) are shipped, so the tarball builds with an external vcpkg + # (-DOPENMS_USE_VCPKG=ON + # -DCMAKE_TOOLCHAIN_FILE=/scripts/buildsystems/vcpkg.cmake) + # as well as against system packages (the default, OPENMS_USE_VCPKG=OFF). + git -C "$GITHUB_WORKSPACE" archive --format=tar.gz \ + --output="$RUNNER_TEMP/$TARBALL" HEAD -- \ + . ':(exclude).github' ':(exclude)THIRDPARTY' ':(exclude)vcpkg' + + - name: Upload Source Code as an Artifact + if: steps.solo.outputs.solo == 'true' + uses: actions/upload-artifact@v7 + with: + name: ${{ steps.source-name.outputs.tarball }} + path: | + ${{ runner.temp }}/${{ steps.source-name.outputs.tarball }} + + # The vcpkg dependencies of the Debug SDK, on their own first. The triplet + # x64-windows-static-md builds every port in both configurations, and the first + # run of a new binary cache builds them all from source (3 h 20 min in a dry + # run, ONNX Runtime alone 54 min); the cache is uploaded only by a job that + # succeeds. One job that went on to build OpenMS in Debug would run close to + # the 6-hour limit and lose the dependencies with every failure, so this job + # stops after configuring. With a warm cache it is a matter of minutes. + build-windows-debug-deps: + name: "Build the Windows Debug SDK dependencies" + runs-on: windows-2025 + # the suffix of this build's cache keys, static so that the post step that + # uploads the vcpkg cache sees it (an input would evaluate to its default + # there; see .github/actions/build/action.yml) + env: + OPENMS_CACHE_KEY_SUFFIX: -windows-x64-debug-ci + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + + - name: Configure OpenMS (Debug) + uses: ./.github/actions/build + with: + compiler: cl.exe + preset: windows-x64-debug-ci + configure_only: "true" + ssh_key: ${{ secrets.ARCHIVE_RRSYNC_SSH }} + ssh_host: ${{ secrets.ARCHIVE_RRSYNC_HOST }} + ssh_port: ${{ secrets.ARCHIVE_RRSYNC_PORT }} + ssh_user: ${{ secrets.ARCHIVE_RRSYNC_USER }} + + # The Windows Debug SDK: MSVC's debug CRT (/MDd) is not compatible with the + # release one, so a Debug build of a consumer cannot link the Release SDK. This + # job builds the libraries once more in Debug, with the vcpkg dependencies in + # their debug form, and packages only the SDK: no installer, no tests (the + # Release job covers them, and the Debug test suite would take many hours). + # The installer upload and the release wait for it but do not need it: no PR + # check builds the Debug halves of the vcpkg ports, so a port that breaks only + # in Debug would otherwise hold them back. When this job or the one before it + # fails, they go ahead without the Debug SDK. + build-windows-debug-sdk: + name: "Build the Windows Debug SDK" + runs-on: windows-2025 + # the suffix of this build's cache keys, static so that the post step that + # uploads the vcpkg cache sees it (an input would evaluate to its default + # there; see .github/actions/build/action.yml) + env: + OPENMS_CACHE_KEY_SUFFIX: -windows-x64-debug-ci + needs: build-windows-debug-deps + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + + - name: Build OpenMS (Debug) + id: build-openms + uses: ./.github/actions/build + with: + compiler: cl.exe + preset: windows-x64-debug-ci + run_tests: "false" + ssh_key: ${{ secrets.ARCHIVE_RRSYNC_SSH }} + ssh_host: ${{ secrets.ARCHIVE_RRSYNC_HOST }} + ssh_port: ${{ secrets.ARCHIVE_RRSYNC_PORT }} + ssh_user: ${{ secrets.ARCHIVE_RRSYNC_USER }} + + - name: Parse the Version Number + id: version + uses: ./.github/actions/version + + # The Dependencies component the SDK installs exists only in a tree + # configured with a PACKAGE_TYPE, as the installer job's is. The build + # afterwards is a no-op unless the reconfigure changed something. + - name: Configure the Package Type + shell: bash + env: + PRESET: ${{ steps.build-openms.outputs.preset }} + run: | + cmake -DPACKAGE_TYPE=nsis "-DSEARCH_ENGINES_DIRECTORY=$GITHUB_WORKSPACE/_thirdparty" "build/$PRESET" + cmake --build "build/$PRESET" + + - name: Package the Developer SDK + shell: bash + env: + PRESET: ${{ steps.build-openms.outputs.preset }} + VERSION: ${{ steps.version.outputs.version }} + run: | + bash tools/ci/package_sdk.sh "build/$PRESET" "$VERSION" "$RUNNER_TEMP/sdk" + + - name: Upload the Developer SDK as an Artifact + uses: actions/upload-artifact@v7 + with: + name: ${{ format('sdk-{0}-{1}-{2}-Debug', steps.version.outputs.name, runner.os, runner.arch) }} + if-no-files-found: error + path: | + ${{ runner.temp }}/sdk/*.zip + + deploy-installer: + name: "Deploy Installer" + # !cancelled(): run after the Debug SDK job also when it failed (see there) + if: ${{ !cancelled() && needs.build-and-test.result == 'success' && (github.event_name != 'workflow_dispatch' || inputs.deploy) }} + runs-on: ubuntu-latest + needs: + - build-and-test + - build-windows-debug-sdk + steps: + - uses: actions/checkout@v6 + with: + sparse-checkout: .github/actions + persist-credentials: false + + - name: Download the Installer + uses: actions/download-artifact@v8 + with: + pattern: installer-* + merge-multiple: true + path: ${{ github.workspace }}/downloads + + - name: Download the Developer SDK + uses: actions/download-artifact@v8 + with: + pattern: sdk-* + merge-multiple: true + path: ${{ github.workspace }}/downloads + + - name: Upload Installer and Mark as Latest + uses: ./.github/actions/rsync + with: + key: ${{ secrets.ARCHIVE_RRSYNC_SSH }} + user: ${{ secrets.ARCHIVE_RRSYNC_USER }} + host: ${{ secrets.ARCHIVE_RRSYNC_HOST }} + port: ${{ secrets.ARCHIVE_RRSYNC_PORT }} + src: ${{ github.workspace }}/downloads/* + dst: /OpenMSInstaller/${{ needs.build-and-test.outputs.version_type }}/${{ needs.build-and-test.outputs.version }} + latest: ${{ needs.build-and-test.outputs.version }} + # The archive has no OpenMSInstaller/release/ yet, and rsync creates only + # the last directory of dst by itself. A nightly's dated folder sits + # below the existing nightly/, so nightlies keep running without it. + mkpath: ${{ needs.build-and-test.outputs.has_version }} + + deploy-docs: + name: "Deploy Documentation" + if: ${{ github.event_name != 'workflow_dispatch' || inputs.deploy }} + runs-on: ubuntu-latest + needs: + - build-and-test + steps: + - uses: actions/checkout@v6 + with: + sparse-checkout: .github/actions + persist-credentials: false + + - name: Download the Documentation + uses: actions/download-artifact@v8 + with: + name: documentation + path: ${{ github.workspace }}/downloads + + - name: Unzip the Documentation + shell: bash + run: | + unzip \ + "$GITHUB_WORKSPACE/downloads/documentation.zip" \ + -d "$GITHUB_WORKSPACE/downloads" + + rm "$GITHUB_WORKSPACE/downloads/documentation.zip" + + - name: Upload Documentation and Mark as Latest + uses: ./.github/actions/rsync + with: + key: ${{ secrets.ARCHIVE_RRSYNC_SSH }} + user: ${{ secrets.ARCHIVE_RRSYNC_USER }} + host: ${{ secrets.ARCHIVE_RRSYNC_HOST }} + port: ${{ secrets.ARCHIVE_RRSYNC_PORT }} + src: ${{ github.workspace }}/downloads/ + dst: /Documentation/${{ needs.build-and-test.outputs.version_type }}/${{ needs.build-and-test.outputs.version }} + latest: ${{ needs.build-and-test.outputs.version }} + + publish-release: + name: "Publish Release" + if: ${{ !cancelled() && needs.deploy-installer.result == 'success' && needs.deploy-docs.result == 'success' }} + runs-on: ubuntu-latest + permissions: write-all + needs: + - build-and-test + - build-windows-debug-sdk + - deploy-installer + - deploy-docs + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + sparse-checkout: | + .github/workflows/release-announcement.txt + CHANGELOG + + - name: Create Change Log + env: + VERSION: ${{ needs.build-and-test.outputs.version }} + VERSION_TYPE: ${{ needs.build-and-test.outputs.version_type }} + shell: bash + run: | + # Return lines matching releases. + function releases() { + grep --line-number -- "----[[:space:]]*OpenMS" CHANGELOG + } + + # Return the two lines matching the current release. + function this_version() { + grep --fixed-strings -A1 "$VERSION" + } + + # Return line numbers from grep output + function line_numbers() { + cut --delimiter=: --fields=1 + } + + # Line numbers delimiting releases. + lines=() + + if releases | this_version >/dev/null; then + # We have a matching release. + mapfile lines < <(releases | this_version | line_numbers) + else + # Use the latest release info instead. + mapfile lines < <(releases | head -n 2 | line_numbers) + fi + + beg=$((lines[0] + 2)) + end=$((lines[1] - 2)) + + sed --quiet -e "${beg},${end} p" CHANGELOG >release-changelog.txt + + - name: Upload CHANGELOG as Artifact + uses: actions/upload-artifact@v7 + with: + name: changelog.txt + path: release-changelog.txt + archive: false + + - name: Generate Release Announcement + env: + VERSION: ${{ needs.build-and-test.outputs.version }} + VERSION_TYPE: ${{ needs.build-and-test.outputs.version_type }} + shell: bash + run: | + # Fill the template with the version and the CHANGELOG section in file $1. + # Okay, maybe this is over the top. + function render() { + awk \ + --assign VERSION_TYPE="$VERSION_TYPE" \ + --assign VERSION="$VERSION" \ + --assign CHANGELOG_FILE="$1" \ + --source ' + BEGIN { + cl_text = "" + while ((getline line < CHANGELOG_FILE) > 0) { + cl_text = cl_text (cl_text ? ORS : "") line + } + close(CHANGELOG_FILE) + } { + line = $0 + + while (match(line, /@@([A-Z_]+)@@/, matches)) { + alt = "MISSING" + + switch(matches[1]) { + case "VERSION_TYPE": + alt = VERSION_TYPE + break + case "VERSION": + alt = VERSION + break + case "CHANGELOG": + alt = cl_text + break + default: + alt = "MISSING" + break; + } + + line = substr(line, 1, RSTART - 1) alt substr(line, RSTART + RLENGTH) + } + + print line + }' <.github/workflows/release-announcement.txt + } + + # The full announcement, for the website. + render release-changelog.txt >release-announcement.txt + + # GitHub keeps only the first 125,000 characters of a release body, and the + # 3.6.0 announcement was longer: its notes stopped mid-word and lost "Known + # issues". If the announcement is too long, the release notes keep the + # introduction and "Known issues" (moved up), then as many whole sections as + # fit, and link the full CHANGELOG for the rest. + python3 - <<'EOF' + import os + import re + + LIMIT = 124000 # characters; GitHub's limit is 125,000 + + with open("release-changelog.txt", encoding="utf-8") as f: + changelog = f.read() + with open("release-announcement.txt", encoding="utf-8") as f: + announcement = f.read() + + notes = changelog + if len(announcement) > LIMIT: + # Sections start with a heading line such as "General:" or "Known issues:". + parts = re.split(r"(?m)^(?=[A-Z][^\n]{0,40}:[ \t]*$)", changelog) + intro, sections = parts[0], parts[1:] + known = [s for s in sections if s.startswith("Known issues:")] + others = [s for s in sections if not s.startswith("Known issues:")] + url = "{}/{}/blob/{}/CHANGELOG".format( + os.environ["GITHUB_SERVER_URL"], os.environ["GITHUB_REPOSITORY"], os.environ["GITHUB_REF_NAME"]) + # room for the template around the CHANGELOG section and for the note below + budget = LIMIT - (len(announcement) - len(changelog)) - 1000 + budget -= len(intro) + sum(len(s) for s in known) + kept, omitted = [], [] + for s in others: + if not omitted and len(s) <= budget: + kept.append(s) + budget -= len(s) + else: + omitted.append(s.split("\n", 1)[0].strip().rstrip(":")) + notes = (intro + "".join(known) + "".join(kept) + + "Not shown here because of GitHub's length limit for release notes: " + + ", ".join(omitted) + ". The complete list of changes is in the CHANGELOG, " + + url + "\n") + + with open("release-notes-changelog.txt", "w", encoding="utf-8") as f: + f.write(notes) + EOF + + # The release notes on GitHub. + render release-notes-changelog.txt >release-notes.txt + echo "Release announcement: $(wc -m . with an optional . + if [[ "$TAG_NAME" =~ ^v([0-9]+)\.([0-9]+)(\.[0-9]+)?$ ]]; then + MAJOR="${BASH_REMATCH[1]}" + MINOR="${BASH_REMATCH[2]}" + + # Extract the raw patch match + PATCH_RAW="${BASH_REMATCH[3]}" + # Strip the leading dot + PATCH="${PATCH_RAW#.}" + else + echo "Error: Invalid version tag format '$TAG_NAME'." >&2 + echo "Must strictly match 'vX.Y' or 'vX.Y.Z' (e.g., v2.0 or v4.12.4)." >&2 + exit 1 + fi + + # Calculate next minor version (increment minor, reset patch to 0) + NEW_MAJOR="$MAJOR" + NEW_MINOR=$((MINOR + 1)) + NEW_PATCH=0 + NEW_VERSION=${NEW_MAJOR}.${NEW_MINOR}.${NEW_PATCH} + + echo "Bumping version from $MAJOR.$MINOR.$PATCH to $NEW_VERSION" + + # Execute your update script + bash tools/update_version_numbers.sh "$NEW_MAJOR" "$NEW_MINOR" "$NEW_PATCH" + + # Push variables to GITHUB_ENV so they populate next step seamlessly + echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_ENV + + # 4. Commit, Push, and PR updated files + - name: Commit, Push, and PR + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BRANCH_NAME: update_package_number + TAG_NAME: ${{ github.ref_name }} + run: | + # 1. Check for changes. If clean, exit early gracefully. + if git diff --exit-code; then + echo "No changes detected. Skipping PR creation." + exit 0 + fi + + FULL_BRANCH_NAME=${BRANCH_NAME}_${NEW_VERSION} + + # 2. Configure Git using the actor's identity + git config --global user.name "${{ github.actor }}" + git config --global user.email "${{ github.actor }}@users.noreply.github.com" + + # 3. Checkout a clean branch and commit changes + git checkout -b "$FULL_BRANCH_NAME" + git add . + git commit -m "Updated OpenMS package version number to $NEW_VERSION" + + # 4. Force push the changes to keep the PR branch updated + git push origin "$FULL_BRANCH_NAME" --force + + # 5. Check if an active PR already exists for this branch targeting develop + PR_EXISTS=$(gh pr list --head "$FULL_BRANCH_NAME" --base develop --state open --json number --jq '.[].number') + + # 6. Create the PR if it doesn't exist targeting develop; otherwise let the force-push update it + if [ -z "$PR_EXISTS" ]; then + gh pr create \ + --title "[GHA] Updated OpenMS package version numbers to $NEW_VERSION" \ + --body "This PR was automatically generated by GitHub Actions following the tag push of **$TAG_NAME** to bump the OpenMS version number to $NEW_VERSION on \`develop\`." \ + --base develop \ + --head "$FULL_BRANCH_NAME" + else + echo "PR #${PR_EXISTS} already exists for branch $FULL_BRANCH_NAME. Branch was force-pushed; PR is now up to date." + fi diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..52030bb94 --- /dev/null +++ b/.gitignore @@ -0,0 +1,282 @@ +# Build artifacts and generated files +.ccache/ +_thirdparty/ +*.cached +*.deb +*.pyc +*.swp +# Temporary files generated during the unit tests have $NAME.tmp.$EXTENSION pattern +*.tmp.* +*.tmp + +*.user +**/.DS_Store +*.canno + +# Cache files created by SwathFile with unique timestamps (YYYYMMDD_HHMMSS_hostname_pid_number.mzML) +[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]_[0-9][0-9][0-9][0-9][0-9][0-9]_*_*_*.mzML + +# SwathFile test cache files +openswath_tmpfile_*.mzML +tmp_osw_cached_*.mzML +tmp_osw_cached*.mzML.cached +tmp_osw_cached_ms1.mzML* +_CPack_Packages +_deps +/src/tests/class_tests/bin +/bin +/lib + +#These are the typical build directories +/build +/build-debug/* +/build-release/* +/OpenMS-build/* +/openms-build +/openms_build + +DartConfiguration.tcl +install_manifest.txt +Makefile +moc_*.cxx* + +# NB: this is the build dir not src/pyOpenMS which is tracked +/pyOpenMS + +# .venv/venv everywhere +**/.venv +**/venv +**/.pytest_cache +**/.mypy_cache +**/__pycache__/ +**/.py-build-cmake_cache + +qrc_resources.cxx +resources.qrc.depends + +# Ephemeral planning documents from agentic development tools +/docs/superpowers + +# Autogenerated files and directories +/src/openms/OpenMS_autogen +/src/openms_gui/*_autogen +/src/openswathalgo/*_autogen +/src/tests/class_tests/openms_gui/*_autogen + +# Various test outputs +/src/tests/topp/tmp_path/ +/src/tests/toppas/TOPPAS_out/ +/src/tests/class_tests/Testing/ +/src/tests/class_tests/openms/Testing/ +/src/tests/class_tests/openms/data/Testing/ +/Testing/ + +thirdparty_licenses.txt +vcpkg_installed + +# Generated CMake files +cmake-*-build +cmake-build-* +cmake_install.cmake +CMakeCache.txt +CMakeDoxyfile.in +CMakeDoxygenDefaults.cmake +CMakeFiles +CPackConfig.cmake +CPackSourceConfig.cmake +CTestTestfile.cmake +OpenMSConfig.cmake +OpenMSConfigVersion.cmake +OpenMSTargets.cmake +# An in-source build copies cmake/Modules/ to the build root +/Modules/ + +# IDE and editor files +*.code-workspace +.cache/* +.clion.* +.idea +.qt/ +.vs +.vscode +OpenMS.config +OpenMS.creator +OpenMS.files +OpenMS.includes + +# Documentation build outputs (keep source files) +/doc/html/ +/doc/xml/ +/doc/latex/ +/doc/doxygen/parameters/ +/doc/doxygen/html/ +/doc/doxygen/xml/ +/doc/doxygen/Doxyfile +/doc/doxygen/Doxyfile_* +/doc/doxygen/doxygen-error.log +/doc/code_examples/*.mzML +/doc/code_examples/*.consensusXML +/doc/code_examples/*.featureXML +/doc/code_examples/*.arrow +/doc/code_examples/*.csv +/doc/code_examples/*.parquet +/doc/code_examples/output/ +/doc/code_examples/data/ + +# Generated header files (CMake-configured) +/src/openms/include/OpenMS/config.h +/src/openms/include/OpenMS/OpenMSConfig.h +/src/openms/include/OpenMS/build_config*.h +/src/openms/include/OpenMS/openms_data_path.h +/src/openms/include/OpenMS/openms_package_version.h +/src/openms/extern/**/*Config.cmake +/src/openms/extern/**/*ConfigVersion.cmake +/src/openms/extern/**/*config*.cmake +/src/openms/extern/**/*.pc +/src/openms_gui/include/OpenMS/VISUAL/OpenMS_GUIConfig.h +/src/openms_gui/qrc_resources.cpp +/src/openswathalgo/include/OpenMS/OPENSWATHALGO/OpenSwathAlgoConfig.h + +# Log files +TOPP.log +TOPPAS.log + +# Test data and output files +/src/tests/class_tests/*/include/OpenMS/test_config.h +/src/tests/topp/OpenNuXL_1_input.mzML.ambiguous_masses.csv +/src/tests/toppas/*.trf + +# Test files in root (should be in proper directories) +/test.mzML +/test.mzData +/test_output.log + +# Security - Credentials, tokens, and secrets +.env +.env.* +.env.local +.env.*.local +*.pem +*.key +*.p12 +*.pfx +*.crt +*.cer +*.der +!*.crt.example +!*.key.example +credentials.json +credentials.yaml +credentials.yml +secrets.json +secrets.yaml +secrets.yml +secrets.toml +**/secrets/ +**/credentials/ +.secrets +.credentials +*.secret +*.secrets + +# AWS +.aws/ +aws_credentials +.boto + +# SSH keys +id_rsa +id_rsa.pub +id_dsa +id_dsa.pub +id_ecdsa +id_ecdsa.pub +id_ed25519 +id_ed25519.pub +*.ppk + +# API tokens and keys +.npmrc +.pypirc +.netrc +.htpasswd +.htaccess +*.token +api_key* +apikey* +auth.json +auth.yaml +auth.yml + +# Docker secrets +docker-compose.override.yml +docker-compose.*.yml +!docker-compose.example.yml + +# Kubernetes +kubeconfig +*.kubeconfig +kube/config + +# OAuth +oauth_token* +oauth-token* +client_secret* +client-secret* + +# GPG +*.gpg +secring.* +pubring.* +trustdb.* + +# Terraform +*.tfstate +*.tfstate.* +*.tfvars +!*.tfvars.example +.terraform/ + +# Ansible +*.vault +vault.yml +vault.yaml +group_vars/*/vault* +host_vars/*/vault* + +# IDE credential storage +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.xml +.idea/**/dataSources.local.xml + +# Shell history (may contain credentials) +.bash_history +.zsh_history +.sh_history + +# Local configuration that may contain secrets +config.local.* +settings.local.* +*.local.json +*.local.yaml +*.local.yml +*.local.toml + +# Jupyter notebooks checkpoints (may contain credentials in outputs) +.ipynb_checkpoints/ + +# GitHub tokens +.github_token +github_token* + +# Claude/AI tokens and session files +.claude_token +.anthropic_key +.claude/scheduled_tasks.lock + +# Link checker cache +.lycheecache + +# Lock files from external tools +*.fasta.lock diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 000000000..77cc03c88 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,143 @@ +========================================================================= + OpenMS -- Open Source Mass Spectrometry +========================================================================= + +The following authors contributed to OpenMS at some point. For the +authors contributing to a specific piece of code, please refer to +the authors tag in the respective file header. + - Achal Bajpai + - Adithya Kammati + - Aditya Muzumdar + - Aditya Sarna + - Ahmed Khalil + - Alen Saric + - Alexandra Scherbart + - Alexandra Zerck + - Alivia Hossain + - Amanda Wein + - Andreas Bertsch + - Andreas Simon + - Anton Kriese + - Anton Pervukhin + - Axel Walter + - Bastian Blank + - Chenghao Zhu + - Chirag Dave + - Chris Bauer + - Chris Bielow + - Christian Ehrlich + - Christie Mathews + - Clemens Groepl + - Cornelia Friedle + - Daniel Jameson + - Darren Kessner + - David Voigt + - David Wojnar + - Dhanmoni Nath + - Dilek Dere + - Dimitri Schachmann + - Dominik Schmitz + - Douglas McCloskey + - Emil Paulitz + - Erhan Kenar + - Eugen Netz + - Eva Lange + - Fabian Aicheler + - Fabian Kriegel + - Felix Droop + - Florian Zeller + - Frederic Lehnert + - George Rosenberger + - Guillaume Belz + - Hannes Roest + - Hendrik Beschorner + - Hendrik Brauer + - Hendrik Weisser + - Holger Franken + - Holger Plattfaut + - Immanuel Luhn + - Jang Jang Jin + - Jeremi Maciejewski + - Jihyung Kim + - Johannes Junker + - Johannes Veit + - Johannes von Kleist + - Johan Teleman + - Joshua Charkow + - Juliane Schmachtenberg + - Julianus Pfeuffer + - Julia Thueringer + - Justin Sing + - Katharina Albers + - Karnajeet Gosavi + - Khue Nguyen + - Knut Reinert + - Krrish Verma + - Kyowon Jeong + - Lars Nilse + - Lenny Kovac + - Leon Bichmann + - Leon Kuchenbecker + - Lucia Espona + - Luis Jacob Keller + - Lukas Mueller + - Lukas Zimmermann + - Marcel Schilling + - Marc Sturm + - Markus Apel + - Markus Mueller + - Martin Langwisch + - Mateusz Łącki + - Mathias Walzer + - Matteo Pilz + - Matthew The + - Matthias Bernt + - Michael R. Crusoe + - Michał Startek + - Mohamed Ali + - Nico Pfeifer + - Nidhish Chauhan + - Nora Heese + - Ole Schulz-Trieglaff + - Oliver Alka + - Oliver Kohlbacher + - Pasquale Domenico Colaianni + - Patricia Scheil + - Patrick Boschmann + - Peter J. Jones + - Peter Kunszt + - Petra Gutenbrunner + - Radu Suciu + - Ralf Gabriels + - Rene Hussong + - Rick Helmus + - Ruben Grünberg + - Samuel Wein + - Sandro Andreotti + - Santhil + - Shubham Padkonde + - Simon Gene Gottlieb + - Steffen Sass + - Stephan Aiche + - Sven Nahnsen + - Svetlana Kutuzova + - Swenja Wagner + - Tapasweni Pathak + - Taraneh Strunk + - Till Englert + - Tilman Aurich + - Timo Sachsenberg + - Tinatin Kasradze + - Tom David Müller + - Tom Lukas Lankenau + - Tom Smith + - Tom Waschischeck + - Uwe Schmitt + - Valentin Noske + - Vincent Musch + - Vipul Patel + - Virginia Rossow + - Volker Mosthaf + - Witold Wolski + - Xiao Liang + - Yasset Perez-Riverol diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 000000000..85862cbea --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,177 @@ +cff-version: 1.2.0 +message: "If you use OpenMS in your research, please cite us using the metadata from this file." +title: "OpenMS" +type: software +url: "https://github.com/OpenMS/OpenMS" +repository-code: "https://github.com/OpenMS/OpenMS" +license: BSD-3-Clause +preferred-citation: + type: article + title: "OpenMS 3 enables reproducible analysis of large-scale mass spectrometry data" + authors: + - family-names: Pfeuffer + given-names: Julianus + - family-names: Bielow + given-names: Chris + - family-names: Wein + given-names: Samuel + - family-names: Jeong + given-names: Kyowon + - family-names: Netz + given-names: Eugen + - family-names: Walter + given-names: Axel + - family-names: Alka + given-names: Oliver + - family-names: Nilse + given-names: Lars + - family-names: Colaianni + given-names: Pasquale Domenico + - family-names: McCloskey + given-names: Douglas + - family-names: Kim + given-names: Jihyung + - family-names: Rosenberger + given-names: George + - family-names: Bichmann + given-names: Leon + - family-names: Walzer + given-names: Mathias + - family-names: Veit + given-names: Johannes + - family-names: Boudaud + given-names: Bertrand + - family-names: Bernt + given-names: Matthias + - family-names: Patikas + given-names: Nikolaos + - family-names: Pilz + given-names: Matteo + - family-names: Startek + given-names: "Micha\u0142 Piotr" + - family-names: Kutuzova + given-names: Svetlana + - family-names: Heumos + given-names: Lukas + - family-names: Charkow + given-names: Joshua + - family-names: Sing + given-names: Justin Cyril + - family-names: Feroz + given-names: Ayesha + - family-names: Siraj + given-names: Arslan + - family-names: Weisser + given-names: Hendrik + - family-names: Dijkstra + given-names: Tjeerd M. H. + - family-names: "P\xe9rez-Riverol" + given-names: Yasset + - family-names: "R\xf6st" + given-names: Hannes + - family-names: Kohlbacher + given-names: Oliver + - family-names: Sachsenberg + given-names: Timo + journal: "Nature Methods" + volume: 21 + issue: 3 + start: 365 + end: 367 + year: 2024 + doi: "10.1038/s41592-024-02197-7" +references: + - type: article + title: "OpenMS: a flexible open-source software platform for mass spectrometry data analysis" + authors: + - family-names: "R\xf6st" + given-names: Hannes L. + - family-names: Sachsenberg + given-names: Timo + - family-names: Aiche + given-names: Stephan + - family-names: Bielow + given-names: Chris + - family-names: Weisser + given-names: Hendrik + - family-names: Aicheler + given-names: Fabian + - family-names: Andreotti + given-names: Sandro + - family-names: Ehrlich + given-names: Hans-Christian + - family-names: Gutenbrunner + given-names: Petra + - family-names: Kenar + given-names: Erhan + - family-names: Liang + given-names: Xiao + - family-names: Nahnsen + given-names: Sven + - family-names: Nilse + given-names: Lars + - family-names: Pfeuffer + given-names: Julianus + - family-names: Rosenberger + given-names: George + - family-names: Rurik + given-names: Marc + - family-names: Schmitt + given-names: Uwe + - family-names: Veit + given-names: Johannes + - family-names: Walzer + given-names: Mathias + - family-names: Wojnar + given-names: David + - family-names: Wolski + given-names: Witold E. + - family-names: Schilling + given-names: Oliver + - family-names: Choudhary + given-names: Jyoti S. + - family-names: "Malmstr\xf6m" + given-names: Lars + - family-names: Aebersold + given-names: Ruedi + - family-names: Reinert + given-names: Knut + - family-names: Kohlbacher + given-names: Oliver + journal: "Nature Methods" + volume: 13 + issue: 9 + start: 741 + end: 748 + year: 2016 + doi: "10.1038/nmeth.3959" + - type: article + title: "OpenMS - an open-source software framework for mass spectrometry" + authors: + - family-names: Sturm + given-names: Marc + - family-names: Bertsch + given-names: Andreas + - family-names: "Gr\xf6pl" + given-names: Clemens + - family-names: Hildebrandt + given-names: Andreas + - family-names: Hussong + given-names: Rene + - family-names: Lange + given-names: Eva + - family-names: Pfeifer + given-names: Nico + - family-names: Schulz-Trieglaff + given-names: Ole + - family-names: Zerck + given-names: Alexandra + - family-names: Reinert + given-names: Knut + - family-names: Kohlbacher + given-names: Oliver + journal: "BMC Bioinformatics" + volume: 9 + start: 163 + year: 2008 + doi: "10.1186/1471-2105-9-163" diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..590eaae82 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,879 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Julianus Pfeuffer $ +# $Authors: Stephan Aiche, Julianus Pfeuffer $ +# -------------------------------------------------------------------------- + + +cmake_minimum_required(VERSION 3.24 FATAL_ERROR) ## Subdirectories pulled +## in via add_subdirectory() deliberately do NOT declare their own: doing so resets the policy scope +## for that directory to the older version + +# The vcpkg toolchain must be selected before project() initializes compilers. +# The CMake presets set OPENMS_USE_VCPKG=ON and build the dependencies with vcpkg. +# A configure without a preset takes them from system packages and CMAKE_PREFIX_PATH. +option(OPENMS_USE_VCPKG "Use vcpkg manifest mode for dependency management (OFF: system packages and CMAKE_PREFIX_PATH)." OFF) + +if(OPENMS_USE_VCPKG AND NOT CMAKE_TOOLCHAIN_FILE) + set(_openms_submodule_vcpkg_toolchain "${CMAKE_CURRENT_SOURCE_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake") + + if(EXISTS "${_openms_submodule_vcpkg_toolchain}") + set(CMAKE_TOOLCHAIN_FILE "${_openms_submodule_vcpkg_toolchain}" CACHE FILEPATH "CMake toolchain file") + else() + message(FATAL_ERROR + "OPENMS_USE_VCPKG is ON, but no vcpkg toolchain was found.\n" + "Either\n" + " - build the dependencies with vcpkg: run 'git submodule update --init vcpkg' " + "(or clone with --recurse-submodules) and configure with a preset, e.g. " + "'cmake --preset linux-x64-release' ('cmake --list-presets' lists them), or set " + "CMAKE_TOOLCHAIN_FILE to /scripts/buildsystems/vcpkg.cmake; or\n" + " - take the dependencies from system packages or CMAKE_PREFIX_PATH: configure " + "with -DOPENMS_USE_VCPKG=OFF.") + endif() + + unset(_openms_submodule_vcpkg_toolchain) +endif() + +# Handle default build type +get_property(multiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(NOT multiConfig AND NOT DEFINED CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build.") +endif() + +# Early MSVC toolset guard (skipped by non-MSVC compiler) +# +# The authoritative compiler version checks live in cmake/min_compiler_versions.cmake +# and run further down, but they are too late to be useful on Windows: with +# OPENMS_USE_VCPKG the toolchain builds every dependency from inside project() +# below, so an unsupported toolset fails while compiling, leaving the user wondering +# what happened -- before any of our own checks run. +# +# We therefore repeat the MSVC check here using %VCToolsVersion%, which vcvars +# always sets and which is the one piece of toolset information available before +# a compiler has been detected. Keep the version in sync with +# cmake/min_compiler_versions.cmake (OPENMS_MIN_MSVC_TOOLSET) +if(WIN32 AND DEFINED ENV{VCToolsVersion} AND "$ENV{VCToolsVersion}" VERSION_LESS "14.44") + message(FATAL_ERROR + "OpenMS requires Visual Studio 2022 version 17.14 or later (MSVC toolset 14.44+), but the current " + "environment provides toolset $ENV{VCToolsVersion}.\n" + "\n" + "Please update Visual Studio.") +endif() + +project("OpenMS_host" LANGUAGES CXX) + +# A toolchain file given by the user (cross compiling, conda, ...) is not +# necessarily vcpkg's. vcpkg.cmake sets VCPKG_TOOLCHAIN; a different toolchain +# would otherwise only surface as missing dependencies much later. +if(OPENMS_USE_VCPKG AND NOT VCPKG_TOOLCHAIN) + message(FATAL_ERROR + "OPENMS_USE_VCPKG is ON, but the toolchain file '${CMAKE_TOOLCHAIN_FILE}' " + "is not vcpkg's. Pass vcpkg's toolchain (/scripts/buildsystems/vcpkg.cmake) and " + "chain-load your own with -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=, or configure with " + "-DOPENMS_USE_VCPKG=OFF to take the dependencies from system packages or CMAKE_PREFIX_PATH.") +endif() + +# required for cmake < 3.13 if ccache is used +set(CMAKE_AUTOMOC_COMPILER_PREDEFINES OFF) + +#------------------------------------------------------------------------------ +# General CMake definitions & helper +#------------------------------------------------------------------------------ +# FetchContent without a sub-build (CMake >= 3.30). +# (required to allow changing the Generator in the main project, without deleting the FetchContent sub-build) +if(POLICY CMP0168) ## obsolete in CMake 3.30+ + cmake_policy(SET CMP0168 NEW) +endif() + +SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) +#------------------------------------------------------------------------------ +## CMake sanity check: sometimes CMAKE_SIZEOF_VOID_P just vanishes when +## updating CMake. +if (NOT CMAKE_SIZEOF_VOID_P) + message(FATAL_ERROR "'CMAKE_SIZEOF_VOID_P' is undefined. Thus you should" + " delete CMakeFiles (the directory) and the" + " CMakeCache.txt and rerun CMake again! This is some" + " weird CMake bug that seems to appear when updating the" + " CMake version.") +endif() + +#------------------------------------------------------------------------------ +# Enable testing with CTest +enable_testing() + +#------------------------------------------------------------------------------ +# entries meant to be configured using CMake cache +# - do NOT hardcode them here! +# - edit them within CMakeCache.txt using ccmake or cmake -DVAR=VALUE +#------------------------------------------------------------------------------ +# CMAKE_PREFIX_PATH +# CMAKE_BUILD_TYPE +# STL_DEBUG +# ADDRESS_SANITIZER +# OPENMS_COVERAGE +#------------------------------------------------------------------------------ +option(MT_ENABLE_OPENMP "Enable OpenMP support" ON) +option(MT_REQUIRE_OPENMP "With MT_ENABLE_OPENMP, fail the configuration if no OpenMP runtime is found, instead of falling back to -fopenmp-simd (no parallel regions). The CI presets set it." OFF) +option(HAS_XSERVER "Indicates if an X server is available. If set to Off it will disable certain tests and the doc target." ON) +option(ENABLE_DOCS "Indicates whether documentation should be built." ON) +option(BUILD_TOPP_TOOLS "Build the TOPP command-line applications." ON) +option(INSTALL_OPENMS_EXAMPLES "Install the OpenMS example data." ON) +option(WITH_GUI "Build GUI parts of OpenMS (TOPPView&Co). This requires QtGui." ON) +option(NO_WEBENGINE_WIDGETS "Do not use QtWebengineWidgets. Disables Javascript views in TOPPView." OFF) +option(WITH_HDF5 "Build HDF5 parts of OpenMS." OFF) +option(WITH_OPENTIMS "Build with Bruker TimsTOF .d file support via opentims" ON) +option(OPENMS_ENABLE_MZPEAK "Build with mzPeak (HUPO-PSI Parquet-based raw data format) support via the vendored mzPeak library (needs Arrow/Parquet, which OpenMS requires anyway)" ON) +option(WITH_ONNX "Build with ONNX Runtime support for PeptDeep ML bindings" OFF) +option(ENABLE_OPENTIMS_TESTS "Download Bruker test data for opentims integration tests" OFF) +# Every platform we build for reads RAW files: the Thermo CommonCore assemblies are +# architecture-neutral IL, and only the bridge around them is compiled per target. +option(WITH_THERMO_RAW "Build with Thermo RAW file reading support via openms-thermo-bridge" ON) +option(ENABLE_THERMO_RAW_TESTS "Download Thermo RAW test data for integration tests" OFF) +option(ENABLE_THERMO_FAIMS_DIA_TESTS "Download Thermo FAIMS-DIA test data for integration tests" OFF) +option(ENABLE_FAIMS_DDA_TESTS "Download FAIMS-DDA test data (mzML) for integration tests" OFF) +option(ENABLE_TDL "Load dependency and compile against TDL (required for CWL file support)." OFF) +option(ENABLE_CWL_GENERATION "Build and validate the CWL description files for all TOPP tools (Requires ENABLE_TDL=ON)." OFF) + +## Build only the applications (TOPP tools and/or the GUI) against an installed OpenMS +## library of the same version instead of building the libraries, e.g. to package OpenMS in +## layers (see cmake/find_installed_openms.cmake). Point OpenMS_DIR or CMAKE_PREFIX_PATH at +## the installation. Tests, documentation and pyOpenMS need the library targets of this build +## and are not built in this mode. +option(OPENMS_USE_INSTALLED_LIBRARY "Build the TOPP tools and/or the GUI against an installed OpenMS library instead of building the libraries." OFF) +if(OPENMS_USE_INSTALLED_LIBRARY AND ENABLE_CWL_GENERATION) + message(FATAL_ERROR "ENABLE_CWL_GENERATION is not supported together with OPENMS_USE_INSTALLED_LIBRARY.") +endif() + +if(ENABLE_CWL_GENERATION AND NOT ENABLE_TDL) + message(FATAL_ERROR "ENABLE_CWL_GENERATION requires ENABLE_TDL to be ON.") +endif() +if(ENABLE_CWL_GENERATION AND NOT BUILD_TOPP_TOOLS) + message(FATAL_ERROR "ENABLE_CWL_GENERATION requires BUILD_TOPP_TOOLS to be ON.") +endif() + +if(MSVC) + option(MT_ENABLE_NESTED_OPENMP "Enable nested parallelism." OFF) +else() + option(MT_ENABLE_NESTED_OPENMP "Enable nested parallelism." ON) +endif() + +if (ENABLE_OPENTIMS_TESTS AND WITH_OPENTIMS) + include(FetchContent) + # Mirror of the timsrust_cpp_bridge "test-data-v1" release, hosted on the OpenMS + # infra fileserver (archive.openms.de). NOTE: this host currently answers only on + # plain HTTP (no HTTPS listener yet) and port 80 is reachable only from whitelisted + # CI/build networks at the perimeter firewall. URL_HASH pins each file's + # integrity so the weaker transport cannot corrupt a download silently. + set(OPENTIMS_TESTDATA_URL "http://archive.openms.de/openms/testfiles") + FetchContent_Declare( + opentims_testdata_dda + URL "${OPENTIMS_TESTDATA_URL}/DDA_HeLa_50ng_5_6min.d.zip" + URL_HASH SHA256=659d691e48d621edcd1fecb8448de5731147c009bda42ba6e7e5ed53e46dc15c + DOWNLOAD_EXTRACT_TIMESTAMP TRUE + ) + FetchContent_Declare( + opentims_testdata_dia + URL "${OPENTIMS_TESTDATA_URL}/DIA_HeLa_50ng_5_6min.d.zip" + URL_HASH SHA256=bacf98b472ed3a3cfef2c2595a726fc6c06f059a41c17d9035b2b864932b6f5d + DOWNLOAD_EXTRACT_TIMESTAMP TRUE + ) + FetchContent_Declare( + opentims_testdata_fasta + URL "${OPENTIMS_TESTDATA_URL}/human_sp.fasta" + URL_HASH SHA256=b205ed9970fee62413e2f192c6fb82daab86e4a5897ef521f907ecbfcd7b3e63 + DOWNLOAD_NO_EXTRACT TRUE + ) + FetchContent_MakeAvailable(opentims_testdata_dda opentims_testdata_dia opentims_testdata_fasta) + set(OPENTIMS_DDA_TEST_DATA "${opentims_testdata_dda_SOURCE_DIR}" CACHE PATH "Path to DDA test .d directory") + set(OPENTIMS_DIA_TEST_DATA "${opentims_testdata_dia_SOURCE_DIR}" CACHE PATH "Path to DIA test .d directory") + set(OPENTIMS_TEST_FASTA "${opentims_testdata_fasta_SOURCE_DIR}/human_sp.fasta" CACHE PATH "Path to human Swiss-Prot FASTA for search tests") +endif() + +if (ENABLE_THERMO_RAW_TESTS AND WITH_THERMO_RAW) + include(FetchContent) + # Angiotensin_AllScans.raw originally from PNNL-Comp-Mass-Spec/Thermo-Raw-File-Reader + # (BSD-2-Clause, (c) 2018 Battelle Memorial Institute), commit 1d8ff309. Contains + # 87 MS1 (FTMS Full ms) plus hundreds of MS2 scans with HCD and supplemental- + # activation (ETD+HCD, ETD+CID) filters at precursor m/z 432.9 — exercises the + # full activation-method switch in ThermoRawFile.cpp and MS1+MSn round-trip via + # mzML. Served from the OpenMS infra mirror (see OPENTIMS_TESTDATA_URL note above + # re: plain HTTP); URL_HASH below pins integrity/reproducibility. + FetchContent_Declare( + thermo_raw_testdata + URL "http://archive.openms.de/openms/testfiles/Angiotensin_AllScans.raw" + URL_HASH SHA256=3a0236f719e7c91e3c958f57f4e66ae422803ec3e6a997b9af4d2af395332b9f + DOWNLOAD_NO_EXTRACT TRUE + ) + FetchContent_MakeAvailable(thermo_raw_testdata) + set(THERMO_RAW_TEST_DATA "${thermo_raw_testdata_SOURCE_DIR}/Angiotensin_AllScans.raw" CACHE PATH "Path to Thermo RAW test file") +endif() + +# Optional end-to-end FAIMS-DIA integration fixture. A developer can either set +# THERMO_FAIMS_DIA_TEST_DATA explicitly to an existing local RAW file, or enable +# ENABLE_THERMO_FAIMS_DIA_TESTS to fetch the pinned public PRIDE fixture. The +# ~308 MB download remains opt-in and is not part of normal OpenMS builds/tests. +set(THERMO_FAIMS_DIA_TEST_DATA "${THERMO_FAIMS_DIA_TEST_DATA}" CACHE FILEPATH + "Path to a Thermo FAIMS-DIA RAW file for integration testing") +if (ENABLE_THERMO_FAIMS_DIA_TESTS AND WITH_THERMO_RAW AND NOT THERMO_FAIMS_DIA_TEST_DATA) + include(FetchContent) + # Public single-CV FAIMS-DIA run from PRIDE PXD029902. The pinned hash fixes + # the exact 308,209,820-byte input used by ThermoRawFile_test. + FetchContent_Declare( + thermo_faims_dia_testdata + URL "https://ftp.pride.ebi.ac.uk/pride/data/archive/2023/08/PXD029902/20210213_WTC11_DIA_5CV.raw" + URL_HASH SHA256=e98b2cc95d162b1dfd24cf003434ef0deef085d7c99ffc0fde695aec8bf236b1 + DOWNLOAD_NO_EXTRACT TRUE + ) + FetchContent_MakeAvailable(thermo_faims_dia_testdata) + set(THERMO_FAIMS_DIA_TEST_DATA + "${thermo_faims_dia_testdata_SOURCE_DIR}/20210213_WTC11_DIA_5CV.raw" + CACHE FILEPATH "Path to a Thermo FAIMS-DIA RAW file for integration testing" FORCE) +endif() + +if (THERMO_FAIMS_DIA_TEST_DATA AND NOT EXISTS "${THERMO_FAIMS_DIA_TEST_DATA}") + message(FATAL_ERROR + "THERMO_FAIMS_DIA_TEST_DATA does not exist: ${THERMO_FAIMS_DIA_TEST_DATA}") +endif() + +if ((ENABLE_THERMO_FAIMS_DIA_TESTS OR THERMO_FAIMS_DIA_TEST_DATA) AND NOT WITH_THERMO_RAW) + message(WARNING + "Thermo FAIMS-DIA integration testing was requested but WITH_THERMO_RAW=OFF; the test will not run.") +endif() + +# Optional end-to-end FAIMS-DDA integration fixture: a 2 h LC-MS/MS DDA run of E. coli lysate on an +# Orbitrap Exploris 480 with FAIMS, stepping through three compensation voltages (-45, -55 and -65 V), +# as mzML (converted from AWulf_060919_Ecoli_UV_S30_FAIMS_45_55_65.raw). A developer can either set +# FAIMS_DDA_TEST_DATA explicitly to a local copy, or enable ENABLE_FAIMS_DDA_TESTS to fetch the pinned +# file. The ~1.1 GB download is opt-in and not part of normal OpenMS builds/tests. +set(FAIMS_DDA_TEST_DATA "${FAIMS_DDA_TEST_DATA}" CACHE FILEPATH + "Path to a FAIMS-DDA mzML file (LC run with several compensation voltages) for integration testing") +if (ENABLE_FAIMS_DDA_TESTS AND NOT FAIMS_DDA_TEST_DATA) + include(FetchContent) + FetchContent_Declare( + faims_dda_testdata + URL "https://archive.openms.de/openms/testfiles/FAIMS/ExplorisFAIMS-DDA-LFQ.mzML" + URL_HASH SHA256=595cf179534200828bd379066690eb45cd6ca8b59c1e147eecfbcc422ce43d29 + DOWNLOAD_NO_EXTRACT TRUE + ) + FetchContent_MakeAvailable(faims_dda_testdata) + set(FAIMS_DDA_TEST_DATA + "${faims_dda_testdata_SOURCE_DIR}/ExplorisFAIMS-DDA-LFQ.mzML" + CACHE FILEPATH "Path to a FAIMS-DDA mzML file (LC run with several compensation voltages) for integration testing" FORCE) +endif() + +if (FAIMS_DDA_TEST_DATA AND NOT EXISTS "${FAIMS_DDA_TEST_DATA}") + message(FATAL_ERROR + "FAIMS_DDA_TEST_DATA does not exist: ${FAIMS_DDA_TEST_DATA}") +endif() + +#------------------------------------------------------------------------------ +# Extend module path with our modules +# (create an empty list if CMAKE_MODULE_PATH does not exist) +if(NOT CMAKE_MODULE_PATH) + set(CMAKE_MODULE_PATH) +endif() +list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/Modules") +## CMake looks for the NSIS script in the module path. +list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/Windows") + +#------------------------------------------------------------------------------ +# OpenMS Version Information +#------------------------------------------------------------------------------ + +set(OPENMS_PACKAGE_VERSION_MAJOR "3") +set(OPENMS_PACKAGE_VERSION_MINOR "7") +set(OPENMS_PACKAGE_VERSION_PATCH "0") +set(OPENMS_PACKAGE_VERSION "${OPENMS_PACKAGE_VERSION_MAJOR}.${OPENMS_PACKAGE_VERSION_MINOR}.${OPENMS_PACKAGE_VERSION_PATCH}") + +message(STATUS "Building OpenMS ${OPENMS_PACKAGE_VERSION}") +#------------------------------------------------------------------------------ +# retrieve detailed information on the working copy (git) +include(GetGitRevisionDescription) +option(GIT_TRACKING "Embedding of Git version control information into the OpenMS library (and OpenMSInfo tool). Note that if activated, every branch-switch or commit will trigger re-generation of the build system (MakeFiles, VS Solutions etc)." ON) +if (GIT_TRACKING) + ## A source tree made by git archive (the Release workflow's source tarball, GitHub's source + ## archives) has no .git of its own, but carries its commit in .git_archival.txt. That takes + ## precedence: a .git further up the tree would belong to another repository. + git_archival_info("${CMAKE_CURRENT_SOURCE_DIR}/.git_archival.txt" + _openms_archival_describe OPENMS_GIT_SHORT_SHA1 OPENMS_GIT_LC_DATE OPENMS_GIT_ARCHIVAL_FOUND) + if(OPENMS_GIT_ARCHIVAL_FOUND) + ## The archive of the tag v of this version carries the plain version below; any + ## other archive is marked as exported, as before. + if(_openms_archival_describe STREQUAL "v${OPENMS_PACKAGE_VERSION}") + set(OPENMS_GIT_SHORT_REFSPEC "${_openms_archival_describe}") + else() + set(OPENMS_GIT_SHORT_REFSPEC "exported") + endif() + set(OPENMS_GIT_INFO_FOUND TRUE) + else() + ## will configure an include file + git_short_info(OPENMS_GIT_SHORT_REFSPEC OPENMS_GIT_SHORT_SHA1 OPENMS_GIT_LC_DATE OPENMS_GIT_INFO_FOUND) + ## The Release workflow builds a release from its tag, a detached checkout whose refspec is "HEAD". + ## If HEAD is the tag v of this version, use the tag as refspec, so that the packages + ## carry the plain version below instead of -pre-HEAD-. + if(OPENMS_GIT_INFO_FOUND AND OPENMS_GIT_SHORT_REFSPEC STREQUAL "HEAD") + git_get_exact_tag(_openms_release_tag --tags --match "v${OPENMS_PACKAGE_VERSION}") + if(_openms_release_tag STREQUAL "v${OPENMS_PACKAGE_VERSION}") + set(OPENMS_GIT_SHORT_REFSPEC "${_openms_release_tag}") + endif() + endif() + endif() +endif() + +if(NOT GIT_TRACKING) + ## allow overwriting of the following variables in case we build release versions + ## from a source package (e.g. on bioconda) + if(NOT DEFINED OPENMS_GIT_SHORT_SHA1) + set(OPENMS_GIT_SHORT_SHA1 "disabled") + endif() + if(NOT DEFINED OPENMS_GIT_SHORT_REFSPEC) + set(OPENMS_GIT_SHORT_REFSPEC "disabled") + endif() + if(NOT DEFINED OPENMS_GIT_LC_DATE) + set(OPENMS_GIT_LC_DATE "1970-01-01") + endif() + message(STATUS " [CMake is not tracking Git commits and branching ('-D GIT_TRACKING=Off')]") +elseif(NOT OPENMS_GIT_INFO_FOUND) + ## Covers a git that runs but fails, e.g. a container refusing a bind-mounted checkout; + ## its marker would otherwise reach VersionInfo and the package file names. + set(OPENMS_GIT_SHORT_SHA1 "exported") + set(OPENMS_GIT_SHORT_REFSPEC "exported") + set(OPENMS_GIT_LC_DATE "1970-01-01") + message(STATUS " [CMake cannot track Git commits and branching, since Git information could not be determined. ('-D GIT_TRACKING=On')]") +else() + # everything found, print some status information + message(STATUS " - Repository revision ${OPENMS_GIT_SHORT_SHA1}") + message(STATUS " - Repository branch ${OPENMS_GIT_SHORT_REFSPEC}") + message(STATUS " - Repository last change date ${OPENMS_GIT_LC_DATE}") + if(OPENMS_GIT_ARCHIVAL_FOUND) + message(STATUS " [Git information from .git_archival.txt, filled in by git archive ('-D GIT_TRACKING=On')]") + else() + message(STATUS " [CMake is tracking Git commits and branching ('-D GIT_TRACKING=On')]") + endif() +endif() + +# Additional versioning information for packaging +# If it is not built from a release branch (or master) it will add the branch name +# and the last change date to everything that can handle strings in the version (e.g. installer filenames) +if(OPENMS_GIT_SHORT_REFSPEC MATCHES "disabled" OR OPENMS_GIT_SHORT_REFSPEC MATCHES "exported") + string(TIMESTAMP DATE "%Y%m%d") + set(OPENMS_PACKAGE_VERSION_PRERELEASE_IDENTIFIER "${OPENMS_GIT_SHORT_REFSPEC}-${DATE}") + set(OPENMS_PACKAGE_VERSION_FULLSTRING "${OPENMS_PACKAGE_VERSION}-pre-${OPENMS_PACKAGE_VERSION_PRERELEASE_IDENTIFIER}") +elseif(OPENMS_GIT_SHORT_REFSPEC MATCHES "release*" OR OPENMS_GIT_SHORT_REFSPEC MATCHES "master" + OR OPENMS_GIT_SHORT_REFSPEC STREQUAL "v${OPENMS_PACKAGE_VERSION}") + set(OPENMS_PACKAGE_VERSION_PRERELEASE_IDENTIFIER "") + set(OPENMS_PACKAGE_VERSION_FULLSTRING "${OPENMS_PACKAGE_VERSION}") +else() + string(REPLACE "/" "-" OPENMS_GIT_SHORT_REFSPEC_REPLACED ${OPENMS_GIT_SHORT_REFSPEC}) + string(REPLACE "_" "-" OPENMS_GIT_SHORT_REFSPEC_REPLACED_AGAIN ${OPENMS_GIT_SHORT_REFSPEC_REPLACED}) + set(OPENMS_GIT_LC_DATE_LIST "${OPENMS_GIT_LC_DATE}") + separate_arguments(OPENMS_GIT_LC_DATE_LIST) + list(GET OPENMS_GIT_LC_DATE_LIST 0 OPENMS_GIT_LC_DATE_ONLY) + set(OPENMS_PACKAGE_VERSION_PRERELEASE_IDENTIFIER "${OPENMS_GIT_SHORT_REFSPEC_REPLACED_AGAIN}-${OPENMS_GIT_LC_DATE_ONLY}") + set(OPENMS_PACKAGE_VERSION_FULLSTRING "${OPENMS_PACKAGE_VERSION}-pre-${OPENMS_PACKAGE_VERSION_PRERELEASE_IDENTIFIER}") +endif() + + + +#------------------------------------------------------------------------------ +# Unsupported systems +#------------------------------------------------------------------------------ +if (MINGW OR MSYS) + message(FATAL_ERROR "MSYS and/or MinGW are not supported! Please use a Visual Studio environment! See Windows build instructions for further information!") +endif() + +#------------------------------------------------------------------------------ +# Setup CMAKE_PREFIX_PATH for finding external libs (vcpkg or system) +#------------------------------------------------------------------------------ +if(OPENMS_USE_VCPKG) + message(STATUS "Dependency provider: vcpkg (${CMAKE_TOOLCHAIN_FILE})") +else() + message(STATUS "Dependency provider: system packages and CMAKE_PREFIX_PATH " + "(the CMake presets, see 'cmake --list-presets', build the dependency set CI tests with vcpkg)") +endif() +include(cmake/setup_lib_find_paths.cmake) + +#------------------------------------------------------------------------------ +# All the multi-threading stuff (OpenMP) +#------------------------------------------------------------------------------ +include(cmake/multithreading.cmake) + +#------------------------------------------------------------------------------ +# Check architecture 32bit vs. 64bit +#------------------------------------------------------------------------------ + +if (CMAKE_SIZEOF_VOID_P MATCHES "8") + set(OPENMS_64BIT_ARCHITECTURE 1 CACHE INTERNAL "Architecture-bits") + message(STATUS "Architecture: 64 bit") +else() + set(OPENMS_64BIT_ARCHITECTURE 0 CACHE INTERNAL "Architecture-bits") + message(STATUS "Architecture: 32 bit") +endif() + +# Force build type into the cache (needs to be set beforehand) +set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." FORCE) + +#------------------------------------------------------------------------------ +# Minimum supported compiler versions (single source of truth; also feeds the +# version numbers quoted in the doxygen install documentation) +#------------------------------------------------------------------------------ +include(cmake/min_compiler_versions.cmake) + +#------------------------------------------------------------------------------ +# Project specific compiler flags +#------------------------------------------------------------------------------ +# Compiler flags of the OpenMS build itself. Whatever a consumer of the installed +# package needs to compile against OpenMS is a usage requirement of the library +# targets (target_compile_features/definitions/options with PUBLIC or INTERFACE +# scope), which the exported targets in OpenMSTargets.cmake carry; +# OpenMSConfig.cmake exports no flag variables. +include(cmake/compiler_flags.cmake) + +# Visibility settings +# (CMP0063, honouring visibility properties for all target types, is from CMake 3.3 +# and is therefore already NEW by default at our minimum -- no policy set needed.) +if (NOT CMAKE_CXX_VISIBILITY_PRESET) + set(CMAKE_CXX_VISIBILITY_PRESET "hidden") +endif() +if (CMAKE_VISIBILITY_INLINES_HIDDEN) + set(CMAKE_VISIBILITY_INLINES_HIDDEN 1) +endif() + +#------------------------------------------------------------------------------ +# Enable STL debug mode (GCC only) +#------------------------------------------------------------------------------ +option(STL_DEBUG "[GCC only] Enable STL-DEBUG mode (very slow)." OFF) +if(STL_DEBUG) + include(cmake/stl_debug.cmake) +endif() + +#------------------------------------------------------------------------------ +# Add options for link time optimizations (LTO) aka interprocedural optimization +#------------------------------------------------------------------------------ +option(ENABLE_IPO + "Enable interprocedural optimizations (LTO)" OFF) +if(ENABLE_IPO) + include(CheckIPOSupported) + check_ipo_supported(RESULT result OUTPUT output) + if(result) + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) + else() + message(SEND_ERROR "IPO/LTO is not supported: ${output}") + endif() +endif() + +#------------------------------------------------------------------------------ +# Enable clang compile time profiling +#------------------------------------------------------------------------------ +option(CLANG_TIME_TRACE "[Clang 9+ only] Enable clang compile time profiling." OFF) +if(CLANG_TIME_TRACE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftime-trace") +endif() + + +#------------------------------------------------------------------------------ +# Enable Coverage +#------------------------------------------------------------------------------ +option(OPENMS_COVERAGE "[Clang/GCC only] Enable Coverage testing with gcov/lcov. Requires the Debug build type, + is slower and uses a lot of disk space (>40GB). Enables the target OpenMS_coverage to generate + a coverage report in html format." OFF) +if(OPENMS_COVERAGE) + include(cmake/Coverage.cmake) +endif() + +#------------------------------------------------------------------------------ +# Enable usage statistics +#------------------------------------------------------------------------------ +option(ENABLE_UPDATE_CHECK "Enable update check." ON) +if(ENABLE_UPDATE_CHECK) + message(STATUS "Collection of usage statistics and update notifications enabled.") + message(STATUS " If you don't want this information to be transmitted to our update sever, you can:") + message(STATUS " - Switch the build variable ENABLE_UPDATE_CHECK to OFF to remove the functionality at build time.") + message(STATUS " - Set the environment variable OPENMS_DISABLE_UPDATE_CHECK to disable the functionality at runtime.") +endif() + + +#------------------------------------------------------------------------------ +# Enable AddressSanitizer +#------------------------------------------------------------------------------ +option(ADDRESS_SANITIZER "Enable AddressSanitizer mode (quite slow)." OFF) +include(${PROJECT_SOURCE_DIR}/cmake/AddressSanitizer.cmake) + +#------------------------------------------------------------------------------ +# we build shared libraries +set(BUILD_SHARED_LIBS true) + +#------------------------------------------------------------------------------ +# Host directory for referencing from subprojects +set(OPENMS_HOST_DIRECTORY "${PROJECT_SOURCE_DIR}") +set(OPENMS_HOST_BINARY_DIRECTORY "${PROJECT_BINARY_DIR}") + +# The additional / is important to remove the last character from the path. +# Note that it does not matter if the OS uses / or \, because we are only +# saving the path size. +string(LENGTH "${PROJECT_SOURCE_DIR}/" CF_SOURCE_PATH_SIZE) +string(LENGTH "${PROJECT_BINARY_DIR}/" BINARY_PATH_SIZE) +# Since the path's length is used to cut away a path, and OPENMS_FILENAME might be used in configured files in the build tree +# , taking the convervative approach here, to make sure we do not cut away too much, no matter if origin is source or build tree +if (BINARY_PATH_SIZE LESS CF_SOURCE_PATH_SIZE) + set(CF_SOURCE_PATH_SIZE ${BINARY_PATH_SIZE}) +endif() + +#------------------------------------------------------------------------------ +# CMake Utitlities +#------------------------------------------------------------------------------ +# include some OpenMS specific macros +include (${PROJECT_SOURCE_DIR}/cmake/build_system_macros.cmake) +# .. and some to ease the installation process +include (${PROJECT_SOURCE_DIR}/cmake/install_macros.cmake) +# .. and some to ease preparing the documentation builds +include (${PROJECT_SOURCE_DIR}/cmake/doc_macros.cmake) +# .. and some to ease the installation process +include (${PROJECT_SOURCE_DIR}/cmake/add_library_macros.cmake) +# .. and some to ease the export process +include (${PROJECT_SOURCE_DIR}/cmake/export_macros.cmake) + + +#------------------------------------------------------------------------------ +# Initialize package building environment +set(VALID_PACKAGE_TYPES "none" # the classical build type make/make install + "rpm" # rpm package + "deb" # deb package + "dmg" # a drag&drop dmg package for macOS + "pkg" # a productbuild installer for macOS + "nsis" # an NSIS installer for Windows + "zip") # a portable version for Windows + +set(PACKAGE_TYPE "none" CACHE STRING "Package type (internal): ${VALID_PACKAGE_TYPES}") +message(STATUS "Package type is '${PACKAGE_TYPE}'") +is_valid_package(${PACKAGE_TYPE}) + +## The install component of the GUI applications (TOPPView, TOPPAS, ..., and the TOPP tools +## that need the GUI library, ExecutePipeline and ImageCreator), separate from the TOPP tools +## (component Applications) so the two can be installed and packaged independently (see +## OPENMS_USE_INSTALLED_LIBRARY). The macOS productbuild installer keeps them in +## Applications: it stages every component in a prefix of its own, and fixing up and +## signing bin/ (cmake/package_mac_productbuild.cmake) addresses the staging prefix of +## Applications. +if("${PACKAGE_TYPE}" STREQUAL "pkg") + set(OPENMS_GUI_APPLICATIONS_COMPONENT Applications) +else() + set(OPENMS_GUI_APPLICATIONS_COMPONENT GUIApplications) +endif() + +## macOS code signing and notarization configuration +## Required for code signing: +## SIGNING_IDENTITY - Developer ID Application certificate identity (e.g., "Developer ID Application: Your Name (TEAMID)") +## Required for notarization (in addition to signing): +## SIGNING_EMAIL - Apple ID email for notarization +## CPACK_PRODUCTBUILD_IDENTITY_NAME - Developer ID Installer certificate identity (for .pkg) +## APPLE_APP_SPECIFIC_NOTARIZATION_PASSWORD environment variable - App-specific password for notarization +if("${PACKAGE_TYPE}" STREQUAL "dmg" OR "${PACKAGE_TYPE}" STREQUAL "pkg") + if (NOT DEFINED SIGNING_IDENTITY OR "${SIGNING_IDENTITY}" STREQUAL "" OR "${SIGNING_IDENTITY}" STREQUAL "-") + message(WARNING "Trying to create macOS package/image without SIGNING_IDENTITY being set. " + "Using ad hoc (https://developer.apple.com/documentation/security/seccodesignatureflags/adhoc) identity. " + "The package will NOT be notarized and users may have trouble running it.") + set(CPACK_BUNDLE_APPLE_CERT_APP "-") + else() + ## CPack has a special variable for the identity + set(CPACK_BUNDLE_APPLE_CERT_APP "${SIGNING_IDENTITY}") + message(STATUS "Code signing identity: ${SIGNING_IDENTITY}") + endif() + + ## Check notarization prerequisites (optional, only warns) + if (NOT DEFINED SIGNING_EMAIL OR "${SIGNING_EMAIL}" STREQUAL "") + message(STATUS "SIGNING_EMAIL not set. Notarization will be skipped.") + endif() +endif() + +#------------------------------------------------------------------------------ +# Output directories +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${OPENMS_HOST_BINARY_DIRECTORY}/lib") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${OPENMS_HOST_BINARY_DIRECTORY}/bin") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${OPENMS_HOST_BINARY_DIRECTORY}/lib") +# Some alternative variable names for internal use +set(OPENMS_BINARY_DIR "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") +set(OPENMS_SHARE_DIR "${PROJECT_SOURCE_DIR}/share/OpenMS") +set(OPENMS_WIN32_DLL_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") + +#------------------------------------------------------------------------------ +# The TOPP tool registry is generated (cmake/topp_tool_macros.cmake) rather than checked in, +# so it lives in the build tree, not in the source share/ directory. It is installed into +# the share component like the rest of share/OpenMS; a build tree that was never installed +# is what OPENMS_BUILD_TOOL_REGISTRY_PATH in config.h points ToolHandler at. +include(${PROJECT_SOURCE_DIR}/cmake/topp_tool_macros.cmake) +set(OPENMS_TOOL_REGISTRY_BUILD_DIR "${OPENMS_HOST_BINARY_DIRECTORY}/share/OpenMS/TOOLS") +set(OPENMS_TOOL_REGISTRY_BUILD_FILE "${OPENMS_TOOL_REGISTRY_BUILD_DIR}/OpenMS.tsv") + +#------------------------------------------------------------------------------ +# define installation subdirectories to allow for custom installations +# note that all those directories are below CMAKE_INSTALL_PREFIX +set(INSTALL_BIN_DIR bin CACHE PATH "Installation directory for executables") +set(INSTALL_SHARE_DIR share/OpenMS CACHE PATH "Installation directory for shared data") +set(INSTALL_DOC_DIR share/doc CACHE PATH "Installation directory for documentation") +set(INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files") + +if(WIN32) + set(DEF_INSTALL_CMAKE_DIR CMake) + set(DEF_INSTALL_LIB_DIR bin) +else() + set(DEF_INSTALL_CMAKE_DIR lib/cmake/OpenMS) + set(DEF_INSTALL_LIB_DIR lib) +endif() + +set(INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files") +set(INSTALL_LIB_DIR ${DEF_INSTALL_LIB_DIR} CACHE PATH "Installation directory for libraries") +set(INSTALL_PLUGIN_SUBDIR plugins CACHE PATH "Installation subdirectory under the lib dir for QT plugins") +set(INSTALL_PLUGIN_DIR ${INSTALL_LIB_DIR}/${INSTALL_PLUGIN_SUBDIR}) +file(RELATIVE_PATH INSTALL_LIB_PATH_REL_TO_BIN /${INSTALL_BIN_DIR} /${INSTALL_LIB_DIR}) +set(QT_PLUGIN_PATH_REL_TO_BIN ${INSTALL_LIB_PATH_REL_TO_BIN}/${INSTALL_PLUGIN_SUBDIR}) + + +if(UNIX) + # use, i.e. don't skip the full RPATH for the build tree + if(NOT DEFINED CMAKE_SKIP_BUILD_RPATH) + SET(CMAKE_SKIP_BUILD_RPATH FALSE) + endif() + + if(NOT DEFINED CMAKE_MACOSX_RPATH) + SET(CMAKE_MACOSX_RPATH TRUE) # should be CMake default + endif() + + # usually when building, don't use the install RPATH already + # (but later on when installing) + if(NOT DEFINED CMAKE_BUILD_WITH_INSTALL_RPATH) + SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) + SET(CMAKE_BUILD_WITH_INSTALL_NAME_DIR FALSE) + endif() + + # Installed binaries must find the shared dependencies they were linked against + # (Homebrew, conda, ...) on their own: add the directories of those + # libraries to the install RPATH. Consumers of an installed libOpenMS then link + # and run without LD_LIBRARY_PATH; the linker also uses this RPATH to resolve + # the private dependencies of libOpenMS. System directories and directories + # below the build tree are never added by CMake (see the vcpkg case below). + # On macOS this also covers dependencies built with @rpath install names (e.g. + # Qt). Packages that relocate dependencies (deb, macOS pkg) skip or override it. + if (NOT DEFINED CMAKE_INSTALL_RPATH_USE_LINK_PATH) + if (APPLE) + if (NOT "${PACKAGE_TYPE}" STREQUAL "pkg") + SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) + endif() + elseif ("${PACKAGE_TYPE}" STREQUAL "none") + SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) + endif() + endif() + + #if(NOT DEFINED CMAKE_INSTALL_NAME_DIR AND APPLE) + # SET(CMAKE_INSTALL_NAME_DIR "$/${INSTALL_LIB_DIR}") + #endif() + + # our default RPATH to be added when installing. Can be changed per-target later, e.g. in app bundles + if(NOT DEFINED CMAKE_INSTALL_RPATH) + if (APPLE) + if(NOT "${PACKAGE_TYPE}" STREQUAL "pkg") + # currently our fix_dependencies.rb script used e.g. for dmg installer, + # requires our lib dir to be present in the RPATHS + # so it can find libOpenMS for one of our executables, even if it is linked as @rpath/libOpenMS. + # Disadvantage: even on the target machine, they will have the build folder baked in. + # Alternative: copy all our libs first so they do not need to be found. + # @loader_path lets an installed libOpenMS find its sibling libraries + # (OpenSwathAlgo, ...) when loaded by an executable outside the prefix. + SET(CMAKE_INSTALL_RPATH "@executable_path/${INSTALL_LIB_PATH_REL_TO_BIN}/;@loader_path/;${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") + else() + SET(CMAKE_INSTALL_RPATH "@executable_path/${INSTALL_LIB_PATH_REL_TO_BIN}/") + endif() + else() # linux and variants + SET(CMAKE_INSTALL_RPATH "$ORIGIN/${INSTALL_LIB_PATH_REL_TO_BIN}/") + endif() + endif() + + # vcpkg installs the dependencies below the build tree, and CMake deliberately + # keeps build-tree directories out of the install RPATH, so the link path above + # does not cover them. For plain (non-packaging) builds, reference the vcpkg + # library directory explicitly: an installation made from a vcpkg build tree + # then works as long as that tree exists, which is the situation of a developer + # or a consumer building against it. Packages copy the dependencies next to + # the libraries instead (see package_general.cmake) and must not carry a + # build-machine path in their RPATH. + # The Debug entry is a generator expression so that multi-config generators + # (Xcode, Ninja Multi-Config) get it for Debug installs as well. + if (OPENMS_USE_VCPKG AND VCPKG_INSTALLED_DIR AND VCPKG_TARGET_TRIPLET + AND "${PACKAGE_TYPE}" STREQUAL "none") + set(_vcpkg_triplet_dir "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}") + list(APPEND CMAKE_INSTALL_RPATH + "$<$:${_vcpkg_triplet_dir}/debug/lib>" + "${_vcpkg_triplet_dir}/lib") + unset(_vcpkg_triplet_dir) + endif() +endif() + +#------------------------------------------------------------------------------ +# lib naming when building with msvc & convenience location of build.bat +# TODO only for msvc or generally on Windows? +if (MSVC) + ## use OpenMSd.dll etc. in debug mode + if(NOT DEFINED CMAKE_DEBUG_POSTFIX) + set(CMAKE_DEBUG_POSTFIX "d") + endif() + if(NOT ("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}")) + file(COPY "${PROJECT_SOURCE_DIR}/tools/build.bat" DESTINATION "${PROJECT_BINARY_DIR}") + endif() +endif() + + +# Find core dependencies here, so all projects have access to the same variables and +# do not have to re-search for the core components + +## Defines openms_add_third_party_notice(), with which the code that installs third-party +## license files (the Thermo bridge in cmake_findExternalLibs.cmake among it) records them +## for share/OpenMS/THIRD-PARTY-NOTICES.txt. +include(cmake/third_party_notices.cmake) +if(OPENMS_USE_INSTALLED_LIBRARY) + include(cmake/find_installed_openms.cmake) +else() + include(cmake/cmake_findExternalLibs.cmake) +endif() + +#------------------------------------------------------------------------------ +# find the Doxygen (required by /doc and /src/OpenMS) +## 'dot' (Graphviz) is requested as an OPTIONAL component: it is only needed by the opt-in +## 'doc_dot' target (documentation with all dot graphs); the default documentation targets do +## not run dot (HAVE_DOT = NO in doc/doxygen/Doxyfile.in). Provides the Doxygen::doxygen / +## Doxygen::dot imported targets and the modern Doxygen_FOUND, Doxygen_VERSION, +## Doxygen_dot_FOUND result variables. +if(NOT OPENMS_USE_INSTALLED_LIBRARY) + find_package(Doxygen OPTIONAL_COMPONENTS dot) +endif() + +if(WITH_ONNX AND NOT OPENMS_USE_INSTALLED_LIBRARY) + # 1. Tell CMake to look for the package ONLY if the switch is ON. + if(OPENMS_USE_VCPKG) + find_package(onnxruntime CONFIG REQUIRED) + else() + find_package(ONNXRuntime REQUIRED) + endif() +endif() + + +## WITH_MIMALLOC (Windows, MSVC): the TOPP tools allocate through mimalloc; defines openms_link_mimalloc(). +include(cmake/mimalloc.cmake) + +#------------------------------------------------------------------------------ +# The actual OpenMS code (headers and source files) +#------------------------------------------------------------------------------ +add_subdirectory(src) + +#------------------------------------------------------------------------------ +# Documentation +#------------------------------------------------------------------------------ +if(NOT OPENMS_USE_INSTALLED_LIBRARY) + add_subdirectory(doc) +endif() + +#------------------------------------------------------------------------------ +# Thirdparty search engines (shipped with the installers) +#------------------------------------------------------------------------------ +set(SEARCH_ENGINES_DIRECTORY "" CACHE PATH "The location where thirdparty search engines (Comet, MSGF+, ...) are located. This directory should have the same structure as the search engine repository at https://github.com/OpenMS/THIRDPARTY after flattening for your platform.") + +#------------------------------------------------------------------------------ +# CWL generation (updates openms/share/commonwl/*.cwl files for all TOPP tools) +#------------------------------------------------------------------------------ +if (ENABLE_CWL_GENERATION) + include(${OPENMS_HOST_DIRECTORY}/cmake/cwl_generation.cmake) +endif() + +#------------------------------------------------------------------------------ +# Handle export of targets and install them +## A build against an installed OpenMS library does not provide a CMake package: the +## installation it builds on already does (OpenMSConfig.cmake), and a second one would +## collide with it where the layers are installed into one prefix. +if(NOT OPENMS_USE_INSTALLED_LIBRARY) + openms_export_targets() + install_export_targets() +endif() + +#------------------------------------------------------------------------------ +# Installation and packaging: +#------------------------------------------------------------------------------ + +## Defines openms_install_third_party_licenses(), which package_general.cmake calls, and +## openms_install_vendored_licenses() and openms_install_vcpkg_licenses(), which every +## installation needs, the pyOpenMS wheels among them. +include(cmake/third_party_licenses.cmake) +## The libraries' licenses and THIRD-PARTY-NOTICES.txt come with the installation that a +## build against an installed OpenMS library builds on. +if(NOT OPENMS_USE_INSTALLED_LIBRARY) + openms_install_vendored_licenses() + openms_install_vcpkg_licenses() +endif() + +if(NOT "${PACKAGE_TYPE}" STREQUAL "none") + + # packaging routines: + include(cmake/package_general.cmake) + if("${PACKAGE_TYPE}" STREQUAL "dmg") # .. macOS dmg + set(CPACK_GENERATOR "DragNDrop") + include(cmake/package_dragndrop_dmg.cmake) + elseif("${PACKAGE_TYPE}" STREQUAL "pkg") # .. macOS pkg + set(CPACK_GENERATOR "productbuild") + include(cmake/package_mac_productbuild.cmake) + elseif("${PACKAGE_TYPE}" STREQUAL "rpm") # .. rpms + set(CPACK_GENERATOR "RPM") + include(cmake/package_rpm.cmake) + elseif("${PACKAGE_TYPE}" STREQUAL "deb") # .. debs + set(CPACK_GENERATOR "DEB") + include(cmake/package_deb.cmake) + elseif("${PACKAGE_TYPE}" STREQUAL "nsis") # .. Windows nsis + # For now we use the old NSIS script AS IS + # i.e. although CMake runs make install etc. NSIS + # will use everything from the usual build folder like before. + # TODO automate more and let CMake generate install commands + # in the script. Unfortunately we have a lot of specific code in the script. + set(CPACK_GENERATOR "NSIS") + include(cmake/package_nsis.cmake) + elseif("${PACKAGE_TYPE}" STREQUAL "zip") + if(NOT WIN32) + message(FATAL_ERROR "The package type ZIP is only supported for windows.") + endif() + set(CPACK_GENERATOR "ZIP") + # For now we use the package nsis script to ensure all dependencies + # are met for the portable version. + # TODO refactor this to only execute the relevant processing steps + include(cmake/package_nsis.cmake) + endif() + include(CPack) + include(cmake/package_components.cmake) +endif() + +## share/OpenMS/THIRD-PARTY-NOTICES.txt, made from the license files recorded above. Last, so +## that it covers all of them. +if(NOT OPENMS_USE_INSTALLED_LIBRARY) + openms_install_third_party_notices() +endif() + +#------------------------------------------------------------------------------ +# Some final messages for the users +#------------------------------------------------------------------------------ +include(cmake/messages.cmake) + +message(STATUS "") +message(STATUS "-----------------------------------------------------------------") +message(STATUS "") +message(STATUS "You have successfully configured OpenMS.") +message(STATUS "") +if (MSVC) + message(STATUS "Execute the 'targets' project to see prominent targets!") + message(STATUS "For faster loading see the individual solution files located in") + message(STATUS "the src/ and doc/ folder and their subfolders") + message(STATUS " e.g., src/openms/OpenMS.sln") + message(STATUS "for the solution containing the OpenMS library.") +else() + message(STATUS "For a full list of make targets execute:") + message(STATUS "'make targets'") +endif() +message(STATUS "") +message(STATUS "-----------------------------------------------------------------") +message(STATUS "") diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 000000000..c3ec427aa --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,477 @@ +{ + "version": 3, + "configurePresets": [ + { + "name": "base", + "hidden": true, + "generator": "Ninja", + "binaryDir": "${sourceDir}/build/${presetName}", + "cacheVariables": { + "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", + "CMAKE_COLOR_DIAGNOSTICS": "ON", + "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/vcpkg/scripts/buildsystems/vcpkg.cmake", + "OPENMS_USE_VCPKG": "ON" + } + }, + { + "name": "linux-base", + "hidden": true, + "inherits": "base", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Linux" + } + }, + { + "name": "macos-base", + "hidden": true, + "inherits": "base", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Darwin" + } + }, + { + "name": "windows-base", + "hidden": true, + "inherits": "base", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + "name": "linux-x64-base", + "hidden": true, + "inherits": "linux-base", + "cacheVariables": { + "VCPKG_TARGET_TRIPLET": "x64-linux-dynamic" + } + }, + { + "name": "linux-arm64-base", + "hidden": true, + "inherits": "linux-base", + "cacheVariables": { + "VCPKG_TARGET_TRIPLET": "arm64-linux-dynamic" + } + }, + { + "name": "macos-arm64-base", + "hidden": true, + "inherits": "macos-base", + "description": "OpenMP_ROOT is where Homebrew on Apple silicon keeps its keg-only libomp (tools/ci/deps-macos.sh installs it). Apple's Clang ships no OpenMP runtime, so without it OpenMS falls back to -fopenmp-simd and runs single-threaded. Pass -DOpenMP_ROOT=$(brew --prefix libomp) for another Homebrew prefix.", + "cacheVariables": { + "VCPKG_TARGET_TRIPLET": "arm64-osx-dynamic-sysroot", + "OpenMP_ROOT": "/opt/homebrew/opt/libomp" + } + }, + { + "name": "windows-x64-base", + "hidden": true, + "inherits": "windows-base", + "description": "Windows x64 settings that do not depend on the build type. VCPKG_TARGET_TRIPLET is deliberately NOT set here: unlike Linux and macOS, whose triplets build every dependency in both debug and release form and so suit any configuration, the Windows triplets differ in exactly that respect, so each preset below has to name the one that matches its build type." + }, + { + "name": "debug-base", + "hidden": true, + "inherits": "base", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "release-base", + "hidden": true, + "inherits": "base", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "relwithdebinfo-base", + "hidden": true, + "inherits": "base", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "RelWithDebInfo" + } + }, + { + "name": "ci-base", + "hidden": true, + "cacheVariables": { + "OPENMS_TEST_INSTALLED_CONSUMER": "ON", + "MT_REQUIRE_OPENMP": "ON", + "WITH_GUI": "ON", + "ENABLE_DOCS": "ON", + "WITH_THERMO_RAW":"ON", + "ENABLE_THERMO_RAW_TESTS": "OFF", + "ENABLE_TUTORIALS": "OFF", + "WITH_ONNX": "ON", + "WITH_OPENTIMS":"ON", + "ENABLE_OPENTIMS_TESTS": "OFF", + "WITH_WNETALIGN": "OFF", + "USE_EXTERNAL_JSON": "ON", + "USE_EXTERNAL_SQLITECPP": "ON", + "USE_EXTERNAL_SIMDE": "ON", + "USE_EXTERNAL_ISOSPEC":"ON", + "USE_EXTERNAL_EOLBSPLINE":"ON", + "WITH_HDF5": "OFF", + "PYOPENMS":"OFF", + "VCPKG_MANIFEST_FEATURES":"isospec;eol-bspline;simde;nlohmann-json;sqlitecpp;openms-thermo-bridge;opentims;onnxruntime" + } + }, + { + "name": "linux-x64-debug", + "displayName": "Linux x64 Debug", + "description": "OpenMS with vcpkg dependencies on Linux x64 Debug", + "inherits": [ + "linux-x64-base", + "debug-base" + ] + }, + { + "name": "linux-x64-relwithdebinfo", + "displayName": "Linux x64 RelWithDebInfo", + "description": "OpenMS with vcpkg dependencies on Linux x64 RelWithDebInfo", + "inherits": [ + "linux-x64-base", + "relwithdebinfo-base" + ] + }, + { + "name": "linux-x64-release", + "displayName": "Linux x64 Release", + "description": "OpenMS with vcpkg dependencies on Linux x64 Release", + "inherits": [ + "linux-x64-base", + "release-base" + ] + }, + { + "name": "linux-arm64-debug", + "displayName": "Linux arm64 Debug", + "description": "OpenMS with vcpkg dependencies on Linux arm64 Debug", + "inherits": [ + "linux-arm64-base", + "debug-base" + ] + }, + { + "name": "linux-arm64-relwithdebinfo", + "displayName": "Linux arm64 RelWithDebInfo", + "description": "OpenMS with vcpkg dependencies on Linux arm64 RelWithDebInfo", + "inherits": [ + "linux-arm64-base", + "relwithdebinfo-base" + ] + }, + { + "name": "linux-arm64-release", + "displayName": "Linux arm64 Release", + "description": "OpenMS with vcpkg dependencies on Linux arm64 Release", + "inherits": [ + "linux-arm64-base", + "release-base" + ] + }, + { + "name": "macos-arm64-debug", + "displayName": "MacOS arm64 Debug", + "description": "OpenMS with vcpkg dependencies on MacOS arm64 Debug", + "inherits": [ + "macos-arm64-base", + "debug-base" + ] + }, + { + "name": "macos-arm64-relwithdebinfo", + "displayName": "MacOS arm64 RelWithDebInfo", + "description": "OpenMS with vcpkg dependencies on MacOS arm64 RelWithDebInfo", + "inherits": [ + "macos-arm64-base", + "relwithdebinfo-base" + ] + }, + { + "name": "macos-arm64-release", + "displayName": "MacOS arm64 Release", + "description": "OpenMS with vcpkg dependencies on MacOS arm64 Release", + "inherits": [ + "macos-arm64-base", + "release-base" + ] + }, + { + "name": "windows-x64-debug", + "displayName": "Windows x64 Debug", + "description": "OpenMS with vcpkg dependencies on Windows x64 Debug. A Debug build links the debug CRT (/MDd) and must not be mixed with release dependencies, so it uses x64-windows-static-md, which sets no VCPKG_BUILD_TYPE and therefore builds every dependency in both debug and release form. There is no working debug-only alternative: ports install their headers from the release half. The Debug build links the debug half, so this preset's first configure is slower than the other Windows presets. It is also the preset to use for a multi-configuration Visual Studio solution, being the only one whose dependencies cover both configurations.", + "inherits": [ + "windows-x64-base", + "debug-base" + ], + "cacheVariables": { + "VCPKG_TARGET_TRIPLET": "x64-windows-static-md" + } + }, + { + "name": "windows-x64-relwithdebinfo", + "displayName": "Windows x64 RelWithDebInfo", + "description": "OpenMS with vcpkg dependencies on Windows x64 RelWithDebInfo. RelWithDebInfo links the release CRT (/MD), so the release-only triplet is sufficient and avoids building every dependency twice.", + "inherits": [ + "windows-x64-base", + "relwithdebinfo-base" + ], + "cacheVariables": { + "VCPKG_TARGET_TRIPLET": "x64-windows-static-md-release" + } + }, + { + "name": "windows-x64-release", + "displayName": "Windows x64 Release", + "description": "OpenMS with vcpkg dependencies on Windows x64 Release. Release links the release CRT (/MD), so the release-only triplet is sufficient and avoids building every dependency twice.", + "inherits": [ + "windows-x64-base", + "release-base" + ], + "cacheVariables": { + "VCPKG_TARGET_TRIPLET": "x64-windows-static-md-release" + } + }, + { + "name": "linux-x64-ci", + "displayName": "Linux x64 CI", + "description": "OpenMS CI preset with vcpkg dependencies on Linux x64", + "inherits": [ + "linux-x64-base", + "release-base", + "ci-base" + ], + "cacheVariables": { + "OPENMS_VERIFY_INTERFACE_HEADER_SETS": "ON" + } + }, + { + "name": "linux-arm64-ci", + "displayName": "Linux arm64 CI", + "description": "OpenMS CI preset with vcpkg dependencies on Linux arm64", + "inherits": [ + "linux-arm64-base", + "release-base", + "ci-base" + ] + }, + { + "name": "macos-arm64-ci", + "displayName": "macOS arm64 CI", + "description": "OpenMS CI preset with vcpkg dependencies on macOS arm64", + "inherits": [ + "macos-arm64-base", + "release-base", + "ci-base" + ] + }, + { + "name": "windows-x64-ci", + "displayName": "Windows x64 CI", + "description": "OpenMS CI preset with vcpkg dependencies on Windows x64. Builds Release, so the release-only triplet is sufficient and avoids building every dependency twice.", + "inherits": [ + "windows-x64-base", + "release-base", + "ci-base" + ], + "cacheVariables": { + "VCPKG_TARGET_TRIPLET": "x64-windows-static-md-release" + } + }, + { + "name": "windows-x64-debug-ci", + "displayName": "Windows x64 Debug CI", + "description": "The CI preset for the Windows Debug SDK (.github/workflows/release.yml): the options of windows-x64-ci, built Debug, without what the SDK does not ship: no test programs (the job runs no tests, and building the class tests in Debug would take hours), no documentation and no GUI. A Debug build links the debug CRT (/MDd), so it uses the x64-windows-static-md triplet, which builds every dependency in both forms (see windows-x64-debug).", + "inherits": [ + "windows-x64-base", + "debug-base", + "ci-base" + ], + "cacheVariables": { + "VCPKG_TARGET_TRIPLET": "x64-windows-static-md", + "ENABLE_CLASS_TESTING": "OFF", + "ENABLE_TOPP_TESTING": "OFF", + "ENABLE_DOCS": "OFF", + "WITH_GUI": "OFF" + } + } + ], + "buildPresets": [ + { + "name": "linux-x64-debug", + "configurePreset": "linux-x64-debug" + }, + { + "name": "linux-x64-release", + "configurePreset": "linux-x64-release" + }, + { + "name": "linux-x64-relwithdebinfo", + "configurePreset": "linux-x64-relwithdebinfo" + }, + { + "name": "linux-arm64-debug", + "configurePreset": "linux-arm64-debug" + }, + { + "name": "linux-arm64-release", + "configurePreset": "linux-arm64-release" + }, + { + "name": "linux-arm64-relwithdebinfo", + "configurePreset": "linux-arm64-relwithdebinfo" + }, + { + "name": "macos-arm64-debug", + "configurePreset": "macos-arm64-debug" + }, + { + "name": "macos-arm64-release", + "configurePreset": "macos-arm64-release" + }, + { + "name": "macos-arm64-relwithdebinfo", + "configurePreset": "macos-arm64-relwithdebinfo" + }, + { + "name": "windows-x64-debug", + "configurePreset": "windows-x64-debug" + }, + { + "name": "windows-x64-release", + "configurePreset": "windows-x64-release" + }, + { + "name": "windows-x64-relwithdebinfo", + "configurePreset": "windows-x64-relwithdebinfo" + }, + { + "name": "linux-x64-ci", + "configurePreset": "linux-x64-ci" + }, + { + "name": "linux-arm64-ci", + "configurePreset": "linux-arm64-ci" + }, + { + "name": "macos-arm64-ci", + "configurePreset": "macos-arm64-ci" + }, + { + "name": "windows-x64-ci", + "configurePreset": "windows-x64-ci" + }, + { + "name": "windows-x64-debug-ci", + "configurePreset": "windows-x64-debug-ci" + } + ], + "testPresets": [ + { + "name": "test-base", + "hidden": true, + "output": { + "outputOnFailure": true + }, + "execution": { + "noTestsAction": "error" + } + }, + { + "name": "test-base-ci", + "hidden": true, + "execution": { + "jobs": 4 + } + }, + { + "name": "linux-x64-debug", + "configurePreset": "linux-x64-debug", + "inherits": "test-base" + }, + { + "name": "linux-x64-release", + "configurePreset": "linux-x64-release", + "inherits": "test-base" + }, + { + "name": "linux-x64-relwithdebinfo", + "configurePreset": "linux-x64-relwithdebinfo", + "inherits": "test-base" + }, + { + "name": "linux-arm64-debug", + "configurePreset": "linux-arm64-debug", + "inherits": "test-base" + }, + { + "name": "linux-arm64-release", + "configurePreset": "linux-arm64-release", + "inherits": "test-base" + }, + { + "name": "linux-arm64-relwithdebinfo", + "configurePreset": "linux-arm64-relwithdebinfo", + "inherits": "test-base" + }, + { + "name": "macos-arm64-debug", + "configurePreset": "macos-arm64-debug", + "inherits": "test-base" + }, + { + "name": "macos-arm64-release", + "configurePreset": "macos-arm64-release", + "inherits": "test-base" + }, + { + "name": "macos-arm64-relwithdebinfo", + "configurePreset": "macos-arm64-relwithdebinfo", + "inherits": "test-base" + }, + { + "name": "windows-x64-debug", + "configurePreset": "windows-x64-debug", + "inherits": "test-base" + }, + { + "name": "windows-x64-release", + "configurePreset": "windows-x64-release", + "inherits": "test-base" + }, + { + "name": "windows-x64-relwithdebinfo", + "configurePreset": "windows-x64-relwithdebinfo", + "inherits": "test-base" + }, + { + "name": "linux-x64-ci", + "configurePreset": "linux-x64-ci", + "inherits": ["test-base","test-base-ci"] + }, + { + "name": "linux-arm64-ci", + "configurePreset": "linux-arm64-ci", + "inherits": ["test-base","test-base-ci"] + }, + { + "name": "macos-arm64-ci", + "configurePreset": "macos-arm64-ci", + "inherits": ["test-base","test-base-ci"] + }, + { + "name": "windows-x64-ci", + "configurePreset": "windows-x64-ci", + "inherits": ["test-base","test-base-ci"] + } + ] +} diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..f65bfef1f --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,73 @@ +### OpenMS Code of Conduct + +#### Code of Conduct (Summary View) + +Below is a summary of the OpenMS Code of Conduct. + +We are dedicated to providing a welcoming and supportive environment for all people, regardless of background or identity. By participating in this community, participants accept to abide by OpenMS' Code of Conduct and accept the procedures by which any Code of Conduct incidents are resolved. Any form of behaviour to exclude, intimidate, or cause discomfort is a violation of the Code of Conduct. In order to foster a positive and professional learning environment we encourage the following kinds of behaviours in all platforms and events: + +* Use welcoming and inclusive language +* Be respectful of different viewpoints and experiences +* Gracefully accept constructive criticism +* Focus on what is best for the community +* Show courtesy and respect towards other community members + +If you believe someone is violating the Code of Conduct, we ask that you report it to the Code of Conduct Committee, who will take the appropriate action to address the situation. + +#### Code of Conduct (Detailed View) + +Part 1. Introduction + +OpenMS is a community-led project. We value the involvement of everyone in the community. We are committed to creating a friendly and respectful place for learning, teaching and contributing. All participants in our events and communications are expected to show respect and courtesy to others. + +To make clear what is expected, everyone participating in OpenMS activities is required to conform to the Code of Conduct. This Code of Conduct applies to all spaces managed by OpenMS including, but not limited to, workshops, email lists, and online forums such as GitHub, Slack and Twitter. Workshop hosts are expected to assist with the enforcement of the Code of Conduct. + +The OpenMS Code of Conduct Committee is responsible for enforcing the Code of Conduct. It can be contacted by emailing [open-ms-c_o_c@lists.sourceforge.net](mailto:open-ms-c_o_c@lists.sourceforge.net). +All reports will be reviewed by the Code of Conduct Committee and will be kept confidential. + +Part 2. OpenMS Code of Conduct + +OpenMS is dedicated to providing a welcoming and supportive environment for all people, regardless of background or identity. As such, we do not tolerate behaviour that is disrespectful to our teachers or learners or that excludes, intimidates, or causes discomfort to others. We do not tolerate discrimination or harassment based on characteristics that include, but are not limited to, gender identity and expression, sexual orientation, disability, physical appearance, body size, citizenship, nationality, ethnic or social origin, pregnancy, familial status, veteran status, genetic information, religion or belief (or lack thereof), membership of a national minority, property, age, education, socio-economic status, technical choices, and experience level. + +Everyone who participates in OpenMS activities is required to conform to this Code of Conduct. It applies to all spaces managed by OpenMS including, but not limited to, workshops, email lists, and online forums such as GitHub, Gitter and Twitter. Workshop hosts are expected to assist with the enforcement of the Code of Conduct. By participating, participants indicate their acceptance of the procedures by which OpenMS resolves any Code of Conduct incidents, which may include storage and processing of their personal information. + +Part 2.1 Expected behaviour + +All participants in our events and communications are expected to show respect and courtesy to others. All interactions should be professional regardless of platform: either online or in-person. In order to foster a positive and professional learning environment we encourage the following kinds of behaviours in all OpenMS events and platforms: + +* Use welcoming and inclusive language +* Be respectful of different viewpoints and experiences +* Gracefully accept constructive criticism +* Focus on what is best for the community +* Show courtesy and respect towards other community members + +Note: See the [four social rules](https://www.recurse.com/manual#sub-sec-social-rules) for further recommendations. + +Part 2.2 Unacceptable behaviour + +Examples of unacceptable behaviour by participants at any OpenMS event/platform include: + +- written or verbal comments which have the effect of excluding people on the basis of membership of any specific group +- causing someone to fear for their safety, such as through stalking, following, or intimidation +- violent threats or language directed against another person +- the display of sexual or violent images +- unwelcome sexual attention +- nonconsensual or unwelcome physical contact +- sustained disruption of talks, events or communications +- insults or put downs +- sexist, racist, homophobic, transphobic, ableist, or exclusionary jokes +- excessive swearing +- incitement to violence, suicide, or self-harm +- continuing to initiate interaction (including photography or recording) with someone after being asked to stop +- publication of private communication without consent + +Part 2.3 Consequences of Unacceptable behaviour + +Participants who are asked to stop any inappropriate behaviour are expected to comply immediately. This applies to any OpenMS events and platforms, either online or in-person. If a participant engages in behaviour that violates this code of conduct, the organisers may warn the offender, ask them to leave the event or platform (without refund), or engage OpenMS Code of Conduct Committee to investigate the Code of Conduct violation and impose appropriate sanctions. + +#### About this Document + +This document is adapted from guidelines written by the [The Carpentries Project](https://github.com/carpentries/handbook/blob/master/topic_folders/policies/code-of-conduct.md), which was itself based on the [Django Project](https://www.djangoproject.com/conduct/enforcement-manual/) and [Ada Initiative](http://geekfeminism.wikia.com/wiki/Conference_anti-harassment/Responding_to_reports) template and the [PyCon 2013 Procedure for Handling Harassment Incidents](https://us.pycon.org/2013/about/code-of-conduct/harassment-incidents/). + +[licensed CC BY 3.0](http://creativecommons.org/licenses/by/3.0/) + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..9bdff9009 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,50 @@ +Help us to make OpenMS better and become part of the OpenMS open-source community. + +This document is displayed because you either opened an issue or you want to provide your code as a pull request for inclusion into OpenMS. Please take a look at the appropriate section below to find some details on how we handle this process. +When interacting with other developers, users or anyone else from our community, please adhere to +[our CODE OF CONDUCT](https://github.com/OpenMS/OpenMS/blob/develop/CODE_OF_CONDUCT.md) + +> **New to open source or the project?** Start with our [Contributor Onboarding Guide](https://openms.de/contribute/) for a beginner-friendly introduction. + +# Reporting an Issue: + +You most likely came here to: + - report bugs or annoyances + - pose questions + - point out missing documentation + - request new features + +To do so, open a [new issue](https://github.com/OpenMS/OpenMS/issues/new/choose) describing the bug, your question, etc. + +If you found a bug, e.g. an OpenMS tool crashes during data processing, it is essential to provide some basic information: + - the OpenMS version you are running + - the platform you are running OpenMS on (Windows 10, ...) + - how you installed OpenMS (e.g., conda, binary installers, self compiled) + - a description on how to reproduce the bug + - relevant tool output (e.g., error messages) + - data to repoduce the bug (If possible as a GitHub gist. Other platforms like Dropbox, Google Drive links also work. If you can't share the data publicly please indicate this and we will contact you in private.) + +If you are an official OpenMS team member: + - label your issue using github labels (e.g. as: question, defect) that indicate the type of issue and which components of OpenMS (blue labels) are affected. The severity is usually assigned by OpenMS maintainers and used internally to e.g. indicate if a bug is a blocker for a new release. + +# Opening a Pull Request + +Before getting started we recommend taking a look at the developer guide: +https://openms.readthedocs.io/en/latest/manual/develop.html + +Before you open the pull request, make sure you + - adhere to [our coding conventions](https://openms.readthedocs.io/en/latest/manual/develop.html#coding-conventions) + - have [unit tests and functional tests](https://openms.readthedocs.io/en/latest/manual/develop.html#automated-unit-tests) - see also [this example](https://github.com/OpenMS/OpenMS/blob/develop/src/tests/class_tests/openms/source/MSNumpressCoder_test.cpp) + - have [proper documentation](https://openms.readthedocs.io/en/latest/manual/develop/developer-faq.html#doxygen-documentation) - see also [this example](https://github.com/OpenMS/OpenMS/blob/develop/src/openms/include/OpenMS/FORMAT/MSNumpressCoder.h) + - have Python bindings — nanobind binding files are in `src/pyOpenMS/bindings/`; see `src/pyOpenMS/CLAUDE.md` for wrapping instructions +A core developer will review your changes to the main development branch (develop) and approve them (or ask for modifications). You may indicate the prefered reviewer(s) by adding links to them in a comment section (e.g., @cbielow @hendrikweisser @hroest @jpfeuffer @timosachsenberg) + +Also consider getting in contact with the core developers early. They might provide additional guidance and valuable information on how your specific aim is achieved. This might give you a head start in, for example, developing novel tools or algorithms. + +Happy coding! + +--- + +## Additional Resources + +For detailed coding conventions, architectural guidelines, and technical documentation, see the [OpenMS Developer Guide](https://openms.readthedocs.io/en/latest/contribute-to-openms/index.html). diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..713de5ecd --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +-------------------------------------------------------------------------- + OpenMS -- Open-Source Mass Spectrometry +-------------------------------------------------------------------------- +Copyright OpenMS Inc. -- Eberhard Karls University Tuebingen, +ETH Zurich, and Freie Universitaet Berlin 2002-present. + +This software is released under a three-clause BSD license: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of any author or any participating institution + may be used to endorse or promote products derived from this software + without specific prior written permission. +For a full list of authors, refer to the file AUTHORS. +-------------------------------------------------------------------------- +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL ANY OF THE AUTHORS OR THE CONTRIBUTING +INSTITUTIONS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 000000000..ea46b8867 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2002-present, OpenMS Inc. -- Eberhard Karls University Tuebingen, ETH Zurich, and Freie Universitaet Berlin +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/License.txt b/License.txt new file mode 100644 index 000000000..56c21ba72 --- /dev/null +++ b/License.txt @@ -0,0 +1,52 @@ +----------------------------------------------------------------- + OpenMS -- Open-Source Mass Spectrometry +----------------------------------------------------------------- +Copyright OpenMS Inc. -- Eberhard Karls University Tuebingen, +ETH Zurich, and Freie Universitaet Berlin 2002-present. + +This software is released under a three-clause BSD license: + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + * Neither the name of any author or any participating + institution may be used to endorse or promote products + derived from this software without specific prior written + permission. +For a full list of authors, refer to the file AUTHORS. +----------------------------------------------------------------- +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL ANY OF THE AUTHORS OR THE +CONTRIBUTING INSTITUTIONS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + +The source code of OpenMS is available via our homepage +http://www.OpenMS.de + +Third-party software. The OpenMS installers and the pyOpenMS +wheels contain third-party software, each part under its own +license. THIRD-PARTY-NOTICES.txt in the share/OpenMS folder of +an installation (pyopenms/share/OpenMS in a pyOpenMS wheel) +lists that software and gives its license, copyright and +notice texts. The files themselves are in share/OpenMS/LICENSES +and in the tool folders under share/OpenMS/THIRDPARTY. + +The OpenMS source code contains third-party code too, each part +with its license file: the libraries in src/openms/extern and +src/openms/thirdparty, and the CMake modules +GetGitRevisionDescription and findCppCheck +(https://github.com/rpavlik/cmake-modules, Boost Software +License 1.0, http://www.boost.org/LICENSE_1_0.txt). diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..6eb4bf6d5 --- /dev/null +++ b/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,33 @@ +## Description + + + +## Checklist +- [ ] Make sure that you are listed in the AUTHORS file +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] New and existing unit tests pass locally with my changes +- [ ] Updated or added python bindings for changed or new classes (Tick if no updates were necessary.) + +No need to edit the CHANGELOG file: entries are generated automatically once per week from merged changes. + +### How can I get additional information on failed tests during CI +
+ Click to expand +If your PR is failing you can check out + +- The details of the action statuses at the end of the PR or the "Checks" tab. +- http://cdash.seqan.de/index.php?project=OpenMS and look for your PR. Use the "Show filters" capability on the top right to search for your PR number. + If you click in the column that lists the failed tests you will get detailed error messages. + +
+ +### Advanced commands (admins / reviewer only) +
+ Click to expand + +- `/reformat` (experimental) applies the clang-format style changes as additional commit. Note: your branch must have a different name (e.g., yourrepo:feature/XYZ) than the receiving branch (e.g., OpenMS:develop). Otherwise, reformat fails to push. + +
+ +--- +:warning: Note: Once you opened a PR try to minimize the number of *pushes* to it as every push will trigger CI (automated builds and test) and is rather heavy on our infrastructure (e.g., if several pushes per day are performed). diff --git a/cmake/AddressSanitizer.cmake b/cmake/AddressSanitizer.cmake new file mode 100644 index 000000000..73c5d4d20 --- /dev/null +++ b/cmake/AddressSanitizer.cmake @@ -0,0 +1,60 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Hannes Roest $ +# $Authors: Hannes Roest, Timo Sachsenberg $ +# -------------------------------------------------------------------------- + + +#------------------------------------------------------------------------------ +# This cmake file enables the AddressSanitizer and UndefinedBehaviorSanitizer +# see http://clang.llvm.org/docs/AddressSanitizer.html and https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html +# http://en.wikipedia.org/wiki/AddressSanitizer + +# Do the check for support in the beginning and NOT FOR EVERY TARGET +#------------------------------------------------------------------------------ +if(ADDRESS_SANITIZER) + if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + # add compiler flag + if (MSVC AND MSVC_VERSION LESS 1920) + message(FATAL_ERROR "AddressSanitizer is not supported for MSVC versions < 2019.") + endif() + else() + message(FATAL_ERROR "AddressSanitizer is supported for OpenMS debug mode only.") + endif() + message(STATUS "AddressSanitizer enabled. Adding flags to every target.") +endif() + + +function(add_asan_to_target TARGET_NAME_ARG) + if(ADDRESS_SANITIZER) + if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + # add compiler flag + if (MSVC) + # add AddressSanitizer for compiler and linker + target_compile_options("${TARGET_NAME_ARG}" + PUBLIC + /fsanitize=address + ) + target_link_options("${TARGET_NAME_ARG}" + PUBLIC + /fsanitize=address + ) + else() + # add AddressSanitizer for compiler and linker + target_compile_options("${TARGET_NAME_ARG}" + PUBLIC + -fsanitize=address,undefined + -fno-sanitize-recover=all + -fno-sanitize=vptr + -fno-omit-frame-pointer) + target_link_options("${TARGET_NAME_ARG}" + PUBLIC + -fsanitize=address,undefined + -fno-sanitize-recover=all + -fno-sanitize=vptr) + endif() + endif() + endif() +endfunction() diff --git a/cmake/Coverage.cmake b/cmake/Coverage.cmake new file mode 100644 index 000000000..1b8a94289 --- /dev/null +++ b/cmake/Coverage.cmake @@ -0,0 +1,30 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Julianus Pfeuffer $ +# $Authors: Julianus Pfeuffer $ +# -------------------------------------------------------------------------- + + +#------------------------------------------------------------------------------ +# This cmake file enables generation of gcov files. + +# add compiler flag +# -> requires clang > 3.1 or gcc > 4.8 (will be checked in module) +if (MSVC) + message(FATAL_ERROR "Coverage tests with gcov/lcov can only be enabled for GCC or Clang in a UNIX environment") +else() + # add Coverage also for compiler + add_compile_options( -fprofile-arcs -ftest-coverage ) + # add Coverage also for linker + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") + include(cmake/modules/CodeCoverage.cmake) + # in addition to system paths, also ignore includes from the prefix path (e.g. the dependency prefix) + setup_target_for_coverage(OpenMS_coverage coverage ${CMAKE_PREFIX_PATH}) + message("Coverage tests enabled. You can run 'make OpenMS_coverage'") +endif() + + diff --git a/cmake/MacOSX/DS_store b/cmake/MacOSX/DS_store new file mode 100644 index 0000000000000000000000000000000000000000..cab570c35ef3a0ab8b0bef3e850175c6f90e21fa GIT binary patch literal 12292 zcmeI0&u<$=6vy8r4z&{}apI(ewv<&P5QtzqZCbYmDXwcoEQnIYX`0Z4bnV^PtE_je z-E~X|1{Vqb1a4eGoH!wlRH#yWM*<`yBK`x8a0=hqUH`}r5JUp;V@8^J&ol46nfc6k z#$zI4nVK?9G(ki`WG*8ED2_?Io#!K|$FJ#wWbh}m0PV9vRo86ih_$E?1Ox#=KoAfF z1c8470o>U<1%Kn-_gY0M2nYiIO9K3SkdV1d`?Bdt_vk?3J^>&DsCEUOoDcfa2giEmg>Z=mn7Q^8Ou7+$-r8H!oYm^DMO@8rv7J+CQhLAKUi-I1M| zosliK<)-YE(cG^>-qQnv0pVjOw$sIz=qb(m* zzFwMpp0LA0(V-5CSk)-CZT`4&>br+i?|O}EIJ4EMchzcZAk+!Hr7MWBdgA|HU6|zLbbej4p zOB&g*kSIqLSeHnpQ92v%iXA^3J4(^`vZ>c9svYkPhiHshd|oIq%kVtkfR1UGrMWDx z?n)2#zTW|7VE$z>j15%PWk-!Em6K5JyFYjj>-MUmZd;0CZ+VC^#-8IZ2-aU!bEgRc9C2Pg9nreqj9UT7nZPZs|@6z4PY+E?5f{Ajf26z;55E=DLExwyq4sraWa{}X?!W!XoQgd z{AnDf>sTzlTpGSEe91H{j6rrzH;euy!+)jSL%xgLyT31|A;Yu)FBO*al&2SH8gP=x ziGzM@0k#F?!2bU0+)tzv66p2(CiwgRWqgsv{{SZhDcl5se=z|T$mX*dOrUjD9i9vS znI$3LMdpdyH9hINpx`FF-hGZk;@6g!pi5kXO#8CwNz@?y?SBM_`~R5Nn7IGl%_s^% hKoAfF1OY)n5D)|e0YN|z5CjAPK|l}?1pY$=eg%0+1A_nn literal 0 HcmV?d00001 diff --git a/cmake/MacOSX/DS_store_new b/cmake/MacOSX/DS_store_new new file mode 100644 index 0000000000000000000000000000000000000000..fad3d2d674bd9e91e0cf0f370062a04f53e876d2 GIT binary patch literal 10244 zcmeHMU5p!76+Yv5Q#-ra_5MLhqiV#aG>FNMRbX*Ofe*z2x6 z`2O_hMkEta0L(JfhsQR=@0qudPt*hht_8Xl=vts_fvyF*7WjX#0QPLAK(8yi&#nc!7U)`F-2$8+WH8H| zkZZ1VQU@N+6#&wYYKMSB3?OA8b3(4U5^q3~+ZEF7Dv2wGeS>=<8mnv;}sW%t>&K-U6WE#ThWBc;_=vsCZAzbndzl5dBF2)n`gbn8`PTQ|zUHo664`?W zH(BC3$`VCte@S(7?JOcJ=n{?jHyZ4h@G!LZhRf`~05!_dKu=8ZN2j zrK-jHPMdYp%GZ~5tgT&pu%TAu2m@?dxbe)NbpH@VKs> zYF8b7wz+XUr_EO_T{oQZ<|>tzZqIk%<0o72&Ouvm95gB>#$SQC=bCoSG+M`Ws|EQ~ zT`lSLIU{e{w%ItYT9#^5_58C7p#i6F*))z=I`^Be0kfWCkNw59+uY!ebBypr9v+@+ z>c-(>I39^bl<SkMAD%3iY5o(%)WDq-j*WCZ9x(V!Xe39sUU-+AVeh zuaN&~c?hG`BZ9p%GRq%g(tHU?IJXVBN8RjT3b5Iqp>m@c|`wqe>EJ!aOI z8+vOyRcS=}Bd;A#SfcMRhn8)&7UcsoT-`zMzw)aS@CEsp$a1(6$uHJsl z_rmHa8hHL=3MMS_RUg92p6*;&_K6mPI7`inzFev3R+g$YJ4?cmrR7>(!&~$?f)5j) zUX~W787_!2UboVByf{<^_ z1-Q?Jq~KA*H1yzD?zE^3(3j~kI)<2CqBZ(9y+uEupVBYrBl;8Fk#2h z*N{O1;>^awaYnvZbe~3>fADvXes|FCK9qej(Oofi4{+U^2l$-8gTR*r9s+(z;9=m4 z0?WX+1ZI_XFvdLV7)1~BvPQttP9hE51fLU<@z41kzQ33r(=%mdBArr_l~gIMrZTAs zUD1@-c&wC2PE_I(@rn|UPbz}80{2B+nJk-)h}vw{b$*6hs-cz4GZ9NyweYG{vvsd) zY*L9iozh;77(14ljIM~xVIoI2S|UelPL94;)?wGO-Fe-2k-bBZemoW-nRx=-z?h(YoYDYtOBcX)c`!pdM>eSo{aF5q@4oaJJ=WcBFc2B5vL0ln*01k;YO6KMFnqW>x)&($`Y}Ag}CgfnJ#-mB}lQx<$u}9KmZS zzXZMrz69oWys)YFu6~I($30+UN3xb^<5ICfsjRCMOOyuJ_JC z&Iy~#-bRD>o(^7;ch-)M@1h-N&>P^7z<0oXSmQo$5_|yc+3}$&3Sumd2`j-fwcmgI zyz4cu{i)R#oDN?3wcA%Wl+Bl~Z74T4m7m#EzWI*Z-qZaX=>01A4e-0*>);#U-+})M zW*vEMFV1-D_jKX!h{^NYZLFK$b;cI|JIQwKJO_CFk(VCM;{E#gmmkdWF~iXfeF~{$ zA)cC@3QxrFNTgzgaDKLs2^XeQv8h64YAQ26;lX8sgN@aANB?f^bIX-GIL*CcZxLZZHoUF!63M z!XFZ7^KOt6^*;H(ziTTP)64qO734@U*B~$mXOoqpWzic)MhK>ECUt_+`emwstBw;L>ccuay$6r{Nx)$hK;Im}`$v;z^$z#n<65D3& zoaJTkX)qJFTXUt;1rKK +source $OPENMS_TOPP_PATH/.TOPP_bash_profile +``` + +--- + +## macOS Code Signing and Notarization + +OpenMS packages for macOS are code signed and notarized to ensure users can run them without security warnings from Gatekeeper. + +### Prerequisites + +1. **Apple Developer Account** ($99/year) - https://developer.apple.com +2. **Xcode** installed with developer tools (`xcode-select --install`) +3. **Certificates** exported from Xcode: + - **Developer ID Application** - for signing binaries + - **Developer ID Installer** - for signing .pkg installers + +### Required GitHub Secrets + +For CI/CD, the following secrets must be configured in your GitHub repository. + +**Note:** Only certificates and passwords need to be secrets. Identity strings and email addresses are public information. + +| Secret | Description | +|--------|-------------| +| `APPLE_DEVELOPER_ID_APPLICATION_CERT` | Base64-encoded Developer ID Application .p12 certificate | +| `APPLE_DEVELOPER_ID_APPLICATION_PASSWORD` | Password for the Application certificate | +| `APPLE_DEVELOPER_ID_INSTALLER_CERT` | Base64-encoded Developer ID Installer .p12 certificate | +| `APPLE_DEVELOPER_ID_INSTALLER_PASSWORD` | Password for the Installer certificate | +| `APPLE_APP_SPECIFIC_NOTARIZATION_PASSWORD` | App-specific password for notarization | +| `KEYCHAIN_PASSWORD` | Password for the temporary CI keychain | + +The following are configured directly in the workflow (not secrets): +- **Signing Identity**: `Developer ID Application: OpenMS Inc. (C64UCGJ5PL)` +- **Installer Identity**: `Developer ID Installer: OpenMS Inc. (C64UCGJ5PL)` +- **Email**: `apple@openms.de` +- **Team ID**: `C64UCGJ5PL` (extracted from the identity string) + +### Exporting Certificates + +1. Open **Xcode → Settings → Accounts** +2. Select your Team and click **Manage Certificates** +3. Create or select **Developer ID Application** certificate +4. Right-click → **Export Certificate** → save as `.p12` with a password +5. Base64 encode for CI: `base64 -i certificate.p12 | pbcopy` +6. Repeat for **Developer ID Installer** certificate + +### Finding Your Identity Strings and Team ID + +Run this command to see your available signing identities: + +```shell +security find-identity -v -p codesigning +``` + +Output example: +``` +1) ABC123XYZ... "Developer ID Application: OpenMS Inc. (C64UCGJ5PL)" +2) DEF456ABC... "Developer ID Installer: OpenMS Inc. (C64UCGJ5PL)" + 2 valid identities found +``` + +- The full quoted string is your identity (e.g., `Developer ID Application: OpenMS Inc. (C64UCGJ5PL)`) +- The 10-character code in parentheses is your Team ID (e.g., `C64UCGJ5PL`) + +### Creating an App-Specific Password + +For notarization, create an app-specific password: + +1. Go to https://appleid.apple.com +2. Sign in → Security → App-Specific Passwords → Generate +3. Use this password for `APPLE_NOTARIZATION_PASSWORD` + +### Local Testing + +To test code signing locally: + +```shell +# Sign a binary +codesign --force --options runtime --timestamp -s "Developer ID Application: Your Name (TEAMID)" /path/to/binary + +# Verify signature +codesign -dv --verbose=4 /path/to/binary + +# Notarize a package (requires CODESIGNPW environment variable) +export CODESIGNPW="your-app-specific-password" +./cmake/MacOSX/notarize.sh package.pkg de.openms your@email.com CODESIGNPW . + +# Verify notarization +spctl -a -vvv -t install package.pkg +``` + +### Troubleshooting + +**"The specified item could not be found in the keychain"** +- Ensure the certificate is imported in the keychain +- Verify the identity string matches exactly (run `security find-identity -v`) + +**Notarization fails with "Invalid"** +- Check if all binaries inside the package are signed with hardened runtime +- Get detailed log: `xcrun notarytool log --apple-id EMAIL --password PW --team-id TEAM log.json` + +**"Developer cannot be verified" warning for users** +- The package was not notarized or stapling failed +- Users can override: System Settings → Privacy & Security → Allow + +### Files in this Directory + +- `notarize.sh` - Script for notarizing packages (.pkg, .dmg, .zip) using notarytool +- `sign_bins_and_libs.rb` - Ruby script to sign all binaries in a directory +- `fix_dependencies.rb` - Script to fix library paths for distribution diff --git a/cmake/MacOSX/TOPP-shell.command b/cmake/MacOSX/TOPP-shell.command new file mode 100755 index 000000000..f41d97a3a --- /dev/null +++ b/cmake/MacOSX/TOPP-shell.command @@ -0,0 +1,15 @@ +#!/bin/bash +clear +echo "" +echo "" +echo " ------------------------------------------------" +echo " Welcome to the OpenMS/TOPP command shell " +echo " ------------------------------------------------" +echo "" +echo "" + +export OPENMS_TOPP_PATH=`dirname "$0"` +# declare as TOPP_SHELL +export IS_TOPP_SHELL="TOPP-SHELL" +bash --rcfile ${OPENMS_TOPP_PATH}/.TOPP_bash_profile + diff --git a/cmake/MacOSX/TOPP_bash_profile b/cmake/MacOSX/TOPP_bash_profile new file mode 100644 index 000000000..2a016fd6e --- /dev/null +++ b/cmake/MacOSX/TOPP_bash_profile @@ -0,0 +1,37 @@ +## Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +## SPDX-License-Identifier: BSD-3-Clause +## + +## bashrc for the OpenMS/TOPP command shell ## + +# check if this is a TOPP-shell or if the user included this file +if [ -n "$IS_TOPP_SHELL" ]; then + ## we need the systems profile for the bash + source /etc/profile + ## also add user profile; if it exists + if [ -e ~/.profile ]; then + source ~/.profile + fi +fi + +if [ -z "${OPENMS_TOPP_PATH}" ]; then + echo "ERROR: You need to set \${OPENMS_TOPP_PATH} to the folder where OpenMS was installed. E.g." + echo "export OPENMS_TOPP_PATH=/Applications/OpenMS-1.10.0/" + echo "source \${OPENMS_TOPP_PATH}/.TOPP_bash_profile" +else + ## setting of the OpenMS data path to the share directory + export OPENMS_DATA_PATH=${OPENMS_TOPP_PATH}/share/OpenMS + + ## add TOPPView, TOPPAS, and INIFileEditor to PATH + export PATH=${OPENMS_TOPP_PATH}/TOPPView.app/Contents/MacOS/:${PATH} + export PATH=${OPENMS_TOPP_PATH}/INIFileEditor.app/Contents/MacOS/:${PATH} + export PATH=${OPENMS_TOPP_PATH}/TOPPAS.app/Contents/MacOS/:${PATH} + ## also the search engines + for folder in ${OPENMS_DATA_PATH}/THIRDPARTY/*/ ; do + export PATH=$folder:$PATH + done + ## and finally the bin folder + export PATH=${OPENMS_TOPP_PATH}/bin:${PATH} +fi + +## EOF diff --git a/cmake/MacOSX/background.odg b/cmake/MacOSX/background.odg new file mode 100644 index 0000000000000000000000000000000000000000..20d692d2e0485d2c4e43e4613308a7f49e867677 GIT binary patch literal 35089 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 HzqbA#@Tc(O literal 0 HcmV?d00001 diff --git a/cmake/MacOSX/background.png b/cmake/MacOSX/background.png new file mode 100644 index 0000000000000000000000000000000000000000..ced8cad8f9d6d6efd75b6bc0101111ea7f2aced7 GIT binary patch literal 46959 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 #{message}" + end +end + +############################################################################### +def fixable(name, path) + if File.directory?(path + name) + return false + elsif name.match(/^\./) + return false + elsif name.match(/\.app$/) + return false + else + filename = "#{path}/#{name}" + debug filename.to_s + otool_out=`otool -L #{filename}` + ## Otool returns exit code 0 even if it is not an object file -> check output + return !( otool_out =~ /.*object file.*/ ) + end +end + +############################################################################### +def isFramework(path) + return path.match(/\.framework/) +end + +############################################################################### +def cleanOtoolEntry(otool_line) + return `echo "#{otool_line}" | tr -d ' \t' | sed 's/(.*//g'`.strip +end + +############################################################################### +def extractInstallName(otool_output) + # Skip file basename + otool_output.delete_at(0).strip + # Save install name (id) + id = otool_output.delete_at(0).strip + # clean id + id = cleanOtoolEntry(id) + # return id and remaining otool output = dependencies + return id, otool_output +end + +##### METHODS USED TO HANDLE THE BUNDLING + +############################################################################### +def fixLoadPath(oldpath,libpath,target) + debug "#{$install_name_tool} -change #{oldpath} #{$executableId}#{libpath} #{target}" + `#{$install_name_tool} -change #{oldpath} #{$executableId}#{libpath} #{target}` +end + +############################################################################### +def fixId(target, libname) + debug "#{$install_name_tool} -id #{$executableId}#{libname} #{target}" + `#{$install_name_tool} -id #{$executableId}#{libname} #{target}` +end + +############################################################################### +def adjustRpaths(target, newpaths) + return if newpaths.nil? + # list existing rpaths + existing = %x[otool -l #{target} | grep -A2 LC_RPATH | grep path | sed -n "s/^.*path\\s*\\(.*\\)(offset.*\\$/\\1/p"].split(/\n/).map(&:strip) + existing.each do |rp| + next if rp.nil? or rp.empty? + debug "#{$install_name_tool} -delete_rpath #{rp} #{target}" + `#{$install_name_tool} -delete_rpath "#{rp}" "#{target}"` + end + + # add only the requested rpaths + newpaths.each do |rp| + next if rp.nil? or rp.empty? + debug "#{$install_name_tool} -add_rpath #{rp} #{target}" + `#{$install_name_tool} -add_rpath "#{rp}" "#{target}"` + end +end + + +############################################################################### +def handleDependencies(otool_out, targetPath, currentLib, rpaths) + rpath = %x[otool -l #{currentLib} | grep -A2 LC_RPATH | grep path | sed -n "s/^.*path\\s*\\(.*\\)(offset.*\$/\\1/p"] + rpaths += rpath.split(/\n/).map(&:strip) + + for index in 0 ... otool_out.size + fix_lib=cleanOtoolEntry(otool_out[index]) + + # (\/usr\/lib|\/System) + if fix_lib.match(/^(\/usr\/lib|\/System)/) + debug "Ignoring system-lib: #{fix_lib}" + elsif $nocopy + if isFramework(fix_lib) + # get framework path (name of dir containing .framework) + frameworkDir=fix_lib.to_s.gsub(/(.*\.framework).*/,'\1') + frameworkName=frameworkDir.to_s.gsub(/(.*\/)([^\/]*\.framework)/,'\2') + + # the actual lib name + internFrameworkDir=fix_lib.to_s.gsub(/(.*\.framework)\/(.*)/,'\2') + libname=frameworkName+'/'+internFrameworkDir + fixLoadPath(fix_lib, libname, currentLib) + else + fixLoadPath(fix_lib, File.basename(fix_lib), currentLib) + end + elsif fix_lib.start_with?("@loader") or fix_lib.start_with?("@executable") + if $EXTRACTFW + # only fix loading of this library if it does not start with executable/loader_path. + # It basically means it should be fixed already. If it was not we will not be able to + # find it anyway. + fixLoadPath(fix_lib, File.basename(fix_lib), currentLib) + else + debug "Ignoring libs that are referenced from a relative reference (#{fix_lib})" + if not fix_lib.start_with?($executableId) + puts "Warning: (#{fix_lib}) does not match the requested prefix, though." + end + end + elsif not fix_lib.match(/\//) # we need a path here, otherwise it is a lib in the same directory + # TODO combine with previous if-case? this is basically relative + debug "We do not fix libs which are in the same directory: #{fix_lib}" + else + newPath="" + libname="" + if isFramework(fix_lib) + _, libname = handleFramework(fix_lib, $lib_dir, rpaths) + else + _, libname = handleDyLib(fix_lib, $lib_dir, rpaths) + end + # fix loading of this library + fixLoadPath(fix_lib, libname, currentLib) + end + end +end + +############################################################################### +def getDylibName(lib) + return File.basename(lib) +end + +############################################################################### +def copyLib(lib, targetPath) + libBasename=File.basename(lib) + # new path + newPath="#{targetPath}/#{libBasename}" + + if not File.exist?(newPath) and not lib.to_s.start_with?($lib_dir.to_s) + debug "Copy #{libBasename} from #{lib} to #{targetPath}" + `cp #{lib} #{targetPath}` + `chmod u+rw #{newPath}` + else + debug "#{libBasename} exists in #{targetPath} or subfolder" + end + + return newPath, libBasename +end + +############################################################################### +def getFrameworkName(frameworkPath) + # get framework path (name of dir containing .framework) + frameworkDir=frameworkPath.gsub(/(.*\.framework).*/,'\1') + frameworkName=frameworkDir.gsub(/(.*\/)([^\/]*\.framework)/,'\2') + return frameworkName +end + +############################################################################### +def getFrameworkDir(frameworkPath) + frameworkDir=frameworkPath.gsub(/(.*\.framework).*/,'\1') + return frameworkDir +end + +############################################################################### +def copyFramework(frameworkPath, targetPath) + # get framework path (name of dir containing .framework) + frameworkDir=frameworkPath.to_s.gsub(/(.*\.framework).*/,'\1') + frameworkName=frameworkDir.to_s.gsub(/(.*\/)([^\/]*\.framework)/,'\2') + + # the actual lib name + internFrameworkDir=frameworkPath.to_s.gsub(/(.*\.framework)\/(.*)/,'\2') + libname=frameworkName+'/'+internFrameworkDir + # the new path + newFrameworkPath="#{targetPath}/#{libname}" + + if not File.exist?(targetPath + frameworkName) and not frameworkPath.to_s.start_with?($lib_dir.to_s) + debug "Copy fw #{frameworkName} from #{frameworkDir} to #{targetPath}" + # preserve symlinks + `cp -R #{frameworkDir} #{targetPath}` + # adjust rights + `chmod -R u+rwX #{newFrameworkPath}` + else + debug "fw #{frameworkName} already exists in #{targetPath} or subfolder" + end + + return newFrameworkPath, libname +end + +############################################################################### +def copyLibFromFramework(frameworkPath, targetPath) + libname=File.basename(frameworkPath) + + # the new path + newFrameworkPath="#{targetPath}/#{libname}" + + if not File.exist?(targetPath + libname) and not frameworkPath.to_s.start_with?($lib_dir.to_s) + debug "Copy lib #{libname} from #{frameworkPath} to #{targetPath}" + # preserve symlinks + `cp #{frameworkPath} #{newFrameworkPath}` + # adjust rights + `chmod u+rwX #{newFrameworkPath}` + else + debug "lib #{libname} already exists in #{targetPath} or subfolder" + end + + return newFrameworkPath, libname +end + +############################################################################### +def handleFramework(frameworkPath, targetPath, rpaths) + $currentIndent+=1 + + debug "RPATHS: #{rpaths}" + + if frameworkPath.to_s.start_with?("@rpath") + for index in 0 ... rpaths.size + if File.file?(frameworkPath.gsub("@rpath", rpaths[index].strip)) + frameworkPath = frameworkPath.gsub("@rpath", rpaths[index].strip) + debug "Found lib with rpath at #{frameworkPath}" + break + end + end + end + + if not frameworkPath.to_s.start_with?("@rpath") + if $EXTRACTFW + newFrameWorkPath, libname = copyLibFromFramework(frameworkPath, targetPath) + else + # copy framework to target directory + newFrameWorkPath, libname = copyFramework(frameworkPath, targetPath) + end + + if not $handledLibraries.include?(libname) + # run otool + otool_out=`otool -L #{frameworkPath}`.strip.split(/\n/) + # strips first two lines + id, otool_out = extractInstallName(otool_out) + + # update the install_name (-id) + fixId(newFrameWorkPath,libname) + debug "Handle FW #{frameworkPath} -> #{id}" + + # check the actual dependencies (lines 3++) + handleDependencies(otool_out, targetPath, newFrameWorkPath, rpaths) + + # adjust rpaths on the copied/handled framework if requested + begin + adjustRpaths(newFrameWorkPath, $target_rpaths) + rescue => e + debug "adjustRpaths failed for #{newFrameWorkPath}: #{e}" + end + + # mark as processed + $handledLibraries.add(libname) + else + debug "Already fixed #{libname}" + end + else + debug "RPath but no lib found. Assuming fixed already: #{frameworkPath}" + if !$EXTRACTFW + # But at least adjust the libname which is used in handleDependencies to fix loading. + # get framework path (name of dir containing .framework) + frameworkDir=frameworkPath.to_s.gsub(/(.*\.framework).*/,'\1') + frameworkName=frameworkDir.to_s.gsub(/(.*\/)([^\/]*\.framework)/,'\2') + + # the actual lib name + internFrameworkDir=frameworkPath.to_s.gsub(/(.*\.framework)\/(.*)/,'\2') + libname=frameworkName+'/'+internFrameworkDir + else + libname=File.basename(frameworkPath) + end + # the new path + newFrameworkPath="#{targetPath}/#{libname}" + begin + adjustRpaths(newFrameworkPath, $target_rpaths) + rescue => e + debug "adjustRpaths failed for assumed framework path #{newFrameworkPath}: #{e}" + end + end + + # update ids of dependencies + $currentIndent-=1 + + return newFrameWorkPath, libname +end + +############################################################################### +def handleDyLib(dylibPath, targetPath, rpaths) + $currentIndent+=1 + + debug "RPATHS: #{rpaths}" + + if dylibPath.to_s.start_with?("@rpath") + for index in 0 ... rpaths.size + if File.file?(dylibPath.gsub("@rpath", rpaths[index].strip)) + dylibPath = dylibPath.gsub("@rpath", rpaths[index].strip) + debug "Found lib with rpath at #{dylibPath}" + break + end + end + end + + if not dylibPath.to_s.start_with?("@rpath") + # copy if necessary + newDyLibPath,libname=copyLib(dylibPath, targetPath) + + if not $handledLibraries.include?(libname) + # run otool + otoolD_out=`otool -D #{dylibPath}`.strip.split(/\n/) + has_install_name = otoolD_out.length() > 1 + otool_out=`otool -L #{dylibPath}`.strip.split(/\n/) + + # update install_name (-id) of current DyLib + if has_install_name + # strips first two lines + id, otool_out = extractInstallName(otool_out) + fixId(newDyLibPath, libname) + debug "Fix install_name of DYLIB #{dylibPath} --> #{id}" + else + otool_out.delete_at(0).strip + end + + # check the actual dependencies (lines 3++) + handleDependencies(otool_out, targetPath, newDyLibPath, rpaths) + + # adjust rpaths on the copied/handled dylib if requested + begin + adjustRpaths(newDyLibPath, $target_rpaths) + rescue => e + debug "adjustRpaths failed for #{newDyLibPath}: #{e}" + end + + # mark as processed + $handledLibraries.add(libname) + else + debug "Already fixed #{libname}. Only change load path." + end + + # readjust + $currentIndent-=1 + + return newDyLibPath,libname + + else + + debug "RPath but no lib found. Assuming fixed already: #{dylibPath}" + libname=File.basename(dylibPath) + $currentIndent-=1 + + newDyLibPath="#{targetPath}/#{libname}" + begin + adjustRpaths(newDyLibPath, $target_rpaths) + rescue => e + debug "adjustRpaths failed for assumed path #{newDyLibPath}: #{e}" + end + return newDyLibPath,libname + + end +end + +############################################################################### +def handleBinary(binaryPath) + $currentIndent+=1 + + debug "Fixing binary #{binaryPath}" + + rpath = %x[otool -l #{binaryPath} | grep -A2 LC_RPATH | grep path | sed -n "s/^.*path\\s*\\(.*\\)(offset.*\$/\\1/p"] + rpaths = rpath.split(/\n/).map(&:strip) + + # no copy, no id change; juts run otool + otool_out=`otool -L #{binaryPath}`.strip.split(/\n/) + + # remove 1st line containing the binary name + otool_out.delete_at(0) + + # handle all referenced libraries and copy them if necessary to + # the lib ref path + # TODO parse RPATH? + handleDependencies(otool_out, $lib_dir, binaryPath, rpaths) + + # readjust + $currentIndent-=1 +end + +############################################################################### +############################################################################### +############################################################################### + +##### INSTANTIATE CMD PARSER +opts = GetoptLong.new( + [ '--help', '-h', GetoptLong::NO_ARGUMENT ], + [ '--verbose', '-v', GetoptLong::NO_ARGUMENT ], + [ '--lib-path', '-l', GetoptLong::OPTIONAL_ARGUMENT ], + [ '--install-name-tool', '-i', GetoptLong::OPTIONAL_ARGUMENT ], + [ '--bin-path', '-b', GetoptLong::OPTIONAL_ARGUMENT ], + [ '--plugin-path', '-p', GetoptLong::OPTIONAL_ARGUMENT ], + [ '--path-prefix', '-e', GetoptLong::OPTIONAL_ARGUMENT ], + [ '--rpaths', '-r', GetoptLong::OPTIONAL_ARGUMENT ], + [ '--extract-from-framework', '-f', GetoptLong::NO_ARGUMENT], + [ '--no-auto-relative', '-n', GetoptLong::NO_ARGUMENT], + [ '--no-copy', '-c', GetoptLong::NO_ARGUMENT] +) + +usage = "#{File.basename($0)} --bin-path PATH-TO-BINARIES --lib-path PATH-TO-STORE-LIBRARIES +-h, --help: + show help +-i, --install-name-tool: + specify the install-name-tool manually +-l, --lib-path: + the target path where the handled libraries should be stored and possibly already libraries exist +-b, --bin-path: + the path were all the binaries that should be handled are located +-p, --plugin-path: + the path were optional plugin libraries like from Qt are located (experimental) +-e, --path-prefix: + the prefix that is added to the new install_name (default: @executable_path/) +-f, --extract-from-framework: + extract the linked libraries from their Framework folder. CAUTION: this does not copy Headers and Resources. Not tested with already present frameworks. +-n, --no-auto-relative: + use path-prefix as is, without adding the relative path between bin path and lib path. +-c, --no-copy: + do not copy dependencies, only fix up loading to relative paths + -r, --rpaths: + comma-separated list of rpaths to set on fixed/copied libraries. All existing rpaths will be removed and only these will be added. +-v, --verbose: + increase verbosity +" + +opts.each do |opt, arg| + case opt + when '--help' + puts usage.to_s + when '--install-name-tool' + $install_name_tool = arg + puts "Use #{install_name_tool} to fix binaries in #{bin}" + when '--rpaths' + if not arg.nil? + $target_rpaths = arg.split(',').map(&:strip) + else + $target_rpaths = [] + end + when '--lib-path' + $lib_dir = Pathname.new(arg).realpath + when '--bin-path' + $bin_dir = Pathname.new(arg).realpath + when '--plugin-path' + $plugin_dir = Pathname.new(arg).realpath + when '--path-prefix' + $executableId = arg + when '--extract-from-framework' + $EXTRACTFW = true + when '--no-auto-relative' + $auto_relative = false + when '--no-copy' + $nocopy = true + when '--verbose' + $DEBUG = true + end +end + +if $lib_dir.nil? and $bin_dir.nil? + puts "Please provide at least a lib path or bin path with no-copy" + puts usage.to_s + exit 1 +elsif $lib_dir.nil? and not $bin_dir.nil? and not $nocopy + puts "If you only specify a bin_dir, no-copy must be active." + puts usage.to_s + exit 1 +elsif !$lib_dir.nil? and !$bin_dir.nil? + if $auto_relative + $executableId = $executableId + $lib_dir.relative_path_from($bin_dir).to_s + end + if not $executableId.empty? + $executableId += "/" + end + puts "Substituting prefix to find libs with:" + puts $executableId +end + + +# fix libraries contained in lib-path +# recurse two-levels to capture the libraries inside the frameworks +if !$lib_dir.nil? + debug "HANDLING LIB DIR" + Dir.chdir($lib_dir.to_s) do + lib_files = Dir.glob(["*","*/*"]) + for content in lib_files + if ($plugin_dir.nil? or not ($lib_dir+content).to_s.start_with?($plugin_dir.to_s)) + if fixable(content, $lib_dir) + if isFramework(content) + handleFramework($lib_dir + content, $lib_dir, []) + elsif (content.end_with?(".dylib") or content.end_with?(".so")) + # TODO what to do with extracted Qt libs. They dont have an ending. + handleDyLib($lib_dir + content, $lib_dir, []) + else + debug "Skipped #{$lib_dir + content} -- No lib or framework?" + end + else + debug "Skipped #{$lib_dir + content} -- Otool not executable on it." + end + else + debug "Skipped #{$lib_dir + content} -- Part of plugin_dir." + end + end + end +end + +# fix binary references +if !$bin_dir.nil? + debug "HANDLING BIN DIR" + for content in Dir.entries($bin_dir) + if fixable(content, $bin_dir) + if (content.end_with?(".dylib") or content.end_with?(".so")) + debug "Handle dylib #{$bin_dir + content}" + handleDyLib($bin_dir + content, $bin_dir, []) + else + debug "Handle binary #{$bin_dir + content}" + handleBinary($bin_dir + content) + end + else + debug "Skipped #{$bin_dir + content} -- No binary or object?" + end + end +end + +## TODO does not really work yet. Would copy all plugin dependencies into plugin_dir +## but it SHOULD copy them into lib and relink relatively if necessary. +## Currently we just copy the plugins and hope they have dependencies that are covered +## by the usual libs. Should work for Qt (our only plugin). +if !$plugin_dir.nil? + debug "HANDLING PLUGIN DIR" + for content in Dir.glob("#{$plugin_dir}/**/*.dylib") + debug "Handle dylib #{$plugin_dir + content}" + handleDyLib($plugin_dir + content, File.dirname($plugin_dir + content), []) + end +end + diff --git a/cmake/MacOSX/notarize.sh b/cmake/MacOSX/notarize.sh new file mode 100755 index 000000000..8ab414f88 --- /dev/null +++ b/cmake/MacOSX/notarize.sh @@ -0,0 +1,202 @@ +#!/bin/bash +# macOS notarization script using notarytool (requires Xcode 13+ / macOS 11.3+) +# altool was deprecated and unsupported after Fall 2023. +# +# Usage: notarize.sh [log_folder] +# +# Arguments: +# bundle_pkg - The package to notarize (.dmg, .pkg, .zip, or .app) +# bundle_id - The bundle identifier (e.g., de.openms) +# apple_id - Apple ID email for notarization +# password_env_var - Environment variable name containing app-specific password +# log_folder - Optional: folder for log files (defaults to current directory) + +# Exit on error and fail on any error in a pipeline +set -e +set -o pipefail + +BUNDLE_PKG="$1" +BUNDLE_ID="$2" +ASC_USERNAME="$3" +ASC_PASSWORD_ENVVAR="$4" +ASC_TEAMID="$5" +LOG_FOLDER="${6:-.}" + +NOTARIZE_LOG="$LOG_FOLDER/notarize.log" + +mkdir -p "$LOG_FOLDER" +touch "$NOTARIZE_LOG" + +REMOVE_PKG=false +IS_ZIP=false + +echo "=== macOS Notarization Script ===" +echo "Bundle: $BUNDLE_PKG" +echo "Bundle ID: $BUNDLE_ID" +echo "Apple ID: $ASC_USERNAME" +echo "Log folder: $LOG_FOLDER" + +# Validate inputs +if [[ -z "$BUNDLE_PKG" ]] || [[ -z "$BUNDLE_ID" ]] || [[ -z "$ASC_USERNAME" ]] || [[ -z "$ASC_PASSWORD_ENVVAR" ]]; then + echo "Error: Missing required arguments" + echo "Usage: $0 [log_folder]" + exit 1 +fi + +# Check that the password environment variable is set +if [[ -z "${!ASC_PASSWORD_ENVVAR}" ]]; then + echo "Error: Environment variable '$ASC_PASSWORD_ENVVAR' is not set or empty" + exit 1 +fi + +# Determine file type and prepare for notarization +# Only notarize the outermost container (zip, pkg, dmg) +if [[ $BUNDLE_PKG == *.dmg ]]; then + BUNDLE_FILE=$BUNDLE_PKG + echo "Notarizing DMG: $BUNDLE_PKG" +elif [[ $BUNDLE_PKG == *.pkg ]]; then + BUNDLE_FILE=$BUNDLE_PKG + echo "Notarizing PKG: $BUNDLE_PKG" +elif [[ $BUNDLE_PKG == *.zip ]]; then + # For zip files, we need to unzip to staple, then re-zip + BUNDLE_FILE="$BUNDLE_PKG" + IS_ZIP=true + echo "Notarizing ZIP: $BUNDLE_PKG (will staple contents)" +elif [[ $BUNDLE_PKG == *.app ]]; then + # Apps need to be zipped for upload, then unzipped for stapling + BUNDLE_FILE=$BUNDLE_PKG + BUNDLE_PKG="${BUNDLE_PKG}.zip" + echo "Zipping app bundle for notarization..." + ditto -c -k --rsrc --keepParent "$BUNDLE_FILE" "$BUNDLE_PKG" + REMOVE_PKG=true + echo "Notarizing APP (via ZIP): $BUNDLE_PKG" +else + echo "Error: Unsupported filetype for notarization: $BUNDLE_PKG" + echo "Supported types: .dmg, .pkg, .zip, .app" + exit 1 +fi + +# Verify the file exists +if [[ ! -f "$BUNDLE_PKG" ]]; then + echo "Error: File not found: $BUNDLE_PKG" + exit 1 +fi + +echo "" +echo "=== Submitting for notarization ===" + +# Submit for notarization using notarytool +# --wait makes the command block until notarization is complete +# +# The Apple notary service (and the runner's network path to it) occasionally +# drops the connection mid-poll with a transient error such as "The Internet +# connection appears to be offline" even though the upload itself succeeded. +# Retry the whole submit+wait a few times with a backoff before giving up, so +# a single transient blip doesn't fail an otherwise-good build. +MAX_SUBMIT_ATTEMPTS=3 +RETRY_DELAY_SECONDS=60 +SUBMIT_EXIT=1 + +for attempt in $(seq 1 "$MAX_SUBMIT_ATTEMPTS"); do + echo "Submission attempt $attempt of $MAX_SUBMIT_ATTEMPTS..." + + set +e + xcrun notarytool submit "$BUNDLE_PKG" \ + --apple-id "$ASC_USERNAME" \ + --password "${!ASC_PASSWORD_ENVVAR}" \ + --team-id "$ASC_TEAMID" \ + --wait \ + 2>&1 | tee "$NOTARIZE_LOG" + SUBMIT_EXIT=${PIPESTATUS[0]} + set -e + + if [[ $SUBMIT_EXIT -eq 0 ]]; then + break + fi + + echo "Submission attempt $attempt failed (exit $SUBMIT_EXIT)." + if [[ $attempt -lt $MAX_SUBMIT_ATTEMPTS ]]; then + echo "Retrying in ${RETRY_DELAY_SECONDS}s..." + sleep "$RETRY_DELAY_SECONDS" + fi +done + +if [[ $SUBMIT_EXIT -eq 0 ]]; then + + echo "" + echo "=== Notarization submission completed ===" + + # Check if notarization was successful + if grep -q "status: Accepted" "$NOTARIZE_LOG"; then + echo "Notarization successful!" + + # Staple the notarization ticket to the bundle + echo "" + echo "=== Stapling notarization ticket ===" + + # Note: You cannot staple a .zip file directly + # If the original was a zip, we need to handle it differently + if [[ "$IS_ZIP" = true ]]; then + echo "Warning: Cannot staple a .zip file. The notarization is stored with Apple." + echo "Users will need to be online for Gatekeeper to verify the notarization." + else + if xcrun stapler staple "$BUNDLE_FILE"; then + echo "Stapling successful!" + + # Verify the stapling worked + echo "" + echo "=== Verifying notarization ===" + xcrun stapler validate "$BUNDLE_FILE" || echo "Warning: Stapler validation returned non-zero" + else + echo "Warning: Stapling failed, but notarization was successful." + echo "Users will need to be online for Gatekeeper to verify." + fi + fi + + # Clean up temporary zip if we created one + if [ "$REMOVE_PKG" = true ]; then + rm -f "$BUNDLE_PKG" + fi + + echo "" + echo "=== Notarization complete ===" + exit 0 + else + echo "Error: Notarization failed!" + echo "Check the log for details: $NOTARIZE_LOG" + + # Try to get the submission ID and fetch detailed logs + SUBMISSION_ID=$(grep -o 'id: [a-f0-9-]*' "$NOTARIZE_LOG" | head -1 | cut -d' ' -f2) + if [[ -n "$SUBMISSION_ID" ]]; then + echo "" + echo "=== Fetching detailed notarization log ===" + xcrun notarytool log "$SUBMISSION_ID" \ + --apple-id "$ASC_USERNAME" \ + --password "${!ASC_PASSWORD_ENVVAR}" \ + --team-id "$ASC_TEAMID" \ + "$LOG_FOLDER/notarization_details.json" 2>&1 || true + + if [[ -f "$LOG_FOLDER/notarization_details.json" ]]; then + echo "Detailed log saved to: $LOG_FOLDER/notarization_details.json" + cat "$LOG_FOLDER/notarization_details.json" + fi + fi + + # Clean up temporary zip if we created one + if [ "$REMOVE_PKG" = true ]; then + rm -f "$BUNDLE_PKG" + fi + + exit 1 + fi +else + echo "Error: notarytool submission failed after $MAX_SUBMIT_ATTEMPTS attempts!" + cat "$NOTARIZE_LOG" + + # Clean up temporary zip if we created one + if [ "$REMOVE_PKG" = true ]; then + rm -f "$BUNDLE_PKG" + fi + + exit 1 +fi diff --git a/cmake/MacOSX/openms_logo_corner_small.png b/cmake/MacOSX/openms_logo_corner_small.png new file mode 100644 index 0000000000000000000000000000000000000000..8f8a2ff0c1fc118c6f84dc3331894a8a938bcc4a GIT binary patch literal 8610 zcmdUV^;aA|@Zc_syW65gix*wo-Q8h1ebeT7q$z&#Zd6{IAyhLlL$z!3DqXPf{EJXzwtyh}%il0!CU-SO1!~Y71wvwun z06=Xb#*+ooYnjGMK}!_?@MQ!5U||5j!>b5(004M!0RV?k06-`M03dPBZq*cdt?;%s zP_$811+cvGr~pJDIpDt*fUhV91pf~&2V@3-{WWtYOnOar0|OW+58_0 zf&>4r_Nxqz@ITsVaM1topZ+s5f!W5s5;SK8LpJ~bgWx{|0y48nU&ru8QASe78+c-h z0wa`NsLoyPI!)$@>cN+x$0#T*k$Evjk|b1+K1+o(_YjtZEXwwQMY{yo(7pbKLh2mXHs z!7ql`q%TFRvC?gSVejFLT~|C^fzT$OKFO3liT4zxu@2k8>=HsWj?NS=%CNRzdWl)2 zq2S~hgQD&%`QUDeBDr|-XlzQMs5Ext82kD1=({^_m(w-DTH8sgTF(=sTAOilm+J$~ zx)g*v$oX4!ULtA~-+7qvS+xsWU`#+1co`{Vs(e0T=`=@;T|rUsXIa3lTh{8j?-!haTCE1Y zh5mz+x{QnrIjey z752zPyld_*l}C!asYrnuOT0wEAW^VW;%J$fRb+*Z)XCL_S`zJ~in%~1x_k;o2>$fw zWR6;i|NU-y0QzCuSw~9KFV8F$6_ti#R{L*k5;=?2rp8jJyMJa&bidZyPL5X z{7OP}z1xOTR6Tl3j`O|fvm~N$$gcE^?g5Y*ICy--RgbA0xpD=W@PS4 zLj7lpRkvTgh0%Vll$My&jIGt&@kjxTXaaO_n1TnFns;_UywBlx{~piqb{W3t zN`LH+A)4>o*v|_hHg5Vvv_Gj`JYVSsNf7sQ+rM{=$k>NX6e*_@S02qMbLuX-9521Q z=*1C7T|g;t=KB4f22Aq{W6bVX>yJ{cqL{lsC3$n-!q9d{)Ab3`c6Q!dt~Qp5 zC={Q&6>w8Vv1r!ReVkj%B{(Y0i_YiLe&62iDLJ37>DZ9LQUVereq{S?^+mHh|ML26o!Pz_0p7XX9kurKZ2X>0 z1lt&XJnJ;?*|S>zDPc^LQ7zk-uT`WpY|$H`h#H~0<~24nq>=Ku(Q&n$Kk0>%X1%hM zI^nW@QcU}v+V_BVxb@#fV$hIz;C;V-B+-VUs$}8v7lh$`oOz)@Xh`_lO=l_YM{oQP)xSCg$93afWv~Nft*yTOimW@u`|A z&tGd^HfxkHsw|4>Dj>v~>~W4UQS71g)z6AOdgqe@?iM@$F^EznmSafQ@AM&fOhs(< zN`(50{UGB*{WDjljbE=7y~zvbKnEawm67bY7yy6G1vz^cPd$bW+dKW4DM}`vaGEJ- zxSPtC4mc%2H+FDfJBm4UwnIys95{5bAU$L6B2Bk$&|b}uPW&rFCuqr%nEmLztx%K5 zMr#^;w+B$C?o&YsP?|NUf@gT@KNSZEhVCx-`T?DqZn6J04HlbdCLK zRDvyXcL66toc>^~jL91a}H8@99^IJ0c={UgL2Cd>r*_y#y9rTVaL025iI{s*JI zLfo0fNC^285wKQ!=nm^$$x0B3+ur0+&Y!pD(POP~iC?t9)_i0EJ~ksY#kN`zjUp8h z|3pGOg2&K>Hw$)^Ie*HSDTb#^;(Fb0(+y?Aol#}QmvI?A{Y+emYV(O;G8Sc(*KpANvOyK zoFW!+k)(B4v~OF?pX4f|oJcYAux676o>S_PjLGMUIYlmi*<#dX`jk;lqMolS?pWD_ zTYiq}Y?>M$8@rv9T2JXjk5J=>xJHIrR`#qw!Q-$}}1s3?(JQDn1HY8FJ}i7Nk>e>!>E#Luw~zsA2P%OH+6QUq2Qitc;FqVU$Le zqe^Y~Jyd2^6)JTlCdTSXO(#y{R!Sc%2;TXO)cMV!UhhLAyj5viR{_=>dzO5E?k=_$ zu;8%s54U(o;UOpw{Ujf#?}&O+V71>LWPjtA@&=97*hdPG#_n2g#Inwo>#`ONGi$u= z2DW;#f`WpU`x7~qyCbOxJfi4nK-$vxMOUa^2srKGWSC2zZ*MZmmuJR?O15+ZgYsEE zcU(5wl$N_zTn#+rkQAsnQRW8~(i%igubpCn`5Sh~X}mZaJ}#<_WeJ=i_suF4<59l- zD?OlP+UBWy-_od1@+QiN9%|Q*D7o9M9zulbq5?Hr(q>sEl&f2?h(K}>+EuC2jYS_- zCVaD`ZNHCHttzM}*heYkt^lf9ewAmrVaQO$^c<9v=YeQP0x$YW=Fy6$LVA#tfOdUp z+lr+2@eM5*1?l}N>RoPC4$Rs$dbIHiHTt_5sjnNQyop;pxntRSyH&~8JukRMQ*r)y zeu9*&ANn=>IbXVeDV`vO#cD#Ain_@2^(;p-HoP+M9#e`B>HY!15jG0ADZ-Qp4IpsF zJ|6)h^efI8gwvG^JkFHMJt_3&hvaI>@kP>oilS?rgGTcF2`m|G;xOJQE@Ut;o=Ule zSoPqR3WbB|Puo*Eq^GIx5Sqao1_U_HY3Yat>MyR9ocwpUoiFUwZKpyWg)O_t5yCAp zRfAStS9{J7#5C1rWck%oN;sVcI!*2AdRGN$rd6#@FNCkK@E5WXfbCma$YgY5GO3{J zH}U~I^^*~%uuMA$7kCLr1UW8TQXN=QBMSPA&I(+g@$8hXOp3c)F$_)x+x(2UW;PQN z!4F#gl=#?w-ps?CaN32RlqaiPvlKd*{{tIZr831Be1qrI`P`Tx;!_7ZkplW++)>?O z8-UKEZM}KJ$`Hb52xWkI$p$sBTQjV8tYkHG_Hqu>o9i6*Db@hKX%?7VKShIaeC%fS zjGO2E)72!M5mukMT`O?van+3aj+eHlJJLl^vTPIygP`m4y+k#BU zBY=Vdt2q0zOlvniIAIC6$<^=Q=5-JmRU@2y@i%&FcPU0l>V0><>2n^zq*>}rhbZ#9 z!0T*XNu%T8up-8QvqGUQ+!M>zbjgoF$m5XS4mz7rtf89073_EwkpS&V&`6wdxc%jo zcd7pK-^0;_Q^$QVnJp|kbw&-$1qC3KG&dLLTmKcAQYR(~gJ>RT4@wB@C(c0XMq$b7@yMx0o;*hM6_$6!^BDsSKtdgYq zPq^XpU8Y?hy3(3c!~b@^9t@OdYB)+SEz(0TRSm3^o~_Lq}+9YQ*+OiTeAi zeVpQezdab7%;S8%*LIQ`G|TFv_oJ>9)%P_Lr4SKpB=5z!(C)$@vs{uG@9oeAJxdj- zdeT28Ll4a0YJ=msAu(Z01KRw+jEGWEFnmXC#@u_>}dlaM_V<~3?#ut zGy^UX_blfSiCzf(bgg0@K9-w(pYUn3^vPg>+-A)n`&3@wLm7F(TNAhdV1oH>%2?*t z3-0HR_ruAXxS!-Fb4B~Bn%2t^;}VQ8&qmVay7y~F@^KqL2cRd+2BZUbA`)}|+E&I~ zlISPvo=Vh90B8v0Xw7`S)`2BfQz^0H_cnu2qqB41av^Gw?c4Rv#voSdE~ArF#_wcY zHh%ThGM*{0u?Dh4Rs(`%Gw`!CO?Zehx9vo>CPIY&-0Wy@86dJN3Jqf(C0~{Wcyaw@ z7O8tYz&%QfCnONS2&(t7l;&Na26l8Ec1OKlvCOgh>Zs6(e-KCNKO9I63G`xoG9Vw-Z|I?v12C0ly?vX8s4Y91o^}z_q zA(4T>z(E8APs>1S0IW#F@_|_B#=g?>%>ZG(zLYg2%$V`=`9Heiapwjk$ikLyI5t>e zA1qEl-%^Nyc>sODqSSd7fC#Vnn=>g?yc2K(`qx0lG${pNE7rKE)-LdIq#btsW+eX- z$Gg_jNaE0?&Bb=NKMBU>IHE*ncNrssC^sQ3Zsdi2$bKJLl1#`}!9?N9pHZ_Fb2S8> zTxQhN*$UV;rFl~nvZwzyb43U1M>keJLBlcp(m7Q0Gbe5!=0Hs-{eil&T034#=ZG&K z=9lo^5pWf68i8`wlmyolRwN5+krAUaIkr=~d-IrgVrUiF0SH;=yKJ6urz3ND2!nXU z)l@t~8gD}myU75+1wW3f52FCV@~5MpOvF2#Z^Js-gS5F{;zgMH$gIkTl6#ZtDGrBw z_^d&XeQ&MImR#0HF&k$)^^lS%6FtwvtXp~Fd{$@QSLoFie6sXO(j%WO)7sG8BeNP# zW?Qz`D2Vd69P_m+0rb9CCVZvR~KIA%BUL@Ca)$Y>1D)@HYD~8*H zHOj5sP;Fz!P`Y9Ai>0l9<`6TJOo2+MYc2pO4Kf3gSbaorBml$lK z+&objW&4))k4rzQ`|r;YGsn11?gs9I^kbUu#YqULA>QS6lH!^~Y_yaFVFcReh}VN} z8!f(_VaC$yQ3!}hiE~I-(z?bicER5b%}O-Kr|wY7jNztQo9`IX;^zc(8?SKTU)ai8 zEd$S5kDID{jp%rrW(}sjDGLL$6>iyr;d28i_EF7uBuNm-IW-3s*Dd0F4rTxZ*|g|^ zHn2=#q*b5vLcJ@>QrK3e&27<=LkT>ROWsM%sz%!_{e=hqWS_x4c!L!dv70k>w-T&o40o z@A0?FGdWV}4Isesj1J~wM-p#yO>3M7NntrYzJRp4IDzr#NU&c{DO2fv(RJfC*T}}Y z?k=28M6O_{F(MvL{;Xb9!s77Peto{k;d^7M;1tw_FTV;Zko>b+hBz8;qK|avuURe= z*srqkXk%))b~w#9+Du2uZ2f-sfC1Bv?RQu=Cj(bT>nNQ6(w@Ha8-ud_4qn218S?Hm zy@aYN^Mi$+htbi!@v%)HRROC(_GU8sItTX-gPLK$FKmqpw)_ZW)D(S1H>qCSD-<;k zpF|4pZYkWr_rJL0Tnbb+fny(dJsUGF?0}MPIhelGKGUd7vcV^Jx|D=FD&|$bHEs({ zIL)?{F-jg8>0@#b6PLQv=g@+Q-Egn7e+GJ8V|z&gcW6)n4UK}78&6oynOYjYdaL;po^MiZ|Lq=tqi0$PQ^UZ_2frVL9KZup1fR6L}JHRPQ zw(?l{sL$)Vk+KejB`+B(;;G_l{c2 zVm+K+T)V5anK*{-9-qzNx+xyz6Ciudc7O=IHRwQW$5Mo!y0KT~F7Vqd|07`rrUU4* zD4C$LXN_|{;5Q{s2k8pUcVv0wTw^2j+Kff-Svwo(7j#8D3`F~l=a_7%xyoFYYUGW0 z%3Y>jR%-;#!yDQ0?*MU`^$`5N6_c}XDH%P})uzJeERm`~S{_!<{AKESV)m+OepBbC zB}On?IgWaluW<=bHYeR4zhp0~y%j7)E8tT9p`$0oaTzqb_B)-5gNu&&7a>UXR~_ae zJ0fh4>xwyhG-B7%H9g`scOmop1%3g!t-pLi`hxVLpV9?n)?}lo*S{$eOm_waG0@LR z@CVi=4BZM5FQ?dLS*q%ud@YP9q;W-X+2{gdu4(;z{?+7Uj^1K~)^bn~YlrhfUnbL*z&BOiC^J$=YIR7sIFGnESC`kxq?lJNsUluHBP^kjVjEacTEnYn?5PI##v? zI$=#e#SUvkK9bp%{dpod14`@TVhP;vf_srcSu6cD(vY@4TRVb30T5!o|* zvN7koc081yl!wXXwGlwa+V3fAyZz4w1}BNfz$Bv&&Y|n1~fO8CQc7>D3}* zd5KH9Q`Bmq=^hQ5g9H5S;AhQ4BPEklT%XI zSDhGVx~I+wO}n?05TgAtcLKa8%B5rY4a6hhah{=XwT7M@TF;S;3auK$o+r2p4{4yS~B4vm5 zN%hUos|n#Wjp>>oe8{-BczNP^&e1}Z9{~1I_83U~SQLr5a&Y0#jUO#M`tm3;%xfGipANF?xxe$r!@`K!j%-DA%~pL&k8;WEcu=A1cYM$L z*lH=bx{^}N%DbMw!}?}Evdap3$emVvLSOFxQsH|g!yw2i$RXh|AKG9pU047lKYnOB z&UEm9!(aR?SU$_}wM~^&^2IOBoFoL1b0%Md&k#o4TPxRWni9rji{C1sNx$<=UN5uf z4-*`ZNGgz1{c>mTF}$p-j3xI>#C7{ksc6^cR037+0$htw3Oj#Exfr*-bDS+hws6ga zLLW?wH<^2l+!JpmPWuz%91|BWyn?L&y~l>T<{2`+1k15BX&1zFx%9;VF|anpD4eR- z+E=a>$Ll%;2J>unDy@kR1XwNMFqVcl{{Z*q2eXT0)4Gyg1~ou>+rIiu+M&3he!EaJ z*Fjy81W|Avm;ZDoG-^-T=-SUItz~Ye2JCcW(}2#INYtXDn8iKtG#T=_$$s@)7Dn3E zU65R4Pp_`MgoP9AG?CC2BNC*~z5N#kd>+hk?3e7O=4hT zsxWP`D`l9P{Vs_eZ?&NlpN|tKvj{ZT-qtUbp4yKRA6Lh77AK38`Bb_C)^TPqiEMZa zSRAnH>qJ{annOfa(Il!wxE-j5F?}Ke2q>T*4CV^JfWh**R%iEHi2fWzOh&q&ElN_-R%$ z#wio6gH^&wI8ymIn}|}_vl79tN_@m03G;kDSslKEbQFcpQeug<+-qu0d>@@fMD&yH z&OGcUZvMn{V6#n*Oy2K?SIzy;hwMWk_REevud~!i`?qO2Ywl*rcZROyS8!T@ZS**^ zPP&O}^aBOJ{0*=QDbRujbK3I|6c?f=qQbQqB%>QrGVWwos2*aSdGqBh_y)APxyXq6`g7$;h#FB#yJ-`e1-c2r5AVHs z^vW)!sMuhY_vTwz6=B3HQxejHNN0^UbqV@y8>>Fe0nD=sD`3L7%gF9_VE$$c8%iCX*|+!yRYUe)SfO|>6wQmjBg>l< z!GmzH5UQpJK_=oI$2H}Nt31*pt>#z8(!VN--Xg~qkR(hRs2e$!fwG7*4C_C?)!=Px z33htAyBL$U%IP(vpCkVIiTl}vu$oN5H6tXQhCLdLt9Tut*-W;h4tdx{)7y=!GC;F? zyOyxmld~-KKF^FOL9#Q27k%PWVC~?OP{IQoO<*gS*_4Sa3MK~)7EXwrT(d=LB{9Gm zLqZ0;&eNC&A{B@jl=^skmI!K0u*A0roN>*HLA@d%U_1%p9`<&mvsL%8Ezs;V>J3hR z%cZv&PL)LP@x2>GLIyKrn?`}B1?_VqHc6(WJEsQoCEWx<7Ra>aIyA9?+4&anxI}5G z#Ti9Re8Peg_8Rr(r6A(b5(QOA`e7*DvMg`LCaKkGdd}aJD^hI==2$g*p05saU2vOT z$m#t9DM_R=OFUovfr$fEHn7x?=9a>&AX`K3$V;JQ=Ae$=p~SikX?FA{L`KoGr(&c? zA?$#s&d|FP-H*Rsp9%6j5PqUmTG3EE=OT^$Sr>VD|KvQ0AaL%a}sL3i)-Gx2>_Ld>81{4uMk>^&eV|I@Hg-JBwAR)a z?ZX14fg%Abx!Ki5&>-eMC*UFo>5XzShK_ht!+Nm>U80fB_^-++Y3 z&c*#CLIPE#L?P;@36DP?V5~$GL?9rV5|Ca^U?Cth-ekl@)IA~3`(_ddb=tQ*9I&PQ zpnP!8sj0KfSdfX;T4diGI?3SpQ(|Q zbiyJh*k6^AX7I_cK$#)YhgL)8Qwh}8-ntB&yPL@Ws8NlDCc`Z4`bmIc zUdT^^l(EPt;O8uq2n<9Z(@(-(f5wx8EI-D>`}6fFmydV92X>aB1mX8p#?!lQuh-|( z1{-+hlLK}(V9e*oKSfNIycNSVLB2vON(DkoEQY*hKQr;JFRKZ7)IMr4gDt+N z&~$zk985QkLTEk`^tuVX*y>x?HjTg(35QJ&yBZ9EXLVi=3`^YXg7hT*hjqRTfQE1~ zGp?0AR1%k(}tUOa@t|d+8X?`#$YmAr4um1az zqFHpZU6ay^z$&#GrcnMgG7d@}k1Es-5JGd3zLBx)~R z>7?7pPx{NQJom_vJ3%hTZ~de|2a@#yIbpG`sw7}&jK6X#yMHa6^`6zERXa*ru(Rvl zB%N}8t$Uc|M4t1Tay^Y~>N&}n=1Q>pUjQCJ<|4v2JDt$6)Q~Pl-vOd$oCx}$$1JfA zW#-&%4qn%A&h?r7#?4pq#i+r*su#%j^@Vt1o_|!#KV0jc5DbHYI0F!R?GaWVc)un2 z*WiEM_daaoYxMT2wS8Rh{&rcN@GHJ=^UqK~V4konc87k_ z85Cef6CCnQHr60Hl)28DS?;Tkf&y-QJ#IfKJ@f?j9@$cF-CGZp^#Bv|s+uNJ`r zCwO%eOBxAZ;vT1o8gL)-{v!NQ^ds~t<8#folb332Q3E8CI}hS!wDwB$b(i8TLY zx+Ql}xvq9NAG8`FmX{506a-js03z6en#ILmehKQRmdeUIOe-H^L;nK@_;S@R7434Q zDFYyn7dpk54`GqlbDTx=xWv0g@-6-QVhq=W-0}4RMSc+IjOl?lWuu=j8BetiSB*U}`?8ux(1O_T+>p?f z@Pw}#gcJ*ASj+2C7?AYetkG)7e!!ZXL3!#DVBnR?x3%=(2q1Rc?w`sh83;F;*ly94 zmz}v3N^5C~V;Z2C1Nz<`#xaK(Of>6yhE2iR%j0ql#*~TA43$AaCai`?c{hWezG=6m%ZED0L!W(KvkPg+^pAk3gjfMn=_(df2DiJ)kT@nlo#l4WG2o?6R z4Q zvHyA42sh>`C5ao7aqXBk-$uAo*j~%t=?2Qr1;=&d!$2 zhJdJZPl0}(jXV_f7{Y0h6xF(?y$*zR+z+rZX_Jdv0!E83xP0k1m`)f_dT&N{@lSG~ zoR_;Ly|tMS%x1v2EBPJ~3M)(zUWjYYkMhhnIt0cCkSFZG=**@&%#Cds|(CzPFg|5L1SH zW{M7}EUEC7a3;wf7$0>T6D84Pn>y3*k9~h-$#jiSm;@uhviZvEnolSI#Q|jL&k88( zBUKh>mwNQr292|w;lC+z53&usD+avU%2bXL?p6)fH%*ghRFlhz(jIasq+@0d$U1|k z^OA!OqY=Xr;cqtd(NV)0?ZW7w2!^!vj=N#DluSvG#&6008Rn1DuW=WcSx&n&0QdbU z55M9B-O^zX&EGP}n>ojnPNhzBO9~ChK}ozG2GuZ9sFXZ|0}@Ik16B}BFgV9WAGg0F zD1CW{rtfb7_vnLODSX8iEEIzVY20v#qZUu$sq|Hf&<>4@Hr%gD1%I0+;MahQ-qKT> z%_gjHAiw6B$#e~j^)o|*Td%tfb_Qa^a*f9I$S8xmv0<8>qS~mn55e|za|LhX2)jcE z0GGPCfZI=f+_=jp-xWY!Ur{Ahe+{w9dzfl0{`+0RF-OZ4f=s@%8;(d`CzJfrNHsSO z$P6eq%QY(wKl8fGAOUF=oUGa?m z{#`v$xfp#u_&d5S;D^nxe_(q8>IJ6#yFJ?;edYC_UFQ#pUR1@b$g-g;FBfh99c>>Ur9J%9I~1NMXdffk!)BlF6mod zYDAnX4E;i5g@Y^GOVu61C!l;AC_3^k_}+<(T1f1;eP|*Zkz49e((>m zpL1NQpa{NvXAo@QG&W3lxz)uyD?V{+;eV~n0WaoKi&MCDx7DTzUg*x82rsYY>G*9N zdbrWF5gmZOW!=kxUK_Fl)NgaWvMsX}W7V*Ro<^cW(fnWRui#FpwL>Sp&4$yX);US$ z^C{u%u?J^tJkrhKcBYU6@Ed@MmE|pwuN#TTP*i zj?{W9Jjal=SlDd?2%q#?Xfjkap--hN0XPm}iOAo+JRpioe_drndxzMfJi`-%c*q@5LQHpOQ#985i2cUXwefyZ9|RG^_?Q)9#zFdLU&9d8W6&^&bbSsQ4J z8Tjkhtt{knYr*$_yF0PS41!dc0;AZ*B9`Ab8^3A8nB|8=O4riub;pqwk1iSW=swi> z`HBQRm)l)m`yfhbY5xUkpJN^z6uD}Gvzr>y3k(p#0S!xpI z;>yFbBdzW*^0F6I)QafE$3-U_iStj{RW)-XIK@FZX?tG9Zfug6LY%kkA}M@Yaxh_wGKx%rUccSHMUk-$5vfBPZyGudClKg{Rk2pDfIMtSfYF^*!Z-%EL>D#0fah~ZV3tz{3%YkPXDOx zVhU_o-6Ox z;<}c%wZ7||c#w`81^0gUZ%ow2i}c6GpL!=-s3{H2|4QVWwacaSc+x7p=w}RW?7ctD zo6=x3fKn&44*`l$Xi*eLLXx1A<*?**hS_@?S}E7}WU*FCLK=jkanQvEuR60b{tN1w z@HLi67~`!!a;kk{Z~;uOtLpg3uAzKYSVS1jb=oOyi^peD{-G+W>@_5n4_M8OKyo1) z*9k>O`>U72EG^l#-g_vRkBcU%lk`{;gD|=r@&~ZWGop`_Cmnj$(Mpj7`A-fXW$Qj1 zZ6wmSoxq>F-=WDi!)cevT1m7xqdVzKpYYGzc2d))V#UfJ zb1p3}+N-xQhs)VwoW1a#JJfianR@ZBco|tM)`89`im~4D%6VDLH*tzh))OjR8YZ8n zSZ6SafN5z&LUttYhtfv>4rPdi;u>dndH(S4WjT3T&sjwAX(nrsXy;KwB&_c@0M7O_ zmMaR8XUkN*&2M9B>^1#HtbhhjJk@_N@5Hx51y=MVmy5G)wym7cx-a9ie8?5)QamNX zb7}7sS*6}zj#ZXj+cb;DV=~$wAepac_fuS1e*NAUGIOpL9cwIOf6#I=9!(d0%tXmS z@{n$qMX(|V+Aw%0@V1gZ6?fP64x~kc*p=L+1o+sbzbj57Z`9u|WV5~(rQF8mx1u#a-HsV0)hPVAWAK@@ z>DJtpWNMUNW0Dd_aNN+JU0CR3c}{83x3!^Fs?EuKGn?weKIu07GJ zOs%3^j*xbNt|2XrWeLd_T)icHwso&TU4kuhde{V(Q0XF@!N<1oA;Pc}gx| z4DrI!C;e7M$dumWZP1>JCnPs@mim;T&um6d;)!Gv13adn@op)EMaC2iq!ne`0Y43t zRGi@gNm?Fg0sX*iPZxCd*h{q{AE-OGvIp1xCH==Qc>yZLP0ntB`e2CSq~92{;dcZa z4#65HGxPLiF;;RJaDxphqV<9!!59-@0>(<-{vo zXhJ{njUc7BN_uVkLkJhCwMaAqeTX8GSoj9Mk(%^?_XSYW7RK4q_iSC<$kO_QsIwhX zqQrLm9%IpKrSdu+zc;h!9?LcRU_?;|AuD4ML$rQqFx_Y}cn1u{6y{lK!5aJUhLRAwOR+E}E*85Fw2zVlqKcf20G?vmE$}w{w6Ri(n+$b=Y`S$C(qWvX2Y4MIUivJCSs;FBXD1rMxX>L0^l5a!3^l4P4%hT)0)dp4%;Dj+Bjr1?SQ} zP5Lz8$NIYRnq@dkzI7_>kS^&{MljXcED$tNZ;55oU@(q(!+1)cQj;@8jw&d;ui)k@8q_EL7g7TRxA^Owj9m zhf}NjtZFvQjOsZk@|s^;@n-KF41eu*4#)Fbh>yFg&g%{drQP4a1A(FF3}(f_sdD&p zps=Ky%cp(cl#T7J?;GORw?Sx!VD1VF7VZEt(T_1HR_C8`-s zymoNrC{TQ3(&a3I{0LidD(-Vv?gJbw`4Qokw>jMKN7W``y!D zT&?LRa9?JQ3%Sm>2v$n&1;a6lWhz%dFcXhKY;0QE0)J`B7E@Pdw(?us5!dXfEdbd( z8Wg^u`^M(=f65EpX=6}i9Clw{1&)UC^AXSB_YV2 zeOipkKasm+OcxK(IgC3aHV2lIshL`8W|jw8F;V!i^IHPtOa#>v=h{nAf^GSl2e~Em z7J!qncCO!Oz)eGV4w0UJagh-aO!{X!s7KV*b?@rie6O1Cy>hg>_98{1vYKGw;O^8k^) z1-JaLcnrq5k&%VPCYj=+oYxHaZYt z)~T}uAchBw9X}aYUuj!ppnSS5jX(~^?p({o7#CQK->jVxq#;)<9aFypNIS*lf*RGU zh}$f=U3=JHkuS8{Le1{DfXAcFA@ufdVKJ|tU|&a{9J;o#Q1kcl;-Rmf+$LlOd=I}l z3{V6%q+FWnqZy4iZk}U^~8E*?#3;AE!e^b}%_nf)pq{mPqo+MSL zKbMWo>l+%J&^0!)_RTXq$C1a$Uq4;DRl@z;Nw1sc;(LLY0^tE>pL)i?*G;pa!x>Je zg?7pX5lXHKPgCj60iu=zD>c;-CF;ztY3IGJ=XEV=K+sXLdzy)CqXA=fKrEfkTEC+1 z!Hgl|lD(bAi)iKIRC5z)s6o0pdNY5&qI<-FzWr2=E!qBH{;wk>`lQL@?-#0DG%?1^ zYdP>T?M@iXbDYSr+Qm@>aK!&e=Hin&sIZ+2NugTGoluC8q@@s^_-?Lg=B=|YCnHGw zGv$VLW{JzDSJBM@sWW*AG%gOlg^cYCe9onGj<@VjyoV!W&F6IGR>br&_QsSXv%0P1 z!a6a^S+}jXQSJ^+8p<6Bicm|xkJ$58fuIK-Sh$XAA9aAlt4Cu)#mTE(h~L#k2lE|Nvi#ND%*34Spt_b+Ul4lfNppo|} zxKBe>O9yn&qMd)T$;;+thZA>2Y-mOP!G6;cOEp0Xm-xo!)L>(rVU6H!aC2RO7?d%z z?s9X_+NaB_KZO6Lk)oDw*@Hd4Lt$Q|w}K$V~jiwMeeGES`J(s*cANAnE*N2$>&tO+ z$LLD&zGX-PMKbfyz5|Rl47ZSLS3583Spm46Tk_^9W9#+nn#&2b*)st2Q_dv{J}+n^ za{qU2wuffx`d8FCH=4@f?kgARxC+mp9U;>uz*Kix%(;TYHPSDwO9)F$#xaa3+W+sMt{%l~J$5XD*^HGT% zS^@$ri?6|BXIH(I@KuP>sKNG=w;fQ73{uo*I_}1tWQK%Abe-8*X~K)mH{Q2?+yCV} zyhj%#`KL>Ad=Yjxr!{nGBKU(Mj~3*bNg9=ty9DjI)QO)K)4Q0JocDqHw*JyF{SLZ~ zj!gt{d}TuppyCwEN=z=8ecFBrc}_t!)Y zM-}~p%WRM{Dps|#?ISzZ;@RlUBf!mY;KBKFED{Q~cl-6z--zx&6wM6xlNW#zybvCA zkR<-;X}mr>p7OB2;ng!l_MUaZ!x)Ui@eRH3*QhF+(a1_z#t=P|4jcIxVr!|(YU%#J z2rp}rGGN=J5H}AiI{DZYxUU=|oJsUtz9=$1G)gAz6|;?uIG zX>^4l4YgpTQ*jOhZ+oImrkN9<6G!SKdhH}E{i0+K1VZm3@j=;1(1acvM}8B(ImzV2 z6VY3^ucadk7l7wEj7y62BUcC+=#Ya#Vd{I$^`vbk3T>{RJJq|)#>x5mupF(*wfftl zo5bmR!O~uhZpkch<16D5Bx1!Aep`nlWkzyQF zvC&bfEPn?x4T8?-`CIvw5rc0@Goui&R@FB>u7qh#B}hcks0Q;eR=s?pPW#G#8AO!g z-ms261SZg#lsUpWMl|RR#-WNg!sFE44~e9Hu_G&vhpkAym}~K1tEkjx3z_6YPs6iV zpLZ>|YOmvCcN*8+WzJJOtq@q9?zX?S8(+e2i}S$f3T^dxh-%s_MMz)E=fsw%*3NPzy%!xP+72K+8zQy5xGdbL3!m3edDj)vmDi;;cwn#cir7}fv}k8*wY zM?&U?GihvIysK5{wb-~RR8Ttw@QaEHe{Y=k2FyJ8oe)dkCEqvhQQ*nDu@ac9S$F5MD3fXWHqml*vuoQAIXpW6L+p zW@-%OHgdHJcVfRHn%Cgm5|&8*e3~^gPf>o|-YERmOZe)kQT7F8YE8-CGwu5|0d%Lc z^>*E1z!3UViZlbF=c_bvGZ3Q?lL)UV`610RrWbq35B7y1ZjZbr=YewTQ5RbZRgCG8 z>T2{h>8buTA6*T6>|JCN1xqx2)gn^&Eqzo^_}}{KhX-@(rT`Y>p!Fjj9-w6rMp~-GSiMTNb9bmFd6hq7#kEQ{^Fv4`d)yc53;C?1 z+Q~Vqr1|1#JCq`ZCeR^(%dHo7DFrAlo|WI!c_Tf!WCK2&fa;v1r#ne}`NphU`XzL=qp|)M~$f)}Pr%-$GGv zhP$bOf~C-}(eb0%-QY(mB9wlA9P{a<88;akeI`o+OG#KSM#sNQZ|aC?57u1RMFlZn z7eL*DN{<`-zQN^#rO}8r`ojhGP?7XJO`7-|{lOH*bTTmXLXuopWJEr{T)*V~)ri0i zU)P#)2cIY&t1aX@SKhV)Hj5bedV7AO(6tq|?Y-W29I~A~88|(W3rZJv@l$=3KIeQ2 zkDaZx$<|lS>F6r_tjnhgD_JTW3K*@A`dO&ef!@?k^BOTSeBT9zogIUmh-q#=-XT1HuzhU>CPkMoNKt}H&LFnrvDjF)lM0`xTS8O z93XOT=pN^&ej)r+G=hX^L(bZ2o!grm%#-##ud8~?|K3~5>y5wpG951VnP@){JK{5d zFbjFx3i=u^1W^W|`6SLb3@t(|U4_%WmqA<9ALnIrF2{fAtg=HXu85bA`MUnoKC?bx z&*kpS1~-E7saUO;K!M%pJolF*&=T}WAy>N>eG8E$9>bM$hLEMcCX+ieDM=68ScNBE zH=6(zdevEb%n|B<^GLm8sY|rpMEwm>VeUMO0hxLYVXJUzL`E>7a%S)EW1aUH$8GdD zW!Ji^xczf)4iOR8kJh~(T&~nPT-c-}w#^sB&Z_SlT}Lx3`9ur)@O)E`&edWUfUgu3A(|tkMEIP}yb-p9ie~fO zRF&3lR14^%QGq524Sb=rlO3~B_WZKY;Qtk2>^^^D{181#9r(O+0!J@~89 z(=5hs_y4lwdOhK(mMk_H@wtP)z}2fj{G{9^oX~E|*}Rdnnzps^3);_h-P@XoTwUwY z19>Xyu@twu&a3KD$s6k6;_yGj`i8R&IvB37lO^Lm5V#myj-i%dYr zHkD~8D<5x8rF}751(mL8gv|{>iJ~pyDZ<;Vqth;{$)U^s>0+ zTu)(j9jq{Vp(CZ}e@9`XJDZG>_^kOJW8cLe$aV8<7cP1h;>hC_@Jr)uo4u^_nHo*s zqFL>QiU3wGh)WKvE<)`up)i}$^TuGFKJX|6wh6>rz*PS7hft|48;P|ANkg4nsmrOq z`iC-nPS43e>C2tL9#HF-bo;L1j{POgv;JENwUiT(|09!`pVj*9eC$E>lx2}Ex3lge zV(s>M`=zw^Hpz^XTW@InQTJ^|AuPM3_~WG~;}F+z%}lVxEpVn59D2EZQkLyk^xhGG zCj{PR%wM_e+U||tUg-Tu@4IVT|9f89(y;XLHWLi4#re4E_5b*L=$5ullQnZYDO7FQ z_xv&7`JJNZqvhky+0S4)=WlXRT!P%XM0~>NG)VxF0JGoA4cFUCi`LX>!?}++|CD}m zb6C&x5$fgpTw2oSMw9LJ7f-0Q$aHZ3KI@N5jZgRI0pu9Z~S-JJL?s&9Z z2R}7hl9LenV9+DC&HH4{*SnGs@HF$`?OM?G{@PldpqPW8b*p8Rm5?i#MV%BJbFSZj z0e@R1#4mUFz2+3;{TB7^=Zc|ju*h%pblMG&{|im_RdusQI4j`~D%9b6N)}tdQm|}j z|3|1$MSFMAHTZJ1Z$hss9gjideb(s z3`lHmGya&ISjj?-{DG}rw=McN@yMn9XoYl3%uhE|f{^D0i$k?f7T&!;7_%YPo!ea8p)&B-~x*;E2hc zBvv(`b;m~Yf|8ST!ALDbr~GWEAa$s8{HwtXtRh<{DZIR{Jr~KiLgGR{7k$6~@fskk zKbPC z3zx42d8%P*xMOrL#7_|^@OLVOwnv*X=z{!E>@RaCC3Cf_MtbL%^|Yo^W3pz~;*@>9 zzIrWP*42I?1#(byJAJ)_eZ9AZGKMD&6`?0TPjHHJo5zTqrbUBv zwep1AHQ0M&#Tn002v*)?C|%cms>8zkrAuv?uVn^suj9^JQ8S~`sZrLToIQ?|G7<`v72q^aG60udTHlcNzq%(|JG1FJKwZ8;N=`X~)NS74N( zsu+hO(CYV50>=+yG;CE?#C=rxnS7~7KwrC`AD=i`Gv#OcucqI)@Qe~?febqRL9t+X zul3-&oW`JOY%9fG*0f&=jCxfohP z2R1ONso>-?#kR6s(hg7Vi*x=wT&`0Of*IkDS0EqbyTz{U2+rl?eGVOwa-LS}ie&^J zoWJ2i9@g=|@`ol`oY1)5N@a62O_kAz9%+Zc`*oPg{oP2Uy2~ipk_L#L;o4-VTe1#8 zm#nQXXrtBP&1~5QwR}1kw0Gs7ga6R5` zJ+zowSpns$jdizDxD)G3^Je`0%!J&Yv)K*^qk64(U>U< zwUNTsL9TmZ(Sx3R?(?erxeH$j?i$`}$I}DA`G_r>A8kY+>_xwUPvY5vyC?SU4|@gBl-0jc)}IU8nN-I@V!TO=h=S5&=E2I zT}eBMF7(n=5{L1_DR7BXw`g4HR`xVkRsQo@;euWKBA`(eR^^S|d1Hy6P#7}h>@<{t z)!lwl=KKSMsGrKuTXjqu#FcNg&>z?wvAZ4Ib+mNhhj?leB*8;N5#BQdeGj`CE0hOh z6LrsVH&ciROZeMsNIZYvrz$30FcsDj51Ztu*pPxyfxumrLyGf5v%JAV9l$ZUd>LJR+5o7 zpr(r;YdQM9-3B@)_0=QR7_aHyb6Ia`v5ZL+iymo;ev0OauaU-_re!JD58LQ(6DlV~ z4S*OD)GeiB%d6OXoE)*n%FniQ7Y&w~^Gh)zoEVCN2ZEm5h5PhF=FM(^O#tUva)f8}p80b#!sB1dkds^57DAdl-O$rXm{=dC_EU`~id$)dEme z>Wy`>vDMX`>63LF!ZcYn0MkDKYp9(0;YDkQs1!1+T=gF6C^&ImBZFcBzx_#*|OYNM*%VKFi z0Fz6ccS%xuFQ4PIavYl~7CCtd-ymDRMNS(+nt*E!q{ddtc&6Z=zt(x-o4gzkc*%UA zvW03v=5w0Wi7u-{gab3~OXqD=i=n7&TL&mBbg$5#(vNEILLL z?ND`dd7QQ%J3}DzKojuAC>YC~C1cvbxU}carSfMc&#M#c=!Ergw=6tgY>#pL~HnlqbxIC|hotP7}kC+^Xtueh;bkIi~ zBZ@^NOF|szMH=t?35w|M>^#yV6EJP@7AiWv?i~o8VNLUI)%$EtIJ|SQAqi=mZ6dwB zQ#80G>?QL0czW`>9RvULqcZCE#XDy?CZdVC6J!hK$##qUG-~y@1L#Ug8>Sr(eQ_Dg zMaK2bv8wO5XZqRAafIYQrzNOF1h(8=O1g|lD=;>S_DK%j{C!{P*|NJavOpgY(Oi~b z_;nY)3y#~0^>lh$3XgN83nB4^ql~&6y9LR|)E9>&-VL^1$;v}?f`BF~nd)4yp>8_A zUh{jy@#7Y8+_X+P|4_)qLdD=?CQ$b4vy`bwkZV-xun*~BDw;@txbN3bKu6p`R|0}0 zY9Y1{_VC2SgrzWf;+IFUgTQRwIGE6H5+91&vApjjZm+1X*}rcV+=b=>a#qp9Xe9_( zm>qKowtIjw)7wDD;gj0oFD2C^ou`rz1`wDHEoCV0y zpxG)y5pLQrAQ|2KF8sdV@eX)i7mK5T&5L!UqF}<&!e`mriU7=UqAn0oh>~Ay*3ISF zw$bfur!k3CT8L)8HP<)T&wuMqms`@X%tn8=%MD0-X12}4JyL)qeKE@6RTO-ZUT|Gr za46O4uhHzlzJKfh)CKac)S(;!r_WEPSV34*8RHtMe*#!135(kQJm}JaW`Bwd=zXbi z5*dw&J_9O3vf>Zo`(lAuVgPzpXURlz5Mrasw2=?ipQ%t*eNJT-4<%Ka(!JR6c#iJV za3ox^E|cQ65RNW1NiWIvnNvhQCD#DkVaw)7rH;XdLh|}!9#s`dmp739`2E0H)l6>B zY|B>-ehsflf=F36CLxJ-{p^+#+5#FGBCUWHyn`;b;XTDvZT4G)n<|)gq1P1#6D*W^ zjxamIQG{jE%Ugfz0mfjl&hH)~Fsv@@zkDSr0*$js6_QkP^LnQv0j1Yh0T4lMAd&ep<#_{iM3U?chK-A z?4BX5F(c0%_YqFI>{_}g0Axk2-fa}?x(Ob3VYq6*rRGE|)g9~odD*7w*E^Jye;VvM z95E^HaaiBIz%$Q3{RFF=3%4~+d}eNVVQbllU*XLagD}wnBL0kF6hgeuDbR-I#}(4j z>U6^Xuh*kf6!2{JVwALz40E+MpZpbhWbXK}nJLds3HsBPoK49D+OT}lcy#kJF&|iM z|IlSu_X+`8V!S;`tS~LLbW#_G)SX2hOdVrzoh<8^cga=sfa^9CLhc}SpeGu zkYu-h-z3%&cJL3{Wvn)RWpVQCP#kK^RB!y*ziidFCUn$mw2JlBaaIqDXDlKut??iu z>tSxdQhh5FD*21J8_qda^#xkbTtx2i6Cxx*K9-c1n~fehhP-D4j0#MP+>SsckyI0V zeF%6u$SA6ioX`ok<%lkxe$~qv1<&ZGy@omJ+Sd2Wbb+H^O|;h@9QgZP&(t!+moLb` z$3#dUa3Y9~FJVI-Yr5Mmr!Z;eiN2CXPOXlIv3{GD4tpSBetxUf_l_y>aW3?Dsyxt~ zxvPb$?z(o8@b4oxy!dCU0&1P%?DZj{PU7KPTGC$uOd#Suee-Z`%e;0Xv4H0+BcnBc zhf2%3DcRe8iqg?1RO#RTpA>8QF{=VU>CzLCn*Jx8)|jI5mV?@%@pV9MSd^+EPDR8td%pjo3l%C>m-y+WstKV|8ni1HNmg zkHp+C?u@N%Ta$$4Rwvy+wWn9fCI5HXBq|yQ`opH7<@LaVbTSm-u1$D;>LeI1r;0_G(XjYNfvs-q2K&PbGQI?A-&2vdB zQ|adGmM#NpHkbV2uw`QvhnKG8jhT$9KRe0sl5pCSjJ;GN`oq!Wl$$$PP%o8YDM^0Z}&0}P*3<>ljvw=~r!m0p2jnnit93}z|H*5SA>l*DoaZfPc zG)cO<5Zr^%iCf}M!EGOfx_ucw&G97VLQli|szOL)WPuPMyOUKM!7f=7$rhlaPG#dZB1aP?h z&n12FI&=;eVRiu2jl>yze=0B2e*I8dQj-LHsr9k8mJEFf%989$B zMM5H@idcl^0Cip3KQn#>$GP$n1+ZDJ5wI41Y?K zcD9mGl-G@ab|n{io`_pYOS&xe5IjjM@l}Qy=Tg!JB3I<55{**rwj)6^azA|OmfFHK zKz=+qQ8DS0gk_Ej>uzz<7aSg4@aUW;9eS!R`S%|FG7g6&oG^bhkTml5V&1Lz7AM~F z`Frmjhux(K(;_u^XfR~DN_V}MjmVPfpj(a_i~;foh|M)@L)r3xGo-<$QXBQU8E1Qc>BO;%w^(Ld~>ek8Qvf4aC#O1 zR#UR)$a`Cx;bKoi7LPxReg-)G2}T{oNuQ$7ge8G{yK+7?#mO*bon$+??xmTt1z|e; zM4mN-I%}ilokPVi9))hZX$2}?7+;qPz`2Aq{p039=)EFy!1aBf=B5MH-cigi6loXbQ@sPaGG#sX4g-JMEL>Q!KCGPWf=V=gQ>^E1R5K zYGJN=d}R(MGM141iK21ktuRt;F7g_C6a0ur1o>o)T@`wVB=1uzK@GSS7_5h(W9OEo$RrB6g<6VWgJ z*sqNxNSDcrgD8;c#3#JHzB{jgv%4>r<^s{+uElsQVCw#bkJ64#5~w{V<>@m1p5y}U z%JfKONEXWbP`8DA>lhe_I9U<<5!U_6_mPXFwEg^+>ywrWIy{fCSf2j*rH(*b|AyWc zAe&_W(0A0o@uN?+OY$5!Pl419Q^SWTnBaj{YquW7H*YoClvUmtrsmtKC7lH_^+pOj z8J95alq+0YxeTTI7qE|*HY^)UKqK>tF8rm!bha^tC0_pV^*2)hH7{!LdGy+k^U0J zl%XccjYO!o5n#4n;1if0CPgs8RpW~ZhFW-SnxT~87n=PCL^)?U+@9Xa6|q%H?_vIS zQ%tO8dUQVhzJ=m5&O3J0H~%{;KsWDriR*-&#q3?65s**aWpt-dkp$ZWdR1g4((;Xx zI3ibi>z2t=;AZIjt!sy&AT0WDcf84%SQqw9e#bg0u@McnmfU8`N4hc(Of?!1yISY4X5t~CyQN0Q^3DZ(}l-Bg|x7>*Kv}QORh*4Qn)WMa5&;Ey^ z3KYK(QPsN+~t)#{KBP^0G)XrFDtzv>|Gsx;g!NOVV8n3S-IIH4++pE{D;1b zsjqK*<4fF}rVN%Bdu;U|PQq`E>2*Wu09!?a$i?Y>kq~HxCC|Mw&q;*MOznC92WJ>-6`rWQLFf4ONvs zG5qyHJZScS)36&1dzf*|JIY*gcBRE(*pmZjJ}qyD_(lNZxqitW8@1kcFGZ`#{%J|+ zUb{h!zKDnfhm$LlUTD$mL9vB41#o{$yt50|`)mPfA$cc1Zk z?sZNA_2HpfE{B=7-P^vw_!AIZZ=$L_%vky8i=|3cd?mjK@D29-)CCxtElOVP`b3n| zEaa{BuE$^t1M)7B6$%|>VS6B#FH`%v*z2Jfgs`Yj$9Zw_4Q>0MmJ`b$u5av@hx1-T z=06B~yhPJ+0x~=J$c4l=L@Lrau9vK8tm_DwF8}N1y5HIGzP}=*L2K_-v1!z9?Y-LQ z+m5YPDX~kWyo=Xt#j z7Ue~0EYsn@xcA~NDzx$GU_Hz)KyOSm^K_BlpJ@Si8U1TVeTIUCO>7WjUX~zaQhs`V zsO!1!?ay57&}F@sEyxg!eA=K>5gL@t?25uiQNZ|7%yADa&)oR$or<^W_e}-%wsO$cIewCi^xmv);YGj z<^_j=g6qJU(RQ{>3v<&@^CDS#-PY+g?vNesWZ1I~7{VVk%Ck}ZPaCNO%*Ti z7`Ig(8iU zT32{Zm&-@$UBNWq-yY><3M8ZkT%Ua`VrfEb2|zyTG(UPz*2skq>=H5T_j%>mAv`1r zPaE@{n&6n#ZS$}S5Rx*o35@Cca$LAV=(8H}^EcbMS53J9PiRm=UmKK^QyWd}vdKdjHboZf}Y# zdNGo1zrf$K)M7J*Y4$5yB4=Eu@u~7zL(SFf(L^TyJSFTuwI#>=&DtS>@gvDK5P~P3 z2~e%kd}d5nsuISXot>R5{OiiG%FaFdLGE_2evR;$dx;v5Qaku4HX=c~78ZCjuia%j zGxRvFqmRfuvY+XyL|(i?hOGS7kjU4qVu7<G}~<@qU|^pXbVlY^0g{9*TAoSZTD9Zvn>X>@LYNpCR7=GUjRM655q& z$SVzDi4r}E-3wG|7x=AehET~(Tvl|}!r_jY#OjVNp-$!au%f(#=_3n`wA$Ty7@L5$ zeQ9wmDiV{~fpjx}8h6tpxPv$UB2CjxbX?gwIjlGsliClFa}&xt^*hl0xxdywkiU-2 zE2p8{ff#*Bd}M+*Ea64+qP=!jFBp*))plKho=+lv&sco@&WzjZg@jFgiVjz2AYmrJ z+{Qn(G2vXc8V0nq%=TrAkkV%DEx@t7W_bqrUti2>YOP;g<-84&Mx@`=vFOZaN7mJt zJMpXt$b;SKQ!M3;H(0ap&!YI8n27iSqQeERO$zuK<&)Kyswp7i30>ItVY{%adBg<~ zQM#UnueAp56pTXq#quIY7&Y$8)E5u6rv7Rf{sqddg>KiuDM?I7leT2sZ1iqH;=pTcBN2+Hx598~cu4fjoz!^gtL zLwVZU#B#6l>QjxwjUU@0{>W9GyOH*NMrh5Z0Z~%op~X*1bHUXC9A>GZ-K__tWCc{6 z55N;>X?^W|sPExVyoa%wa_@rnEYeXv1M|{+#I^Fc;anLx@~1If)KTyncO_sVw^H(l z&!eSDaBxHK#&FvnqtXjqitYdM%l$zxh=|8Q4qiaqL#ieP_ep5m$%#(2lvm2n|KR70 zm{4Nw2kI_dLEK?d3iP%Ze4%h^g54Y(2MSM!3o^=BY--%RkQAuPS!1g%;IIA>)5j=_DZ)&_8?h@TBxn`INrA5XXLV0+F@( z4x*TnNKKB5H)}n{!Ko)Xp=^y53|sU&7*6RM;ZPmwd73t0R}ZM9RgOnBqVwT}7VS%~ zG~2!~r*t1CiQ%w_$8OFJbhrASd!+PHMo04pGK@a;9%pF5?Q7Q8#gue-X;!W}r7vd& zQTn!@iLjc;z6Ve@P1N*Lwm}5@{uJ+O6s;H+RDGzS7&!j?}B)=#-dChDpv=ZEDrwhJv?23 z1?g$=AHog5<7^thSF5AzRr*TyFZI&)82atr*r)jqQ^2V5| zuH60j%sQjKeNMyXO;-XS)fO!te}&x>OA7mXPQmZXwI=Ay_%G~ovFcncM_UDF*+tVJ z$MY>1+00yD^$d=Y8Tk52^Wd0Q%ui&|o@@rYX78L63pA&hm$FVC?T?kP=(m)(9|8Nz zL{Hu5;}m{E2Q#h{Z4|Uipi}1XthqO=^%V0U>!|=(8l7f6ZOgBh7rjHwVCxi4pGLS3 ztv8tN<7KoC(ODRu!tFE%{W2;=w5Nxul8Ucz53O3(Cc}^otvm#G?8U~1jgqWfqepb7g%>R`Rv+(E0811>K{g1bbEAgf9{c*O-utoW(?x z(J>d}pGnW}E9G!uV+e}x36la*i;`J~F!a=F^rJn(s}o-#v8>eqV5ATWOF4Nm`Gu%eq<(-QJd0z$MJc$_G?3_MWxf6$?ZvDV7_MLQ z{JxM=t}=hdg`~uMd|_6a*tTGD2HD!?8MMXy;p}d64_|>wV1NmP5f zHYf=t~l<(a?6YhTAxP-xtLzOdefdUH$hgmzAAfm?XyW85m!Olwq; z;YDojh{sL`j#Io{M^13SG^(}&&h8nZgnPcO9s<@7d}DYgOP`0iC#P(PEc{0sm4a8~ zD4d<5-mgFTA`-Mz5ti(Snbb4f7?in3+gmx6cE7v3`1mUDHtV!gtAP|fFBxaL0=8XW zpkcn1i(P$WyvS2z9L}7|2 zv;Ly$s;eqoo%FY34+OuJ+qwFkVyuHIIKDk$3iQd=4E?%kHu&Yi^V5o43E4`9DwOcC z`27yZa(FL5GQ-2e?XomyiPz-wh8uHnU2#algO3z%r|69lO>F=pe%omIuJZ4aLSVzr zq&soFiB?87zYCq|9+lOHUHML&H+p#Z5xc9~D9Go^%z5fEeP$7Nk(U-cy+k6c1iPdh#ZfX$E^# zH~rZysB>ktt3R7&I0iy>tFEZm*5PW?o7339pZ)e&*85dr;ZPSg{+S@37D{NWaPSFI z#9>*cN!jS`RYu75&g~h7*@cM*Y-c5?rWJmidR{okB6W9%@#MsWg5aZf_IDHF;eo40 z1YoZGHAo*FKSS+uBXekwHa8$a{T-+DsCy$-=hb!W0D^&>=Tht}@3850SykAXA`58`woIv|sJ3k|H;uljh7CSqXLGk?@q*SV~ndp*{XT|iT zjmor>dRRp$Ubpyf2Y{M^ZGx^zS|UwU3J^(#lY#+>-zQ)|dvqOZ9Ok?}(&JdrVIV*{ z(=<=vC@R@y&YF_?`kM!ZlT(>+w-(nP&q);0E3~m5A3Qq{eCH2P$QPCU!9_uP^qGD@ zHtXW*PiZvNW8$g)_n@Hr<NM1-hw1 zrxv;;c%2;EH`gV>wf#DATc$!2TkN7Nt|PF3D#^TwemE)ur@5%RU(b3AzvrfzV@d9m zB{xo^Lz+`^H2sQ1$u9<2DwqP#_3H+%|6G=+8lZP%LycLzfU1%wrB?h28z6u6zvNY7uE`qODQfDRX*2ev#RDKp-zdSdh*-5T3D}u@z9c{inqCb8* zb&-YHX&|yQJ2J?g8Y5bS3Lui`$ej93A2nJkM@LBJ%4Kv?DrTrusoE`w*;(sA>DXD6 zYmG>w2i0&-vlFueLoWD0b~PSND+@}A5u6>hJEzlQ&?|jhPZ$_|j&^u>&#|6UG5GDx zDrEdEivR*}ZhDEc$uY!If(UJ3Vw>HHUY)V^T0Hetp4d3~n4L-cX7bqU}Xf zrkG&VRF{y3p7Yg#qXenNYaHa4bccC3mb&-y^^AwheFqW0U5o#VLty`y2oQqN${)~T zDg1;k`q1bL&7J0kBnu1EM3QGULhI~IS&YEl+ki3tNr4nD-p@+6YN*?I=XXZ{K(zjR<4>Wu@6;?FX4B8EXWucg*1yceqOLN8g^%o7_oM_phy^-LTWvy(| z{?UfCmesI>2Qb7+{!dyXQpzo*u(NwJP7`UukzM6!UNXF~8M@DsL-2xq>Z0m0d?_TH z333T`&wnzrQpUm06rud6Rlku_+lfOmXVzQ%gsb?rZsR;cgQApB95s>&nYBbx$Li-W zu{~SMVf16Sf88+nQt9vD>(f2FhgO|)A+>it*!T5rU>vO>S2i_7gwaj`5rFm<*J8v| z3`Xq_iKg?d<2P&sZ1QBpK&2-9uql~pbysNl2pQFR=aJT32v7KN+Iw_6&15*35%zg8 zIUr#U#H`M|t;fFyNZusMU6v`}Rw%4!0utB(-%TpFA1AoB)V4iEWU*;pi@pt3J(@MI zbzi8fy9=^cMEnRYlx36rF*KH*v_9yU@l zejan+>*M#*kvsi8bG5q`t*pZH0@Um%jp$h}C#o%hg$G#RDWjKRwP(RbyLW)Vd%i>52cQo2jqp z@IDEUhDb2cj-%IRR>BazToMGZYnstnkWFBZY>3G{5e8eTwD|x0I7lX9wATufI!@UD zHf7N((TQNyV8RE=1af@HVAH{2=ZgGF*i@+#V{?mDM*Rof7IFZLjzRaYlS^;ACWWv`!{0-jo`+QFbT;zSb?yshJ zwkda+;{6=(zioxGxg3DEs!9fGi7wjkZ`edZQXVpO8$RXk?`}|^4$S}=%;qs|L&u&ZK#FOaESgNDsBGz literal 0 HcmV?d00001 diff --git a/cmake/MacOSX/openms_logo_large_transparent.png b/cmake/MacOSX/openms_logo_large_transparent.png new file mode 100644 index 0000000000000000000000000000000000000000..328d8d7cbb2fcd463c137a05715c22c446370e6c GIT binary patch literal 14066 zcmeHuRa6^c+ieoG6bhkuu_DExSb<_Ggkr@lxVyU*2-@HUiWQ0#4erH)6l-y}BE=nw zOM#Pq=kBa?{jdMxyU5C9*34w)eV=zf``P=MNL6K70z4`_002NBF9%fz0DvF=eQ>eS zd*JP_2GL)ST;z1!0RS9~e;?on0lF^qPD&3Mn1_b5m4~;fn8+nd|g$===E)Wwq9 z+08oRP>c!ypa;l9-)Q<|9xVE%8EBu!q$ni=5pn;t;^OW7{q~cH z{M6>6!}48aRQA>mOa5(^`x2gfz#jJ&wVD+*9?FR=&-1PGoBE zFnLrwdzHI8@?&4_x5Bo8_F!vfD3sCO5B{w}bV%KRz2h37m!UT(Db5iReTsVcU_~wk z70?#sfYH+${~* zAo8=y)85_*Q~fj=#Cg@0ud|cab0~Bu#RrZ+Y|LFeupj?Ma3!%72l~Tu?<1c}K^I!O zo%8$~{9_>_3WeU~pmD4mP!4%Wy=p%23n-x^uOFJNp*|6N#im{Cz2$IQeyy-U`E@)J z(c1*YU@~txm2nA-F+?$R7_xse?mF%)X*p zsd}0|!p%NS=g#krvzfY;Ix~+z*yty~;1)Dn!r&&4?d-RHzqGYn<6&17`4jB}Tc>Sm zyTzL9rNFWsOupKI?hHI2S2 z6uJi4Pp#sMbALth;hA^NRY767J08J&t@$zW%m??1TYuIHeuI8BXqUZv)2}79kwm@* z|6G`ld3j&ajhLX Z+^@t| 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 b2miWNsI8vWcvResO8_l3J=N+5c2WNaaYq6E literal 0 HcmV?d00001 diff --git a/cmake/MacOSX/setIcon.sh.in b/cmake/MacOSX/setIcon.sh.in new file mode 100644 index 000000000..3f2395c88 --- /dev/null +++ b/cmake/MacOSX/setIcon.sh.in @@ -0,0 +1,39 @@ +#!/bin/sh +# Sets an icon on file or directory +TARGETSUBFOLDER=@CPACK_PACKAGING_INSTALL_PREFIX@ +# Usage setIcon.sh iconimage.jpg /path/to/[file|folder] + +iconSource=$DSTROOT$TARGETSUBFOLDER/@OPENMS_LOGO_NAME@ +iconDestination=$DSTROOT$TARGETSUBFOLDER +icon=$TMPDIR/`basename $iconSource` +rsrc=$TMPDIR/icon.rsrc + +# Create icon from the iconSource +cp $iconSource $icon + +# Add icon to image file, meaning use itself as the icon +sips -i $icon + +# Take that icon and put it into a rsrc file +DeRez -only icns $icon > $rsrc + +# Apply the rsrc file to +SetFile -a C $iconDestination + +if [ -f $iconDestination ]; then + # Destination is a file + Rez -append $rsrc -o $iconDestination +elif [ -d $iconDestination ]; then + # Destination is a directory + # Create the magical Icon\r file + touch $iconDestination/$'Icon\r' + Rez -append $rsrc -o $iconDestination/Icon? + SetFile -a V $iconDestination/Icon? +fi + +# Sometimes Finder needs to be reactivated +#osascript -e 'tell application "Finder" to quit' +#osascript -e 'delay 2' +#osascript -e 'tell application "Finder" to activate' + +rm $rsrc $icon $DSTROOT$TARGETSUBFOLDER/@OPENMS_LOGO_NAME@ \ No newline at end of file diff --git a/cmake/MacOSX/setup_applescript.scpt.in b/cmake/MacOSX/setup_applescript.scpt.in new file mode 100644 index 000000000..f3aaaec98 --- /dev/null +++ b/cmake/MacOSX/setup_applescript.scpt.in @@ -0,0 +1,89 @@ +on run argv + set image_name to item 1 of argv + tell application "Finder" + tell disk image_name + + -- wait for the image to finish mounting + set open_attempts to 0 + repeat while open_attempts < 4 + try + open + delay 1 + set open_attempts to 5 + close + on error errStr number errorNumber + set open_attempts to open_attempts + 1 + delay 10 + end try + end repeat + delay 5 + + -- open the image the first time and save a DS_Store with just + -- background and icon setup + open + set current view of container window to icon view + set theViewOptions to the icon view options of container window + set background picture of theViewOptions to file ".background:background.png" + set arrangement of theViewOptions to not arranged + set icon size of theViewOptions to 128 + delay 5 + close + + -- next setup the position of the app and Applications symlink + -- plus hide all the window decoration + open + update without registering applications + set theXOrigin to 400 + set theYOrigin to 200 + set theBottomRightX to 1030 + set theBottomRightY to 785 + + tell container window + set sidebar width to 0 + set toolbar visible to false + set statusbar visible to false + set the bounds to {theXOrigin, theYOrigin, theBottomRightX, theBottomRightY} + set statusbar visible to false + set the position of item "@CPACK_PACKAGE_FILE_NAME@" to {470, 140} + + -- change the icon of the OpenMS Folder. + + do shell script("cd /Volumes/@CPACK_PACKAGE_FILE_NAME@ + # Rename to just OpenMS-version + mv '@CPACK_PACKAGE_FILE_NAME@' '@OPENMS_DMG_FOLDER_NAME@' + # Take an image and make the image its own icon: + sips -i @OPENMS_LOGO@ >> ~/logfile.log 2>&1 + + # Extract the icon to its own resource file: + DeRez -only icns @OPENMS_LOGO@ > /tmp/tmpicns.rsrc + + # append this resource to the file you want to icon-ize. + Rez -append /tmp/tmpicns.rsrc -o $'@OPENMS_DMG_FOLDER_NAME@/Icon\r' + + # Use the resource to set the icon. + SetFile -a C @OPENMS_DMG_FOLDER_NAME@ + + # Hide the Icon\r file from Finder. + SetFile -a V $'@OPENMS_DMG_FOLDER_NAME@/Icon\r' + + # clean up. + rm /tmp/tmpicns.rsrc + ") + + set the position of item "Applications" to {160, 140} + end tell + update without registering applications + delay 5 + close + + -- one last open and close so you can see everything looks correct + open + delay 5 + close + + end tell + -- Weird behaviour of the CPACK module. Sometimes it does not write the changes to the dmg. + delay 20 + end tell + -- Codesigning does not work here. You have to do it manually. CPack is not able to perform post packaging scripts. +end run diff --git a/cmake/MacOSX/sign_bins_and_libs.rb b/cmake/MacOSX/sign_bins_and_libs.rb new file mode 100755 index 000000000..b319c172f --- /dev/null +++ b/cmake/MacOSX/sign_bins_and_libs.rb @@ -0,0 +1,130 @@ +#!/usr/bin/ruby + +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# -------------------------------------------------------------------------- +# $Maintainer: Stephan Aiche $ +# $Authors: Stephan Aiche $ +# -------------------------------------------------------------------------- + +require 'getoptlong' +require 'pathname' +require 'set' +require 'fileutils' + +##### GLOBAL VARIABLES +$dir = nil +$codesign_tool=`which codesign`.strip +$signing_id = nil +$DEBUG = false + +############################################################################### +def debug(message) + if($DEBUG) + puts "#{message}" + end +end + +############################################################################### +def deletePRL(path) + if path.to_s.match(/.*\.app\/.*/) + return + end + if path.to_s.match(/.*\.framework\/.*\.prl/) + puts "Deleting #{path}" + File.delete(path) + end +end + +def fixable(path) + if path.to_s.match(/.*\.app\/.*/) + return false + elsif path.to_s.match(/.*\.app$/) + return false + elsif path.to_s.match(/.*\.framework$/) + return true + elsif path.to_s.match(/.*\.framework\/.*/) + return false + elsif path.to_s.match(/.*\.dylib$/) + return true + elsif path.to_s.match(/.*\.so$/) + return true + elsif File.directory?(path) + return false + elsif File.executable?(path) + return true + #elsif path.to_s.match(/.*share\/doc\/.*/) + # return false + else + return false + end +end + +def sign(path) + `#{$codesign_tool} --deep --force --options runtime --timestamp -s "#{$signing_id}" "#{path}"` +end + +############################################################################### +############################################################################### +############################################################################### + +##### INSTANTIATE CMD PARSER +opts = GetoptLong.new( + [ '--help', '-h', GetoptLong::NO_ARGUMENT ], + [ '--verbose', '-v', GetoptLong::NO_ARGUMENT ], + [ '--dir-path', '-d', GetoptLong::REQUIRED_ARGUMENT ], + [ '--signing-identity', '-s', GetoptLong::REQUIRED_ARGUMENT ], + [ '--codesign-tool', '-c', GetoptLong::OPTIONAL_ARGUMENT ] +) + +usage = "#{File.basename($0)} --bin-path PATH-TO-BINARIES --lib-path PATH-TO-STORE-LIBRARIES +-h, --help: + show help +-c, --codesign-tool: + specify the codesign-tool manually +-s, --signing-identity: + specify the signing identity. Needs to be in default keychain and unlocked. +-d, --dir-path: + the target path where the files should be signed +-v, --verbose: + increase verbosity +" + +opts.each do |opt, arg| + case opt + when '--help' + puts usage.to_s + when '--codesign-tool' + $codesign_tool = arg + when '--dir-path' + $dir = Pathname.new(arg).realpath + when '--signing-identity' + $signing_id = arg + when '--verbose' + $DEBUG = true + end +end + +if $dir.nil? + puts "Please provide a path" + puts usage.to_s + exit 1 +end + +if $signing_id.nil? + puts "Please provide a signing identity" + puts usage.to_s + exit 1 +end + +debug "CLEANING frameworks" +for content in Dir.glob("#{$dir}/**/*") + deletePRL($dir + content) +end + +debug "HANDLING DIR" +for content in Dir.glob("#{$dir}/**/*") + if fixable($dir + content) + sign($dir + content) + end +end diff --git a/cmake/Modules/CPack.distribution.dist.in b/cmake/Modules/CPack.distribution.dist.in new file mode 100644 index 000000000..1377d7aa3 --- /dev/null +++ b/cmake/Modules/CPack.distribution.dist.in @@ -0,0 +1,9 @@ + + + @CPACK_PACKAGE_NAME@ + + + + @CPACK_OPENMS_ALLOWED_OS_VERSIONS@ +@CPACK_APPLE_PKG_INSTALLER_CONTENT@ + diff --git a/cmake/Modules/CheckLibArchitecture.cmake b/cmake/Modules/CheckLibArchitecture.cmake new file mode 100644 index 000000000..52e661029 --- /dev/null +++ b/cmake/Modules/CheckLibArchitecture.cmake @@ -0,0 +1,75 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Chris Bielow $ +# $Authors: Chris Bielow $ +# -------------------------------------------------------------------------- + + +## Check if link libraries have right architecture (.lib can be either a static or link library for a dll) +## Motivation: if 32bit libs are accidentally linked against a 64bit OpenMS, weird linker errors (symbol not found, etc) will appear. +## These are really hard to track down, so we check in advance. +function(check_lib_architecture link_libs) + + if (MSVC) + message(STATUS " Checking architecture of link libraries ...") + + ## check for 'dumpbin.exe' which comes with every VS to extract architecture + find_program(PROG_DUMPBIN "dumpbin" DOC "dumpbin allows to extract information from (link) libraries") + if (NOT PROG_DUMPBIN) + message(FATAL_ERROR "\n\nCould not find 'dumpbin.exe' (${PROG_DUMPBIN})! Please make sure it's in %PATH%.\n\n") + endif() + set(LIB_ARCH_TIMEOUT 3 CACHE STRING "Timeout in seconds for running dumpbin.exe to find lib architecture.") + + foreach(lib_file ${${link_libs}}) + if (${lib_file} MATCHES "\\.lib$") ## ends with '.lib' + get_filename_component(LIB_VAR_N "${lib_file}" NAME) + set(LIB_VAR "LIB_ARCH_CHECKED_${LIB_VAR_N}") + if (${LIB_VAR} EQUAL 1) + ## Architecture of ${LIB_VAR_N} was checked already. Force re-check by setting '${LIB_VAR}' to zero. + else() + set(${LIB_VAR} "0" CACHE STRING "Checking of link library ${LIB_VAR_N} architecture (32/64bit): 1 if done (will not be repeated), 0 otherwise.") + + ## call 'dumpbin.exe' on each lib + execute_process(COMMAND "${PROG_DUMPBIN}" "/HEADERS" "${lib_file}" + RESULT_VARIABLE DUMP_RESULT + OUTPUT_VARIABLE PIPE_OUT_LIB + ERROR_VARIABLE PIPE_OUT_LIB + TIMEOUT ${LIB_ARCH_TIMEOUT}) ## three seconds should be enough to get the first lines, which suffice to know what we need; big libs may need much longer! + ## do not check '${DUMP_RESULT} EQUAL 0' here since a timeout could set it to 'Process terminated due to timeout' + ## get a shorter version for (faster) regex matching below + string(LENGTH "${PIPE_OUT_LIB}" PIPE_OUT_LIB_LEN) + if (${PIPE_OUT_LIB_LEN} LESS 601) + set(PIPE_OUT_LIB_S "${PIPE_OUT_LIB}") + else() + string(SUBSTRING "${PIPE_OUT_LIB}" 0 600 PIPE_OUT_LIB_S) + endif() + ## check if substring is long enough + if (NOT PIPE_OUT_LIB_S MATCHES "[Mm]achine") + message(STATUS " - Timeout before data could be acquired. Data was:\n'${PIPE_OUT_LIB_S}'\n--\nMake sure your machine is not too busy or increase 'LIB_ARCH_TIMEOUT'.") + else() + ## we expect consistent architectures, output can be + ## 'Machine : 8664 (x64)' + ## or + ## '8664 machine (x64)' + ## (similar for x86) + set(M_64bit "Machine : 8664 \\(x64\\)|8664 machine \\(x64\\)") + set(M_32bit "Machine : 14C \\(x86\\)|14C machine \\(x86\\)") + if ((OPENMS_64BIT_ARCHITECTURE EQUAL 1) AND NOT (${PIPE_OUT_LIB_S} MATCHES ${M_64bit})) + message(FATAL_ERROR "\n####Extracted from lib:\n####${PIPE_OUT_LIB_S}\n####\n\nWe detected an external 32-bit link library ('${lib_file}') which cannot be linked to this 64-bit OpenMS! Find or compile a 64-bit version and run CMake again! Evidence see above. Expected substring regex was '${M_64bit}'.") + elseif((OPENMS_64BIT_ARCHITECTURE EQUAL 0) AND NOT(${PIPE_OUT_LIB_S} MATCHES ${M_32bit})) + message(FATAL_ERROR "\n####Extracted from lib:####\n${PIPE_OUT_LIB_S}\n####\n\nWe detected an external 64-bit link library ('${lib_file}') which cannot be linked to this 32-bit OpenMS! Find or compile a 32-bit version and run CMake again! Evidence see above. Expected substring was '${M_32bit}'.") + endif() + ## prevent this function from running its (expensive) body during next call to cmake + set(${LIB_VAR} "1" CACHE STRING "Checking of link library ${LIB_VAR_N} architecture (32/64bit): 1 if done (will not be repeated), 0 otherwise." FORCE) + endif() ## data was long enough + endif() ## checked already + endif() ## .lib-file + endforeach(lib_file) + message(STATUS " Checking architecture of link libraries ... done") + else() + ## not implemented yet for Linux/MacOSX + endif() + + endfunction() diff --git a/cmake/Modules/GetGitRevisionDescription.cmake b/cmake/Modules/GetGitRevisionDescription.cmake new file mode 100644 index 000000000..5960017a0 --- /dev/null +++ b/cmake/Modules/GetGitRevisionDescription.cmake @@ -0,0 +1,264 @@ +# - Returns a version string from Git +# +# These functions force a re-configure on each git commit so that you can +# trust the values of the variables in your build system. +# +# get_git_head_revision( [ ...]) +# +# Returns the refspec and sha hash of the current head revision +# +# git_describe( [ ...]) +# +# Returns the results of git describe on the source tree, and adjusting +# the output so that it tests false if an error occurs. +# +# git_get_exact_tag( [ ...]) +# +# Returns the results of git describe --exact-match on the source tree, +# and adjusting the output so that it tests false if there was no exact +# matching tag. +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +if(__get_git_revision_description) + return() +endif() +set(__get_git_revision_description YES) + +# We must run the following at "include" time, not at function call time, +# to find the path to this module rather than the path to a calling list file +get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) + +function(get_git_head_revision _refspecvar _hashvar) + set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + set(GIT_DIR "${GIT_PARENT_DIR}/.git") + while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories + set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}") + get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH) + if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT) + # We have reached the root directory, we are not in git + set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE) + set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE) + return() + endif() + set(GIT_DIR "${GIT_PARENT_DIR}/.git") + endwhile() + # check if this is a submodule + if(NOT IS_DIRECTORY ${GIT_DIR}) + file(READ ${GIT_DIR} submodule) + string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule}) + get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH) + get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE) + endif() + set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data") + if(NOT EXISTS "${GIT_DATA}") + file(MAKE_DIRECTORY "${GIT_DATA}") + endif() + + if(NOT EXISTS "${GIT_DIR}/HEAD") + return() + endif() + set(HEAD_FILE "${GIT_DATA}/HEAD") + configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY) + + configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" + "${GIT_DATA}/grabRef.cmake" + @ONLY) + include("${GIT_DATA}/grabRef.cmake") + + set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE) + set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE) +endfunction() + +function(git_describe _var) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + get_git_head_revision(refspec hash) + if(NOT GIT_FOUND) + set(${_var} "GIT-NOTFOUND" PARENT_SCOPE) + return() + endif() + if(NOT hash) + set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE) + return() + endif() + + # TODO sanitize + #if((${ARGN}" MATCHES "&&") OR + # (ARGN MATCHES "||") OR + # (ARGN MATCHES "\\;")) + # message("Please report the following error to the project!") + # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") + #endif() + + #message(STATUS "Arguments to execute_process: ${ARGN}") + + execute_process(COMMAND + "${GIT_EXECUTABLE}" + describe + ${hash} + ${ARGN} + WORKING_DIRECTORY + "${CMAKE_SOURCE_DIR}" + RESULT_VARIABLE + res + OUTPUT_VARIABLE + out + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT res EQUAL 0) + set(out "${out}-${res}-NOTFOUND") + endif() + + set(${_var} "${out}" PARENT_SCOPE) +endfunction() + +function(git_get_exact_tag _var) + git_describe(out --exact-match ${ARGN}) + set(${_var} "${out}" PARENT_SCOPE) +endfunction() + +## An optional 4th argument reports whether every git call succeeded. The metadata +## strings cannot signal that on their own: a branch may be named like a sentinel. +function(git_short_info _refspecvar _hashvar _lc_datevar) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + if(ARGC GREATER 3) + set(${ARGV3} FALSE PARENT_SCOPE) + endif() + get_git_head_revision(refspec hash) + if(NOT GIT_FOUND) + set(${_refspecvar} "GIT-NOTFOUND" PARENT_SCOPE) + set(${_hashvar} "GIT-NOTFOUND" PARENT_SCOPE) + set(${_lc_datevar} "GIT-NOTFOUND" PARENT_SCOPE) + return() + endif() + if(NOT hash) + set(${_refspecvar} "HEAD-HASH-NOTFOUND" PARENT_SCOPE) + set(${_hashvar} "HEAD-HASH-NOTFOUND" PARENT_SCOPE) + set(${_lc_datevar} "HEAD-HASH-NOTFOUND" PARENT_SCOPE) + return() + endif() + + set(_ok TRUE) + + execute_process(COMMAND + "${GIT_EXECUTABLE}" + rev-parse + --short=7 + ${hash} + WORKING_DIRECTORY + "${CMAKE_SOURCE_DIR}" + RESULT_VARIABLE + res + OUTPUT_VARIABLE + out + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT res EQUAL 0) + set(out "${out}-${res}-NOTFOUND") + set(_ok FALSE) + endif() + + set(${_hashvar} "${out}" PARENT_SCOPE) + + execute_process(COMMAND + "${GIT_EXECUTABLE}" + rev-parse + --abbrev-ref + HEAD + WORKING_DIRECTORY + "${CMAKE_SOURCE_DIR}" + RESULT_VARIABLE + res + OUTPUT_VARIABLE + out + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT res EQUAL 0) + set(out "${out}-${res}-NOTFOUND") + set(_ok FALSE) + endif() + + set(${_refspecvar} "${out}" PARENT_SCOPE) + + execute_process(COMMAND + "${GIT_EXECUTABLE}" + log + -n 1 + --simplify-by-decoration + --pretty=%ai + WORKING_DIRECTORY + "${CMAKE_SOURCE_DIR}" + RESULT_VARIABLE + res + OUTPUT_VARIABLE + out + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT res EQUAL 0) + set(out "${out}-${res}-NOTFOUND") + set(_ok FALSE) + endif() + + set(${_lc_datevar} "${out}" PARENT_SCOPE) + + if(ARGC GREATER 3) + set(${ARGV3} ${_ok} PARENT_SCOPE) + endif() +endfunction() + +## Reads what git archive filled into <_file>, the source tree's .git_archival.txt (export-subst +## in .gitattributes): the commit, its date and the nearest release tag (git describe; empty if +## there is none). <_foundvar> is TRUE only in a source tree made by git archive; in a checkout +## the file still holds its $Format placeholders. Hash and date come in the formats of +## git_short_info. src/tests/git_archival/run.cmake tests it. +function(git_archival_info _file _describevar _hashvar _lc_datevar _foundvar) + set(${_foundvar} FALSE PARENT_SCOPE) + if(NOT EXISTS "${_file}") + return() + endif() + file(STRINGS "${_file}" lines) + set(hash "") + set(lc_date "") + set(describe "") + foreach(line IN LISTS lines) + if(line MATCHES "^node: ([0-9a-f]+)$") + set(hash "${CMAKE_MATCH_1}") + elseif(line MATCHES "^node-date: (.+)$") + set(lc_date "${CMAKE_MATCH_1}") + elseif(line MATCHES "^describe-name: (.*)$") + set(describe "${CMAKE_MATCH_1}") + endif() + endforeach() + if(NOT hash) + return() + endif() + ## git before 2.35 knows no describe options and leaves the placeholder as it is + if(describe MATCHES "^%\\(") + message(WARNING "${_file}: the git that made this archive did not fill in describe-name " + "(that needs git 2.35 or later), so the build cannot tell a release.") + set(describe "") + endif() + string(SUBSTRING "${hash}" 0 7 hash) + ## 2026-09-30T08:25:00+02:00 (%cI) -> 2026-09-30 08:25:00 +0200 (%ai); since git 2.45, %cI + ## writes UTC as Z + string(REGEX REPLACE "Z$" "+00:00" lc_date "${lc_date}") + string(REGEX REPLACE "^([0-9-]+)T([0-9:]+)([+-][0-9][0-9]):?([0-9][0-9])$" "\\1 \\2 \\3\\4" lc_date "${lc_date}") + set(${_describevar} "${describe}" PARENT_SCOPE) + set(${_hashvar} "${hash}" PARENT_SCOPE) + set(${_lc_datevar} "${lc_date}" PARENT_SCOPE) + set(${_foundvar} TRUE PARENT_SCOPE) +endfunction() diff --git a/cmake/Modules/GetGitRevisionDescription.cmake.in b/cmake/Modules/GetGitRevisionDescription.cmake.in new file mode 100644 index 000000000..888ce13aa --- /dev/null +++ b/cmake/Modules/GetGitRevisionDescription.cmake.in @@ -0,0 +1,38 @@ +# +# Internal file for GetGitRevisionDescription.cmake +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +set(HEAD_HASH) + +file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) + +string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) +if(HEAD_CONTENTS MATCHES "ref") + # named branch + string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") + if(EXISTS "@GIT_DIR@/${HEAD_REF}") + configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) + elseif(EXISTS "@GIT_DIR@/logs/${HEAD_REF}") + configure_file("@GIT_DIR@/logs/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) + set(HEAD_HASH "${HEAD_REF}") + endif() +else() + # detached HEAD + configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) +endif() + +if(NOT HEAD_HASH) + file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) + string(STRIP "${HEAD_HASH}" HEAD_HASH) +endif() diff --git a/cmake/OpenMSConfig.cmake.in b/cmake/OpenMSConfig.cmake.in new file mode 100644 index 000000000..e980f266e --- /dev/null +++ b/cmake/OpenMSConfig.cmake.in @@ -0,0 +1,281 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Julianus Pfeuffer $ +# $Authors: Julianus Pfeuffer $ +# -------------------------------------------------------------------------- + +@PACKAGE_INIT@ + +### CMake package configuration of OpenMS for external code. +### Configured by the OpenMS build system from /cmake/OpenMSConfig.cmake.in. +### +### The installed package is layered: an installation contains the core layer and +### optionally the CLI layer on top of it and the GUI layer on top of that (see +### cmake/install_macros.cmake for the install components of each layer). +### find_package(OpenMS CONFIG) provides the imported targets of the layers present: +### OpenMS::OpenMS the OpenMS library (component Core, always) +### OpenMS::OpenSwathAlgo the OpenSWATH algorithm library (component OpenSwathAlgo, always) +### OpenMS::OpenMS_CLI the TOPP tool framework (TOPPBase, ToolHandler, ...); a +### TOPP-style tool links this (component CLI; install +### components library_cli and cmake_cli) +### OpenMS::OpenMS_GUI the GUI library of a WITH_GUI build (component GUI, on request; +### install components library_gui and cmake_gui) +### and, for projects written against earlier releases, the un-namespaced aliases +### OpenMS and OpenSwathAlgo, plus OpenMS_CLI and OpenMS_GUI when those layers are +### installed. A core-only installation (install +### components library, OpenMS_headers, OpenSwathAlgo_headers, thirdparty_headers, +### share and cmake, e.g. what the pyOpenMS wheels are built against) provides the +### first two targets; requesting COMPONENTS CLI fails on it. Requesting COMPONENTS GUI +### (or OPTIONAL_COMPONENTS GUI) also finds the Qt6 modules the GUI library was built +### against; without it, a consumer that links OpenMS::OpenMS_GUI finds Qt6 itself. +### +### Variables: +### OpenMS_VERSION version of this installation +### OpenMS_CLI_FOUND the CLI layer is part of this installation +### OpenMS_GUI_FOUND the GUI component was requested and satisfied +### OpenMS_WITH_GUI the GUI library is part of this installation +### OpenMS_WITH_HDF5, OpenMS_WITH_OPENTIMS, OpenMS_WITH_THERMO_RAW, OpenMS_WITH_ONNX, +### OpenMS_WITH_OPENMP, OpenMS_WITH_WNETALIGN, OpenMS_BUILD_TOPP_TOOLS +### build options of this installation +### OPENMS_DATA_DIR (= OPENMS_SHARE_DIR), OPENMS_LIB_DIR, OPENMS_BIN_DIR, OPENMS_DOC_DIR +### directories of this installation + +# Consumers use exported header file sets and share the build's CMake minimum. +if(CMAKE_VERSION VERSION_LESS 3.24) + set(OpenMS_FOUND FALSE) + set(OpenMS_NOT_FOUND_MESSAGE + "OpenMS requires CMake 3.24 or newer in the consuming project (running ${CMAKE_VERSION}).") + return() +endif() + +#------------------------------------------------------------------------------ +# Directories of this installation. +# They expand PACKAGE_PREFIX_DIR, which @PACKAGE_INIT@ derived from the location +# of this file. Every package configuration generated with +# configure_package_config_file() (Eigen3Config.cmake among them) resets that +# variable to its own prefix when a dependency lookup below includes it, so the +# directories have to be evaluated before any dependency is searched. +set(OPENMS_DATA_DIR "@PACKAGE_INSTALL_SHARE_DIR@") +set(OPENMS_SHARE_DIR "${OPENMS_DATA_DIR}") +set(OPENMS_BIN_DIR "@PACKAGE_INSTALL_BIN_DIR@") +set(OPENMS_DOC_DIR "@PACKAGE_INSTALL_DOC_DIR@") +set(OPENMS_LIB_DIR "@PACKAGE_INSTALL_LIB_DIR@") +# only for the OpenMP lookup below +set(_openms_include_dir "@PACKAGE_INSTALL_INCLUDE_DIR@") + +#------------------------------------------------------------------------------ +# Build options of this installation (OpenMS_WITH_GUI is set with the imported +# targets below: it is true only when the GUI library is installed, not merely built) +set(_openms_built_with_gui "@WITH_GUI@") +set(OpenMS_WITH_HDF5 "@WITH_HDF5@") +set(OpenMS_WITH_OPENTIMS "@WITH_OPENTIMS@") +set(OpenMS_WITH_THERMO_RAW "@WITH_THERMO_RAW@") +set(OpenMS_WITH_ONNX "@WITH_ONNX@") +set(OpenMS_WITH_OPENMP "@OPENMP_FOUND@") +set(OpenMS_WITH_WNETALIGN "@WITH_WNETALIGN@") +set(OpenMS_BUILD_TOPP_TOOLS "@BUILD_TOPP_TOOLS@") + +#------------------------------------------------------------------------------ +# Dependencies that are part of the public link interface of the imported targets. +# Everything else OpenMS links is PRIVATE: the installed shared library resolves it +# through its own RPATH/soname, and consumers need neither the CMake packages nor +# the development files of those libraries (CURL, libxml2, libsvm, SQLite, +# HDF5, Arrow, ...). + +include(CMakeFindDependencyMacro) + +# Boost is private: no installed header includes it, so consumers of the shared +# library need no Boost development files. A static export keeps its private link +# dependencies, among them the header-only Boost::boost target, so only then is +# Boost resolved. The version OpenMS was built against is the minimum (falling back +# to the minimum OpenMS itself requires should a build not record it). +if(NOT "@BUILD_SHARED_LIBS@") + set(_openms_boost_version "@Boost_VERSION@") + if(NOT _openms_boost_version) + set(_openms_boost_version 1.81.0) + endif() + find_dependency(Boost ${_openms_boost_version}) + # libxml2's own package config first, as OpenMS itself found it: only it carries + # the link dependencies of a static libxml2 (and LIBXML_STATIC on Windows). + # A config package that is found but fails (e.g. a missing dependency of its own) + # is an error, not a reason to fall back to the module. + find_package(LibXml2 2.13 CONFIG QUIET NAMES LibXml2 libxml2) + if(NOT LibXml2_FOUND AND LibXml2_NOT_FOUND_MESSAGE) + set(OpenMS_FOUND FALSE) + set(OpenMS_NOT_FOUND_MESSAGE + "The libxml2 package configuration failed: ${LibXml2_NOT_FOUND_MESSAGE}") + return() + elseif(NOT LibXml2_FOUND) + find_dependency(LibXml2 2.13 MODULE) + endif() + unset(_openms_boost_version) +endif() + +# Eigen: a consumer of the shared library OpenMS ships needs nothing of it. No +# installed header includes Eigen -- DATASTRUCTURES/MatrixEigen.h, the one that does, +# is internal and not installed -- and CMake omits the PRIVATE dependencies of a +# SHARED library from the exported link interface, so OpenMSTargets.cmake names no +# Eigen target at all. A STATIC build is the exception: CMake keeps its private +# dependencies as $, which has to resolve to a target in the +# consuming project. So the lookup follows the library configuration the producer +# recorded instead of running for every consumer; the OpenMS build sets +# BUILD_SHARED_LIBS unconditionally, so it normally does not run at all. +# +# Two-step lookup as in cmake/cmake_findExternalLibs.cmake: the version range admits +# Eigen 5 where the package version file understands ranges (CMake issue 24581). The +# fallback is deliberately a plain minimum: a version file written with +# SameMajorVersion compatibility rejects the range 3.4.0...<6 even for Eigen 3.4 +# itself, because both ends of a range must lie in the same major version. An +# Eigen3::Eigen target that the consuming project defines itself (e.g. a vendored +# Eigen) is accepted as is, like in the OpenMS build; its version is that project's call. +# +# Deliberately a private helper rather than a documented OpenMS_* variable: a +# consumer that needs to know how this installation was built reads it off the +# imported target, get_target_property(OpenMS::OpenMS TYPE), which reports +# SHARED_LIBRARY or STATIC_LIBRARY and cannot drift from what was installed. The +# recorded value exists only because the targets file is included further below, +# after the dependency lookups, so the property is not available here yet. +set(_openms_built_shared_libs "@BUILD_SHARED_LIBS@") +if(NOT _openms_built_shared_libs) + set(_openms_eigen3_version "@Eigen3_VERSION@") + if(NOT _openms_eigen3_version) + set(_openms_eigen3_version 3.4.0) + endif() + find_package(Eigen3 ${_openms_eigen3_version}...<6 QUIET) + if(NOT TARGET Eigen3::Eigen) + find_dependency(Eigen3 ${_openms_eigen3_version}) + endif() + unset(_openms_eigen3_version) +endif() +unset(_openms_built_shared_libs) + +# OpenMP: OpenMP::OpenMP_CXX is PUBLIC in an OpenMS built with OpenMP. +# +# The macOS package and SDK bundle the OpenMP runtime (lib/libomp.dylib) and install its +# omp.h with the headers (cmake/package_general.cmake). FindOpenMP of the consuming project +# is pointed at both: a program that loads a second OpenMP runtime next to the one +# libOpenMS uses aborts ("OMP: Error #15"). The cache entries are only filled in when +# empty, so a project that chose its own libomp keeps it, with a warning. +if(OpenMS_WITH_OPENMP AND APPLE AND EXISTS "${OPENMS_LIB_DIR}/libomp.dylib" + AND EXISTS "${_openms_include_dir}/omp.h") + set(_openms_libomp "${OPENMS_LIB_DIR}/libomp.dylib") + if(NOT OpenMP_libomp_LIBRARY) + set(OpenMP_libomp_LIBRARY "${_openms_libomp}" CACHE FILEPATH + "Path to the libomp library for OpenMP" FORCE) + foreach(_openms_omp_language IN ITEMS C CXX) + if(NOT OpenMP_${_openms_omp_language}_INCLUDE_DIR) + set(OpenMP_${_openms_omp_language}_INCLUDE_DIR "${_openms_include_dir}" CACHE PATH + "Directory of omp.h" FORCE) + endif() + endforeach() + unset(_openms_omp_language) + elseif(NOT OpenMP_libomp_LIBRARY STREQUAL _openms_libomp AND NOT OpenMS_FIND_QUIETLY) + message(WARNING + "OpenMS bundles the OpenMP runtime ${_openms_libomp}, but this project uses " + "${OpenMP_libomp_LIBRARY} (OpenMP_libomp_LIBRARY). A program that loads both aborts " + "with \"OMP: Error #15\"; unset OpenMP_libomp_LIBRARY and OpenMP_CXX_INCLUDE_DIR to " + "use the bundled runtime.") + endif() + unset(_openms_libomp) +endif() +unset(_openms_include_dir) +if(OpenMS_WITH_OPENMP) + find_dependency(OpenMP COMPONENTS CXX) +endif() + +#------------------------------------------------------------------------------ +# The imported targets: one file per layer. The core file is always present. The +# CLI and GUI files are installed by the components cmake_cli and cmake_gui (with +# the libraries in library_cli and library_gui), so they exist only when the +# installation includes those layers. Each file refers to the targets of the layer +# below and is therefore included after it; a GUI file without the CLI layer is +# an incomplete installation and is left out. The GUI file is also ignored when +# this configuration was made without the GUI library: a file of an earlier +# WITH_GUI configuration surviving in the same build or install directory does +# not make the layer available. +include("${CMAKE_CURRENT_LIST_DIR}/@_OPENMS_EXPORT_FILE@") +set(OpenMS_CLI_FOUND FALSE) +if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@_OPENMS_CLI_EXPORT_FILE@") + include("${CMAKE_CURRENT_LIST_DIR}/@_OPENMS_CLI_EXPORT_FILE@") + set(OpenMS_CLI_FOUND TRUE) +endif() +set(OpenMS_WITH_GUI FALSE) +if(OpenMS_CLI_FOUND AND _openms_built_with_gui + AND EXISTS "${CMAKE_CURRENT_LIST_DIR}/@_OPENMS_GUI_EXPORT_FILE@") + include("${CMAKE_CURRENT_LIST_DIR}/@_OPENMS_GUI_EXPORT_FILE@") + set(OpenMS_WITH_GUI TRUE) +endif() + +#------------------------------------------------------------------------------ +# Components. Core and OpenSwathAlgo are always present, CLI when the installation +# includes the CLI layer. GUI is satisfied when the installation includes the GUI +# library and the Qt6 modules it links are found; the lookup runs only when the +# component is requested, so consumers of the core library never need Qt6. +set(_openms_known_components Core OpenSwathAlgo CLI GUI) +set(OpenMS_Core_FOUND TRUE) +set(OpenMS_OpenSwathAlgo_FOUND TRUE) +if("CLI" IN_LIST OpenMS_FIND_COMPONENTS AND NOT OpenMS_CLI_FOUND AND OpenMS_FIND_REQUIRED_CLI) + set(OpenMS_NOT_FOUND_MESSAGE + "This OpenMS installation does not include the TOPP tool framework library OpenMS::OpenMS_CLI (install components library_cli and cmake_cli).") +endif() +set(OpenMS_GUI_FOUND FALSE) +if("GUI" IN_LIST OpenMS_FIND_COMPONENTS) + if(OpenMS_WITH_GUI) + if(OpenMS_FIND_REQUIRED_GUI AND NOT OpenMS_FIND_QUIETLY) + set(_openms_qt_quiet) + else() + set(_openms_qt_quiet QUIET) + endif() + # the Qt6 modules the GUI library was built against (Core plus the module lists + # of cmake/cmake_findExternalLibs.cmake); a newer Qt6 is binary compatible + set(_openms_gui_qt_modules Core @OpenMS_GUI_QT_COMPONENTS@ @OpenMS_GUI_QT_FOUND_COMPONENTS_OPT@) + find_package(Qt6 @Qt6_VERSION@ ${_openms_qt_quiet} COMPONENTS ${_openms_gui_qt_modules}) + unset(_openms_qt_quiet) + if(Qt6_FOUND) + set(OpenMS_GUI_FOUND TRUE) + elseif(OpenMS_FIND_REQUIRED_GUI) + string(REPLACE ";" " " _openms_gui_qt_modules "${_openms_gui_qt_modules}") + string(CONCAT OpenMS_NOT_FOUND_MESSAGE + "The OpenMS GUI component needs Qt6 @Qt6_VERSION@ or newer with the modules " + "${_openms_gui_qt_modules}, which were not found. Add the Qt installation to CMAKE_PREFIX_PATH.") + endif() + unset(_openms_gui_qt_modules) + elseif(OpenMS_FIND_REQUIRED_GUI) + if(_openms_built_with_gui) + set(OpenMS_NOT_FOUND_MESSAGE + "This OpenMS installation does not include the GUI library OpenMS::OpenMS_GUI (install components library_gui and cmake_gui, which need library_cli and cmake_cli).") + else() + set(OpenMS_NOT_FOUND_MESSAGE + "This OpenMS installation was built without the GUI library (WITH_GUI=OFF).") + endif() + endif() +endif() +unset(_openms_built_with_gui) +foreach(_openms_component IN LISTS OpenMS_FIND_COMPONENTS) + if(NOT _openms_component IN_LIST _openms_known_components + AND OpenMS_FIND_REQUIRED_${_openms_component}) + set(OpenMS_NOT_FOUND_MESSAGE + "Unknown OpenMS component '${_openms_component}' (known components: ${_openms_known_components}).") + endif() +endforeach() +unset(_openms_component) +unset(_openms_known_components) + +#------------------------------------------------------------------------------ +# Aliases for projects that link the un-namespaced names of earlier releases. +if(NOT TARGET OpenMS) + add_library(OpenMS ALIAS OpenMS::OpenMS) +endif() +if(NOT TARGET OpenSwathAlgo) + add_library(OpenSwathAlgo ALIAS OpenMS::OpenSwathAlgo) +endif() +if(TARGET OpenMS::OpenMS_CLI AND NOT TARGET OpenMS_CLI) + add_library(OpenMS_CLI ALIAS OpenMS::OpenMS_CLI) +endif() +if(TARGET OpenMS::OpenMS_GUI AND NOT TARGET OpenMS_GUI) + add_library(OpenMS_GUI ALIAS OpenMS::OpenMS_GUI) +endif() + +check_required_components(OpenMS) diff --git a/cmake/OpenMSPackageDescriptionFile.txt b/cmake/OpenMSPackageDescriptionFile.txt new file mode 100644 index 000000000..0e79e8523 --- /dev/null +++ b/cmake/OpenMSPackageDescriptionFile.txt @@ -0,0 +1,7 @@ + +This package contains + +OpenMS - An open-source framework for mass spectrometry and +TOPP - The OpenMS PiPeline + +For more information visit our website at www.OpenMS.de. diff --git a/cmake/OpenMSPackageResourceReadme.txt b/cmake/OpenMSPackageResourceReadme.txt new file mode 100644 index 000000000..9243f582e --- /dev/null +++ b/cmake/OpenMSPackageResourceReadme.txt @@ -0,0 +1,3 @@ +After the installation you can use the TOPP-tools via the terminal. TOPPView and the INIFileEditor are native MacOSX applications and can be used accordingly. + +For more information visit our website at www.OpenMS.de. diff --git a/cmake/OpenMSPackageResourceWelcomeFile.txt b/cmake/OpenMSPackageResourceWelcomeFile.txt new file mode 100644 index 000000000..51b5eb9c6 --- /dev/null +++ b/cmake/OpenMSPackageResourceWelcomeFile.txt @@ -0,0 +1,6 @@ +Welcome to the installation of OpenMS/TOPP. + +OpenMS - An open-source framework for mass spectrometry and +TOPP - The OpenMS PiPeline + +For more information visit our website at www.OpenMS.de. diff --git a/cmake/Windows/Contrib/Inetc/afxres.h b/cmake/Windows/Contrib/Inetc/afxres.h new file mode 100644 index 000000000..3fbfaa463 --- /dev/null +++ b/cmake/Windows/Contrib/Inetc/afxres.h @@ -0,0 +1,2 @@ +#include +#define IDC_STATIC (-1) diff --git a/cmake/Windows/Contrib/Inetc/api.h b/cmake/Windows/Contrib/Inetc/api.h new file mode 100644 index 000000000..e871de3d4 --- /dev/null +++ b/cmake/Windows/Contrib/Inetc/api.h @@ -0,0 +1,83 @@ +/* + * apih + * + * This file is a part of NSIS. + * + * Copyright (C) 1999-2013 Nullsoft and Contributors + * + * Licensed under the zlib/libpng license (the "License"); + * you may not use this file except in compliance with the License. + * + * Licence details can be found in the file COPYING. + * + * This software is provided 'as-is', without any express or implied + * warranty. + */ + +#ifndef _NSIS_EXEHEAD_API_H_ +#define _NSIS_EXEHEAD_API_H_ + +// Starting with NSIS 2.42, you can check the version of the plugin API in exec_flags->plugin_api_version +// The format is 0xXXXXYYYY where X is the major version and Y is the minor version (MAKELONG(y,x)) +// When doing version checks, always remember to use >=, ex: if (pX->exec_flags->plugin_api_version >= NSISPIAPIVER_1_0) {} + +#define NSISPIAPIVER_1_0 0x00010000 +#define NSISPIAPIVER_CURR NSISPIAPIVER_1_0 + +// NSIS Plug-In Callback Messages +enum NSPIM +{ + NSPIM_UNLOAD, // This is the last message a plugin gets, do final cleanup + NSPIM_GUIUNLOAD, // Called after .onGUIEnd +}; + +// Prototype for callbacks registered with extra_parameters->RegisterPluginCallback() +// Return NULL for unknown messages +// Should always be __cdecl for future expansion possibilities +typedef UINT_PTR (*NSISPLUGINCALLBACK)(enum NSPIM); + +// extra_parameters data structures containing other interesting stuff +// but the stack, variables and HWND passed on to plug-ins. +typedef struct +{ + int autoclose; + int all_user_var; + int exec_error; + int abort; + int exec_reboot; // NSIS_SUPPORT_REBOOT + int reboot_called; // NSIS_SUPPORT_REBOOT + int XXX_cur_insttype; // depreacted + int plugin_api_version; // see NSISPIAPIVER_CURR + // used to be XXX_insttype_changed + int silent; // NSIS_CONFIG_SILENT_SUPPORT + int instdir_error; + int rtl; + int errlvl; + int alter_reg_view; + int status_update; +} exec_flags_t; + +#ifndef NSISCALL +# define NSISCALL __stdcall +#endif + +typedef struct { + exec_flags_t *exec_flags; + int (NSISCALL *ExecuteCodeSegment)(int, HWND); + void (NSISCALL *validate_filename)(LPTSTR); + int (NSISCALL *RegisterPluginCallback)(HMODULE, NSISPLUGINCALLBACK); // returns 0 on success, 1 if already registered and < 0 on errors +} extra_parameters; + +// Definitions for page showing plug-ins +// See Ui.c to understand better how they're used + +// sent to the outer window to tell it to go to the next inner window +#define WM_NOTIFY_OUTER_NEXT (WM_USER+0x8) + +// custom pages should send this message to let NSIS know they're ready +#define WM_NOTIFY_CUSTOM_READY (WM_USER+0xd) + +// sent as wParam with WM_NOTIFY_OUTER_NEXT when user cancels - heed its warning +#define NOTIFY_BYE_BYE 'x' + +#endif /* _PLUGIN_H_ */ diff --git a/cmake/Windows/Contrib/Inetc/crt.cpp b/cmake/Windows/Contrib/Inetc/crt.cpp new file mode 100644 index 000000000..a06db263a --- /dev/null +++ b/cmake/Windows/Contrib/Inetc/crt.cpp @@ -0,0 +1,105 @@ +#include + +#if defined(_MSC_VER) && _MSC_VER+0 >= 1400 +#if defined(_MSC_FULL_VER) && _MSC_FULL_VER+0 >= 140050727 +#include +#else +EXTERN_C void __stosb(BYTE*,BYTE,size_t); +#endif +#pragma intrinsic(__stosb) +#define CRTINTRINSIC_memset(p,c,s) __stosb((BYTE*)(p),(BYTE)(c),(s)) +#endif + +extern "C" void* __cdecl memset(void *p, int c, size_t z) +{ +#ifdef CRTINTRINSIC_memset + CRTINTRINSIC_memset(p, c, z); +#else + BYTE *pb = reinterpret_cast(p); + for(size_t i=0; istring_size) +* HTTP POST added +* Jun 06, 2005 IDOK on "Enter" key locked +* POST HTTP header added +* Jun 22, 2005 non-interaptable mode /nocancel +* and direct connect /noproxy +* Jun 29, 2005 post.php written and tested +* Jul 05, 2005 60 sec delay on WinInet detach problem +* solved (not fine, but works including +* installer exit and system reboot) +* Jul 08, 2005 'set foreground' finally removed +* Jul 26, 2005 POPUP translate option +* Aug 23, 2005 https service type in InternetConnect +* and "ignore certificate" flags +* Sep 30, 2005 https with bad certificate from old OS; +* Forbidden handling +* Dec 23, 2005 'put' entry point, new names, 12003 +* ftp error handling (on ftp write permission) +* 405 http error (method not allowed) +* Mar 12, 2006 Internal authorization via InternetErrorDlg() +* and Unauthorized (401) handling. +* Jun 10, 2006 Caption text option for Resume download +* MessageBox +* Jun 24, 2006 HEAD method, silent mode clean up +* Sep 05, 2006 Center dialog code from Backland +* Sep 07, 2006 NSISdl crash fix /Backland idea/ +* Sep 08, 2006 POST as dll entry point. +* Sep 21, 2006 parent dlg progr.bar style and font, +* nocancel via ws_sysmenu +* Sep 22, 2006 current lang IDCANCEL text, /canceltext +* and /useragent options +* Sep 24, 2006 .onInit improvements and defaults +* Nov 11, 2006 FTP path creation, root|current dir mgmt +* Jan 01, 2007 Global char[] cleanup, GetLastError() to +* status string on ERR_DIALOG, few MSVCRT replaces +* Jan 13, 2007 /HEADER option added +* Jan 28, 2007 _open -> CreateFile and related +* Feb 18, 2007 Speed calculating improved (pauses), +* /popup text parameter to hide URL +* Jun 07, 2007 Local file truncation added for download +* (CREATE_ALWAYS) +* Jun 11, 2007 FTP download permitted even if server rejects +* SIZE request (ProFTPD). +* Aug 11, 2007 Backland' fix for progress bar redraw/style +* issue in NSISdl display mode. +* Jan 09, 2008 {_trueparuex^}' fix - InternetSetFilePointer() +* returns -1 on error. +* /question option added for cancel question. +* Feb 15, 2008 PUT content-length file size fix +* Feb 17, 2008 char -> TCHAR replace for UNICODE option +* Feb 19, 2008 janekschwarz fix for HTTP PUT with auth +* CreateFile INVALID_HANDLE_VALUE on error fix +* Feb 20, 2008 base64 encoder update for unicode +* Feb 27, 2008 Unicode configurations added to VS 6 dsp +* Mar 20, 2008 HTTP PUT with proxy auth finally fixed +* FTP errors handling improved. +* HEAD bug fixed +* Mar 27, 2008 Details window hide/show in NSISdl mode +* Apr 10, 2008 Auth test method changed to HEAD for +* old proxy's +* Apr 30, 2008 InternetErrorDlg() ERROR_SUCESS on cancel +* click patched +* 3xx errors added to status list. +* May 20, 2008 InternetReadFile on cable disconnect patched +* May 20, 2008 Reply status "0" patch (name resolution?) +* Jul 15, 2008 HTTP 304 parsing. Incorrect size reported fix. +* Aug 21, 2009 Escape sequence convertion removed (caused +* error in signature with %2b requests) +* Marqueue progess bar style for unknown file size. +* Feb 04, 2010 Unicode POST patch - body converted to multibyte +* Jul 11, 2010 /FILE POST option added +* Nov 04, 2010 Disabled cookies and cache for cleanliness +* Feb 14, 2011 Fixed reget bug introduced in previous commit +* Feb 18, 2011 /NOCOOKIES option added +* Mar 02, 2011 User-agent buffer increased. Small memory leak fix +* Mar 23, 2011 Use caption on embedded progressbar - zenpoy +* Apr 05, 2011 reget fix - INTERNET_FLAG_RELOAD for first connect only +* Apr 27, 2011 /receivetimeout option added for big files and antivirus +* Jun 15, 2011 Stack clean up fix on cancel - zenpoy +* Oct 19, 2011 FTP PUT error parsing fix - tperquin +* Aug 19, 2013 Fix focus stealing when in silent - negativesir, JohnTHaller +* Jul 20, 2014 - 1.0.4.4 - Stuart 'Afrow UK' Welch +* /tostack & /tostackconv added +* Version information resource added +* Updated to NSIS 3.0 plugin API +* Upgraded to Visual Studio 2012 +* 64-bit build added +* MSVCRT dependency removed +* Sep 04, 2015 - 1.0.5.0 - anders_k +* HTTPS connections are more secure by default +* Added /weaksecurity switch, reverts to old cert. security checks +* Sep 06, 2015 - 1.0.5.1 - anders_k +* Don't allow infinite FtpCreateDirectory tries +* Use memset intrinsic when possible to avoid VC code generation bug +* Oct 17, 2015 - 1.0.5.2 - anders_k +* Tries to set FTP mode to binary before querying the size. +* Calls FtpGetFileSize if it exists. +*******************************************************/ + + +#define _WIN32_WINNT 0x0500 + +#include +//#include +#include +#include +#include "pluginapi.h" +#include "resource.h" + +#include // strstr etc + +#ifndef PBM_SETMARQUEE +#define PBM_SETMARQUEE (WM_USER + 10) +#define PBS_MARQUEE 0x08 +#endif +#ifndef HTTP_QUERY_PROXY_AUTHORIZATION +#define HTTP_QUERY_PROXY_AUTHORIZATION 61 +#endif +#ifndef SECURITY_FLAG_IGNORE_REVOCATION +#define SECURITY_FLAG_IGNORE_REVOCATION 0x00000080 +#endif +#ifndef SECURITY_FLAG_IGNORE_UNKNOWN_CA +#define SECURITY_FLAG_IGNORE_UNKNOWN_CA 0x00000100 +#endif + +// IE 4 safety and VS 6 compatibility +typedef BOOL (__stdcall *FTP_CMD)(HINTERNET,BOOL,DWORD,LPCTSTR,DWORD,HINTERNET *); +FTP_CMD myFtpCommand; + +#define PLUGIN_NAME TEXT("Inetc plug-in") +#define INETC_USERAGENT TEXT("NSIS_Inetc (Mozilla)") +#define PB_RANGE 400 // progress bar values range +#define PAUSE1_SEC 2 // transfer error indication time, for reget only +#define PAUSE2_SEC 3 // paused state time, increase this if need (60?) +#define PAUSE3_SEC 1 // pause after resume button pressed +#define NOT_AVAILABLE 0xffffffff +#define POST_HEADER TEXT("Content-Type: application/x-www-form-urlencoded") +#define PUT_HEADER TEXT("Content-Type: octet-stream\nContent-Length: %d") +#define INTERNAL_OK 0xFFEE +#define PROGRESS_MS 1000 // screen values update interval +#define DEF_QUESTION TEXT("Are you sure that you want to stop download?") +#define HOST_AUTH_HDR TEXT("Authorization: basic %s") +#define PROXY_AUTH_HDR TEXT("Proxy-authorization: basic %s") + +//#define MY_WEAKSECURITY_CERT_FLAGS SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_REVOCATION | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | SECURITY_FLAG_IGNORE_CERT_CN_INVALID +#define MY_WEAKSECURITY_CERT_FLAGS SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_REVOCATION +#define MY_REDIR_FLAGS INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP | INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS +#define MY_HTTPS_FLAGS (MY_REDIR_FLAGS | INTERNET_FLAG_SECURE) + +enum STATUS_CODES { + ST_OK = 0, + ST_CONNECTING, + ST_DOWNLOAD, + ST_CANCELLED, + ST_URLOPEN, + // ST_OPENING, + ST_PAUSE, + ERR_TERMINATED, + ERR_DIALOG, + ERR_INETOPEN, + ERR_URLOPEN, + ERR_TRANSFER, + ERR_FILEOPEN, + ERR_FILEWRITE, + ERR_FILEREAD, + ERR_REGET, + ERR_CONNECT, + ERR_OPENREQUEST, + ERR_SENDREQUEST, + ERR_CRACKURL, + ERR_NOTFOUND, + ERR_THREAD, + ERR_PROXY, + ERR_FORBIDDEN, + ERR_NOTALLOWED, + ERR_REQUEST, + ERR_SERVER, + ERR_AUTH, + ERR_CREATEDIR, + ERR_PATH, + ERR_NOTMODIFIED, + ERR_REDIRECTION +}; + + +static TCHAR szStatus[][32] = { + TEXT("OK"),TEXT("Connecting"),TEXT("Downloading"),TEXT("Cancelled"),TEXT("Connecting"), //TEXT("Opening URL")), + TEXT("Reconnect Pause"),TEXT("Terminated"),TEXT("Dialog Error"),TEXT("Open Internet Error"), + TEXT("Open URL Error"),TEXT("Transfer Error"),TEXT("File Open Error"),TEXT("File Write Error"),TEXT("File Read Error"), + TEXT("Reget Error"),TEXT("Connection Error"),TEXT("OpenRequest Error"),TEXT("SendRequest Error"), + TEXT("URL Parts Error"),TEXT("File Not Found (404)"),TEXT("CreateThread Error"),TEXT("Proxy Error (407)"), + TEXT("Access Forbidden (403)"),TEXT("Not Allowed (405)"),TEXT("Request Error"),TEXT("Server Error"), + TEXT("Unauthorized (401)"),TEXT("FtpCreateDir failed (550)"),TEXT("Error FTP path (550)"),TEXT("Not Modified"), + TEXT("Redirection") +}; + +HINSTANCE g_hInstance; +TCHAR fn[MAX_PATH]=TEXT(""), +*url = NULL, +*szAlias = NULL, +*szProxy = NULL, +*szHeader = NULL, +*szBanner = NULL, +*szQuestion = NULL, +szCancel[64]=TEXT(""), +szCaption[128]=TEXT(""), +szUserAgent[256]=TEXT(""), +szResume[256] = TEXT("Your internet connection seems to be not permitted or dropped out!\nPlease reconnect and click Retry to resume installation."); +CHAR *szPost = NULL, +post_fname[MAX_PATH] = ""; +DWORD fSize = 0; +TCHAR *szToStack = NULL; + +int status; +DWORD cnt = 0, +cntToStack = 0, +fs = 0, +timeout = 0, +receivetimeout = 0; +DWORD startTime, transfStart, openType; +bool silent, popup, resume, nocancel, noproxy, nocookies, convToStack, g_ignorecertissues; + +HWND childwnd; +HWND hDlg; +bool fput = false, fhead = false; + + +#define Option_IgnoreCertIssues() ( g_ignorecertissues ) + +static FARPROC GetWininetProcAddress(LPCSTR Name) +{ + return GetProcAddress(LoadLibraryA("WININET"), Name); +} + +/***************************************************** +* FUNCTION NAME: sf(HWND) +* PURPOSE: +* moves HWND to top and activates it +* SPECIAL CONSIDERATIONS: +* commented because annoying +*****************************************************/ +/* +void sf(HWND hw) +{ +DWORD ctid = GetCurrentThreadId(); +DWORD ftid = GetWindowThreadProcessId(GetForegroundWindow(), NULL); +AttachThreadInput(ftid, ctid, TRUE); +SetForegroundWindow(hw); +AttachThreadInput(ftid, ctid, FALSE); +} +*/ + +static TCHAR szUrl[64] = TEXT(""); +static TCHAR szDownloading[64] = TEXT("Downloading %s"); +static TCHAR szConnecting[64] = TEXT("Connecting ..."); +static TCHAR szSecond[64] = TEXT("second"); +static TCHAR szMinute[32] = TEXT("minute"); +static TCHAR szHour[32] = TEXT("hour"); +static TCHAR szPlural[32] = TEXT("s"); +static TCHAR szProgress[128] = TEXT("%dkB (%d%%) of %dkB @ %d.%01dkB/s"); +static TCHAR szRemaining[64] = TEXT(" (%d %s%s remaining)"); +static TCHAR szBasic[128] = TEXT(""); +static TCHAR szAuth[128] = TEXT(""); + +// is it possible to make it working with unicode strings? + +/* Base64 encode one byte */ +static TCHAR encode(unsigned char u) { + + if(u < 26) return TEXT('A')+u; + if(u < 52) return TEXT('a')+(u-26); + if(u < 62) return TEXT('0')+(u-52); + if(u == 62) return TEXT('+'); + return TEXT('/'); +} + +TCHAR *encode_base64(int size, TCHAR *src, TCHAR *dst) { + + int i; + TCHAR *p; + + if(!src) + return NULL; + + if(!size) + size= lstrlen(src); + + p = dst; + + for(i=0; i>2; + b5= ((b1&0x3)<<4)|(b2>>4); + b6= ((b2&0xf)<<2)|(b3>>6); + b7= b3&0x3f; + + *p++= encode(b4); + *p++= encode(b5); + + if(i+1 0) + { + dw = data_buf; + if(!InternetWriteFile(hFile, dw, bytesDone, &rslt) || rslt == 0) + { + status = ERR_TRANSFER; + break; + } + dw += rslt; + cnt += rslt; + bytesDone -= rslt; + } + } + else + { + if(!InternetReadFile(hFile, data_buf, sizeof(data_buf), &rslt)) + { + status = ERR_TRANSFER; + break; + } + if(rslt == 0) // EOF reached or cable disconnect + { +// on cable disconnect returns TRUE and 0 bytes. is cnt == 0 OK (zero file size)? +// cannot check this if reply is chunked (no content-length, http 1.1) + status = (fs != NOT_AVAILABLE && cnt < fs) ? ERR_TRANSFER : ST_OK; + break; + } + if(szToStack) + { + for (DWORD i = 0; cntToStack < g_stringsize && i < rslt; i++, cntToStack++) + *(szToStack + cntToStack) = data_buf[i]; + } + else if(!WriteFile(localFile, data_buf, rslt, &bytesDone, NULL) || + rslt != bytesDone) + { + status = ERR_FILEWRITE; + break; + } + cnt += rslt; + } + } +} + +/***************************************************** +* FUNCTION NAME: mySendRequest() +* PURPOSE: +* HttpSendRequestEx() sends headers only - for PUT +* We also can use InetWriteFile for POST body I guess +* SPECIAL CONSIDERATIONS: +* +*****************************************************/ +int mySendRequest(HINTERNET hFile) +{ + INTERNET_BUFFERS BufferIn = {0}; + if(fput) + { + BufferIn.dwStructSize = sizeof( INTERNET_BUFFERS ); + BufferIn.dwBufferTotal = fs; + return HttpSendRequestEx( hFile, &BufferIn, NULL, HSR_INITIATE, 0); + } + return HttpSendRequest(hFile, NULL, 0, szPost, fSize); +} + +/***************************************************** +* FUNCTION NAME: queryStatus() +* PURPOSE: +* http status code comes before download (get) and +* after upload (put), so this is called from 2 places +* SPECIAL CONSIDERATIONS: +* +*****************************************************/ +bool queryStatus(HINTERNET hFile) +{ + TCHAR buf[256] = TEXT(""); + DWORD rslt; + if(HttpQueryInfo(hFile, HTTP_QUERY_STATUS_CODE, + buf, &(rslt = sizeof(buf)), NULL)) + { + buf[3] = 0; + if(lstrcmp(buf, TEXT("0")) == 0 || *buf == 0) + status = ERR_SENDREQUEST; + else if(lstrcmp(buf, TEXT("401")) == 0) + status = ERR_AUTH; + else if(lstrcmp(buf, TEXT("403")) == 0) + status = ERR_FORBIDDEN; + else if(lstrcmp(buf, TEXT("404")) == 0) + status = ERR_NOTFOUND; + else if(lstrcmp(buf, TEXT("407")) == 0) + status = ERR_PROXY; + else if(lstrcmp(buf, TEXT("405")) == 0) + status = ERR_NOTALLOWED; + else if(lstrcmp(buf, TEXT("304")) == 0) + status = ERR_NOTMODIFIED; + else if(*buf == TEXT('3')) + { + status = ERR_REDIRECTION; + wsprintf(szStatus[status] + lstrlen(szStatus[status]), TEXT(" (%s)"), buf); + } + else if(*buf == TEXT('4')) + { + status = ERR_REQUEST; + wsprintf(szStatus[status] + lstrlen(szStatus[status]), TEXT(" (%s)"), buf); + } + else if(*buf == TEXT('5')) + { + status = ERR_SERVER; + wsprintf(szStatus[status] + lstrlen(szStatus[status]), TEXT(" (%s)"), buf); + } + return true; + } + return false; +} + +/***************************************************** +* FUNCTION NAME: openFtpFile() +* PURPOSE: +* control connection, size request, re-get lseek +* SPECIAL CONSIDERATIONS: +* +*****************************************************/ +HINTERNET openFtpFile(HINTERNET hConn, + TCHAR *path) +{ + TCHAR buf[256] = TEXT(""), *movp; + HINTERNET hFile; + DWORD rslt, err, gle; + bool https_req_ok = false; + + /* reads connection / auth responce info and cleares 'control' buffer this way */ + InternetGetLastResponseInfo(&err, buf, &(rslt = sizeof(buf))); + if(cnt == 0) + { + if(!fput) // we know local file size already + { + if (myFtpCommand) + { + /* Try to set the REPRESENTATION TYPE to I[mage] (Binary) because some servers + don't accept the SIZE command in ASCII mode */ + myFtpCommand(hConn, false, FTP_TRANSFER_TYPE_ASCII, TEXT("TYPE I"), 0, &hFile); + } + /* too clever myFtpCommand returnes false on the valid TEXT("550 Not found/Not permitted" server answer, + to read answer I had to ignory returned false (!= 999999) :-( + GetLastError also possible, but MSDN description of codes is very limited */ + wsprintf(buf, TEXT("SIZE %s"), path + 1); + if(myFtpCommand != NULL && + myFtpCommand(hConn, false, FTP_TRANSFER_TYPE_ASCII, buf, 0, &hFile) != 9999 && + memset(buf, 0, sizeof(buf)) != NULL && + InternetGetLastResponseInfo(&err, buf, &(rslt = sizeof(buf)))) + { + if(_tcsstr(buf, TEXT("213 "))) + { + fs = myatou(_tcschr(buf, TEXT(' ')) + 1); + } + /* stupid ProFTPD returns error on SIZE request. let's continue without size. + But IE knows some trick to get size from ProFTPD...... + else if(mystrstr(buf, TEXT("550 TEXT(")) + { + status = ERR_SIZE_NOT_PERMITTED; + return NULL; + } + */ + } + if(fs == 0) + { + fs = NOT_AVAILABLE; + } + } + } + else + { + wsprintf(buf, TEXT("REST %d"), cnt); + if(myFtpCommand == NULL || + !myFtpCommand(hConn, false, FTP_TRANSFER_TYPE_BINARY, buf, 0, &hFile) || + memset(buf, 0, sizeof(buf)) == NULL || + !InternetGetLastResponseInfo(&err, buf, &(rslt = sizeof(buf))) || + (_tcsstr(buf, TEXT("350")) == NULL && _tcsstr(buf, TEXT("110")) == NULL)) + { + status = ERR_REGET; + return NULL; + } + } + if((hFile = FtpOpenFile(hConn, path + 1, fput ? GENERIC_WRITE : GENERIC_READ, + FTP_TRANSFER_TYPE_BINARY|INTERNET_FLAG_RELOAD,0)) == NULL) + { + gle = GetLastError(); + *buf = 0; + InternetGetLastResponseInfo(&err, buf, &(rslt = sizeof(buf))); + // wrong path - dir may not exist or upload may be not allowed + // we use ftp://host//path (double /) to define path from FS root + if(fput && (_tcsstr(buf, TEXT("550")) != NULL || _tcsstr(buf, TEXT("553")) != NULL)) + { + movp = path + 1; + if(*movp == TEXT('/')) movp++; // don't need to create root + for (UINT8 escapehatch = 0; ++escapehatch;) // Weak workaround for http://forums.winamp.com/showpost.php?p=3031692&postcount=513 bug + { + TCHAR *pbs = _tcschr(movp, TEXT('/')); + if (!pbs) break; + *pbs = TEXT('\0'); + FtpCreateDirectory(hConn, path + 1); + InternetGetLastResponseInfo(&err, buf, &(rslt = sizeof(buf))); + *(movp + lstrlen(movp)) = TEXT('/'); + movp = _tcschr(movp, TEXT('/')) + 1; + } + if(status != ERR_CREATEDIR && + (hFile = FtpOpenFile(hConn, path + 1, GENERIC_WRITE, + FTP_TRANSFER_TYPE_BINARY|INTERNET_FLAG_RELOAD,0)) == NULL) + { + status = ERR_PATH; + if(InternetGetLastResponseInfo(&err, buf, &(rslt = sizeof(buf)))) + lstrcpyn(szStatus[status], _tcsstr(buf, TEXT("550")), sizeof(szStatus[0]) / sizeof(TCHAR)); + } + } + // may be firewall related error, let's give user time to disable it + else if(gle == 12003) // ERROR_INTERNET_EXTENDED_ERROR + { + if(_tcsstr(buf, TEXT("550"))) + { + status = ERR_NOTFOUND; + lstrcpyn(szStatus[status], _tcsstr(buf, TEXT("550")), sizeof(szStatus[0]) / sizeof(TCHAR)); + } + else + { + lstrcpyn(szStatus[status], buf, sizeof(szStatus[0]) / sizeof(TCHAR)); + } + } + // timeout (firewall or dropped connection problem) + else if(gle == 12002) // ERROR_INTERNET_TIMEOUT + { + if(!silent) + resume = true; + status = ERR_URLOPEN; + } + } + else + InternetGetLastResponseInfo(&err, buf, &(rslt = sizeof(buf))); + if (hFile && NOT_AVAILABLE == fs) + { + FARPROC ftpgfs = GetWininetProcAddress("FtpGetFileSize"); // IE5+ + if (ftpgfs) + { + DWORD shi, slo = ((DWORD(WINAPI*)(HINTERNET,DWORD*))ftpgfs)(hFile, &shi); + if (slo != -1 && !shi) fs = slo; + } + } + return hFile; +} + + +/***************************************************** +* FUNCTION NAME: openHttpFile() +* PURPOSE: +* file open, size request, re-get lseek +* SPECIAL CONSIDERATIONS: +* +*****************************************************/ +HINTERNET openHttpFile(HINTERNET hConn, INTERNET_SCHEME nScheme, TCHAR *path) +{ + TCHAR buf[256] = TEXT(""); + HINTERNET hFile; + DWORD rslt, err; + bool first_attempt = true;; + +// test connection for PUT, the only way to do this before sending data +// OPTIONS fails on HttpOpenRequest step for HTTPS +// but works for HEAD I guess + if(fput)// && nScheme != INTERNET_SCHEME_HTTPS) + { +// old proxy's may not support OPTIONS request, so changed to HEAD.... + if((hFile = HttpOpenRequest(hConn, TEXT("HEAD"), path, NULL, NULL, NULL, +// if((hFile = HttpOpenRequest(hConn, TEXT("OPTIONS"), path, NULL, NULL, NULL, + INTERNET_FLAG_RELOAD | INTERNET_FLAG_KEEP_CONNECTION | + (nocookies ? (INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_COOKIES) : 0), 0)) != NULL) + { + if(*szAuth) + { + wsprintf(buf, PROXY_AUTH_HDR, szAuth); + HttpAddRequestHeaders(hFile, buf, -1, + HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE); + } +resend_proxy1: + if(*szBasic) + { + wsprintf(buf, HOST_AUTH_HDR, szBasic); + HttpAddRequestHeaders(hFile, buf, -1, + HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE); + } +resend_auth1: + if(HttpSendRequest(hFile, NULL, 0, NULL, 0)) + { + queryStatus(hFile); +// may be don't need to read all from socket, but this looks safer + while(InternetReadFile(hFile, buf, sizeof(buf), &rslt) && rslt > 0) {} + if(!silent && (status == ERR_PROXY || status == ERR_AUTH))// || status == ERR_FORBIDDEN)) + { + rslt = InternetErrorDlg(hDlg, hFile, + ERROR_INTERNET_INCORRECT_PASSWORD, + FLAGS_ERROR_UI_FILTER_FOR_ERRORS | + FLAGS_ERROR_UI_FLAGS_GENERATE_DATA | + FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS, + NULL); + if (rslt == ERROR_INTERNET_FORCE_RETRY) + { + status = ST_URLOPEN; + if(status == ERR_PROXY) goto resend_proxy1; + else goto resend_auth1; + } + else + { + status = ST_CANCELLED; + } + + } + // no such file is OK for PUT. server first checks authentication + if(status == ERR_NOTFOUND || status == ERR_FORBIDDEN || status == ERR_NOTALLOWED) + { +// MessageBox(childwnd, TEXT("NOT_FOUND"), "", 0); + status = ST_URLOPEN; + } + // parameters might be updated during dialog popup + if(status == ST_URLOPEN) + { + *buf = 0; + if(HttpQueryInfo(hFile, HTTP_QUERY_AUTHORIZATION, buf, &(rslt = sizeof(buf)), NULL) && *buf) + lstrcpyn(szBasic, buf, rslt); + *buf = 0; + if(HttpQueryInfo(hFile, HTTP_QUERY_PROXY_AUTHORIZATION, buf, &(rslt = sizeof(buf)), NULL) && *buf) + lstrcpyn(szAuth, buf, rslt); + } + } + else status = ERR_SENDREQUEST; + InternetCloseHandle(hFile); + } + else status = ERR_OPENREQUEST; + } +// request itself + if(status == ST_URLOPEN) + { + DWORD secflags = nScheme == INTERNET_SCHEME_HTTPS ? MY_HTTPS_FLAGS : 0; + if (Option_IgnoreCertIssues()) secflags |= MY_WEAKSECURITY_CERT_FLAGS; + DWORD cokflags = nocookies ? (INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_COOKIES) : 0; + if((hFile = HttpOpenRequest(hConn, fput ? TEXT("PUT") : (fhead ? TEXT("HEAD") : (szPost ? TEXT("POST") : NULL)), + path, NULL, NULL, NULL, + // INTERNET_FLAG_RELOAD conflicts with reget - hidden re-read from beginning has place + // INTERNET_FLAG_RESYNCHRONIZE // note - sync may not work with some http servers + // reload on first connect (and any req. except GET), just continue on resume. + // HTTP Proxy still is a problem for reget + (cnt ? 0 : INTERNET_FLAG_RELOAD) | INTERNET_FLAG_KEEP_CONNECTION | cokflags | secflags, 0)) != NULL) + { + if(*szAuth) + { + wsprintf(buf, PROXY_AUTH_HDR, szAuth); + HttpAddRequestHeaders(hFile, buf, -1, + HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE); + } +resend_proxy2: + if(szPost != NULL) + HttpAddRequestHeaders(hFile, POST_HEADER, + -1, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE); + if(*post_fname) + HttpAddRequestHeadersA(hFile, post_fname, + -1, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE); + if(szHeader != NULL) + HttpAddRequestHeaders(hFile, szHeader, -1, + HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE); + if(*szBasic) + { + wsprintf(buf, HOST_AUTH_HDR, szBasic); + HttpAddRequestHeaders(hFile, buf, -1, + HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE); + } + if(fput) + { + wsprintf(buf, PUT_HEADER, fs); + HttpAddRequestHeaders(hFile, buf, -1, + HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE); + } +resend_auth2: + first_attempt = true; + if(nScheme == INTERNET_SCHEME_HTTPS) + { + if(!mySendRequest(hFile)) + { + InternetQueryOption (hFile, INTERNET_OPTION_SECURITY_FLAGS, + (LPVOID)&rslt, &(err = sizeof(rslt))); + rslt |= Option_IgnoreCertIssues() ? MY_WEAKSECURITY_CERT_FLAGS : 0; + InternetSetOption (hFile, INTERNET_OPTION_SECURITY_FLAGS, + &rslt, sizeof(rslt) ); + } + else first_attempt = false; + } +// https Request answer may be after optional second Send only on Win98 + if(!first_attempt || mySendRequest(hFile)) + { +// no status for PUT - headers were sent only. And not need to get size / set position + if(!fput) + { + queryStatus(hFile); + if(!silent && (status == ERR_PROXY || status == ERR_AUTH)) + { + rslt = InternetErrorDlg(hDlg, hFile, + ERROR_INTERNET_INCORRECT_PASSWORD, + FLAGS_ERROR_UI_FILTER_FOR_ERRORS | + FLAGS_ERROR_UI_FLAGS_GENERATE_DATA | + FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS, + NULL); + if (rslt == ERROR_INTERNET_FORCE_RETRY) + { + status = ST_URLOPEN; + if(status == ERR_PROXY) goto resend_proxy2; + else goto resend_auth2; + } + else + status = ST_CANCELLED; + + } +// get size / set position + if(status == ST_URLOPEN) + { + if(cnt == 0) + { + if(HttpQueryInfo(hFile, HTTP_QUERY_CONTENT_LENGTH, buf, + &(rslt = sizeof(buf)), NULL)) + fs = myatou(buf); + else + fs = NOT_AVAILABLE; + } + else + { + if((int)InternetSetFilePointer(hFile, cnt, NULL, FILE_BEGIN, 0) == -1) + status = ERR_REGET; + } + } + } + } + else + { + if(!queryStatus(hFile)) + status = ERR_SENDREQUEST; + } + } + else status = ERR_OPENREQUEST; + } + return hFile; +} + +/***************************************************** +* FUNCTION NAME: inetTransfer() +* PURPOSE: +* http/ftp file transfer +* SPECIAL CONSIDERATIONS: +* +*****************************************************/ +DWORD __stdcall inetTransfer(void *hw) +{ + HINTERNET hSes, hConn, hFile; + HANDLE localFile = NULL; + HWND hDlg = (HWND)hw; + DWORD lastCnt, rslt, err; + static TCHAR hdr[2048]; + TCHAR *host = (TCHAR*)LocalAlloc(LPTR, g_stringsize * sizeof(TCHAR)), + *path = (TCHAR*)LocalAlloc(LPTR, g_stringsize * sizeof(TCHAR)), + *params = (TCHAR*)LocalAlloc(LPTR, g_stringsize * sizeof(TCHAR)), + *user = (TCHAR*)LocalAlloc(LPTR, g_stringsize * sizeof(TCHAR)), + *passwd = (TCHAR*)LocalAlloc(LPTR, g_stringsize * sizeof(TCHAR)); + + URL_COMPONENTS uc = {sizeof(URL_COMPONENTS), NULL, 0, + (INTERNET_SCHEME)0, host, g_stringsize, 0 , user, g_stringsize, + passwd, g_stringsize, path, g_stringsize, params, g_stringsize}; + + if((hSes = InternetOpen(szUserAgent, openType, szProxy, NULL, 0)) != NULL) + { + if(InternetQueryOption(hSes, INTERNET_OPTION_CONNECTED_STATE, &(rslt=0), + &(lastCnt=sizeof(DWORD))) && + (rslt & INTERNET_STATE_DISCONNECTED_BY_USER)) + { + INTERNET_CONNECTED_INFO ci = {INTERNET_STATE_CONNECTED, 0}; + InternetSetOption(hSes, + INTERNET_OPTION_CONNECTED_STATE, &ci, sizeof(ci)); + } + if(timeout > 0) + lastCnt = InternetSetOption(hSes, INTERNET_OPTION_CONNECT_TIMEOUT, &timeout, sizeof(timeout)); + if(receivetimeout > 0) + InternetSetOption(hSes, INTERNET_OPTION_RECEIVE_TIMEOUT, &receivetimeout, sizeof(receivetimeout)); + // 60 sec WinInet.dll detach delay on socket time_wait fix + myFtpCommand = (FTP_CMD) GetWininetProcAddress( +#ifdef UNICODE + "FtpCommandW" +#else + "FtpCommandA" +#endif + ); + while(!popstring(url) && lstrcmpi(url, TEXT("/end")) != 0) + { + // too many customers requested not to do this + // sf(hDlg); + if(popstring(fn) != 0 || lstrcmpi(url, TEXT("/end")) == 0) break; + status = ST_CONNECTING; + cnt = fs = *host = *user = *passwd = *path = *params = 0; + PostMessage(hDlg, WM_TIMER, 1, 0); // show url & fn, do it sync + if(szToStack || (localFile = CreateFile(fn, fput ? GENERIC_READ : GENERIC_WRITE, FILE_SHARE_READ, + NULL, fput ? OPEN_EXISTING : CREATE_ALWAYS, 0, NULL)) != INVALID_HANDLE_VALUE) + { + uc.dwHostNameLength = uc.dwUserNameLength = uc.dwPasswordLength = + uc.dwUrlPathLength = uc.dwExtraInfoLength = g_stringsize; + if(fput) + { + fs = GetFileSize(localFile, NULL); + } + if(InternetCrackUrl(url, 0, 0/*ICU_ESCAPE*/ , &uc)) + { + // auth headers for HTTP PUT seems to be lost, preparing encoded login:password + if(*user && *passwd) + { + wsprintf(hdr, TEXT("%s:%s"), user, passwd); + // does unicode version of encoding works correct? + // are user and passwd ascii only? + encode_base64(lstrlen(hdr), hdr, szBasic); + *hdr = 0; + } + lstrcat(path, params); // BUGBUG: Could overflow path? + transfStart = GetTickCount(); + do + { + // re-PUT to already deleted tmp file on http server is not possible. + // the same with POST - must re-send data to server. for 'resume' loop + if((fput && uc.nScheme != INTERNET_SCHEME_FTP) || szPost) + { + cnt = 0; + SetFilePointer(localFile, 0, NULL, FILE_BEGIN); + } + status = ST_CONNECTING; + lastCnt = cnt; + if((hConn = InternetConnect(hSes, host, uc.nPort, + lstrlen(user) > 0 ? user : NULL, + lstrlen(passwd) > 0 ? passwd : NULL, + uc.nScheme == INTERNET_SCHEME_FTP ? INTERNET_SERVICE_FTP : INTERNET_SERVICE_HTTP, + uc.nScheme == INTERNET_SCHEME_FTP ? INTERNET_FLAG_PASSIVE : 0, 0)) != NULL) + { + status = ST_URLOPEN; + hFile = uc.nScheme == INTERNET_SCHEME_FTP ? + openFtpFile(hConn, path) : openHttpFile(hConn, uc.nScheme, path); + if(status != ST_URLOPEN && hFile != NULL) + { + InternetCloseHandle(hFile); + hFile = NULL; + } + if(hFile != NULL) + { + if(fhead) + {// repeating calls clear headers.. + if(HttpQueryInfo(hFile, HTTP_QUERY_RAW_HEADERS_CRLF, hdr, &(rslt=2048), NULL)) + { + if(szToStack) + { + for (DWORD i = 0; cntToStack < g_stringsize && i < rslt; i++, cntToStack++) + *(szToStack + cntToStack) = hdr[i]; + } + else + { + WriteFile(localFile, hdr, rslt, &lastCnt, NULL); + } + } + status = ST_OK; + } + else + { + HWND hBar = GetDlgItem(hDlg, IDC_PROGRESS1); + SendDlgItemMessage(hDlg, IDC_PROGRESS1, PBM_SETPOS, 0, 0); + SetWindowText(GetDlgItem(hDlg, IDC_STATIC5), fs == NOT_AVAILABLE ? TEXT("Not Available") : TEXT("")); + SetWindowText(GetDlgItem(hDlg, IDC_STATIC4), fs == NOT_AVAILABLE ? TEXT("Unknown") : TEXT("")); + SetWindowLong(hBar, GWL_STYLE, fs == NOT_AVAILABLE ? + (GetWindowLong(hBar, GWL_STYLE) | PBS_MARQUEE) : (GetWindowLong(hBar, GWL_STYLE) & ~PBS_MARQUEE)); + SendDlgItemMessage(hDlg, IDC_PROGRESS1, PBM_SETMARQUEE, (WPARAM)(fs == NOT_AVAILABLE ? 1 : 0), (LPARAM)50 ); + fileTransfer(localFile, hFile); + if(fput && uc.nScheme != INTERNET_SCHEME_FTP) + { + rslt = HttpEndRequest(hFile, NULL, 0, 0); + queryStatus(hFile); + } + } + InternetCloseHandle(hFile); + } + InternetCloseHandle(hConn); + } + else + { + status = ERR_CONNECT; + if(uc.nScheme == INTERNET_SCHEME_FTP && + InternetGetLastResponseInfo(&err, hdr, &(rslt = sizeof(hdr))) && + _tcsstr(hdr, TEXT("530"))) + { + lstrcpyn(szStatus[status], _tcsstr(hdr, TEXT("530")), sizeof(szStatus[0]) / sizeof(TCHAR)); + } + else + { + rslt = GetLastError(); + if((rslt == 12003 || rslt == 12002) && !silent) + resume = true; + } + } + } while(((!fput || uc.nScheme == INTERNET_SCHEME_FTP) && + cnt > lastCnt && + status == ERR_TRANSFER && + SleepEx(PAUSE1_SEC * 1000, false) == 0 && + (status = ST_PAUSE) != ST_OK && + SleepEx(PAUSE2_SEC * 1000, false) == 0) + || (resume && + status != ST_OK && + status != ST_CANCELLED && + status != ERR_NOTFOUND && + ShowWindow(hDlg, SW_HIDE) != -1 && + MessageBox(GetParent(hDlg), szResume, *szCaption ? szCaption : PLUGIN_NAME, MB_RETRYCANCEL|MB_ICONWARNING) == IDRETRY && + (status = ST_PAUSE) != ST_OK && + ShowWindow(hDlg, silent ? SW_HIDE : SW_SHOW) == false && + SleepEx(PAUSE3_SEC * 1000, false) == 0)); + } + else status = ERR_CRACKURL; + CloseHandle(localFile); + if(!fput && status != ST_OK && !szToStack) + { + rslt = DeleteFile(fn); + break; + } + } + else status = ERR_FILEOPEN; + } + InternetCloseHandle(hSes); + if (lstrcmpi(url, TEXT("/end"))==0) + pushstring(url); + } + else status = ERR_INETOPEN; + LocalFree(host); + LocalFree(path); + LocalFree(user); + LocalFree(passwd); + LocalFree(params); + if(IsWindow(hDlg)) + PostMessage(hDlg, WM_COMMAND, MAKELONG(IDOK, INTERNAL_OK), 0); + return status; +} + +/***************************************************** +* FUNCTION NAME: fsFormat() +* PURPOSE: +* formats DWORD (max 4 GB) file size for dialog, big MB +* SPECIAL CONSIDERATIONS: +* +*****************************************************/ +void fsFormat(DWORD bfs, TCHAR *b) +{ + if(bfs == NOT_AVAILABLE) + lstrcpy(b, TEXT("???")); + else if(bfs == 0) + lstrcpy(b, TEXT("0")); + else if(bfs < 10 * 1024) + wsprintf(b, TEXT("%u bytes"), bfs); + else if(bfs < 10 * 1024 * 1024) + wsprintf(b, TEXT("%u kB"), bfs / 1024); + else wsprintf(b, TEXT("%u MB"), (bfs / 1024 / 1024)); +} + + +/***************************************************** +* FUNCTION NAME: progress_callback +* PURPOSE: +* old-style progress bar text updates +* SPECIAL CONSIDERATIONS: +* +*****************************************************/ + +void progress_callback(void) +{ + static TCHAR buf[1024] = TEXT(""), b[1024] = TEXT(""); + int time_sofar = max(1, (GetTickCount() - transfStart) / 1000); + int bps = cnt / time_sofar; + int remain = (cnt > 0 && fs != NOT_AVAILABLE) ? (MulDiv(time_sofar, fs, cnt) - time_sofar) : 0; + TCHAR *rtext=szSecond; + if(remain < 0) remain = 0; + if (remain >= 60) + { + remain/=60; + rtext=szMinute; + if (remain >= 60) + { + remain/=60; + rtext=szHour; + } + } + wsprintf(buf, + szProgress, + cnt/1024, + fs > 0 && fs != NOT_AVAILABLE ? MulDiv(100, cnt, fs) : 0, + fs != NOT_AVAILABLE ? fs/1024 : 0, + bps/1024,((bps*10)/1024)%10 + ); + if (remain) wsprintf(buf + lstrlen(buf), + szRemaining, + remain, + rtext, + remain==1?TEXT(""):szPlural + ); + SetDlgItemText(hDlg, IDC_STATIC1, (cnt == 0 || status == ST_CONNECTING) ? szConnecting : buf); + if(fs > 0 && fs != NOT_AVAILABLE) + SendMessage(GetDlgItem(hDlg, IDC_PROGRESS1), PBM_SETPOS, MulDiv(cnt, PB_RANGE, fs), 0); + if (*szCaption == 0) + wsprintf(buf, szDownloading, _tcsrchr(fn, TEXT('\\')) ? _tcsrchr(fn, TEXT('\\')) + 1 : fn); + else + wsprintf(buf, TEXT("%s"),szCaption); + HWND hwndS = GetDlgItem(childwnd, 1006); + if(!silent && hwndS != NULL && IsWindow(hwndS)) + { + GetWindowText(hwndS, b, sizeof(b)); + if(lstrcmp(b, buf) != 0) + SetWindowText(hwndS, buf); + } +} + +/***************************************************** +* FUNCTION NAME: onTimer() +* PURPOSE: +* updates text fields every second +* SPECIAL CONSIDERATIONS: +* +*****************************************************/ +void onTimer(HWND hDlg) +{ + TCHAR b[128]; + DWORD ct = (GetTickCount() - transfStart) / 1000, + tt = (GetTickCount() - startTime) / 1000; + // dialog window caption + wsprintf(b, TEXT("%s - %s"), *szCaption ? szCaption : PLUGIN_NAME, szStatus[status]); + if(fs > 0 && fs != NOT_AVAILABLE && status == ST_DOWNLOAD) + { + wsprintf(b + lstrlen(b), TEXT(" %d%%"), MulDiv(100, cnt, fs)); + } + if(szBanner == NULL) SetWindowText(hDlg, b); + // current file and url + SetDlgItemText(hDlg, IDC_STATIC1, (szAlias && *szAlias) ? szAlias : url); + SetDlgItemText(hDlg, IDC_STATIC2, /*_tcsrchr(fn, '\\') ? _tcsrchr(fn, '\\') + 1 : */fn); + // bytes done and rate + if(cnt > 0) + { + fsFormat(cnt, b); + if(ct > 1 && status == ST_DOWNLOAD) + { + lstrcat(b, TEXT(" ( ")); + fsFormat(cnt / ct, b + lstrlen(b)); + lstrcat(b, TEXT("/sec )")); + } + } + else *b = 0; + SetDlgItemText(hDlg, IDC_STATIC3, b); + // total download time + wsprintf(b, TEXT("%d:%02d:%02d"), tt / 3600, (tt / 60) % 60, tt % 60); + SetDlgItemText(hDlg, IDC_STATIC6, b); + // file size, time remaining, progress bar + if(fs > 0 && fs != NOT_AVAILABLE) + { + fsFormat(fs, b); + SetDlgItemText(hDlg, IDC_STATIC5, b); + SendDlgItemMessage(hDlg, IDC_PROGRESS1, PBM_SETPOS, MulDiv(cnt, PB_RANGE, fs), 0); + if(cnt > 5000) + { + ct = MulDiv(fs - cnt, ct, cnt); + wsprintf(b, TEXT("%d:%02d:%02d"), ct / 3600, (ct / 60) % 60, ct % 60); + } + else *b = 0; + SetWindowText(GetDlgItem(hDlg, IDC_STATIC4), b); + } +} + +/***************************************************** +* FUNCTION NAME: centerDlg() +* PURPOSE: +* centers dlg on NSIS parent +* SPECIAL CONSIDERATIONS: +* +*****************************************************/ +void centerDlg(HWND hDlg) +{ + HWND hwndParent = GetParent(hDlg); + RECT nsisRect, dlgRect, waRect; + int dlgX, dlgY, dlgWidth, dlgHeight; + + if(hwndParent == NULL || silent) + return; + if(popup) + GetWindowRect(hwndParent, &nsisRect); + else GetClientRect(hwndParent, &nsisRect); + GetWindowRect(hDlg, &dlgRect); + + dlgWidth = dlgRect.right - dlgRect.left; + dlgHeight = dlgRect.bottom - dlgRect.top; + dlgX = (nsisRect.left + nsisRect.right - dlgWidth) / 2; + dlgY = (nsisRect.top + nsisRect.bottom - dlgHeight) / 2; + + if(popup) + { + SystemParametersInfo(SPI_GETWORKAREA, 0, &waRect, 0); + if(dlgX > waRect.right - dlgWidth) + dlgX = waRect.right - dlgWidth; + if(dlgX < waRect.left) dlgX = waRect.left; + if(dlgY > waRect.bottom - dlgHeight) + dlgY = waRect.bottom - dlgHeight; + if(dlgY < waRect.top) dlgY = waRect.top; + } + else dlgY += 20; + + SetWindowPos(hDlg, HWND_TOP, dlgX, dlgY, 0, 0, SWP_NOSIZE); +} + +/***************************************************** +* FUNCTION NAME: onInitDlg() +* PURPOSE: +* dlg init +* SPECIAL CONSIDERATIONS: +* +*****************************************************/ +void onInitDlg(HWND hDlg) +{ + HFONT hFont; + HWND hPrbNew; + HWND hPrbOld; + HWND hCan = GetDlgItem(hDlg, IDCANCEL); + + if(childwnd) + { + hPrbNew = GetDlgItem(hDlg, IDC_PROGRESS1); + hPrbOld = GetDlgItem(childwnd, 0x3ec); + + // Backland' fix for progress bar redraw/style issue. + // Original bar may be hidden because of interfernce with other plug-ins. + LONG prbStyle = WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; + if(hPrbOld != NULL) + { + prbStyle |= GetWindowLong(hPrbOld, GWL_STYLE); + } + SetWindowLong(hPrbNew, GWL_STYLE, prbStyle); + + if(!popup) + { + if((hFont = (HFONT)SendMessage(childwnd, WM_GETFONT, 0, 0)) != NULL) + { + SendDlgItemMessage(hDlg, IDC_STATIC1, WM_SETFONT, (WPARAM)hFont, 0); + SendDlgItemMessage(hDlg, IDCANCEL, WM_SETFONT, (WPARAM)hFont, 0); + } + if(*szCancel == 0) + GetWindowText(GetDlgItem(GetParent(childwnd), IDCANCEL), szCancel, sizeof(szCancel)); + SetWindowText(hCan, szCancel); + SetWindowPos(hPrbNew, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); + } + } + + if(nocancel) + { + if(hCan != NULL) + ShowWindow(hCan, SW_HIDE); + if(popup) + SetWindowLong(hDlg, GWL_STYLE, GetWindowLong(hDlg, GWL_STYLE) ^ WS_SYSMENU); + } + SendDlgItemMessage(hDlg, IDC_PROGRESS1, PBM_SETRANGE, + 0, MAKELPARAM(0, PB_RANGE)); + if(szBanner != NULL) + { + SendDlgItemMessage(hDlg, IDC_STATIC13, STM_SETICON, + (WPARAM)LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(103)), 0); + SetDlgItemText(hDlg, IDC_STATIC12, szBanner); + SetWindowText(hDlg, *szCaption ? szCaption : PLUGIN_NAME); + } + SetTimer(hDlg, 1, 1000, NULL); + if(*szUrl != 0) + { + SetDlgItemText(hDlg, IDC_STATIC20, szUrl); + SetDlgItemText(hDlg, IDC_STATIC21, szDownloading); + SetDlgItemText(hDlg, IDC_STATIC22, szConnecting); + SetDlgItemText(hDlg, IDC_STATIC23, szProgress); + SetDlgItemText(hDlg, IDC_STATIC24, szSecond); + SetDlgItemText(hDlg, IDC_STATIC25, szRemaining); + } +} + +/***************************************************** +* FUNCTION NAME: dlgProc() +* PURPOSE: +* dlg message handling procedure +* SPECIAL CONSIDERATIONS: +* todo: better dialog design +*****************************************************/ +INT_PTR CALLBACK dlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) +{ + switch(message) + { + case WM_INITDIALOG: + onInitDlg(hDlg); + centerDlg(hDlg); + return false; + case WM_PAINT: + // child dialog redraw problem. return false is important + RedrawWindow(GetDlgItem(hDlg, IDC_STATIC1), NULL, NULL, RDW_INVALIDATE); + RedrawWindow(GetDlgItem(hDlg, IDCANCEL), NULL, NULL, RDW_INVALIDATE); + RedrawWindow(GetDlgItem(hDlg, IDC_PROGRESS1), NULL, NULL, RDW_INVALIDATE); + UpdateWindow(GetDlgItem(hDlg, IDC_STATIC1)); + UpdateWindow(GetDlgItem(hDlg, IDCANCEL)); + UpdateWindow(GetDlgItem(hDlg, IDC_PROGRESS1)); + return false; + case WM_TIMER: + if(!silent && IsWindow(hDlg)) + { + // long connection period and paused state updates + if(status != ST_DOWNLOAD && GetTickCount() - transfStart > PROGRESS_MS) + transfStart += PROGRESS_MS; + if(popup) onTimer(hDlg); else progress_callback(); + RedrawWindow(GetDlgItem(hDlg, IDC_STATIC1), NULL, NULL, RDW_INVALIDATE); + RedrawWindow(GetDlgItem(hDlg, IDCANCEL), NULL, NULL, RDW_INVALIDATE); + RedrawWindow(GetDlgItem(hDlg, IDC_PROGRESS1), NULL, NULL, RDW_INVALIDATE); + } + break; + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDCANCEL: + if(nocancel) break; + if(szQuestion && + MessageBox(hDlg, szQuestion, *szCaption ? szCaption : PLUGIN_NAME, MB_ICONWARNING|MB_YESNO) == IDNO) + break; + status = ST_CANCELLED; + // FallThrough + case IDOK: + if(status != ST_CANCELLED && HIWORD(wParam) != INTERNAL_OK) break; + // otherwise in the silent mode next banner windows may go to background + // if(silent) sf(hDlg); + KillTimer(hDlg, 1); + DestroyWindow(hDlg); + break; + } + return false; + default: + return false; + } + return true; +} + +/***************************************************** +* FUNCTION NAME: get() +* PURPOSE: +* http/https/ftp file download entry point +* SPECIAL CONSIDERATIONS: +* +*****************************************************/ +extern "C" +void __declspec(dllexport) __cdecl get(HWND hwndParent, + int string_size, + TCHAR *variables, + stack_t **stacktop, + extra_parameters *extra + ) +{ + HANDLE hThread; + DWORD dwThreadId; + MSG msg; + TCHAR szUsername[64]=TEXT(""), // proxy params + szPassword[64]=TEXT(""); + + + EXDLL_INIT(); + +// for repeating /nounload plug-un calls - global vars clean up + silent = popup = resume = nocancel = noproxy = nocookies = false; + g_ignorecertissues = false; + myFtpCommand = NULL; + openType = INTERNET_OPEN_TYPE_PRECONFIG; + status = ST_CONNECTING; + *szCaption = *szCancel = *szUserAgent = *szBasic = *szAuth = 0; + + url = (TCHAR*)LocalAlloc(LPTR, string_size * sizeof(TCHAR)); + if(szPost) + { + popstring(url); +#ifdef UNICODE + WideCharToMultiByte(CP_ACP, 0, url, -1, szPost, string_size, NULL, NULL); +#else + lstrcpy(szPost, url); +#endif + fSize = (DWORD)lstrlenA(szPost); + } + // global silent option + if(extra->exec_flags->silent != 0) + silent = true; + // we must take this from stack, or push url back + while(!popstring(url) && *url == TEXT('/')) + { + if(lstrcmpi(url, TEXT("/silent")) == 0) + silent = true; + else if(lstrcmpi(url, TEXT("/weaksecurity")) == 0) + g_ignorecertissues = true; + else if(lstrcmpi(url, TEXT("/caption")) == 0) + popstring(szCaption); + else if(lstrcmpi(url, TEXT("/username")) == 0) + popstring(szUsername); + else if(lstrcmpi(url, TEXT("/password")) == 0) + popstring(szPassword); + else if(lstrcmpi(url, TEXT("/nocancel")) == 0) + nocancel = true; + else if(lstrcmpi(url, TEXT("/nocookies")) == 0) + nocookies = true; + else if(lstrcmpi(url, TEXT("/noproxy")) == 0) + openType = INTERNET_OPEN_TYPE_DIRECT; + else if(lstrcmpi(url, TEXT("/popup")) == 0) + { + popup = true; + szAlias = (TCHAR*)LocalAlloc(LPTR, string_size * sizeof(TCHAR)); + popstring(szAlias); + } + else if(lstrcmpi(url, TEXT("/resume")) == 0) + { + popstring(url); + if(url[0]) lstrcpy(szResume, url); + resume = true; + } + else if(lstrcmpi(url, TEXT("/translate")) == 0) + { + if(popup) + { + popstring(szUrl); + popstring(szStatus[ST_DOWNLOAD]); // Downloading + popstring(szStatus[ST_CONNECTING]); // Connecting + lstrcpy(szStatus[ST_URLOPEN], szStatus[ST_CONNECTING]); + popstring(szDownloading);// file name + popstring(szConnecting);// received + popstring(szProgress);// file size + popstring(szSecond);// remaining time + popstring(szRemaining);// total time + } + else + { + popstring(szDownloading); + popstring(szConnecting); + popstring(szSecond); + popstring(szMinute); + popstring(szHour); + popstring(szPlural); + popstring(szProgress); + popstring(szRemaining); + } + } + else if(lstrcmpi(url, TEXT("/banner")) == 0) + { + popup = true; + szBanner = (TCHAR*)LocalAlloc(LPTR, string_size * sizeof(TCHAR)); + popstring(szBanner); + } + else if(lstrcmpi(url, TEXT("/canceltext")) == 0) + { + popstring(szCancel); + } + else if(lstrcmpi(url, TEXT("/question")) == 0) + { + szQuestion = (TCHAR*)LocalAlloc(LPTR, string_size * sizeof(TCHAR)); + popstring(szQuestion); + if(*szQuestion == 0) lstrcpy(szQuestion, DEF_QUESTION); + } + else if(lstrcmpi(url, TEXT("/useragent")) == 0) + { + popstring(szUserAgent); + } + else if(lstrcmpi(url, TEXT("/proxy")) == 0) + { + szProxy = (TCHAR*)LocalAlloc(LPTR, string_size * sizeof(TCHAR)); + popstring(szProxy); + openType = INTERNET_OPEN_TYPE_PROXY; + } + else if(lstrcmpi(url, TEXT("/connecttimeout")) == 0) + { + popstring(url); + timeout = myatou(url) * 1000; + } + else if(lstrcmpi(url, TEXT("/receivetimeout")) == 0) + { + popstring(url); + receivetimeout = myatou(url) * 1000; + } + else if(lstrcmpi(url, TEXT("/header")) == 0) + { + szHeader = (TCHAR*)LocalAlloc(LPTR, string_size * sizeof(TCHAR)); + popstring(szHeader); + } + else if(!fput && ((convToStack = lstrcmpi(url, TEXT("/tostackconv")) == 0) || lstrcmpi(url, TEXT("/tostack")) == 0)) + { + szToStack = (TCHAR*)LocalAlloc(LPTR, string_size * sizeof(TCHAR)); + cntToStack = 0; + lstrcpy(fn, TEXT("file")); + } + else if(lstrcmpi(url, TEXT("/file")) == 0) + { + HANDLE hFile = CreateFileA(szPost, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + DWORD rslt; + if(hFile == INVALID_HANDLE_VALUE) + { + status = ERR_FILEOPEN; + goto cleanup; + } + if((fSize = GetFileSize(hFile, NULL)) == 0) + { + CloseHandle(hFile); + status = ERR_FILEREAD; + goto cleanup; + } + wsprintfA(post_fname, "Filename: %s", + strchr(szPost, '\\') ? strrchr(szPost, '\\') + 1 : szPost); + LocalFree(szPost); + szPost = (char*)LocalAlloc(LPTR, fSize); + if(ReadFile(hFile, szPost, fSize, &rslt, NULL) == 0 || rslt != fSize) + { + CloseHandle(hFile); + status = ERR_FILEREAD; + goto cleanup; + } + CloseHandle(hFile); + } + } + pushstring(url); +// if(*szCaption == 0) lstrcpy(szCaption, PLUGIN_NAME); + if(*szUserAgent == 0) lstrcpy(szUserAgent, INETC_USERAGENT); + if(*szPassword && *szUsername) + { + wsprintf(url, TEXT("%s:%s"), szUsername, szPassword); + encode_base64(lstrlen(url), url, szAuth); + } + // may be silent for plug-in, but not so for installer itself - let's try to define 'progress text' + if(hwndParent != NULL && + (childwnd = FindWindowEx(hwndParent, NULL, TEXT("#32770"), NULL)) != NULL && + !silent) + SetDlgItemText(childwnd, 1006, *szCaption ? szCaption : PLUGIN_NAME); + else InitCommonControls(); // or NSIS do this before .onInit? + // cannot embed child dialog to non-existing parent. Using 'silent' to hide it + if(childwnd == NULL && !popup) silent = true; + // let's use hidden popup dlg in the silent mode - works both on .onInit and Page + if(silent) { resume = false; popup = true; } + // google says WS_CLIPSIBLINGS helps to redraw... not in my tests... + if(!popup) + { + unsigned int wstyle = GetWindowLong(childwnd, GWL_STYLE); + wstyle |= WS_CLIPSIBLINGS; + SetWindowLong(childwnd, GWL_STYLE, wstyle); + } + startTime = GetTickCount(); + if((hDlg = CreateDialog(g_hInstance, + MAKEINTRESOURCE(szBanner ? IDD_DIALOG2 : (popup ? IDD_DIALOG1 : IDD_DIALOG3)), + (popup ? hwndParent : childwnd), dlgProc)) != NULL) + { + + if((hThread = CreateThread(NULL, 0, inetTransfer, (LPVOID)hDlg, 0, + &dwThreadId)) != NULL) + { + HWND hButton = GetDlgItem(childwnd, 0x403); + HWND hList = GetDlgItem(childwnd, 0x3f8); + DWORD dwStyleButton = 0; + BOOL fVisibleList = false; + if(!silent) + { + ShowWindow(hDlg, SW_NORMAL); + if(childwnd && !popup) + { + if(hButton) + { + dwStyleButton = GetWindowLong(hButton, GWL_STYLE); + EnableWindow(hButton, false); + } + if(hList) + { + fVisibleList = IsWindowVisible(hList); + ShowWindow(hList, SW_HIDE); + } + } + } + + while(IsWindow(hDlg) && + GetMessage(&msg, NULL, 0, 0) > 0) + { + if(!IsDialogMessage(hDlg, &msg) && + !IsDialogMessage(hwndParent, &msg) && + !TranslateMessage(&msg)) + DispatchMessage(&msg); + } + + if(WaitForSingleObject(hThread, 3000) == WAIT_TIMEOUT) + { + TerminateThread(hThread, 1); + status = ERR_TERMINATED; + } + CloseHandle(hThread); + if(!silent && childwnd) + { + SetDlgItemText(childwnd, 1006, TEXT("")); + if(!popup) + { + if(hButton) + SetWindowLong(hButton, GWL_STYLE, dwStyleButton); + if(hList && fVisibleList) + ShowWindow(hList, SW_SHOW); + } + // RedrawWindow(childwnd, NULL, NULL, RDW_INVALIDATE|RDW_ERASE); + } + } + else + { + status = ERR_THREAD; + DestroyWindow(hDlg); + } + } + else { + status = ERR_DIALOG; + wsprintf(szStatus[status] + lstrlen(szStatus[status]), TEXT(" (Err=%d)"), GetLastError()); + } +cleanup: + // we need to clean up stack from remaining url/file pairs. + // this multiple files download head pain and may be not safe + while(!popstring(url) && lstrcmpi(url, TEXT("/end")) != 0) + { + /* nothing MessageBox(NULL, url, TEXT(""), 0);*/ + } + LocalFree(url); + if(szAlias) LocalFree(szAlias); + if(szBanner) LocalFree(szAlias); + if(szQuestion) LocalFree(szQuestion); + if(szProxy) LocalFree(szProxy); + if(szPost) LocalFree(szPost); + if(szHeader) LocalFree(szHeader); + + url = szProxy = szHeader = szAlias = szQuestion = NULL; + szPost = NULL; + fput = fhead = false; + + if(szToStack && status == ST_OK) + { + if(cntToStack > 0 && convToStack) + { +#ifdef UNICODE + int required = MultiByteToWideChar(CP_ACP, 0, (CHAR*)szToStack, string_size * sizeof(TCHAR), NULL, 0); + if(required > 0) + { + WCHAR* pszToStackNew = (WCHAR*)LocalAlloc(LPTR, sizeof(WCHAR) * (required + 1)); + if(pszToStackNew) + { + if(MultiByteToWideChar(CP_ACP, 0, (CHAR*)szToStack, string_size * sizeof(TCHAR), pszToStackNew, required) > 0) + pushstring(pszToStackNew); + LocalFree(pszToStackNew); + } + } +#else + int required = WideCharToMultiByte(CP_ACP, 0, (WCHAR*)szToStack, -1, NULL, 0, NULL, NULL); + if(required > 0) + { + CHAR* pszToStackNew = (CHAR*)LocalAlloc(LPTR, required + 1); + if(pszToStackNew) + { + if(WideCharToMultiByte(CP_ACP, 0, (WCHAR*)szToStack, -1, pszToStackNew, required, NULL, NULL) > 0) + pushstring(pszToStackNew); + LocalFree(pszToStackNew); + } + } +#endif + } + else + { + pushstring(szToStack); + } + LocalFree(szToStack); + szToStack = NULL; + } + + pushstring(szStatus[status]); +} + +/***************************************************** +* FUNCTION NAME: put() +* PURPOSE: +* http/ftp file upload entry point +* SPECIAL CONSIDERATIONS: +* re-put not works with http, but ftp REST - may be. +*****************************************************/ +extern "C" +void __declspec(dllexport) __cdecl put(HWND hwndParent, + int string_size, + TCHAR *variables, + stack_t **stacktop, + extra_parameters *extra + ) +{ + fput = true; + lstrcpy(szDownloading, TEXT("Uploading %s")); + lstrcpy(szStatus[2], TEXT("Uploading")); + get(hwndParent, string_size, variables, stacktop, extra); +} + +/***************************************************** +* FUNCTION NAME: post() +* PURPOSE: +* http post entry point +* SPECIAL CONSIDERATIONS: +* +*****************************************************/ +extern "C" +void __declspec(dllexport) __cdecl post(HWND hwndParent, + int string_size, + TCHAR *variables, + stack_t **stacktop, + extra_parameters *extra + ) +{ + szPost = (CHAR*)LocalAlloc(LPTR, string_size); + get(hwndParent, string_size, variables, stacktop, extra); +} + +/***************************************************** +* FUNCTION NAME: head() +* PURPOSE: +* http/ftp file upload entry point +* SPECIAL CONSIDERATIONS: +* re-put not works with http, but ftp REST - may be. +*****************************************************/ +extern "C" +void __declspec(dllexport) __cdecl head(HWND hwndParent, + int string_size, + TCHAR *variables, + stack_t **stacktop, + extra_parameters *extra + ) +{ + fhead = true; + get(hwndParent, string_size, variables, stacktop, extra); +} + +/***************************************************** +* FUNCTION NAME: DllMain() +* PURPOSE: +* Dll main (initialization) entry point +* SPECIAL CONSIDERATIONS: +* +*****************************************************/ +#ifdef _VC_NODEFAULTLIB +#define DllMain _DllMainCRTStartup +#endif +EXTERN_C BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + g_hInstance = hinstDLL; + return TRUE; +} diff --git a/cmake/Windows/Contrib/Inetc/inetc.rc b/cmake/Windows/Contrib/Inetc/inetc.rc new file mode 100755 index 000000000..0384750c8 --- /dev/null +++ b/cmake/Windows/Contrib/Inetc/inetc.rc @@ -0,0 +1,199 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Russian (Russia) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS) +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT +#pragma code_page(1251) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // Russian (Russia) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG1 DIALOGEX 0, 0, 286, 71 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Inetc plug-in" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + LTEXT "",IDC_STATIC1,50,4,230,12,SS_CENTERIMAGE,WS_EX_STATICEDGE + LTEXT "",IDC_STATIC2,50,18,230,12,SS_CENTERIMAGE,WS_EX_STATICEDGE + CTEXT "",IDC_STATIC3,50,32,102,12,SS_CENTERIMAGE,WS_EX_STATICEDGE + CTEXT "",IDC_STATIC4,220,32,60,12,SS_CENTERIMAGE,WS_EX_STATICEDGE + CONTROL "Progress1",IDC_PROGRESS1,"msctls_progress32",NOT WS_VISIBLE,5,62,275,7 + CTEXT "",IDC_STATIC5,50,46,102,12,SS_CENTERIMAGE,WS_EX_STATICEDGE + CTEXT "",IDC_STATIC6,220,46,60,12,SS_CENTERIMAGE,WS_EX_STATICEDGE + CONTROL "URL",IDC_STATIC20,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,5,6,44,10 + CONTROL "File name",IDC_STATIC21,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,5,20,44,10 + CONTROL "Transfered",IDC_STATIC22,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,5,34,44,10 + CONTROL "File size",IDC_STATIC23,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,5,48,44,10 + CONTROL "Remaining time",IDC_STATIC24,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,164,34,55,10 + CONTROL "Total time",IDC_STATIC25,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,164,48,55,10 +END + +IDD_DIALOG2 DIALOG 0, 0, 226, 62 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Inetc plug-in" +FONT 8, "MS Sans Serif" +BEGIN + ICON 103,IDC_STATIC13,4,4,20,20 + LTEXT "Please wait",IDC_STATIC12,35,6,184,28 + CONTROL "Progress1",IDC_PROGRESS1,"msctls_progress32",NOT WS_VISIBLE,12,40,201,11 +END + +IDD_DIALOG3 DIALOG 0, 0, 266, 62 +STYLE DS_SETFONT | DS_CONTROL | WS_CHILD | WS_VISIBLE +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "Progress1",IDC_PROGRESS1,"msctls_progress32",0x0,0,23,266,11 + CTEXT "",IDC_STATIC1,0,8,266,11 + PUSHBUTTON "Cancel",IDCANCEL,166,41,80,16 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_DIALOG1, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 279 + TOPMARGIN, 7 + BOTTOMMARGIN, 64 + END + + IDD_DIALOG2, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 219 + TOPMARGIN, 7 + BOTTOMMARGIN, 55 + END + + IDD_DIALOG3, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 259 + TOPMARGIN, 7 + BOTTOMMARGIN, 55 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (United Kingdom) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,5,2 + PRODUCTVERSION 1,0,5,2 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileDescription", "inetc NSIS plug-in" + VALUE "FileVersion", "1.0.5.2" + VALUE "InternalName", "inetc.dll" + VALUE "LegalCopyright", "Copyright © Takhir Bedertdinov" + VALUE "OriginalFilename", "inetc.dll" + VALUE "ProductName", "inetc NSIS plug-in" + VALUE "ProductVersion", "1.0.5.2" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // English (United Kingdom) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/cmake/Windows/Contrib/Inetc/inetc.sln b/cmake/Windows/Contrib/Inetc/inetc.sln new file mode 100755 index 000000000..04b4db351 --- /dev/null +++ b/cmake/Windows/Contrib/Inetc/inetc.sln @@ -0,0 +1,42 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "inetc", "inetc.vcxproj", "{6B2D8C40-38A9-457A-9FA6-BED0108CAC37}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug Unicode|Win32 = Debug Unicode|Win32 + Debug Unicode|x64 = Debug Unicode|x64 + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release Unicode|Win32 = Release Unicode|Win32 + Release Unicode|x64 = Release Unicode|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Debug Unicode|Win32.ActiveCfg = Debug Unicode|Win32 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Debug Unicode|Win32.Build.0 = Debug Unicode|Win32 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Debug Unicode|Win32.Deploy.0 = Debug Unicode|Win32 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Debug Unicode|x64.ActiveCfg = Debug Unicode|x64 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Debug Unicode|x64.Build.0 = Debug Unicode|x64 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Debug|Win32.ActiveCfg = Debug|Win32 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Debug|Win32.Build.0 = Debug|Win32 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Debug|Win32.Deploy.0 = Debug|Win32 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Debug|x64.ActiveCfg = Debug|x64 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Debug|x64.Build.0 = Debug|x64 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Release Unicode|Win32.ActiveCfg = Release Unicode|Win32 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Release Unicode|Win32.Build.0 = Release Unicode|Win32 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Release Unicode|Win32.Deploy.0 = Release Unicode|Win32 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Release Unicode|x64.ActiveCfg = Release Unicode|x64 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Release Unicode|x64.Build.0 = Release Unicode|x64 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Release|Win32.ActiveCfg = Release|Win32 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Release|Win32.Build.0 = Release|Win32 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Release|Win32.Deploy.0 = Release|Win32 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Release|x64.ActiveCfg = Release|x64 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/cmake/Windows/Contrib/Inetc/inetc.vcxproj b/cmake/Windows/Contrib/Inetc/inetc.vcxproj new file mode 100755 index 000000000..94346b6b7 --- /dev/null +++ b/cmake/Windows/Contrib/Inetc/inetc.vcxproj @@ -0,0 +1,441 @@ + + + + + Debug Unicode + Win32 + + + Debug Unicode + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Unicode + Win32 + + + Release Unicode + x64 + + + Release + Win32 + + + Release + x64 + + + + + + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37} + + + + DynamicLibrary + v110 + Unicode + + + DynamicLibrary + v110 + Unicode + + + DynamicLibrary + v110 + MultiByte + + + DynamicLibrary + v110 + MultiByte + + + DynamicLibrary + v110 + Unicode + + + DynamicLibrary + v110 + Unicode + + + DynamicLibrary + v110 + MultiByte + + + DynamicLibrary + v110 + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + $(SolutionDir)..\..\Plugins\ + + + false + $(ProjectName)64 + $(SolutionDir)..\..\Plugins\ + + + $(SolutionDir)..\..\Unicode\Plugins\ + true + false + + + true + false + $(ProjectName)64 + + + $(SolutionDir)..\..\Plugins\ + false + + + false + $(ProjectName)64 + + + false + $(SolutionDir)..\..\Unicode\Plugins\ + + + false + $(ProjectName)64 + $(SolutionDir)..\..\Unicode\Plugins\ + + + + MultiThreaded + MinSpace + true + Level3 + WIN32;NDEBUG;_WINDOWS;_USRDLL;inetc_EXPORTS;_VC80_UPGRADE=0x0600;%(PreprocessorDefinitions) + false + + + true + NDEBUG;%(PreprocessorDefinitions) + .\debug\inetc.tlb + true + Win32 + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\debug\inetc.bsc + + + true + true + wininet.lib;comctl32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + false + DllMain + libc.lib + true + + + + + MultiThreaded + MinSpace + true + Level3 + WIN32;NDEBUG;_WINDOWS;_USRDLL;inetc_EXPORTS;_VC80_UPGRADE=0x0600;%(PreprocessorDefinitions) + false + + + true + NDEBUG;%(PreprocessorDefinitions) + .\debug\inetc.tlb + true + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\debug\inetc.bsc + + + true + true + true + wininet.lib;comctl32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + false + libc.lib + DllMain + + + + + MultiThreadedDebug + Disabled + true + Level3 + EditAndContinue + EnableFastChecks + WIN32;_DEBUG;_WINDOWS;_USRDLL;inetc_EXPORTS;_VC80_UPGRADE=0x0600;%(PreprocessorDefinitions) + false + + + true + _DEBUG;%(PreprocessorDefinitions) + .\Debug_Unicode\inetc.tlb + true + Win32 + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug_Unicode\inetc.bsc + + + true + true + .\Debug_Unicode\inetc.lib + wininet.lib;comctl32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + false + + + + + MultiThreadedDebug + Disabled + true + Level3 + ProgramDatabase + EnableFastChecks + WIN32;_DEBUG;_WINDOWS;_USRDLL;inetc_EXPORTS;_VC80_UPGRADE=0x0600;%(PreprocessorDefinitions) + false + + + true + _DEBUG;%(PreprocessorDefinitions) + .\Debug_Unicode\inetc.tlb + true + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug_Unicode\inetc.bsc + + + true + true + .\Debug_Unicode\inetc.lib + wininet.lib;comctl32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + false + + + + + MultiThreadedDebug + Disabled + true + Level3 + EditAndContinue + WIN32;_DEBUG;_WINDOWS;_USRDLL;inetc_EXPORTS;_VC80_UPGRADE=0x0600;%(PreprocessorDefinitions) + EnableFastChecks + + + true + _DEBUG;%(PreprocessorDefinitions) + .\Debug\inetc.tlb + true + Win32 + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug\inetc.bsc + + + true + true + true + wininet.lib;comctl32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + false + + + + + MultiThreadedDebug + Disabled + true + Level3 + ProgramDatabase + WIN32;_DEBUG;_WINDOWS;_USRDLL;inetc_EXPORTS;_VC80_UPGRADE=0x0600;%(PreprocessorDefinitions) + EnableFastChecks + + + true + _DEBUG;%(PreprocessorDefinitions) + .\Debug\inetc.tlb + true + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug\inetc.bsc + + + true + true + true + wininet.lib;comctl32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + false + + + + + MultiThreaded + MinSpace + true + Level3 + WIN32;NDEBUG;_WINDOWS;UNICODE;_USRDLL;inetc_EXPORTS;_VC80_UPGRADE=0x0600;%(PreprocessorDefinitions) + false + + + true + NDEBUG;%(PreprocessorDefinitions) + .\Debug_Unicode\inetc.tlb + true + Win32 + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\Debug_Unicode\inetc.bsc + + + true + true + wininet.lib;comctl32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + true + false + DllMain + libc.lib + + + + + MultiThreaded + MinSpace + true + Level3 + WIN32;NDEBUG;_WINDOWS;UNICODE;_USRDLL;inetc_EXPORTS;_VC80_UPGRADE=0x0600;%(PreprocessorDefinitions) + false + + + true + NDEBUG;%(PreprocessorDefinitions) + .\Debug_Unicode\inetc.tlb + true + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\Debug_Unicode\inetc.bsc + + + true + true + wininet.lib;comctl32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + true + false + libc.lib + DllMain + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cmake/Windows/Contrib/Inetc/inetc.vcxproj.filters b/cmake/Windows/Contrib/Inetc/inetc.vcxproj.filters new file mode 100755 index 000000000..50d7628fb --- /dev/null +++ b/cmake/Windows/Contrib/Inetc/inetc.vcxproj.filters @@ -0,0 +1,52 @@ + + + + + {7803dcf0-655c-4f71-89dd-7fd695066a28} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {8edac42d-b9b9-469f-9864-3dbc65bf4365} + ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + {67a938b1-f16b-478b-81df-d0fd26de6d8a} + h;hpp;hxx;hm;inl + + + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + + + Resource Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + diff --git a/cmake/Windows/Contrib/Inetc/nsis_tchar.h b/cmake/Windows/Contrib/Inetc/nsis_tchar.h new file mode 100644 index 000000000..210bab16d --- /dev/null +++ b/cmake/Windows/Contrib/Inetc/nsis_tchar.h @@ -0,0 +1,229 @@ +/* + * nsis_tchar.h + * + * This file is a part of NSIS. + * + * Copyright (C) 1999-2013 Nullsoft and Contributors + * + * This software is provided 'as-is', without any express or implied + * warranty. + * + * For Unicode support by Jim Park -- 08/30/2007 + */ + +// Jim Park: Only those we use are listed here. + +#pragma once + +#ifdef _UNICODE + +#ifndef _T +#define __T(x) L ## x +#define _T(x) __T(x) +#define _TEXT(x) __T(x) +#endif + +#ifndef _TCHAR_DEFINED +#define _TCHAR_DEFINED +#if !defined(_NATIVE_WCHAR_T_DEFINED) && !defined(_WCHAR_T_DEFINED) +typedef unsigned short TCHAR; +#else +typedef wchar_t TCHAR; +#endif +#endif + + +// program +#define _tenviron _wenviron +#define __targv __wargv + +// printfs +#define _ftprintf fwprintf +#define _sntprintf _snwprintf +#if (defined(_MSC_VER) && (_MSC_VER<=1310)) || defined(__MINGW32__) +# define _stprintf swprintf +#else +# define _stprintf _swprintf +#endif +#define _tprintf wprintf +#define _vftprintf vfwprintf +#define _vsntprintf _vsnwprintf +#if defined(_MSC_VER) && (_MSC_VER<=1310) +# define _vstprintf vswprintf +#else +# define _vstprintf _vswprintf +#endif + +// scanfs +#define _tscanf wscanf +#define _stscanf swscanf + +// string manipulations +#define _tcscat wcscat +#define _tcschr wcschr +#define _tcsclen wcslen +#define _tcscpy wcscpy +#define _tcsdup _wcsdup +#define _tcslen wcslen +#define _tcsnccpy wcsncpy +#define _tcsncpy wcsncpy +#define _tcsrchr wcsrchr +#define _tcsstr wcsstr +#define _tcstok wcstok + +// string comparisons +#define _tcscmp wcscmp +#define _tcsicmp _wcsicmp +#define _tcsncicmp _wcsnicmp +#define _tcsncmp wcsncmp +#define _tcsnicmp _wcsnicmp + +// upper / lower +#define _tcslwr _wcslwr +#define _tcsupr _wcsupr +#define _totlower towlower +#define _totupper towupper + +// conversions to numbers +#define _tcstoi64 _wcstoi64 +#define _tcstol wcstol +#define _tcstoul wcstoul +#define _tstof _wtof +#define _tstoi _wtoi +#define _tstoi64 _wtoi64 +#define _ttoi _wtoi +#define _ttoi64 _wtoi64 +#define _ttol _wtol + +// conversion from numbers to strings +#define _itot _itow +#define _ltot _ltow +#define _i64tot _i64tow +#define _ui64tot _ui64tow + +// file manipulations +#define _tfopen _wfopen +#define _topen _wopen +#define _tremove _wremove +#define _tunlink _wunlink + +// reading and writing to i/o +#define _fgettc fgetwc +#define _fgetts fgetws +#define _fputts fputws +#define _gettchar getwchar + +// directory +#define _tchdir _wchdir + +// environment +#define _tgetenv _wgetenv +#define _tsystem _wsystem + +// time +#define _tcsftime wcsftime + +#else // ANSI + +#ifndef _T +#define _T(x) x +#define _TEXT(x) x +#endif + +#ifndef _TCHAR_DEFINED +#define _TCHAR_DEFINED +typedef char TCHAR; +#endif + +// program +#define _tenviron environ +#define __targv __argv + +// printfs +#define _ftprintf fprintf +#define _sntprintf _snprintf +#define _stprintf sprintf +#define _tprintf printf +#define _vftprintf vfprintf +#define _vsntprintf _vsnprintf +#define _vstprintf vsprintf + +// scanfs +#define _tscanf scanf +#define _stscanf sscanf + +// string manipulations +#define _tcscat strcat +#define _tcschr strchr +#define _tcsclen strlen +#define _tcscnlen strnlen +#define _tcscpy strcpy +#define _tcsdup _strdup +#define _tcslen strlen +#define _tcsnccpy strncpy +#define _tcsrchr strrchr +#define _tcsstr strstr +#define _tcstok strtok + +// string comparisons +#define _tcscmp strcmp +#define _tcsicmp _stricmp +#define _tcsncmp strncmp +#define _tcsncicmp _strnicmp +#define _tcsnicmp _strnicmp + +// upper / lower +#define _tcslwr _strlwr +#define _tcsupr _strupr + +#define _totupper toupper +#define _totlower tolower + +// conversions to numbers +#define _tcstol strtol +#define _tcstoul strtoul +#define _tstof atof +#define _tstoi atoi +#define _tstoi64 _atoi64 +#define _tstoi64 _atoi64 +#define _ttoi atoi +#define _ttoi64 _atoi64 +#define _ttol atol + +// conversion from numbers to strings +#define _i64tot _i64toa +#define _itot _itoa +#define _ltot _ltoa +#define _ui64tot _ui64toa + +// file manipulations +#define _tfopen fopen +#define _topen _open +#define _tremove remove +#define _tunlink _unlink + +// reading and writing to i/o +#define _fgettc fgetc +#define _fgetts fgets +#define _fputts fputs +#define _gettchar getchar + +// directory +#define _tchdir _chdir + +// environment +#define _tgetenv getenv +#define _tsystem system + +// time +#define _tcsftime strftime + +#endif + +// is functions (the same in Unicode / ANSI) +#define _istgraph isgraph +#define _istascii __isascii + +#define __TFILE__ _T(__FILE__) +#define __TDATE__ _T(__DATE__) +#define __TTIME__ _T(__TIME__) diff --git a/cmake/Windows/Contrib/Inetc/pluginapi.c b/cmake/Windows/Contrib/Inetc/pluginapi.c new file mode 100755 index 000000000..c507e31a2 --- /dev/null +++ b/cmake/Windows/Contrib/Inetc/pluginapi.c @@ -0,0 +1,294 @@ +#include + +#include "pluginapi.h" + +#ifdef _countof +#define COUNTOF _countof +#else +#define COUNTOF(a) (sizeof(a)/sizeof(a[0])) +#endif + +unsigned int g_stringsize; +stack_t **g_stacktop; +TCHAR *g_variables; + +// utility functions (not required but often useful) + +int NSISCALL popstring(TCHAR *str) +{ + stack_t *th; + if (!g_stacktop || !*g_stacktop) return 1; + th=(*g_stacktop); + if (str) lstrcpy(str,th->text); + *g_stacktop = th->next; + GlobalFree((HGLOBAL)th); + return 0; +} + +int NSISCALL popstringn(TCHAR *str, int maxlen) +{ + stack_t *th; + if (!g_stacktop || !*g_stacktop) return 1; + th=(*g_stacktop); + if (str) lstrcpyn(str,th->text,maxlen?maxlen:g_stringsize); + *g_stacktop = th->next; + GlobalFree((HGLOBAL)th); + return 0; +} + +void NSISCALL pushstring(const TCHAR *str) +{ + stack_t *th; + if (!g_stacktop) return; + th=(stack_t*)GlobalAlloc(GPTR,(sizeof(stack_t)+(g_stringsize)*sizeof(TCHAR))); + lstrcpyn(th->text,str,g_stringsize); + th->next=*g_stacktop; + *g_stacktop=th; +} + +TCHAR* NSISCALL getuservariable(const int varnum) +{ + if (varnum < 0 || varnum >= __INST_LAST) return NULL; + return g_variables+varnum*g_stringsize; +} + +void NSISCALL setuservariable(const int varnum, const TCHAR *var) +{ + if (var != NULL && varnum >= 0 && varnum < __INST_LAST) + lstrcpy(g_variables + varnum*g_stringsize, var); +} + +#ifdef _UNICODE +int NSISCALL PopStringA(char* ansiStr) +{ + wchar_t* wideStr = (wchar_t*) GlobalAlloc(GPTR, g_stringsize*sizeof(wchar_t)); + int rval = popstring(wideStr); + WideCharToMultiByte(CP_ACP, 0, wideStr, -1, ansiStr, g_stringsize, NULL, NULL); + GlobalFree((HGLOBAL)wideStr); + return rval; +} + +int NSISCALL PopStringNA(char* ansiStr, int maxlen) +{ + int realLen = maxlen ? maxlen : g_stringsize; + wchar_t* wideStr = (wchar_t*) GlobalAlloc(GPTR, realLen*sizeof(wchar_t)); + int rval = popstringn(wideStr, realLen); + WideCharToMultiByte(CP_ACP, 0, wideStr, -1, ansiStr, realLen, NULL, NULL); + GlobalFree((HGLOBAL)wideStr); + return rval; +} + +void NSISCALL PushStringA(const char* ansiStr) +{ + wchar_t* wideStr = (wchar_t*) GlobalAlloc(GPTR, g_stringsize*sizeof(wchar_t)); + MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, wideStr, g_stringsize); + pushstring(wideStr); + GlobalFree((HGLOBAL)wideStr); + return; +} + +void NSISCALL GetUserVariableW(const int varnum, wchar_t* wideStr) +{ + lstrcpyW(wideStr, getuservariable(varnum)); +} + +void NSISCALL GetUserVariableA(const int varnum, char* ansiStr) +{ + wchar_t* wideStr = getuservariable(varnum); + WideCharToMultiByte(CP_ACP, 0, wideStr, -1, ansiStr, g_stringsize, NULL, NULL); +} + +void NSISCALL SetUserVariableA(const int varnum, const char* ansiStr) +{ + if (ansiStr != NULL && varnum >= 0 && varnum < __INST_LAST) + { + wchar_t* wideStr = g_variables + varnum * g_stringsize; + MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, wideStr, g_stringsize); + } +} + +#else +// ANSI defs +int NSISCALL PopStringW(wchar_t* wideStr) +{ + char* ansiStr = (char*) GlobalAlloc(GPTR, g_stringsize); + int rval = popstring(ansiStr); + MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, wideStr, g_stringsize); + GlobalFree((HGLOBAL)ansiStr); + return rval; +} + +int NSISCALL PopStringNW(wchar_t* wideStr, int maxlen) +{ + int realLen = maxlen ? maxlen : g_stringsize; + char* ansiStr = (char*) GlobalAlloc(GPTR, realLen); + int rval = popstringn(ansiStr, realLen); + MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, wideStr, realLen); + GlobalFree((HGLOBAL)ansiStr); + return rval; +} + +void NSISCALL PushStringW(wchar_t* wideStr) +{ + char* ansiStr = (char*) GlobalAlloc(GPTR, g_stringsize); + WideCharToMultiByte(CP_ACP, 0, wideStr, -1, ansiStr, g_stringsize, NULL, NULL); + pushstring(ansiStr); + GlobalFree((HGLOBAL)ansiStr); +} + +void NSISCALL GetUserVariableW(const int varnum, wchar_t* wideStr) +{ + char* ansiStr = getuservariable(varnum); + MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, wideStr, g_stringsize); +} + +void NSISCALL GetUserVariableA(const int varnum, char* ansiStr) +{ + lstrcpyA(ansiStr, getuservariable(varnum)); +} + +void NSISCALL SetUserVariableW(const int varnum, const wchar_t* wideStr) +{ + if (wideStr != NULL && varnum >= 0 && varnum < __INST_LAST) + { + char* ansiStr = g_variables + varnum * g_stringsize; + WideCharToMultiByte(CP_ACP, 0, wideStr, -1, ansiStr, g_stringsize, NULL, NULL); + } +} +#endif + +// playing with integers + +INT_PTR NSISCALL nsishelper_str_to_ptr(const TCHAR *s) +{ + INT_PTR v=0; + if (*s == _T('0') && (s[1] == _T('x') || s[1] == _T('X'))) + { + s++; + for (;;) + { + int c=*(++s); + if (c >= _T('0') && c <= _T('9')) c-=_T('0'); + else if (c >= _T('a') && c <= _T('f')) c-=_T('a')-10; + else if (c >= _T('A') && c <= _T('F')) c-=_T('A')-10; + else break; + v<<=4; + v+=c; + } + } + else if (*s == _T('0') && s[1] <= _T('7') && s[1] >= _T('0')) + { + for (;;) + { + int c=*(++s); + if (c >= _T('0') && c <= _T('7')) c-=_T('0'); + else break; + v<<=3; + v+=c; + } + } + else + { + int sign=0; + if (*s == _T('-')) sign++; else s--; + for (;;) + { + int c=*(++s) - _T('0'); + if (c < 0 || c > 9) break; + v*=10; + v+=c; + } + if (sign) v = -v; + } + + return v; +} + +unsigned int NSISCALL myatou(const TCHAR *s) +{ + unsigned int v=0; + + for (;;) + { + unsigned int c=*s++; + if (c >= _T('0') && c <= _T('9')) c-=_T('0'); + else break; + v*=10; + v+=c; + } + return v; +} + +int NSISCALL myatoi_or(const TCHAR *s) +{ + int v=0; + if (*s == _T('0') && (s[1] == _T('x') || s[1] == _T('X'))) + { + s++; + for (;;) + { + int c=*(++s); + if (c >= _T('0') && c <= _T('9')) c-=_T('0'); + else if (c >= _T('a') && c <= _T('f')) c-=_T('a')-10; + else if (c >= _T('A') && c <= _T('F')) c-=_T('A')-10; + else break; + v<<=4; + v+=c; + } + } + else if (*s == _T('0') && s[1] <= _T('7') && s[1] >= _T('0')) + { + for (;;) + { + int c=*(++s); + if (c >= _T('0') && c <= _T('7')) c-=_T('0'); + else break; + v<<=3; + v+=c; + } + } + else + { + int sign=0; + if (*s == _T('-')) sign++; else s--; + for (;;) + { + int c=*(++s) - _T('0'); + if (c < 0 || c > 9) break; + v*=10; + v+=c; + } + if (sign) v = -v; + } + + // Support for simple ORed expressions + if (*s == _T('|')) + { + v |= myatoi_or(s+1); + } + + return v; +} + +INT_PTR NSISCALL popintptr() +{ + TCHAR buf[128]; + if (popstringn(buf,COUNTOF(buf))) + return 0; + return nsishelper_str_to_ptr(buf); +} + +int NSISCALL popint_or() +{ + TCHAR buf[128]; + if (popstringn(buf,COUNTOF(buf))) + return 0; + return myatoi_or(buf); +} + +void NSISCALL pushintptr(INT_PTR value) +{ + TCHAR buffer[30]; + wsprintf(buffer, sizeof(void*) > 4 ? _T("%Id") : _T("%d"), value); + pushstring(buffer); +} diff --git a/cmake/Windows/Contrib/Inetc/pluginapi.h b/cmake/Windows/Contrib/Inetc/pluginapi.h new file mode 100644 index 000000000..ca671a8ed --- /dev/null +++ b/cmake/Windows/Contrib/Inetc/pluginapi.h @@ -0,0 +1,104 @@ +#ifndef ___NSIS_PLUGIN__H___ +#define ___NSIS_PLUGIN__H___ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "api.h" +#include "nsis_tchar.h" + +#ifndef NSISCALL +# define NSISCALL __stdcall +#endif + +#define EXDLL_INIT() { \ + g_stringsize=string_size; \ + g_stacktop=stacktop; \ + g_variables=variables; } + +typedef struct _stack_t { + struct _stack_t *next; + TCHAR text[1]; // this should be the length of string_size +} stack_t; + +enum +{ +INST_0, // $0 +INST_1, // $1 +INST_2, // $2 +INST_3, // $3 +INST_4, // $4 +INST_5, // $5 +INST_6, // $6 +INST_7, // $7 +INST_8, // $8 +INST_9, // $9 +INST_R0, // $R0 +INST_R1, // $R1 +INST_R2, // $R2 +INST_R3, // $R3 +INST_R4, // $R4 +INST_R5, // $R5 +INST_R6, // $R6 +INST_R7, // $R7 +INST_R8, // $R8 +INST_R9, // $R9 +INST_CMDLINE, // $CMDLINE +INST_INSTDIR, // $INSTDIR +INST_OUTDIR, // $OUTDIR +INST_EXEDIR, // $EXEDIR +INST_LANG, // $LANGUAGE +__INST_LAST +}; + +extern unsigned int g_stringsize; +extern stack_t **g_stacktop; +extern TCHAR *g_variables; + +void NSISCALL pushstring(const TCHAR *str); +void NSISCALL pushintptr(INT_PTR value); +#define pushint(v) pushintptr((INT_PTR)(v)) +int NSISCALL popstring(TCHAR *str); // 0 on success, 1 on empty stack +int NSISCALL popstringn(TCHAR *str, int maxlen); // with length limit, pass 0 for g_stringsize +INT_PTR NSISCALL popintptr(); +#define popint() ( (int) popintptr() ) +int NSISCALL popint_or(); // with support for or'ing (2|4|8) +INT_PTR NSISCALL nsishelper_str_to_ptr(const TCHAR *s); +#define myatoi(s) ( (int) nsishelper_str_to_ptr(s) ) // converts a string to an integer +unsigned int NSISCALL myatou(const TCHAR *s); // converts a string to an unsigned integer, decimal only +int NSISCALL myatoi_or(const TCHAR *s); // with support for or'ing (2|4|8) +TCHAR* NSISCALL getuservariable(const int varnum); +void NSISCALL setuservariable(const int varnum, const TCHAR *var); + +#ifdef _UNICODE +#define PopStringW(x) popstring(x) +#define PushStringW(x) pushstring(x) +#define SetUserVariableW(x,y) setuservariable(x,y) + +int NSISCALL PopStringA(char* ansiStr); +void NSISCALL PushStringA(const char* ansiStr); +void NSISCALL GetUserVariableW(const int varnum, wchar_t* wideStr); +void NSISCALL GetUserVariableA(const int varnum, char* ansiStr); +void NSISCALL SetUserVariableA(const int varnum, const char* ansiStr); + +#else +// ANSI defs + +#define PopStringA(x) popstring(x) +#define PushStringA(x) pushstring(x) +#define SetUserVariableA(x,y) setuservariable(x,y) + +int NSISCALL PopStringW(wchar_t* wideStr); +void NSISCALL PushStringW(wchar_t* wideStr); +void NSISCALL GetUserVariableW(const int varnum, wchar_t* wideStr); +void NSISCALL GetUserVariableA(const int varnum, char* ansiStr); +void NSISCALL SetUserVariableW(const int varnum, const wchar_t* wideStr); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif//!___NSIS_PLUGIN__H___ diff --git a/cmake/Windows/Contrib/Inetc/resource.h b/cmake/Windows/Contrib/Inetc/resource.h new file mode 100644 index 000000000..17d43c349 --- /dev/null +++ b/cmake/Windows/Contrib/Inetc/resource.h @@ -0,0 +1,47 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by inetc.rc +// +#define IDC_SLOGIN 8 +#define IDC_PROGRESS 10 +#define IDC_SUBTEXT 11 +#define IDC_SPWD 11 +#define IDC_ICON1 12 +#define IDD_DIALOG1 101 +#define IDI_ICON1 102 +#define IDI_ICON2 103 +#define IDD_AUTH 104 +#define IDI_ICON3 105 +#define IDI_ICON4 106 +#define IDI_ICON5 107 +#define IDD_DIALOG2 108 +#define IDI_ICON6 109 +#define IDD_DIALOG3 110 +#define IDC_STATIC1 1001 +#define IDC_STATIC2 1002 +#define IDC_STATIC3 1003 +#define IDC_STATIC4 1004 +#define IDC_PROGRESS1 1005 +#define IDC_STATIC5 1006 +#define IDC_STATIC6 1007 +#define IDC_STATIC12 1008 +#define IDC_STATIC13 1009 +#define IDC_STATIC20 1009 +#define IDC_STATIC21 1010 +#define IDC_STATIC22 1011 +#define IDC_STATIC23 1012 +#define IDC_STATIC24 1013 +#define IDC_STATIC25 1014 +#define IDC_ELOGIN 1015 +#define IDC_EPWD 1016 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 111 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1018 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/cmake/Windows/Docs/Advanced Uninstall Log/Readme.txt b/cmake/Windows/Docs/Advanced Uninstall Log/Readme.txt new file mode 100644 index 000000000..4e17940da --- /dev/null +++ b/cmake/Windows/Docs/Advanced Uninstall Log/Readme.txt @@ -0,0 +1,121 @@ +Overview + +Advanced Uninstall Log for NSIS was born in the need to cover a specific gap. +It's been discussed fairly enough that the File /r command is very useful +in cases when developers want to add a huge amount of sub directories and +files, nevertheless it has the disadvantage that such an installation should +be uninstalled with RmDir /r which is risky and removes also data that has +been added/created later within the installation folder. + + + + +About Advanced Uninstall Log. + +Advanced Uninstall Log is a macro system provided in a NSIS header that +is able to monitor an installation and build an uninstall log file which +is used by the uninstaller to uninstall files/directories that have been +added within specific installation blocks. + +This means that files which have been installed outside these blocks, +or added later either by the user or application's activities, ignored +by the uninstaller. + +Moreover files that might exist into the target directory prior the current +installation, ignored as well. + +Advanced Uninstall Log creates an uninstall log that removes only files that +have been installed and optionally interacts with users for every other file +and/or directory has found in installation folder and requires permission to +remove these files/directories. + +It is enhanced as well to support updates, e.g. if the installer later would +update the installation by adding new data, the uninstaller would remove the +new data that has been added by the installer, without bothering users about. + + + + +Features + +If target installation folder exists and contains files and/or directories +they all preserved from being uninstalled. + +Uninstaller removes data that has been added within specific installation +blocks, preserving all other data that has been created/added outside of +these installation blocks. See included examples for details. + +Supports unlimited updates/reinstallations. + +Supports two uninstaller modes. Interactive mode requires confirmation +to remove every other file exept those files that have been installed. +Unattended mode leaves intact every other file without bothering users. + +In case when uninstall log (uninstall.dat) has been removed manually instead +of execute uninstaller, if users attempt to run the installer later, a warning +issued that they should select a new output folder. + +Implements only the included with NSIS release headers FileFunc and TextFunc. +There is no need for external plugins and headers, adds a very small overhead. + + + + +Restrictions + +If uninstall log (uninstall.dat) is missing uninstaller won't execute at all. + +Due to file create - write procedure that is required in order to add/update +the uninstall log (uninstall.dat), restricted users on NT based systems won't +be able to execute the installer. + + + + +Disadvantage + +Since the header does not implement anything else than the common NSIS release, +a delay occurs while builds and reads the uninstall log because it needs to +throw the list several times. Talking for common cases, most likely the delay +won't be noticeable, however, in cases where the target directory isn't empty +and contains a large amount of data which will be excluded from uninstall log, +or added large amount of data after the installation which will be excluded also, +the delay should be noticeable. + + + + +Credits + +A very big thanks goes to kichik. +When my idea of the Advanced Uninstall Log became an NSIS header, it was +indeed an amateur's attempt to write a flexible and errors free NSIS header. +Kichik dropped me a dozen of suggestions helping me to achieve my plan. +However, his main suggestion to eliminate the mentioned above disadvantage, +still remains untouched by me. + + + + +License + +This header file is provided 'as-is', without any express or implied warranty. +In no event will the author be held liable for any damages arising from the use +of this header file. + +Permission is granted to anyone to use this header file for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + + 1. The origin of this header file must not be misrepresented; + you must not claim that you wrote the original header file. + If you use this header file in a product, an acknowledgment in + the product documentation would be appreciated but is not required. + + 2. Altered versions must be plainly marked as such, and must not be + misrepresented as being the original header file. + + 3. This notice may not be removed or altered from any distribution. + + +eof diff --git a/cmake/Windows/Docs/Inetc/Readme.htm b/cmake/Windows/Docs/Inetc/Readme.htm new file mode 100755 index 000000000..0913e7425 --- /dev/null +++ b/cmake/Windows/Docs/Inetc/Readme.htm @@ -0,0 +1,153 @@ +
+

Contents

+
    +
  • 1 Links +
  • 2 Description +
  • 3 Commands +
      +
    • 3.1 get +
    • 3.2 post +
    • 3.3 head +
    • 3.4 put +
    +
  • 4 Examples +
  • 5 Credits +
+
+ +

Links

+Download:
http://nsis.sourceforge.net/Inetc_plug-in + +

Description

+Internet client plug-in for files download and upload. Based on the InetLoad plug-in. +Network implementation uses MS WinInet API, supports http/https and ftp protocols. +Plugin has better proxy support compare to NSISdl plug-in. Command line may include +few URL/File pairs to be transfered. If server or proxy login/password are not setten in the script, +displays IE-style authentication dialog (except silent mode). Plug-in supports 3 +"transfer in progress" display modes: +
    +
  • old NSISdl style - additional embedded progress bar and text on the INSTFILES page; +
  • POPUP dialog mode with detailed info; +
  • BANNER mode with simple popup window. +
+Plug-in recognizes Installer's Silent mode and this case hides any output (this feature +requires NSIS 2.03 or later). Program implements simple re-get functionality - host +reconnect and download from current position after short pause. While program depends on IE settings, +it changes current IE mode to online. NSISdl code fragment was used for progress bar displaying +in the "old style" mode. For ftp use "host/path" for file location relative to user's home dir and +"host//path" for absolute path. + +

Commands

+ +Plug-in DLL functions (entry points): get, post, head, put + +

get

+ +inetc::get [/PROXY IP:PORT] [/USERNAME PROXY_LOGIN /PASSWORD PROXY_PASSWD] [/NOCOOKIES] + [/NOPROXY] [/NOCANCEL] [/CONNECTTIMEOUT TO_SEC] [/RECEIVETIMEOUT TO_SEC] [/SILENT] [/WEAKSECURITY] + [/CAPTION TEXT] [/NOCOOKIES] [/RESUME RETRY_QUESTION] [/POPUP HOST_ALIAS | /BANNER TEXT] + [/CANCELTEXT CANCEL_TEXT] [/QUESTION CANCEL_QUESTION] [/USERAGENT USER_AGENT_TEXT] + [/HEADER HEADER_TEXT] [/TRANSLATE LANG_PARAMS] [/TOSTACK | /TOSTACKCONV] + URL1 local_file1 [URL2 local_file2 [...]] [/END] +

This call returns "OK" string if successful, error description string if failed (see included InetLoad.cpp file for a full set of status strings). Usage and result processing samples are included to the package. +

/PROXY - +Overwrites current proxy settings, not required in most cases. IE settings will be used by default. +

/USERNAME - +Proxy username (http only). +

/PASSWORD - +Proxy password (http only). For server (http/ftp) authentication it is possible to use URL encoded name and password, for example http://username:password@nsis.sourceforge.net. +

/NOPROXY - +Disables proxy settings for this connection (if any) +

/NOCANCEL - +Prevents download from being interrupted by user (locks Esc, Alt-F4, Cancel handling, removes sysmenu) +

/CONNECTTIMEOUT - +Sets INTERNET_OPTION_CONNECT_TIMEOUT, seconds, default - IE current parameter value. +

/RECEIVETIMEOUT - +Sets INTERNET_OPTION_RECEIVE_TIMEOUT, seconds, default - IE current parameter value. +

/SILENT - +Key hides plug-in' output (both popup dialog and embedded progress bar). Not required if 'SilentInstall silent' mode was defined in script (NSIS 2.03 or later). +

/WEAKSECURITY - +Ignore unknown and revoked certificates +

/RESUME - +On the permanent connection/transfer error instead of exit first displays message box with "resume download" question. Useful for dial-up connections and big files - allows user to restore connection and resume download. Default is "Your internet connection seems to have dropped out!\nPlease reconnect and click Retry to resume downloading...". +

/CAPTION - +Defines caption text for /BANNER mode, caption prefix (left of '-') for /POPUP mode and caption for RESUME MessageBox. Default is "InetLoad plug-in" if not set or "". 127 chars maximum. +

/POPUP - +This mode displays detailed download dialog instead of embedded progress bar. Also useful in .onInit function (i.e. not in Section). If HOST_ALIAS is not "", text will replace URL in the dialog - this allows to hide real URL (including password). +

/BANNER - +Displays simple popup dialog (MSI Banner mode) and sets dialog TEXT (up to 3 lines using $\n). +

/CANCELTEXT - +Text for the Cancel button in the NSISdl mode. Default is NSIS dialog Cancel button text (current lang). +

/QUESTION - +Text for the optional MessageBox if user tries to cancel download. If /QUESTION "" was used default +"Are you sure that you want to stop download?" will be substituted. +

/USERAGENT - +UserAgent http request header value. Default is "NSIS_Inetc (Mozilla)". 256 chars maximum. +

/HEADER - +Adds or replaces http request header. Common HEADER_TEXT format is "header: value". +

/NOCOOKIES - +Removes cookies from http request +

/TOSTACK - +Outputs the post/get/head response to the NSIS stack rather than to the file (specify an empty string for local_file1, local_file2 etc.) +

/TOSTACKCONV - +Outputs the post/get/head response to the NSIS stack while converting character encodings:
+ASCII -> Unicode for the Unicode plug-in build
+Unicode -> ASCII for the ASCII plug-in build +

/END - +Allows to limit plug-in stack reading (optional, required if you stores other vars in the stack). +

/TRANSLATE - +Allows translating plug-in text in the POPUP or NSISdl modes. 8 parameters both cases.
+ +NSISdl mode parameters:
+ /TRANSLATE downloading connecting second minute hour plural progress remaining
+With default values:
+ "Downloading %s" "Connecting ..." second minute hour s "%dkB (%d%%) of %dkB @ %d.%01dkB/s" "(%d %s%s remaining)"
+ +POPUP mode parameters:
+ /TRANSLATE url downloading connecting file_name received file_size remaining_time total_time
+With default values:
+ URL Downloading Connecting "File Name" Received "File Size" "Remaining Time" "Total Time"
+ +

post

+ +inetc::post TEXT2POST [/FILE] [/PROXY IP:PORT] [/NOPROXY] [/NOCANCEL] + [/USERNAME PROXY_LOGIN /PASSWORD PROXY_PASSWD] [/TIMEOUT INT_MS] [/SILENT] [/WEAKSECURITY] + [/CAPTION TEXT] [/POPUP | /BANNER TEXT] [/CANCELTEXT CANCEL_TEXT] + [/USERAGENT USER_AGENT_TEXT] [/TRANSLATE LANG_PARAMS] [/TOSTACK | /TOSTACKCONV] + URL1 local_file1 [URL2 local_file2 [...]] [/END] +

Sets POST http mode and defines text string to be used in the POST (http only). Disables auto re-get. No char replaces used (%20 and others). +If /FILE presents in command line, TEXT2POST is filename to be sent in POST request. Also 'Filename:' header will be added to HTTP headers. + +

head

+ +The same as get, but requests http headers only. Writes raw headers to file. + +

put

+ +inetc::put [/PROXY IP:PORT] [/USERNAME PROXY_LOGIN /PASSWORD PROXY_PASSWD] [/NOPROXY] + [/NOCANCEL] [/TIMEOUT INT_MS] [/SILENT] [/WEAKSECURITY] [/CAPTION TEXT] [/POPUP | /BANNER TEXT] + [/CANCELTEXT CANCEL_TEXT] [/USERAGENT USER_AGENT_TEXT] + [/TRANSLATE LANG_PARAMS] URL1 local_file1 [URL2 local_file2 [...]] [/END] +

Return value and parameters (if applicable) are the same as for previous entry point. + +

Examples

+
  inetc::put "http://dl.zvuki.ru/6306/mp3/12.mp3" "$EXEDIR\12.mp3" \
+     "ftp://dl.zvuki.ru/6306/mp3/11.mp3" "$EXEDIR\11.mp3"
+  Pop $0
+  inetc::put /BANNER "Cameron Diaz upload in progress..." \
+    "http://www.dreamgirlswallpaper.co.uk/fiveyearsonline/wallpaper/Cameron_Diaz/camerond09big.JPG" \
+    "$EXEDIR\cd.jpg"
+  Pop $0
+  StrCmp $0 "OK" dlok
+  MessageBox MB_OK|MB_ICONEXCLAMATION "http upload Error, click OK to abort installation" /SD IDOK
+  Abort
+dlok:
+  ...
+ +

Credits

+

Many thanks to Backland who offered a simple way to fix NSISdl mode crashes, added 'center parent' function, offers few nice design ideas and spent a lot of time testing the plug-in.

+
+

v1.0.4.4 by Stuart 'Afrow UK' Welch

+

v1.0.5.0..v1.0.5.2 by anders_k

+
+

See Contrib\inetc\inetc.cpp for changes.

diff --git a/cmake/Windows/Docs/Inetc/wiki.txt b/cmake/Windows/Docs/Inetc/wiki.txt new file mode 100644 index 000000000..384bdd37c --- /dev/null +++ b/cmake/Windows/Docs/Inetc/wiki.txt @@ -0,0 +1,161 @@ +{{PageAuthor|Takhir}} + +== Links == + +Download:
+Inetc.zip
+ +[http://forums.winamp.com/showthread.php?threadid=198596 Forum thread] + +== Description == + +Internet client plug-in for files download and upload. Based on the InetLoad plug-in. Network implementation uses MS WinInet API, supports http/https and ftp protocols. Plugin has better proxy support compared to NSISdl plug-in. Command line may include few URL/File pairs to be transfered. If server or proxy login/password are not set in the script, it displays IE-style authentication dialog (except silent mode). Plug-in supports 3 "transfer in progress" display modes: + +# old NSISdl style - additional embedded progress bar and text on the INSTFILES page; +# POPUP dialog mode with detailed info; +# BANNER mode with simple popup window. + +Plug-in recognizes Installer's Silent mode and this case hides any output (this feature requires NSIS 2.03 or later). Program implements simple re-get functionality - host reconnect and download from current position after short pause. While program depends on IE settings, it changes current IE mode to online. NSISdl code fragment was used for progress bar displaying in the "old style" mode. +For ftp use "host/path" for file location relative to user's home dir and +"host//path" for absolute path. + +== Commands == + +Plug-in DLL functions (entry points): get, post, head, put + +=== get === + +inetc::get [/PROXY IP:PORT] [/USERNAME PROXY_LOGIN /PASSWORD PROXY_PASSWD] + [/NOPROXY] [/NOCANCEL] [/CONNECTTIMEOUT TO_SEC] [/RECEIVETIMEOUT TO_SEC] [/SILENT] [/WEAKSECURITY] + [/CAPTION TEXT] [/NOCOOKIES] [/RESUME RETRY_QUESTION] [/POPUP HOST_ALIAS | /BANNER TEXT] + [/CANCELTEXT CANCEL_TEXT] [/QUESTION CANCEL_QUESTION] [/USERAGENT USER_AGENT_TEXT] + [/HEADER HEADER_TEXT] [/TRANSLATE LANG_PARAMS] [/TOSTACK | /TOSTACKCONV] + URL1 local_file1 [URL2 local_file2 [...]] [/END] +This call returns "OK" string if successful, error description string if failed (see included InetLoad.cpp file for a full set of status strings). Usage and result processing samples are included to the package. + +; /PROXY +: Overwrites current proxy settings, not required in most cases. IE settings will be used by default. + +; /USERNAME +: Proxy username (http only). + +; /PASSWORD +: Proxy password (http only). For server (http/ftp) authentication it is possible to use URL encoded name and password, for example http://username:password@nsis.sourceforge.net. + +; /NOPROXY +: Disables proxy settings for this connection (if any) + +; /NOCANCEL +: Prevents download from being interrupted by user (locks Esc, Alt-F4, Cancel handling) + +; /CONNECTTIMEOUT - +:Sets INTERNET_OPTION_CONNECT_TIMEOUT, seconds, default - IE current parameter value. + +; /RECEIVETIMEOUT - +:Sets INTERNET_OPTION_RECEIVE_TIMEOUT, seconds, default - IE current parameter value. + +; /SILENT +: Key hides plug-in' output (both popup dialog and embedded progress bar). Not required if 'SilentInstall silent' mode was defined in script (NSIS 2.03 or later). + +; /WEAKSECURITY +: Ignore unknown and revoked certificates + +; /RESUME +: On the permanent connection/transfer error instead of exit first displays message box with "resume download" question. Useful for dial-up connections and big files - allows user to restore connection and resume download. Default is "Your internet connection seems to have dropped out!\nPlease reconnect and click Retry to resume downloading...". + +; /CAPTION +: Defines caption text for /BANNER mode, caption prefix (left of '-') for /POPUP mode and caption for RESUME MessageBox. Default is "InetLoad plug-in" if not set or "". + +; /POPUP +: This mode displays detailed download dialog instead of embedded progress bar. Also useful in .onInit function (i.e. not in Section). If HOST_ALIAS is not "", text will replace URL in the dialog - this allows to hide real URL (including password). + +; /BANNER +: Displays simple popup dialog (MSI Banner mode) and sets dialog TEXT (up to 3 lines using $\n). + +; /CANCELTEXT +: Text for the Cancel button in the NSISdl mode. Default is NSIS dialog Cancel button text (current lang). + +; /QUESTION +: Text for the optional MessageBox if user tries to cancel download. If /QUESTION "" was used default "Are you sure that you want to stop download?" will be substituted. + +; /USERAGENT +: UserAgent http request header value. Default is "NSIS_Inetc (Mozilla)". + +; /HEADER +: Adds or replaces http request header. Common HEADER_TEXT format is "header: value". + +; /NOCOOKIES +: Removes cookies from http request + +; /TOSTACK +: Outputs the post/get/head response to the NSIS stack rather than to the file (specify an empty string for local_file1, local_file2 etc.) + +; /TOSTACKCONV +: Outputs the post/get/head response to the NSIS stack while converting character encodings: +: ASCII -> Unicode for the Unicode plug-in build +: Unicode -> ASCII for the ASCII plug-in build + +; /END +: Allows to limit plug-in stack reading (optional, required if you stores other vars in the stack). + +; /TRANSLATE +: Allows translating plug-in text in the POPUP or "old style" (NSISdl) modes (see Readme for parameters). In the BANNER mode text is also customizable. + +=== post === + +inetc::post TEXT2POST [/PROXY IP:PORT] [/USERNAME PROXY_LOGIN /PASSWORD PROXY_PASSWD] + [/NOPROXY] [/NOCANCEL] [/CONNECTTIMEOUT TO_SEC] [/RECEIVETIMEOUT TO_SEC] [/SILENT] [/WEAKSECURITY] + [/FILE] [/CAPTION TEXT] [/NOCOOKIES] [/POPUP HOST_ALIAS | /BANNER TEXT] + [/CANCELTEXT CANCEL_TEXT] [/USERAGENT USER_AGENT_TEXT] [/TRANSLATE LANG_PARAMS] + [/TOSTACK | /TOSTACKCONV] + URL1 local_file1 [URL2 local_file2 [...]] [/END] +Sets POST http mode and defines text string or file name to be used in the POST (http only). Disables auto re-get. No char replaces used (%20 and others). /FILE option allows to send TEXT2POST file content to server, additional 'Filename:' header added to request this case. + +=== head === + +The same as get, but requests http headers only. Writes raw headers to file. + +=== put === + +inetc::put [/PROXY IP:PORT] [/USERNAME PROXY_LOGIN /PASSWORD PROXY_PASSWD] [/NOPROXY] + [/NOCANCEL] [/CONNECTTIMEOUT TO_SEC] [/RECEIVETIMEOUT TO_SEC] [/SILENT] [/WEAKSECURITY] [/CAPTION TEXT] + [/POPUP HOST_ALIAS | /BANNER TEXT] [/CANCELTEXT CANCEL_TEXT] [/USERAGENT USER_AGENT_TEXT] + [/TRANSLATE LANG_PARAMS] [/NOCOOKIES] + URL1 local_file1 [URL2 local_file2 [...]] [/END] +Return value and parameters (if applicable) are the same as for previous entry point. + +== Examples == + + +inetc::put "http://dl.zvuki.ru/6306/mp3/12.mp3" "$EXEDIR\12.mp3" \ + "ftp://dl.zvuki.ru/6306/mp3/11.mp3" "$EXEDIR\11.mp3" +Pop $0 + + + +inetc::put /BANNER "Cameron Diaz upload in progress..." \ +"http://www.dreamgirlswallpaper.co.uk/fiveyearsonline/wallpaper/Cameron_Diaz/camerond09big.JPG" \ +"$EXEDIR\cd.jpg" + Pop $0 + StrCmp $0 "OK" dlok + MessageBox MB_OK|MB_ICONEXCLAMATION "http upload Error, click OK to abort installation" /SD IDOK + Abort +dlok: + ... + + + +; Following attribute also can restore installer Window +; BGGradient 000000 000080 FFFFFF + +== Credits == + +

Many thanks to Backland who offered a simple way to fix NSISdl mode crashes, added 'center parent' function, offers few nice design ideas and spent a lot of time testing the plug-in.

+
+

v1.0.4.4 by Stuart 'Afrow UK' Welch

+

v1.0.5.0..v1.0.5.2 by anders_k

+
+

See Contrib\inetc\inetc.cpp for changes.

+ + +[[Category:Plugins]] diff --git a/cmake/Windows/Examples/Advanced Uninstall Log/Uninstall_Log_Default_UI.nsi b/cmake/Windows/Examples/Advanced Uninstall Log/Uninstall_Log_Default_UI.nsi new file mode 100644 index 000000000..66f24eedf --- /dev/null +++ b/cmake/Windows/Examples/Advanced Uninstall Log/Uninstall_Log_Default_UI.nsi @@ -0,0 +1,170 @@ +#************************************ Enter script definitions **********************************# + +!define APP_NAME "Advanced Uninstall Log Demo" +# +# +;.................................................................................................. +;Following two definitions required. Uninstall log will use these definitions. +;You may use these definitions also, when you want to set up the InstallDirRagKey, +;store the language selection, store Start Menu folder etc. +;Enter the windows uninstall reg sub key to add uninstall information to Add/Remove Programs also. + +!define INSTDIR_REG_ROOT "HKLM" +!define INSTDIR_REG_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" +;.................................................................................................. + +#************************************* Include NSIS Headers ***********************************# +# +# +;.................................................................................................. +;include the Uninstall log header +!include AdvUninstLog.nsh +;.................................................................................................. + +Name "${APP_NAME}" +OutFile "${APP_NAME}[DEFAULT UI].exe" +ShowInstDetails show +ShowUninstDetails show +LicenseData "${NSISDIR}\License.txt" +LicenseBkColor 0xFFFFFF +InstallDir "$PROGRAMFILES\${APP_NAME}" +InstallDirRegKey ${INSTDIR_REG_ROOT} "${INSTDIR_REG_KEY}" "InstallDir" + +;.................................................................................................. +;Specify the preferred uninstaller operation mode, either unattended or interactive. +;You have to type either !insertmacro UNATTENDED_UNINSTALL, or !insertmacro INTERACTIVE_UNINSTALL. +;Be aware only one of the following two macros has to be inserted, neither both, neither none. + + !insertmacro UNATTENDED_UNINSTALL + ;!insertmacro INTERACTIVE_UNINSTALL +;.................................................................................................. + +Page License +Page Components +Page Directory +Page InstFiles + + +Section "Main Application" sec01 + + SetOutPath '$INSTDIR' + +;After set the output path open the uninstall log macros block and add files/dirs with File /r +;This should be repeated every time the parent output path is changed either within the same +;section, or if there are more sections including optional components. + !insertmacro UNINSTALL.LOG_OPEN_INSTALL + + File /r /x "uninst-nsis.exe" /x "Docs" /x "Stubs" "${NSISDIR}\*" + +;........................................................................................ +;Now for the 2nd run (update installation mode) uncomment the File /r instruction below, +;and comment the File /r instruction above. New installation files would be appended to log. +;Everything that's included within the macros block uninstall_log_open/close added in log. +;Files that added outside the block either manually or from application's usage, +;never added to log, so uninstaller knows about them and requests confirmation to delete. + + ;File /r '${NSISDIR}\Docs' +;........................................................................................ + +;Once required files/dirs added and before change the parent output directory we need to +;close the opened previously uninstall log macros block. + !insertmacro UNINSTALL.LOG_CLOSE_INSTALL + + CreateDirectory '$SMPROGRAMS\${APP_NAME}' + CreateShortcut '$SMPROGRAMS\${APP_NAME}\nsis.lnk' '$INSTDIR\nsis.exe' + ;create shortcut for uninstaller always use ${UNINST_EXE} instead of uninstall.exe + CreateShortcut '$SMPROGRAMS\${APP_NAME}\uninstall.lnk' '${UNINST_EXE}' + + WriteRegStr ${INSTDIR_REG_ROOT} "${INSTDIR_REG_KEY}" "InstallDir" "$INSTDIR" + WriteRegStr ${INSTDIR_REG_ROOT} "${INSTDIR_REG_KEY}" "DisplayName" "${APP_NAME}" + ;Same as create shortcut you need to use ${UNINST_EXE} instead of anything else. + WriteRegStr ${INSTDIR_REG_ROOT} "${INSTDIR_REG_KEY}" "UninstallString" "${UNINST_EXE}" + +#............................................................................... +;instead of adding files/folders manually to perform our test, we do it here :) + File /r '${NSISDIR}\Stubs' +#............................................................................... + +SectionEnd + + +Section "Application Data" sec02 + + SetOutPath "$APPDATA\${APP_NAME}" + +;After set the output path open the uninstall log macros block and add files/dirs with File /r +;This should be repeated every time the parent output path is changed either within the same +;section, or if there are more sections including optional components. + !insertmacro UNINSTALL.LOG_OPEN_INSTALL + + File /r '${NSISDIR}\Stubs\*' + +;........................................................................................ +;Now for the 2nd run (update installation mode) uncomment the File /r instruction below, +;and comment the File /r instruction above. New installation files would be appended to log. +;Everything that's included within the macros block uninstall_log_open/close added in log. +;Files that added outside the block either manually or from application's usage, +;never added to log, so uninstaller knows about them and requests confirmation to delete. + + ;File /r '${NSISDIR}\Contrib' +;........................................................................................ + +;Once required files/dirs added and before change the parent output directory we need to +;close the opened previously uninstall log macros block. + !insertmacro UNINSTALL.LOG_CLOSE_INSTALL + +#............................................................................... +;instead of adding files/folders manually to perform our test, we do it here :) + File /r '${NSISDIR}\Plugins' +#............................................................................... + +SectionEnd + + +Function .onInit + + ;prepare log always within .onInit function + !insertmacro UNINSTALL.LOG_PREPARE_INSTALL + +FunctionEnd + + +Function .onInstSuccess + + ;create/update log always within .onInstSuccess function + !insertmacro UNINSTALL.LOG_UPDATE_INSTALL + +FunctionEnd + +####################################################################################### + +Section UnInstall + + ;begin uninstall, especially for MUI could be added in UN.onInit function instead + !insertmacro UNINSTALL.LOG_BEGIN_UNINSTALL + + ;uninstall from path, must be repeated for every install logged path individual + !insertmacro UNINSTALL.LOG_UNINSTALL "$INSTDIR" + + ;uninstall from path, must be repeated for every install logged path individual + !insertmacro UNINSTALL.LOG_UNINSTALL "$APPDATA\${APP_NAME}" + + ;end uninstall, after uninstall from all logged paths has been performed + !insertmacro UNINSTALL.LOG_END_UNINSTALL + + Delete "$SMPROGRAMS\${APP_NAME}\nsis.lnk" + Delete "$SMPROGRAMS\${APP_NAME}\uninstall.lnk" + RmDir "$SMPROGRAMS\${APP_NAME}" + + DeleteRegKey /ifempty ${INSTDIR_REG_ROOT} "${INSTDIR_REG_KEY}" + +SectionEnd + +/* +Function UN.onInit + + ;begin uninstall, could be added on top of uninstall section instead + !insertmacro UNINSTALL.LOG_BEGIN_UNINSTALL + +FunctionEnd +*/ diff --git a/cmake/Windows/Examples/Advanced Uninstall Log/Uninstall_Log_Modern_UI.nsi b/cmake/Windows/Examples/Advanced Uninstall Log/Uninstall_Log_Modern_UI.nsi new file mode 100644 index 000000000..b62330b36 --- /dev/null +++ b/cmake/Windows/Examples/Advanced Uninstall Log/Uninstall_Log_Modern_UI.nsi @@ -0,0 +1,178 @@ +#************************************ Enter script definitions **********************************# + +!define APP_NAME "Advanced Uninstall Log Demo" +# +# +;.................................................................................................. +;Following two definitions required. Uninstall log will use these definitions. +;You may use these definitions also, when you want to set up the InstallDirRagKey, +;store the language selection, store Start Menu folder etc. +;Enter the windows uninstall reg sub key to add uninstall information to Add/Remove Programs also. + +!define INSTDIR_REG_ROOT "HKLM" +!define INSTDIR_REG_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" +;.................................................................................................. + +#************************************* Include NSIS Headers ***********************************# + +!include MUI.nsh +# +# +;.................................................................................................. +;include the Uninstall log header +!include AdvUninstLog.nsh +;.................................................................................................. + +Name "${APP_NAME}" +OutFile "${APP_NAME}[MODERN UI].exe" +ShowInstDetails show +ShowUninstDetails show +InstallDir "$PROGRAMFILES\${APP_NAME}" +InstallDirRegKey ${INSTDIR_REG_ROOT} "${INSTDIR_REG_KEY}" "InstallDir" + +;.................................................................................................. +;Specify the preferred uninstaller operation mode, either unattended or interactive. +;You have to type either !insertmacro UNATTENDED_UNINSTALL, or !insertmacro INTERACTIVE_UNINSTALL. +;Be aware only one of the following two macros has to be inserted, neither both, neither none. + + ;!insertmacro UNATTENDED_UNINSTALL + !insertmacro INTERACTIVE_UNINSTALL +;.................................................................................................. + + !insertmacro MUI_PAGE_WELCOME + !insertmacro MUI_PAGE_LICENSE "${NSISDIR}\License.txt" + !insertmacro MUI_PAGE_COMPONENTS + !insertmacro MUI_PAGE_DIRECTORY + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_PAGE_FINISH + + !insertmacro MUI_UNPAGE_WELCOME + !insertmacro MUI_UNPAGE_CONFIRM + !insertmacro MUI_UNPAGE_INSTFILES + !insertmacro MUI_UNPAGE_FINISH + + !insertmacro MUI_LANGUAGE "English" + + +Section "Main Application" sec01 + + SetOutPath '$INSTDIR' + +;After set the output path open the uninstall log macros block and add files/dirs with File /r +;This should be repeated every time the parent output path is changed either within the same +;section, or if there are more sections including optional components. + !insertmacro UNINSTALL.LOG_OPEN_INSTALL + + File /r /x "uninst-nsis.exe" /x "Docs" /x "Stubs" "${NSISDIR}\*" + +;........................................................................................ +;Now for the 2nd run (update installation mode) uncomment the File /r instruction below, +;and comment the File /r instruction above. New installation files would be appended to log. +;Everything that's included within the macros block uninstall_log_open/close added in log. +;Files that added outside the block either manually or from application's usage, +;never added to log, so uninstaller knows about them and requests confirmation to delete. + + ;File /r '${NSISDIR}\Docs' +;........................................................................................ + +;Once required files/dirs added and before change the parent output directory we need to +;close the opened previously uninstall log macros block. + !insertmacro UNINSTALL.LOG_CLOSE_INSTALL + + CreateDirectory '$SMPROGRAMS\${APP_NAME}' + CreateShortcut '$SMPROGRAMS\${APP_NAME}\nsis.lnk' '$INSTDIR\nsis.exe' + ;create shortcut for uninstaller always use ${UNINST_EXE} instead of uninstall.exe + CreateShortcut '$SMPROGRAMS\${APP_NAME}\uninstall.lnk' '${UNINST_EXE}' + + WriteRegStr ${INSTDIR_REG_ROOT} "${INSTDIR_REG_KEY}" "InstallDir" "$INSTDIR" + WriteRegStr ${INSTDIR_REG_ROOT} "${INSTDIR_REG_KEY}" "DisplayName" "${APP_NAME}" + ;Same as create shortcut you need to use ${UNINST_EXE} instead of anything else. + WriteRegStr ${INSTDIR_REG_ROOT} "${INSTDIR_REG_KEY}" "UninstallString" "${UNINST_EXE}" + +#............................................................................... +;instead of adding files/folders manually to perform our test, we do it here :) + File /r '${NSISDIR}\Stubs' +#............................................................................... + +SectionEnd + + +Section "Application Data" sec02 + + SetOutPath "$APPDATA\${APP_NAME}" + +;After set the output path open the uninstall log macros block and add files/dirs with File /r +;This should be repeated every time the parent output path is changed either within the same +;section, or if there are more sections including optional components. + !insertmacro UNINSTALL.LOG_OPEN_INSTALL + + File /r '${NSISDIR}\Stubs\*' + +;........................................................................................ +;Now for the 2nd run (update installation mode) uncomment the File /r instruction below, +;and comment the File /r instruction above. New installation files would be appended to log. +;Everything that's included within the macros block uninstall_log_open/close added in log. +;Files that added outside the block either manually or from application's usage, +;never added to log, so uninstaller knows about them and requests confirmation to delete. + + ;File /r '${NSISDIR}\Contrib' +;........................................................................................ + +;Once required files/dirs added and before change the parent output directory we need to +;close the opened previously uninstall log macros block. + !insertmacro UNINSTALL.LOG_CLOSE_INSTALL + +#............................................................................... +;instead of adding files/folders manually to perform our test, we do it here :) + File /r '${NSISDIR}\Plugins' +#............................................................................... + +SectionEnd + + +Function .onInit + + ;prepare log always within .onInit function + !insertmacro UNINSTALL.LOG_PREPARE_INSTALL + +FunctionEnd + + +Function .onInstSuccess + + ;create/update log always within .onInstSuccess function + !insertmacro UNINSTALL.LOG_UPDATE_INSTALL + +FunctionEnd + +####################################################################################### + +Section UnInstall + + ;begin uninstall, especially for MUI could be added in UN.onInit function instead + ;!insertmacro UNINSTALL.LOG_BEGIN_UNINSTALL + + ;uninstall from path, must be repeated for every install logged path individual + !insertmacro UNINSTALL.LOG_UNINSTALL "$INSTDIR" + + ;uninstall from path, must be repeated for every install logged path individual + !insertmacro UNINSTALL.LOG_UNINSTALL "$APPDATA\${APP_NAME}" + + ;end uninstall, after uninstall from all logged paths has been performed + !insertmacro UNINSTALL.LOG_END_UNINSTALL + + Delete "$SMPROGRAMS\${APP_NAME}\nsis.lnk" + Delete "$SMPROGRAMS\${APP_NAME}\uninstall.lnk" + RmDir "$SMPROGRAMS\${APP_NAME}" + + DeleteRegKey /ifempty ${INSTDIR_REG_ROOT} "${INSTDIR_REG_KEY}" + +SectionEnd + + +Function UN.onInit + + ;begin uninstall, could be added on top of uninstall section instead + !insertmacro UNINSTALL.LOG_BEGIN_UNINSTALL + +FunctionEnd diff --git a/cmake/Windows/Examples/Inetc/Example.nsi b/cmake/Windows/Examples/Inetc/Example.nsi new file mode 100755 index 000000000..e64bc9fa9 --- /dev/null +++ b/cmake/Windows/Examples/Inetc/Example.nsi @@ -0,0 +1,54 @@ + +;-------------------------------- +; General Attributes + +Name "Inetc plug-in Test" +OutFile "inetc.exe" +;SilentInstall silent +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install-colorful.ico" + !insertmacro MUI_PAGE_WELCOME + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" + +;SetFont 14 + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + + SetDetailsView hide + +; two files download, popup mode + inetc::get /caption "2003-2004 reports" /popup "" "http://ineum.narod.ru/spr_2003.htm" "$EXEDIR\spr3.htm" "http://ineum.narod.ru/spr_2004.htm" "$EXEDIR\spr4.htm" /end + Pop $0 # return value = exit code, "OK" means OK + +; single file, NSISdl-style embedded progress bar with specific cancel button text + inetc::get /caption "2005 report" /canceltext "interrupt!" "http://ineum.narod.ru/spr_2005.htm" "$EXEDIR\spr5.htm" /end + Pop $1 # return value = exit code, "OK" means OK + +; banner with 2 text lines and disabled Cancel button + inetc::get /caption "2006 report" /banner "Banner mode with /nocancel option setten$\nSecond Line" /nocancel "http://ineum.narod.ru/spr_2006.htm" "$EXEDIR\spr6.htm" /end + Pop $2 # return value = exit code, "OK" means OK + + MessageBox MB_OK "Download Status: $0, $1, $2" +SectionEnd + + +;-------------------------------- +;Installer Functions + +Function .onInit + +; plug-in auto-recognizes 'no parent dlg' in onInit and works accordingly +; inetc::head /RESUME "Network error. Retry?" "http://ineum.narod.ru/spr_2003.htm" "$EXEDIR\spr3.txt" +; Pop $4 + +FunctionEnd diff --git a/cmake/Windows/Examples/Inetc/auth_dlg.nsi b/cmake/Windows/Examples/Inetc/auth_dlg.nsi new file mode 100755 index 000000000..6fc8ee17d --- /dev/null +++ b/cmake/Windows/Examples/Inetc/auth_dlg.nsi @@ -0,0 +1,32 @@ + +;-------------------------------- +; General Attributes + +Name "Inetc http auth Test" +OutFile "auth_dlg.exe" +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install-colorful.ico" + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" + + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + +; Displays IE auth dialog. +; Both server and proxy auth. +; Please test this with your own link. + + inetc::get "http://www.cnt.ru/personal" "$EXEDIR\auth.html" + Pop $0 # return value = exit code, "OK" if OK + MessageBox MB_OK "Download Status: $0" + +SectionEnd diff --git a/cmake/Windows/Examples/Inetc/ftp_auth.nsi b/cmake/Windows/Examples/Inetc/ftp_auth.nsi new file mode 100755 index 000000000..83c1d967b --- /dev/null +++ b/cmake/Windows/Examples/Inetc/ftp_auth.nsi @@ -0,0 +1,32 @@ + +;-------------------------------- +; General Attributes + +Name "Inetc ftp authentication Test" +OutFile "ftp_auth.exe" +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install-colorful.ico" + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" + + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + +; use your own URL and login@pwd. Password hidden from user with /popup "ALIAS" + + inetc::get /caption "service pack download" /popup "ftp://localhost/" "ftp://login:pwd@localhost/W2Ksp3.exe" "$EXEDIR\sp3.exe" +; inetc::put /caption "service pack upload" /popup "" "ftp://login:pwd@localhost/W2Ksp3.bu.exe" "$EXEDIR\sp3.exe" + Pop $0 # return value = exit code, "OK" if OK + MessageBox MB_OK "Download Status: $0" + +SectionEnd + diff --git a/cmake/Windows/Examples/Inetc/head.nsi b/cmake/Windows/Examples/Inetc/head.nsi new file mode 100755 index 000000000..fef90ec5e --- /dev/null +++ b/cmake/Windows/Examples/Inetc/head.nsi @@ -0,0 +1,30 @@ + +;-------------------------------- +; General Attributes + +Name "Inetc Head Test" +OutFile "head.exe" +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" + + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + + DetailPrint "New version check out (internet connection)" + inetc::head /silent "http://ineum.narod.ru/spr_2006.htm" "$EXEDIR\head.txt" + Pop $0 # return value = exit code, "OK" if OK + MessageBox MB_OK "Download Status: $0" + +SectionEnd + + diff --git a/cmake/Windows/Examples/Inetc/headers.nsi b/cmake/Windows/Examples/Inetc/headers.nsi new file mode 100755 index 000000000..b4a2b4841 --- /dev/null +++ b/cmake/Windows/Examples/Inetc/headers.nsi @@ -0,0 +1,32 @@ + +;-------------------------------- +; General Attributes + +Name "Headers Test" +OutFile "headers.exe" +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" + + + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + +; additional headers. Sample php returns raw headers + inetc::get /useragent "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1)" /header "SOAPAction: urn:anonOutInOpe" "http://localhost/headers.php" "$EXEDIR\headers.html" + Pop $0 + + MessageBox MB_OK "Download Status: $0" + +SectionEnd + + diff --git a/cmake/Windows/Examples/Inetc/headers.php b/cmake/Windows/Examples/Inetc/headers.php new file mode 100755 index 000000000..f531bc500 --- /dev/null +++ b/cmake/Windows/Examples/Inetc/headers.php @@ -0,0 +1,7 @@ + $value) { + echo "$header: $value
\n"; +} +?> diff --git a/cmake/Windows/Examples/Inetc/https.nsi b/cmake/Windows/Examples/Inetc/https.nsi new file mode 100755 index 000000000..9bc9975db --- /dev/null +++ b/cmake/Windows/Examples/Inetc/https.nsi @@ -0,0 +1,27 @@ + +;-------------------------------- +; General Attributes + +Name "Inetc https Test" +OutFile "https.exe" +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" + + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + + inetc::get /POPUP "" /CAPTION "bending_property_demo.zip" "https://secure.codeproject.com/cs/miscctrl/bending_property/bending_property_src.zip" "$EXEDIR\bending_property_src.zip" + Pop $0 # return value = exit code, "OK" if OK + MessageBox MB_OK "Download Status: $0" + +SectionEnd diff --git a/cmake/Windows/Examples/Inetc/inetc_local.nsi b/cmake/Windows/Examples/Inetc/inetc_local.nsi new file mode 100755 index 000000000..53160aa70 --- /dev/null +++ b/cmake/Windows/Examples/Inetc/inetc_local.nsi @@ -0,0 +1,81 @@ + +;-------------------------------- +; General Attributes + +Name "Inetc Local Test" +OutFile "inetc_local.exe" +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install-colorful.ico" + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" + + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + + +; PUT test + +; FTP requires anonymous access in sample below. +; HTTP sample put.php included to package. Stores test.jpg as m2.bmp +; check server files present after upload + + inetc::put "http://localhost/put.php" "$EXEDIR\test.jpg" + Pop $0 + + inetc::put "ftp://localhost/test.jpg" "$EXEDIR\test.jpg" +; not anonymous format +; inetc::put "ftp://login:password@localhost/test.jpg" "$EXEDIR\test.jpg" + Pop $1 + + DetailPrint "PUT: HTTP $0, FTP $1 (verify server files)" + + +; POST test + +; HTTP sample post.php and post_form.htm (to compare results) included + + inetc::post "login=ami&passwd=333" "http://localhost/post.php?lg=iam&pw=44" "$EXEDIR\post_reply.htm" + Pop $2 + + DetailPrint "POST: $2 (post_reply.htm)" + + +; HEAD test + +; uses uploaded earlier test.jpg + + inetc::head /silent "http://localhost/m2.bmp" "$EXEDIR\head.txt" + Pop $3 + + DetailPrint "HEAD: $3 (head.txt)" + + +; GET test + +; 2 files download in nsisdl mode + inetc::get "http://localhost/m2.bmp" "$EXEDIR\get1.jpg" "http://localhost/m2.bmp" "$EXEDIR\get2.jpg" + Pop $4 + + inetc::get /popup "Localhost:GET with Popup" "http://localhost/m2.bmp" "$EXEDIR\get3.jpg" + Pop $5 + + inetc::get /banner "Local Test GET with Banner" "http://localhost/m2.bmp" "$EXEDIR\get4.jpg" + Pop $6 + + inetc::get /silent "ftp://localhost/test.jpg" "$EXEDIR\get5.jpg" + Pop $7 + + DetailPrint "GET: NSISDL $4, POPUP $5, BANNER $6, FTP $7 (get1-5.jpg)" + + SetDetailsView show + +SectionEnd diff --git a/cmake/Windows/Examples/Inetc/post.nsi b/cmake/Windows/Examples/Inetc/post.nsi new file mode 100755 index 000000000..3c64117f8 --- /dev/null +++ b/cmake/Windows/Examples/Inetc/post.nsi @@ -0,0 +1,31 @@ + +;-------------------------------- +; General Attributes + +Name "Inetc Post Test" +OutFile "post.exe" +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" + + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + +; this is my LAN sample, use your own URL for tests. Sample post.php included + + inetc::post "login=ami&passwd=333" "http://localhost/post.php?lg=iam&pw=44" "$EXEDIR\post_reply.htm" + Pop $0 # return value = exit code, "OK" if OK + MessageBox MB_OK "Download Status: $0" + +SectionEnd + + diff --git a/cmake/Windows/Examples/Inetc/post.php b/cmake/Windows/Examples/Inetc/post.php new file mode 100755 index 000000000..d2a40bcb8 --- /dev/null +++ b/cmake/Windows/Examples/Inetc/post.php @@ -0,0 +1,13 @@ + + + + +"; +echo "post.passwd=".$_POST['passwd']."
"; +echo "get.lg=".$_GET['lg']."
"; +echo "get.pw=".$_GET['pw']."
"; +?> + + + diff --git a/cmake/Windows/Examples/Inetc/post_file.nsi b/cmake/Windows/Examples/Inetc/post_file.nsi new file mode 100755 index 000000000..c93f2961a --- /dev/null +++ b/cmake/Windows/Examples/Inetc/post_file.nsi @@ -0,0 +1,31 @@ + +;-------------------------------- +; General Attributes + +Name "Inetc Post Test" +OutFile "post_file.exe" +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" + + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + +; this is my LAN sample, use your own URL for tests. Sample post.php included + + inetc::post "$EXEDIR\inetc.cpp" /file "http://localhost/post_file.php" "$EXEDIR\post_file.htm" + Pop $0 # return value = exit code, "OK" if OK + MessageBox MB_OK "Download Status: $0" + +SectionEnd + + diff --git a/cmake/Windows/Examples/Inetc/post_file.php b/cmake/Windows/Examples/Inetc/post_file.php new file mode 100755 index 000000000..059bf7402 --- /dev/null +++ b/cmake/Windows/Examples/Inetc/post_file.php @@ -0,0 +1,10 @@ + $value) { + echo "$header: $value
\n"; +} +echo "new
"; +foreach ($_FILES as $key => $value) echo $key . "<>" . $value . "
\n"; +echo file_get_contents('php://input'); +?> diff --git a/cmake/Windows/Examples/Inetc/post_form.html b/cmake/Windows/Examples/Inetc/post_form.html new file mode 100755 index 000000000..0bde9208d --- /dev/null +++ b/cmake/Windows/Examples/Inetc/post_form.html @@ -0,0 +1,18 @@ + + +Registration form for post.php test + + +This form sends POST request to server. It was interesting to compare server echo
+reply (by included post.php) for this form and InetLoad plug-in - in my
+tests server did not see any difference between them :)
+
+ +
+
+ + +
+ + + diff --git a/cmake/Windows/Examples/Inetc/put.nsi b/cmake/Windows/Examples/Inetc/put.nsi new file mode 100755 index 000000000..ce74a0403 --- /dev/null +++ b/cmake/Windows/Examples/Inetc/put.nsi @@ -0,0 +1,31 @@ + +;-------------------------------- +; General Attributes + +Name "Inetc Test" +OutFile "put.exe" +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install-colorful.ico" + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" + + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + +; this is my LAN sample, use your own URL for tests. Login/pwd hidden from user. Sample put.php (for http request) included + + inetc::put "http://localhost/put.php" "$EXEDIR\test.jpg" +; inetc::put /POPUP "ftp://localhost/" /CAPTION "my local ftp upload" "ftp://localhost/test.jpg" "$EXEDIR\test.jpg" + Pop $0 + MessageBox MB_OK "Upload Status: $0" + +SectionEnd diff --git a/cmake/Windows/Examples/Inetc/put.php b/cmake/Windows/Examples/Inetc/put.php new file mode 100755 index 000000000..dc71943be --- /dev/null +++ b/cmake/Windows/Examples/Inetc/put.php @@ -0,0 +1,19 @@ + diff --git a/cmake/Windows/Examples/Inetc/recursive.nsi b/cmake/Windows/Examples/Inetc/recursive.nsi new file mode 100755 index 000000000..a21aa12aa --- /dev/null +++ b/cmake/Windows/Examples/Inetc/recursive.nsi @@ -0,0 +1,65 @@ +Name "Inetc Recursive Dir Upload Test" +OutFile "recursive.exe" +RequestExecutionLevel user + +!include "MUI2.nsh" +!insertmacro MUI_PAGE_INSTFILES +!insertmacro MUI_LANGUAGE "English" +!include "FileFunc.nsh" +!insertmacro GetFileAttributes + +var url +var path + +Function dirul + + Push $0 ; search handle + Push $1 ; file name + Push $2 ; attributes + + FindFirst $0 $1 "$path\*" +loop: + StrCmp $1 "" done + ${GetFileAttributes} "$path\$1" DIRECTORY $2 + IntCmp $2 1 isdir +retry: + Inetc::put $url/$1 "$path\$1" /end + Pop $2 + DetailPrint "$2 $path\$1" + StrCmp $2 "OK" cont + MessageBox MB_YESNO "$path\$1 file upload failed. Retry?" IDYES retry + Abort "terminated by user" + Goto cont +isdir: + StrCmp $1 . cont + StrCmp $1 .. cont + Push $path + Push $url + StrCpy $path "$path\$1" + StrCpy $url "$url/$1" + Call dirul + Pop $url + Pop $path +cont: + FindNext $0 $1 + Goto loop +done: + FindClose $0 + + Pop $2 + Pop $1 + Pop $0 + +FunctionEnd + + +Section "Dummy Section" SecDummy + + SetDetailsView hide + StrCpy $path "$EXEDIR" +; put is dir in the user's ftp home, use //put for root-relative path + StrCpy $url ftp://takhir:pwd@localhost/put + Call dirul + SetDetailsView show + +SectionEnd diff --git a/cmake/Windows/Examples/Inetc/redirect.nsi b/cmake/Windows/Examples/Inetc/redirect.nsi new file mode 100755 index 000000000..3761692ca --- /dev/null +++ b/cmake/Windows/Examples/Inetc/redirect.nsi @@ -0,0 +1,31 @@ + +;-------------------------------- +; General Attributes + +Name "Redirect Test" +OutFile "redirect.exe" +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" + + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + + SetDetailsView hide + + inetc::get "http://localhost/redirect.php" "$EXEDIR\redirect.htm" /end + Pop $1 + + MessageBox MB_OK "Download Status: $1" + +SectionEnd + diff --git a/cmake/Windows/Examples/Inetc/redirect.php b/cmake/Windows/Examples/Inetc/redirect.php new file mode 100755 index 000000000..900833fe1 --- /dev/null +++ b/cmake/Windows/Examples/Inetc/redirect.php @@ -0,0 +1,6 @@ + diff --git a/cmake/Windows/Examples/Inetc/timeout.nsi b/cmake/Windows/Examples/Inetc/timeout.nsi new file mode 100755 index 000000000..a8a306963 --- /dev/null +++ b/cmake/Windows/Examples/Inetc/timeout.nsi @@ -0,0 +1,32 @@ + +;-------------------------------- +; General Attributes + +Name "Timeout Test" +OutFile "to.exe" +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" + + + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + +; additional headers. Sample php returns raw headers + inetc::get /receivetimeout 12 "http://localhost/to.php" "$EXEDIR\to.html" + Pop $0 + + MessageBox MB_OK "Download Status: $0" + +SectionEnd + + diff --git a/cmake/Windows/Examples/Inetc/tostack.nsi b/cmake/Windows/Examples/Inetc/tostack.nsi new file mode 100755 index 000000000..cfd729b7b --- /dev/null +++ b/cmake/Windows/Examples/Inetc/tostack.nsi @@ -0,0 +1,32 @@ + +;-------------------------------- +; General Attributes + +Name "Inetc To Stack Test" +OutFile "ToStack.exe" +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install-colorful.ico" + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" + + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + + inetc::get /TOSTACK "http://www.google.com" "" /END + Pop $0 # return value = exit code, "OK" if OK + MessageBox MB_OK "Download Status: $0" + Pop $0 # return text + StrLen $1 $0 + MessageBox MB_OK "Download Length: $1" + MessageBox MB_OK "$0" + +SectionEnd diff --git a/cmake/Windows/Examples/Inetc/translate.nsi b/cmake/Windows/Examples/Inetc/translate.nsi new file mode 100755 index 000000000..079cfea08 --- /dev/null +++ b/cmake/Windows/Examples/Inetc/translate.nsi @@ -0,0 +1,33 @@ + +;-------------------------------- +; General Attributes + +Name "Inetc Translate Test" +OutFile "Translate.exe" +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install-colorful.ico" + !insertmacro MUI_PAGE_WELCOME + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_PAGE_FINISH + !insertmacro MUI_LANGUAGE "Russian" + + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + +; This is russian variant. See Readme.txt for a list of parameters. +; Use LangStrings as TRANSLATE parameters for multilang options + + inetc::load /POPUP "" /CAPTION "Ôàéë ãàëåðåè" /TRANSLATE "URL" "Çàãðóçêà" "Ïîïûòêà ñîåäèíåíèÿ" "Èìÿ ôàéëà" Ïîëó÷åíî "Ðàçìåð" "Îñòàëîñü" "Ïðîøëî" "http://ineum.narod.ru/g06s.htm" "$EXEDIR\g06s.htm" + Pop $0 # return value = exit code, "OK" if OK + MessageBox MB_OK "Download Status: $0" + +SectionEnd diff --git a/cmake/Windows/FolderList.exe b/cmake/Windows/FolderList.exe new file mode 100644 index 0000000000000000000000000000000000000000..bb65825270a79762444fb6f367d8c972666f50da GIT binary patch literal 49152 zcmeIb4SZC^)jxhWSzv*MERtZ9C|g}LHW7n~7+jPMY+k^;?B-~K%=~>L8zjo?Tv{VUgSlo`}>}`_wGwxtUm4U z^ZY;mPgW;$@64GqXU?2CbLPylQsxp>W8Le44#ue42Wz)uu8)H&X zKNQop?8EubB&gwF%F_vl@P07m>x7S3e2%?eU%oxzeZ1$+IhSyl!9Saj%JSb%_?X3g z2_GQNE??p#T>UAxC39T5CX_qk`P8E39p}O{V>P43a5YF#Qm?GQvjJf}0wvNj0`Z4_ zYRt9Zh4Szt{;?PKjz3De60uz4uQ<-ep8mZ*iyJvEEfB?ej!V!4CImlE})5z*@{ocJESd+8VP9KENTbVa4YID&Au8G@>C z-(@n?YQ-c&s|TU86PTq&6g+D+=`{RkhZM7b3TegmqTO0f&W{8hU;fzO{0@x;By}eP z1#5_yq-|(%Xe zb)sD>T0^26TKLhPG_7}PEZV3xY6yPii)&3$;>mn)P4A7^i308peZI^&Y7Qr}(i>rt z`K2#LgZ(UHO=pAv|9u1c!`*9jrcqC%o3!4D1falE6gnZDP%G<2met2_Ce}5idIvCgDN0d(8<**ZJA{k_aHHj zyb|7sL~0;!O0bFV$+e@54%u4DM*Xp>5T%<;fjo$nIs9YlCq_W_{@3aswEeUGz4kl6 zI~_@r!F-ONlp_|JB6En77NB*vN14yL`W6-!snUq?La=&qlz7sUrL}u9wZcdlSj;yH z4x^YFEu=(?S+PQ9te77sIO4?A1R*6s%t{n86UF>lf@7ALY7tT_VwP3Nw2Jv@f+I~# zO&3zq#VnhUX%q8viv>rnIzEXaJrSulpXRTi$|D`(KFNjg=x#4?cNCaUyS@}Vii;Mu zLS(`b1A%B*bVi8g;Vy0EdvWkv0AwNw_Nf%Pn#Y~%!WfL8_ zLVm96kwNGRqUTCRkNe9g_g7J9l}d)|i$Mx1&5{)-q;?NRjjBI$pykl|8k@Vfz>{m@ z#ZKWVQzzs<8v~(+29I?3Dh!rM?zTb`n0K4Q4b5Oe(J z`s)7r+TAl%gn=H|6Hr92krRA=223=(#q% zI zWDOe;M}uaPI7cg{$LT`b8}_0V;nWIOm}rTGBG!p}yb);xHJ)kb8+91?`i7RU%`J_o zTI!y`lqpCWiXM4>^G$13pssIm>BRBgh;*uEWWY3_c21E(EzJk0UhA*YFXZTUtpnX4 z9lGH4c8nxFs}3E;pgge`B-sYA$lV(yChNttaL5kGV7#!#MaCaBx8@6FeZrz%A>;VH z$oi19U8}m+x87H9By%7aysr$Uwb+!8) zEl6lM>T<<H$&=qMNHO- z2C6Vu6CJuoOwzgcXd4c?LJ?JHY~BbPn$Y}hBxZ2p>v(aVR?O=SeXrr5!YV!zWybCn z?a^u}PALU|P_)z=p$NxlF{4Y7j^r-6POAoT3^*btP&hKq1dNh};@=ke1SCkmN2vN; zy6GFHKcU`F2C4T>yO>M*@}!ueC2aytQfgY9Ej@fCy7fKj-fz9$q6L9tP?oQigUFYT zB+HO5uG7UIC5dwN3X3joGOyF~R>7q+pJqZaI$xc(G1)XOx+u5|?vALQBciKUTt`z< z80C`@C{IQwDMR+l!{5Z8Z5(z8!PT}VAhZlFkCQ! zVD>nUA!HB|l^H~jffiXL=+t>cZr=k#wGUJ0I(<<4zFn0pxG-6<=IO;`gU>L@Qk$q# z+NT?;eV=5??NgOZK#$7wyf73!gYtWhpWmSOJ!wxAMrC_}%I<=mk9_PNkL(3kux!Z2 zDaLKPLXF>g3ZTc`t0R_2<%yLh6Y)KYcy2PE6VMMrr74`hmiQkoJ^4?@{|I9GIad#u z9#t&F6)nPaqiaRV_~4Yh9ET^R0QjOYb4b@f-?-Z%Nyy~_%52!#Df8pNQ2ZFIf9Cr8 zXRO>m(#w-M4&5WOM5pkBx`+5NPiB{oA4wTQ_D*LfS|OV�I_14snXIJMyI+XujCK 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 ${NSIS_MAX_STRLEN} + SetErrors + DetailPrint "Current $1 length ($6) too long to modify in NSIS; set manually if needed. Missed entry was: '$4'" + Pop $8 + Pop $7 + Pop $6 + Goto EnvVarUpdate_Restore_Vars + ${EndIf} + Pop $8 + Pop $7 + Pop $6 +;;khc + + ; Make sure we've got some work to do + ${If} $5 == "" + ${AndIf} $2 == "R" + SetErrors + DetailPrint "$1 is empty - Nothing to remove" + Goto EnvVarUpdate_Restore_Vars + ${EndIf} + + ; Step 2: Scrub EnvVar + ; + StrCpy $0 $5 ; Copy the contents to $0 + ; Remove spaces around semicolons (NOTE: spaces before the 1st entry or + ; after the last one are not removed here but instead in Step 3) + ${If} $0 != "" ; If EnvVar is not empty ... + ${Do} + ${${UN}StrStr} $7 $0 " ;" + ${If} $7 == "" + ${ExitDo} + ${EndIf} + ${${UN}StrRep} $0 $0 " ;" ";" ; Remove ';' + ${Loop} + ${Do} + ${${UN}StrStr} $7 $0 "; " + ${If} $7 == "" + ${ExitDo} + ${EndIf} + ${${UN}StrRep} $0 $0 "; " ";" ; Remove ';' + ${Loop} + ${Do} + ${${UN}StrStr} $7 $0 ";;" + ${If} $7 == "" + ${ExitDo} + ${EndIf} + ${${UN}StrRep} $0 $0 ";;" ";" + ${Loop} + + ; Remove a leading or trailing semicolon from EnvVar + StrCpy $7 $0 1 0 + ${If} $7 == ";" + StrCpy $0 $0 "" 1 ; Change ';' to '' + ${EndIf} + StrLen $6 $0 + IntOp $6 $6 - 1 + StrCpy $7 $0 1 $6 + ${If} $7 == ";" + StrCpy $0 $0 $6 ; Change ';' to '' + ${EndIf} + ; DetailPrint "Scrubbed $1: [$0]" ; Uncomment to debug + ${EndIf} + + /* Step 3. Remove all instances of the target path/string (even if "A" or "P") + $6 = bool flag (1 = found and removed PathString) + $7 = a string (e.g. path) delimited by semicolon(s) + $8 = entry counter starting at 0 + $9 = copy of $0 + $R0 = tempChar */ + + ${If} $5 != "" ; If EnvVar is not empty ... + StrCpy $9 $0 + StrCpy $0 "" + StrCpy $8 0 + StrCpy $6 0 + + ${Do} + ${${UN}StrTok} $7 $9 ";" $8 "0" ; $7 = next entry, $8 = entry counter + + ${If} $7 == "" ; If we've run out of entries, + ${ExitDo} ; were done + ${EndIf} ; + + ; Remove leading and trailing spaces from this entry (critical step for Action=Remove) + ${Do} + StrCpy $R0 $7 1 + ${If} $R0 != " " + ${ExitDo} + ${EndIf} + StrCpy $7 $7 "" 1 ; Remove leading space + ${Loop} + ${Do} + StrCpy $R0 $7 1 -1 + ${If} $R0 != " " + ${ExitDo} + ${EndIf} + StrCpy $7 $7 -1 ; Remove trailing space + ${Loop} + ${If} $7 == $4 ; If string matches, remove it by not appending it + StrCpy $6 1 ; Set 'found' flag + ${ElseIf} $7 != $4 ; If string does NOT match + ${AndIf} $0 == "" ; and the 1st string being added to $0, + StrCpy $0 $7 ; copy it to $0 without a prepended semicolon + ${ElseIf} $7 != $4 ; If string does NOT match + ${AndIf} $0 != "" ; and this is NOT the 1st string to be added to $0, + StrCpy $0 $0;$7 ; append path to $0 with a prepended semicolon + ${EndIf} ; + + IntOp $8 $8 + 1 ; Bump counter + ${Loop} ; Check for duplicates until we run out of paths + ${EndIf} + + ; Step 4: Perform the requested Action + ; + ${If} $2 != "R" ; If Append or Prepend + ${If} $6 == 1 ; And if we found the target + DetailPrint "Target is already present in $1. It will be removed and" + ${EndIf} + ${If} $0 == "" ; If EnvVar is (now) empty + StrCpy $0 $4 ; just copy PathString to EnvVar + ${If} $6 == 0 ; If found flag is either 0 + ${OrIf} $6 == "" ; or blank (if EnvVarName is empty) + DetailPrint "$1 was empty and has been updated with the target" + ${EndIf} + ${ElseIf} $2 == "A" ; If Append (and EnvVar is not empty), + StrCpy $0 $0;$4 ; append PathString + ${If} $6 == 1 + DetailPrint "appended to $1" + ${Else} + DetailPrint "Target was appended to $1" + ${EndIf} + ${Else} ; If Prepend (and EnvVar is not empty), + StrCpy $0 $4;$0 ; prepend PathString + ${If} $6 == 1 + DetailPrint "prepended to $1" + ${Else} + DetailPrint "Target was prepended to $1" + ${EndIf} + ${EndIf} + ${Else} ; If Action = Remove + ${If} $6 == 1 ; and we found the target + DetailPrint "Target was found and removed from $1" + ${Else} + DetailPrint "Target was NOT found in $1 (nothing to remove)" + ${EndIf} + ${If} $0 == "" + DetailPrint "$1 is now empty" + ${EndIf} + ${EndIf} + + ; Step 5: Update the registry at RegLoc with the updated EnvVar and announce the change + ; + ClearErrors + ${If} $3 == HKLM + WriteRegExpandStr ${hklm_all_users} $1 $0 ; Write it in all users section + ${ElseIf} $3 == HKCU + WriteRegExpandStr ${hkcu_current_user} $1 $0 ; Write it to current user section + ${EndIf} + + IfErrors 0 +4 + MessageBox MB_OK|MB_ICONEXCLAMATION "Could not write updated $1 to $3" + DetailPrint "Could not write updated $1 to $3" + Goto EnvVarUpdate_Restore_Vars + + ; "Export" our change + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 + + EnvVarUpdate_Restore_Vars: + ; + ; Restore the user's variables and return ResultVar + Pop $R0 + Pop $9 + Pop $8 + Pop $7 + Pop $6 + Pop $5 + Pop $4 + Pop $3 + Pop $2 + Pop $1 + Push $0 ; Push my $0 (ResultVar) + Exch + Pop $0 ; Restore his $0 + +FunctionEnd + +!macroend ; EnvVarUpdate UN +!insertmacro EnvVarUpdate "" +!insertmacro EnvVarUpdate "un." +;----------------------------------- EnvVarUpdate end---------------------------------------- + +!verbose pop +!endif diff --git a/cmake/Windows/Include/IncludeScript_FileLogging.nsh b/cmake/Windows/Include/IncludeScript_FileLogging.nsh new file mode 100644 index 000000000..4b545851f --- /dev/null +++ b/cmake/Windows/Include/IncludeScript_FileLogging.nsh @@ -0,0 +1,140 @@ +## most of this is copied from VLC install script +## , with bugfixes and decorated with some additional comments for better understanding +!ifndef FOLDERLIST_EXE + !define FOLDERLIST_EXE FolderList.exe +!endif + +;;;;;;;;;;;;;;; +; 4. Logging ; +;;;;;;;;;;;;;;; +Var UninstallLog # handle to a log file +!macro OpenUninstallLog + FileOpen $UninstallLog "$INSTDIR\uninstall.log" a + FileSeek $UninstallLog 0 END +!macroend + +!macro CloseUninstallLog + FileClose $UninstallLog + SetFileAttributes "$INSTDIR\uninstall.log" HIDDEN +!macroend + + +;;;;;;;;;;;;;;;;;;;; +; 5. Installations ; +;;;;;;;;;;;;;;;;;;;; +!macro InstallFile FILEREGEX + # do the normal job + File "${FILEREGEX}" + ## add files to uninstall.log + + #strip source path (retain filename only) + push $R0 + ${GetFileName} "${FILEREGEX}" $R0 + + !define Index 'Line${__LINE__}' + # search for filename in target path + FindFirst $0 $1 "$OUTDIR\$R0" + StrCmp $0 "" "${Index}-End" + "${Index}-Loop:" + StrCmp $1 "" "${Index}-End" + FileWrite $UninstallLog "$OUTDIR\$1$\r$\n" + FindNext $0 $1 + Goto "${Index}-Loop" + "${Index}-End:" + !undef Index + + pop $R0 +!macroend + + +!macro InstallFolder FOLDER EXCLUDEREGEX + #old: File /r "${FOLDER}" + !system "${FOLDERLIST_EXE} /r $\"${FOLDER} $\" $\"${EXCLUDEREGEX}$\"" + !include "${FOLDERLIST_EXE}.txt" + + Push "$OUTDIR" + Call InstallFolderInternal +!macroend + +## $9 is the complete folder name +Function InstallFolderInternal + Pop $9 + !define Index 'Line${__LINE__}' + FindFirst $0 $1 "$9\*" + StrCmp $0 "" "${Index}-End" + "${Index}-Loop:" + StrCmp $1 "" "${Index}-End" + StrCmp $1 "." "${Index}-Next" + StrCmp $1 ".." "${Index}-Next" + IfFileExists "$9\$1\*" 0 "${Index}-Write" + Push $0 + Push $9 + Push "$9\$1" + Call InstallFolderInternal + Pop $9 + Pop $0 + Goto "${Index}-Next" + "${Index}-Write:" + FileWrite $UninstallLog "$9\$1$\r$\n" + "${Index}-Next:" + FindNext $0 $1 + Goto "${Index}-Loop" + "${Index}-End:" + !undef Index +FunctionEnd + + +; TrimNewlines (copied from NSIS documentation) +; input, top of stack (e.g. whatever$\r$\n) +; output, top of stack (replaces, with e.g. whatever) +; modifies no other variables. + +Function un.TrimNewlines + Exch $R0 + Push $R1 + Push $R2 + StrCpy $R1 0 + + loop: + IntOp $R1 $R1 - 1 + StrCpy $R2 $R0 1 $R1 + StrCmp $R2 "$\r" loop + StrCmp $R2 "$\n" loop + IntOp $R1 $R1 + 1 + IntCmp $R1 0 no_trim_needed + StrCpy $R0 $R0 $R1 + + no_trim_needed: + Pop $R2 + Pop $R1 + Exch $R0 +FunctionEnd + +; From AdvUninstallLog(2).nsh +; Function un.RemoveEmptyDirs + ; Pop $9 + ; !define Index 'Line${__LINE__}' + ; FindFirst $0 $1 "$INSTDIR$9*" + ; StrCmp $0 "" "${Index}-End" + ; "${Index}-Loop:" + ; StrCmp $1 "" "${Index}-End" + ; StrCmp $1 "." "${Index}-Next" + ; StrCmp $1 ".." "${Index}-Next" + ; Push $0 + ; Push $1 + ; Push $9 + ; Push "$9$1\" + ; Call un.RemoveEmptyDirs + ; Pop $9 + ; Pop $1 + ; Pop $0 + ; "${Index}-Remove:" + ; RMDir "$INSTDIR$9$1" + ; "${Index}-Next:" + ; FindNext $0 $1 + ; Goto "${Index}-Loop" + ; "${Index}-End:" + ; FindClose $0 + ; !undef Index +; FunctionEnd + diff --git a/cmake/Windows/Include/IncludeScript_Misc.nsh b/cmake/Windows/Include/IncludeScript_Misc.nsh new file mode 100644 index 000000000..1167506f3 --- /dev/null +++ b/cmake/Windows/Include/IncludeScript_Misc.nsh @@ -0,0 +1,90 @@ + +############################## +### register filetypes (code borrowed from VLC project) +;; Function that register one extension for VLC + +Function RegisterExtension + ; back up old value for extension $R0 (eg. ".mzData") and Program $R1 (e.g. TOPPView) + ReadRegStr $1 HKCR "$R0" "" + StrCmp $1 "" NoBackup + StrCmp $1 "OPENMS$R0" "NoBackup" + WriteRegStr HKCR "$R0" "OPENMS.backup" $1 +NoBackup: + WriteRegStr HKCR "$R0" "" "OPENMS$R0" + ReadRegStr $0 HKCR "OPENMS$R0" "" + WriteRegStr HKCR "OPENMS$R0" "" "OPENMS data file ($R0)" + #WriteRegStr HKCR "OPENMS$R0\shell" "" "Open" + WriteRegStr HKCR "OPENMS$R0\shell\open\command" "" '"$INSTDIR\bin\$R1.exe" "%1"' + WriteRegStr HKCR "OPENMS$R0\DefaultIcon" "" '"$INSTDIR\share\OpenMS_$R1.ico",0' + +;;; Vista Only part + ; Vista detection +# ReadRegStr $R1 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion +# StrCpy $R2 $R1 3 +# StrCmp $R2 '6.0' ForVista ToEnd +#ForVista: +# WriteRegStr HKLM "Software\Clients\Media\VLC\Capabilities\FileAssociations" "$R0" "VLC$R0" + +ToEnd: +FunctionEnd + +;; Function that removes one extension that OPENMS owns. +Function un.RegisterExtension + ;start of restore script + ReadRegStr $1 HKCR "$R0" "" + StrCmp $1 "OPENMS$R0" 0 NoOwn ; only do this if we own it + ; Read the old value from Backup + ReadRegStr $1 HKCR "$R0" "OPENMS.backup" + StrCmp $1 "" 0 Restore ; if backup="" then delete the whole key + DeleteRegKey HKCR "$R0" + Goto NoOwn +Restore: + WriteRegStr HKCR "$R0" "" $1 + DeleteRegValue HKCR "$R0" "OPENMS.backup" +NoOwn: + DeleteRegKey HKCR "OPENMS$R0" ;Delete key with association settings +# DeleteRegKey HKLM "Software\Clients\Media\OPENMS\Capabilities\FileAssociations\OPENMS$R0" ; for vista +FunctionEnd + +!macro RegisterExtensionSection EXT PROGRAMEXE + Section ${EXT} + SectionIn 1 3 + Push $R0 + Push $R1 + StrCpy $R0 ${EXT} + StrCpy $R1 ${PROGRAMEXE} + Call RegisterExtension + Pop $R1 + Pop $R0 + SectionEnd +!macroend + +!macro UnRegisterExtensionSection EXT PROGRAMEXE + Push $R0 + Push $R1 + StrCpy $R0 ${EXT} + StrCpy $R1 ${PROGRAMEXE} + Call un.RegisterExtension + Pop $R1 + Pop $R0 +!macroend + + +!macro REBOOT_ON_INCOMPLETE_DELETION PROGRAMPATH + ClearErrors + SetRebootFlag false + # old installer directory structure + Delete /REBOOTOK ${PROGRAMPATH}\lib\*.dll + Delete /REBOOTOK ${PROGRAMPATH}\GUI\*.exe + Delete /REBOOTOK ${PROGRAMPATH}\TOPP\*.exe + # new installer directory structure + Delete /REBOOTOK ${PROGRAMPATH}\bin\*.dll + Delete /REBOOTOK ${PROGRAMPATH}\bin\*.exe + + IfRebootFlag 0 noreboot + MessageBox MB_OK|MB_ICONQUESTION "Not all OpenMS files could be deleted. A reboot is required! \ + Click 'OK' when you are ready to reboot." + Reboot + noreboot: +!macroend + diff --git a/cmake/Windows/Include/LogicLib.nsh b/cmake/Windows/Include/LogicLib.nsh new file mode 100644 index 000000000..9a39a4893 --- /dev/null +++ b/cmake/Windows/Include/LogicLib.nsh @@ -0,0 +1,792 @@ +; NSIS LOGIC LIBRARY - LogicLib.nsh +; Version 2.6 - 08/12/2007 +; By dselkirk@hotmail.com +; and eccles@users.sf.net +; with IfNot support added by Message +; +; Questions/Comments - +; See http://forums.winamp.com/showthread.php?s=&postid=1116241 +; +; Description: +; Provides the use of various logic statements within NSIS. +; +; Usage: +; The following "statements" are available: +; If|IfNot|Unless..{ElseIf|ElseIfNot|ElseUnless}..[Else]..EndIf|EndUnless +; - Conditionally executes a block of statements, depending on the value +; of an expression. IfNot and Unless are equivalent and +; interchangeable, as are ElseIfNot and ElseUnless. +; AndIf|AndIfNot|AndUnless|OrIf|OrIfNot|OrUnless +; - Adds any number of extra conditions to If, IfNot, Unless, ElseIf, +; ElseIfNot and ElseUnless statements. +; IfThen|IfNotThen..|..| +; - Conditionally executes an inline statement, depending on the value +; of an expression. +; IfCmd..||..| +; - Conditionally executes an inline statement, depending on a true +; value of the provided NSIS function. +; Select..{Case[2|3|4|5]}..[CaseElse|Default]..EndSelect +; - Executes one of several blocks of statements, depending on the value +; of an expression. +; Switch..{Case|CaseElse|Default}..EndSwitch +; - Jumps to one of several labels, depending on the value of an +; expression. +; Do[While|Until]..{ExitDo|Continue|Break}..Loop[While|Until] +; - Repeats a block of statements until stopped, or depending on the +; value of an expression. +; While..{ExitWhile|Continue|Break}..EndWhile +; - An alias for DoWhile..Loop (for backwards-compatibility) +; For[Each]..{ExitFor|Continue|Break}..Next +; - Repeats a block of statements varying the value of a variable. +; +; The following "expressions" are available: +; Standard (built-in) string tests (which are case-insensitive): +; a == b; a != b +; Additional case-insensitive string tests (using System.dll): +; a S< b; a S>= b; a S> b; a S<= b +; Case-sensitive string tests: +; a S== b; a S!= b +; Standard (built-in) signed integer tests: +; a = b; a <> b; a < b; a >= b; a > b; a <= b +; Standard (built-in) unsigned integer tests: +; a U< b; a U>= b; a U> b; a U<= b +; 64-bit integer tests (using System.dll): +; a L= b; a L<> b; a L< b; a L>= b; a L> b; a L<= b +; Built-in NSIS flag tests: +; ${Abort}; ${Errors}; ${RebootFlag}; ${Silent} +; Built-in NSIS other tests: +; ${FileExists} a +; Any conditional NSIS instruction test: +; ${Cmd} a +; Section flag tests: +; ${SectionIsSelected} a; ${SectionIsSectionGroup} a; +; ${SectionIsSectionGroupEnd} a; ${SectionIsBold} a; +; ${SectionIsReadOnly} a; ${SectionIsExpanded} a; +; ${SectionIsPartiallySelected} a +; +; Examples: +; See LogicLib.nsi in the Examples folder for lots of example usage. + +!verbose push +!verbose 3 +!ifndef LOGICLIB_VERBOSITY + !define LOGICLIB_VERBOSITY 3 +!endif +!define _LOGICLIB_VERBOSITY ${LOGICLIB_VERBOSITY} +!undef LOGICLIB_VERBOSITY +!verbose ${_LOGICLIB_VERBOSITY} + +!ifndef LOGICLIB + !define LOGICLIB + !define | "'" + !define || "' '" + !define LOGICLIB_COUNTER 0 + + !include Sections.nsh + + !macro _LOGICLIB_TEMP + !ifndef _LOGICLIB_TEMP + !define _LOGICLIB_TEMP + Var /GLOBAL _LOGICLIB_TEMP ; Temporary variable to aid the more elaborate logic tests + !endif + !macroend + + !macro _IncreaseCounter + !define _LOGICLIB_COUNTER ${LOGICLIB_COUNTER} + !undef LOGICLIB_COUNTER + !define /math LOGICLIB_COUNTER ${_LOGICLIB_COUNTER} + 1 + !undef _LOGICLIB_COUNTER + !macroend + + !macro _PushLogic + !insertmacro _PushScope Logic _LogicLib_Label_${LOGICLIB_COUNTER} + !insertmacro _IncreaseCounter + !macroend + + !macro _PopLogic + !insertmacro _PopScope Logic + !macroend + + !macro _PushScope Type label + !ifdef _${Type} ; If we already have a statement + !define _Cur${Type} ${_${Type}} + !undef _${Type} + !define _${Type} ${label} + !define ${_${Type}}Prev${Type} ${_Cur${Type}} ; Save the current logic + !undef _Cur${Type} + !else + !define _${Type} ${label} ; Initialise for first statement + !endif + !macroend + + !macro _PopScope Type + !ifndef _${Type} + !error "Cannot use _Pop${Type} without a preceding _Push${Type}" + !endif + !ifdef ${_${Type}}Prev${Type} ; If a previous statment was active then restore it + !define _Cur${Type} ${_${Type}} + !undef _${Type} + !define _${Type} ${${_Cur${Type}}Prev${Type}} + !undef ${_Cur${Type}}Prev${Type} + !undef _Cur${Type} + !else + !undef _${Type} + !endif + !macroend + + ; String tests + !macro _== _a _b _t _f + StrCmp `${_a}` `${_b}` `${_t}` `${_f}` + !macroend + + !macro _!= _a _b _t _f + !insertmacro _== `${_a}` `${_b}` `${_f}` `${_t}` + !macroend + + ; Case-sensitive string tests + !macro _S== _a _b _t _f + StrCmpS `${_a}` `${_b}` `${_t}` `${_f}` + !macroend + + !macro _S!= _a _b _t _f + !insertmacro _S== `${_a}` `${_b}` `${_f}` `${_t}` + !macroend + + ; Extra string tests (cannot do these case-sensitively - I tried and lstrcmp still ignored the case) + !macro _StrCmpI _a _b _e _l _m + !insertmacro _LOGICLIB_TEMP + System::Call `kernel32::lstrcmpi(ts, ts) i.s` `${_a}` `${_b}` + Pop $_LOGICLIB_TEMP + IntCmp $_LOGICLIB_TEMP 0 `${_e}` `${_l}` `${_m}` + !macroend + + !macro _S< _a _b _t _f + !insertmacro _StrCmpI `${_a}` `${_b}` `${_f}` `${_t}` `${_f}` + !macroend + + !macro _S>= _a _b _t _f + !insertmacro _S< `${_a}` `${_b}` `${_f}` `${_t}` + !macroend + + !macro _S> _a _b _t _f + !insertmacro _StrCmpI `${_a}` `${_b}` `${_f}` `${_f}` `${_t}` + !macroend + + !macro _S<= _a _b _t _f + !insertmacro _S> `${_a}` `${_b}` `${_f}` `${_t}` + !macroend + + ; Integer tests + !macro _= _a _b _t _f + IntCmp `${_a}` `${_b}` `${_t}` `${_f}` `${_f}` + !macroend + + !macro _<> _a _b _t _f + !insertmacro _= `${_a}` `${_b}` `${_f}` `${_t}` + !macroend + + !macro _< _a _b _t _f + IntCmp `${_a}` `${_b}` `${_f}` `${_t}` `${_f}` + !macroend + + !macro _>= _a _b _t _f + !insertmacro _< `${_a}` `${_b}` `${_f}` `${_t}` + !macroend + + !macro _> _a _b _t _f + IntCmp `${_a}` `${_b}` `${_f}` `${_f}` `${_t}` + !macroend + + !macro _<= _a _b _t _f + !insertmacro _> `${_a}` `${_b}` `${_f}` `${_t}` + !macroend + + ; Unsigned integer tests (NB: no need for extra equality tests) + !macro _U< _a _b _t _f + IntCmpU `${_a}` `${_b}` `${_f}` `${_t}` `${_f}` + !macroend + + !macro _U>= _a _b _t _f + !insertmacro _U< `${_a}` `${_b}` `${_f}` `${_t}` + !macroend + + !macro _U> _a _b _t _f + IntCmpU `${_a}` `${_b}` `${_f}` `${_f}` `${_t}` + !macroend + + !macro _U<= _a _b _t _f + !insertmacro _U> `${_a}` `${_b}` `${_f}` `${_t}` + !macroend + + ; Int64 tests + !macro _Int64Cmp _a _o _b _t _f + !insertmacro _LOGICLIB_TEMP + System::Int64Op `${_a}` `${_o}` `${_b}` + Pop $_LOGICLIB_TEMP + !insertmacro _= $_LOGICLIB_TEMP 0 `${_f}` `${_t}` + !macroend + + !macro _L= _a _b _t _f + !insertmacro _Int64Cmp `${_a}` = `${_b}` `${_t}` `${_f}` + !macroend + + !macro _L<> _a _b _t _f + !insertmacro _L= `${_a}` `${_b}` `${_f}` `${_t}` + !macroend + + !macro _L< _a _b _t _f + !insertmacro _Int64Cmp `${_a}` < `${_b}` `${_t}` `${_f}` + !macroend + + !macro _L>= _a _b _t _f + !insertmacro _L< `${_a}` `${_b}` `${_f}` `${_t}` + !macroend + + !macro _L> _a _b _t _f + !insertmacro _Int64Cmp `${_a}` > `${_b}` `${_t}` `${_f}` + !macroend + + !macro _L<= _a _b _t _f + !insertmacro _L> `${_a}` `${_b}` `${_f}` `${_t}` + !macroend + + ; Flag tests + !macro _Abort _a _b _t _f + IfAbort `${_t}` `${_f}` + !macroend + !define Abort `"" Abort ""` + + !macro _Errors _a _b _t _f + IfErrors `${_t}` `${_f}` + !macroend + !define Errors `"" Errors ""` + + !macro _FileExists _a _b _t _f + IfFileExists `${_b}` `${_t}` `${_f}` + !macroend + !define FileExists `"" FileExists` + + !macro _RebootFlag _a _b _t _f + IfRebootFlag `${_t}` `${_f}` + !macroend + !define RebootFlag `"" RebootFlag ""` + + !macro _Silent _a _b _t _f + IfSilent `${_t}` `${_f}` + !macroend + !define Silent `"" Silent ""` + + ; "Any instruction" test + !macro _Cmd _a _b _t _f + !define _t=${_t} + !ifdef _t= ; If no true label then make one + !define __t _LogicLib_Label_${LOGICLIB_COUNTER} + !insertmacro _IncreaseCounter + !else + !define __t ${_t} + !endif + ${_b} ${__t} + !define _f=${_f} + !ifndef _f= ; If a false label then go there + Goto ${_f} + !endif + !undef _f=${_f} + !ifdef _t= ; If we made our own true label then place it + ${__t}: + !endif + !undef __t + !undef _t=${_t} + !macroend + !define Cmd `"" Cmd` + + ; Section flag test + !macro _SectionFlagIsSet _a _b _t _f + !insertmacro _LOGICLIB_TEMP + SectionGetFlags `${_b}` $_LOGICLIB_TEMP + IntOp $_LOGICLIB_TEMP $_LOGICLIB_TEMP & `${_a}` + !insertmacro _= $_LOGICLIB_TEMP `${_a}` `${_t}` `${_f}` + !macroend + !define SectionIsSelected `${SF_SELECTED} SectionFlagIsSet` + !define SectionIsSubSection `${SF_SUBSEC} SectionFlagIsSet` + !define SectionIsSubSectionEnd `${SF_SUBSECEND} SectionFlagIsSet` + !define SectionIsSectionGroup `${SF_SECGRP} SectionFlagIsSet` + !define SectionIsSectionGroupEnd `${SF_SECGRPEND} SectionFlagIsSet` + !define SectionIsBold `${SF_BOLD} SectionFlagIsSet` + !define SectionIsReadOnly `${SF_RO} SectionFlagIsSet` + !define SectionIsExpanded `${SF_EXPAND} SectionFlagIsSet` + !define SectionIsPartiallySelected `${SF_PSELECTED} SectionFlagIsSet` + + !define IfCmd `!insertmacro _IfThen "" Cmd ${|}` + + !macro _If _c _a _o _b + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + !insertmacro _PushLogic + !define ${_Logic}If + !define ${_Logic}Else _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the Else + !insertmacro _IncreaseCounter + !define _c=${_c} + !ifdef _c=true ; If is true + !insertmacro _${_o} `${_a}` `${_b}` "" ${${_Logic}Else} + !else ; If condition is false + !insertmacro _${_o} `${_a}` `${_b}` ${${_Logic}Else} "" + !endif + !undef _c=${_c} + !verbose pop + !macroend + !define If `!insertmacro _If true` + !define Unless `!insertmacro _If false` + !define IfNot `!insertmacro _If false` + + !macro _And _c _a _o _b + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + !ifndef _Logic | ${_Logic}If + !error "Cannot use And without a preceding If or IfNot/Unless" + !endif + !ifndef ${_Logic}Else + !error "Cannot use And following an Else" + !endif + !define _c=${_c} + !ifdef _c=true ; If is true + !insertmacro _${_o} `${_a}` `${_b}` "" ${${_Logic}Else} + !else ; If condition is false + !insertmacro _${_o} `${_a}` `${_b}` ${${_Logic}Else} "" + !endif + !undef _c=${_c} + !verbose pop + !macroend + !define AndIf `!insertmacro _And true` + !define AndUnless `!insertmacro _And false` + !define AndIfNot `!insertmacro _And false` + + !macro _Or _c _a _o _b + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + !ifndef _Logic | ${_Logic}If + !error "Cannot use Or without a preceding If or IfNot/Unless" + !endif + !ifndef ${_Logic}Else + !error "Cannot use Or following an Else" + !endif + !define _label _LogicLib_Label_${LOGICLIB_COUNTER} ; Skip this test as we already + !insertmacro _IncreaseCounter + Goto ${_label} ; have a successful result + ${${_Logic}Else}: ; Place the Else label + !undef ${_Logic}Else ; and remove it + !define ${_Logic}Else _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the next Else and perform the new If + !insertmacro _IncreaseCounter + !define _c=${_c} + !ifdef _c=true ; If is true + !insertmacro _${_o} `${_a}` `${_b}` "" ${${_Logic}Else} + !else ; If condition is false + !insertmacro _${_o} `${_a}` `${_b}` ${${_Logic}Else} "" + !endif + !undef _c=${_c} + ${_label}: + !undef _label + !verbose pop + !macroend + !define OrIf `!insertmacro _Or true` + !define OrUnless `!insertmacro _Or false` + !define OrIfNot `!insertmacro _Or false` + + !macro _Else + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + !ifndef _Logic | ${_Logic}If + !error "Cannot use Else without a preceding If or IfNot/Unless" + !endif + !ifndef ${_Logic}Else + !error "Cannot use Else following an Else" + !endif + !ifndef ${_Logic}EndIf ; First Else for this If? + !define ${_Logic}EndIf _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the EndIf + !insertmacro _IncreaseCounter + !endif + Goto ${${_Logic}EndIf} ; Go to the EndIf + ${${_Logic}Else}: ; Place the Else label + !undef ${_Logic}Else ; and remove it + !verbose pop + !macroend + !define Else `!insertmacro _Else` + + !macro _ElseIf _c _a _o _b + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + ${Else} ; Perform the Else + !define ${_Logic}Else _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the next Else and perform the new If + !insertmacro _IncreaseCounter + !define _c=${_c} + !ifdef _c=true ; If is true + !insertmacro _${_o} `${_a}` `${_b}` "" ${${_Logic}Else} + !else ; If condition is false + !insertmacro _${_o} `${_a}` `${_b}` ${${_Logic}Else} "" + !endif + !undef _c=${_c} + !verbose pop + !macroend + !define ElseIf `!insertmacro _ElseIf true` + !define ElseUnless `!insertmacro _ElseIf false` + !define ElseIfNot `!insertmacro _ElseIf false` + + !macro _EndIf _n + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + !ifndef _Logic | ${_Logic}If + !error "Cannot use End${_n} without a preceding If or IfNot/Unless" + !endif + !ifdef ${_Logic}Else + ${${_Logic}Else}: ; Place the Else label + !undef ${_Logic}Else ; and remove it + !endif + !ifdef ${_Logic}EndIf + ${${_Logic}EndIf}: ; Place the EndIf + !undef ${_Logic}EndIf ; and remove it + !endif + !undef ${_Logic}If + !insertmacro _PopLogic + !verbose pop + !macroend + !define EndIf `!insertmacro _EndIf If` + !define EndUnless `!insertmacro _EndIf Unless` + + !macro _IfThen _a _o _b _t + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + ${If} `${_a}` `${_o}` `${_b}` + ${_t} + ${EndIf} + !verbose pop + !macroend + !define IfThen `!insertmacro _IfThen` + + !macro _IfNotThen _a _o _b _t + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + ${IfNot} `${_a}` `${_o}` `${_b}` + ${_t} + ${EndIf} + !verbose pop + !macroend + !define IfNotThen `!insertmacro _IfNotThen` + + !macro _ForEach _v _f _t _o _s + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + StrCpy "${_v}" "${_f}" ; Assign the initial value + Goto +2 ; Skip the loop expression for the first iteration + !define _DoLoopExpression `IntOp "${_v}" "${_v}" "${_o}" "${_s}"` ; Define the loop expression + !define _o=${_o} + !ifdef _o=+ ; Check the loop expression operator + !define __o > ; to determine the correct loop condition + !else ifdef _o=- + !define __o < + !else + !error "Unsupported ForEach step operator (must be + or -)" + !endif + !undef _o=${_o} + !insertmacro _Do For false `${_v}` `${__o}` `${_t}` ; Let Do do the rest + !undef __o + !verbose pop + !macroend + !define ForEach `!insertmacro _ForEach` + + !macro _For _v _f _t + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + ${ForEach} `${_v}` `${_f}` `${_t}` + 1 ; Pass on to ForEach + !verbose pop + !macroend + !define For `!insertmacro _For` + + !define ExitFor `!insertmacro _Goto ExitFor For` + + !define Next `!insertmacro _Loop For Next "" "" "" ""` + + !define While `!insertmacro _Do While true` + + !define ExitWhile `!insertmacro _Goto ExitWhile While` + + !define EndWhile `!insertmacro _Loop While EndWhile "" "" "" ""` + + !macro _Do _n _c _a _o _b + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + !insertmacro _PushLogic + !define ${_Logic}${_n} _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the start of the loop + !insertmacro _IncreaseCounter + ${${_Logic}${_n}}: + !insertmacro _PushScope Exit${_n} _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the end of the loop + !insertmacro _IncreaseCounter + !insertmacro _PushScope Break ${_Exit${_n}} ; Break goes to the end of the loop + !ifdef _DoLoopExpression + ${_DoLoopExpression} ; Special extra parameter for inserting code + !undef _DoLoopExpression ; between the Continue label and the loop condition + !endif + !define _c=${_c} + !ifdef _c= ; No starting condition + !insertmacro _PushScope Continue _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for Continue at the end of the loop + !insertmacro _IncreaseCounter + !else + !insertmacro _PushScope Continue ${${_Logic}${_n}} ; Continue goes to the start of the loop + !ifdef _c=true ; If is true + !insertmacro _${_o} `${_a}` `${_b}` "" ${_Exit${_n}} + !else ; If condition is false + !insertmacro _${_o} `${_a}` `${_b}` ${_Exit${_n}} "" + !endif + !endif + !undef _c=${_c} + !define ${_Logic}Condition ${_c} ; Remember the condition used + !verbose pop + !macroend + !define Do `!insertmacro _Do Do "" "" "" ""` + !define DoWhile `!insertmacro _Do Do true` + !define DoUntil `!insertmacro _Do Do false` + + !macro _Goto _n _s + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + !ifndef _${_n} + !error "Cannot use ${_n} without a preceding ${_s}" + !endif + Goto ${_${_n}} + !verbose pop + !macroend + !define ExitDo `!insertmacro _Goto ExitDo Do` + + !macro _Loop _n _e _c _a _o _b + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + !ifndef _Logic | ${_Logic}${_n} + !error "Cannot use ${_e} without a preceding ${_n}" + !endif + !define _c=${${_Logic}Condition} + !ifdef _c= ; If Do had no condition place the Continue label + ${_Continue}: + !endif + !undef _c=${${_Logic}Condition} + !define _c=${_c} + !ifdef _c= ; No ending condition + Goto ${${_Logic}${_n}} + !else ifdef _c=true ; If condition is true + !insertmacro _${_o} `${_a}` `${_b}` ${${_Logic}${_n}} ${_Exit${_n}} + !else ; If condition is false + !insertmacro _${_o} `${_a}` `${_b}` ${_Exit${_n}} ${${_Logic}${_n}} + !endif + !undef _c=${_c} + Goto ${_Continue} ; Just to ensure it is referenced at least once + Goto ${_Exit${_n}} ; Just to ensure it is referenced at least once + ${_Exit${_n}}: ; Place the loop exit point + !undef ${_Logic}Condition + !insertmacro _PopScope Continue + !insertmacro _PopScope Break + !insertmacro _PopScope Exit${_n} + !undef ${_Logic}${_n} + !insertmacro _PopLogic + !verbose pop + !macroend + !define Loop `!insertmacro _Loop Do Loop "" "" "" ""` + !define LoopWhile `!insertmacro _Loop Do LoopWhile true` + !define LoopUntil `!insertmacro _Loop Do LoopUntil false` + + !define Continue `!insertmacro _Goto Continue "For or Do or While"` + !define Break `!insertmacro _Goto Break "For or Do or While"` + + !macro _Select _a + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + !insertmacro _PushLogic + !define ${_Logic}Select `${_a}` ; Remember the left hand side of the comparison + !verbose pop + !macroend + !define Select `!insertmacro _Select` + + !macro _Select_CaseElse + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + !ifndef _Logic | ${_Logic}Select + !error "Cannot use Case without a preceding Select" + !endif + !ifdef ${_Logic}EndSelect ; This is set only after the first case + !ifndef ${_Logic}Else + !error "Cannot use Case following a CaseElse" + !endif + Goto ${${_Logic}EndSelect} ; Go to the EndSelect + ${${_Logic}Else}: ; Place the Else label + !undef ${_Logic}Else ; and remove it + !else + !define ${_Logic}EndSelect _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the EndSelect + !insertmacro _IncreaseCounter + !endif + !verbose pop + !macroend + !define CaseElse `!insertmacro _CaseElse` + !define Case_Else `!insertmacro _CaseElse` ; Compatibility with 2.2 and earlier + !define Default `!insertmacro _CaseElse` ; For the C-minded + + !macro _Select_Case _a + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + ${CaseElse} ; Perform the CaseElse + !define ${_Logic}Else _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the next Else and perform the new Case + !insertmacro _IncreaseCounter + !insertmacro _== `${${_Logic}Select}` `${_a}` "" ${${_Logic}Else} + !verbose pop + !macroend + !define Case `!insertmacro _Case` + + !macro _Case2 _a _b + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + ${CaseElse} ; Perform the CaseElse + !define ${_Logic}Else _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the next Else and perform the new Case + !insertmacro _IncreaseCounter + !insertmacro _== `${${_Logic}Select}` `${_a}` +2 "" + !insertmacro _== `${${_Logic}Select}` `${_b}` "" ${${_Logic}Else} + !verbose pop + !macroend + !define Case2 `!insertmacro _Case2` + + !macro _Case3 _a _b _c + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + ${CaseElse} ; Perform the CaseElse + !define ${_Logic}Else _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the next Else and perform the new Case + !insertmacro _IncreaseCounter + !insertmacro _== `${${_Logic}Select}` `${_a}` +3 "" + !insertmacro _== `${${_Logic}Select}` `${_b}` +2 "" + !insertmacro _== `${${_Logic}Select}` `${_c}` "" ${${_Logic}Else} + !verbose pop + !macroend + !define Case3 `!insertmacro _Case3` + + !macro _Case4 _a _b _c _d + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + ${CaseElse} ; Perform the CaseElse + !define ${_Logic}Else _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the next Else and perform the new Case + !insertmacro _IncreaseCounter + !insertmacro _== `${${_Logic}Select}` `${_a}` +4 "" + !insertmacro _== `${${_Logic}Select}` `${_b}` +3 "" + !insertmacro _== `${${_Logic}Select}` `${_c}` +2 "" + !insertmacro _== `${${_Logic}Select}` `${_d}` "" ${${_Logic}Else} + !verbose pop + !macroend + !define Case4 `!insertmacro _Case4` + + !macro _Case5 _a _b _c _d _e + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + ${CaseElse} ; Perform the CaseElse + !define ${_Logic}Else _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the next Else and perform the new Case + !insertmacro _IncreaseCounter + !insertmacro _== `${${_Logic}Select}` `${_a}` +5 "" + !insertmacro _== `${${_Logic}Select}` `${_b}` +4 "" + !insertmacro _== `${${_Logic}Select}` `${_c}` +3 "" + !insertmacro _== `${${_Logic}Select}` `${_d}` +2 "" + !insertmacro _== `${${_Logic}Select}` `${_e}` "" ${${_Logic}Else} + !verbose pop + !macroend + !define Case5 `!insertmacro _Case5` + + !macro _EndSelect + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + !ifndef _Logic | ${_Logic}Select + !error "Cannot use EndSelect without a preceding Select" + !endif + !ifdef ${_Logic}Else + ${${_Logic}Else}: ; Place the Else label + !undef ${_Logic}Else ; and remove it + !endif + !ifdef ${_Logic}EndSelect ; This won't be set if there weren't any cases + ${${_Logic}EndSelect}: ; Place the EndSelect + !undef ${_Logic}EndSelect ; and remove it + !endif + !undef ${_Logic}Select + !insertmacro _PopLogic + !verbose pop + !macroend + !define EndSelect `!insertmacro _EndSelect` + + !macro _Switch _a + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + !insertmacro _PushLogic + !insertmacro _PushScope Switch ${_Logic} ; Keep a separate stack for switch data + !insertmacro _PushScope Break _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a lable for beyond the end of the switch + !insertmacro _IncreaseCounter + !define ${_Switch}Var `${_a}` ; Remember the left hand side of the comparison + !tempfile ${_Switch}Tmp ; Create a temporary file + !define ${_Logic}Switch _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the end of the switch + !insertmacro _IncreaseCounter + Goto ${${_Logic}Switch} ; and go there + !verbose pop + !macroend + !define Switch `!insertmacro _Switch` + + !macro _Case _a + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + !ifdef _Logic & ${_Logic}Select ; Check for an active Select + !insertmacro _Select_Case `${_a}` + !else ifndef _Switch ; If not then check for an active Switch + !error "Cannot use Case without a preceding Select or Switch" + !else + !define _label _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for this case, + !insertmacro _IncreaseCounter + ${_label}: ; place it and add it's check to the temp file + !appendfile "${${_Switch}Tmp}" `!insertmacro _== $\`${${_Switch}Var}$\` $\`${_a}$\` ${_label} ""$\n` + !undef _label + !endif + !verbose pop + !macroend + + !macro _CaseElse + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + !ifdef _Logic & ${_Logic}Select ; Check for an active Select + !insertmacro _Select_CaseElse + !else ifndef _Switch ; If not then check for an active Switch + !error "Cannot use Case without a preceding Select or Switch" + !else ifdef ${_Switch}Else ; Already had a default case? + !error "Cannot use CaseElse following a CaseElse" + !else + !define ${_Switch}Else _LogicLib_Label_${LOGICLIB_COUNTER} ; Get a label for the default case, + !insertmacro _IncreaseCounter + ${${_Switch}Else}: ; and place it + !endif + !verbose pop + !macroend + + !macro _EndSwitch + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + !ifndef _Logic | ${_Logic}Switch + !error "Cannot use EndSwitch without a preceding Switch" + !endif + Goto ${_Break} ; Skip the jump table + ${${_Logic}Switch}: ; Place the end of the switch + !undef ${_Logic}Switch + !include "${${_Switch}Tmp}" ; Include the jump table + !delfile "${${_Switch}Tmp}" ; and clear it up + !ifdef ${_Switch}Else ; Was there a default case? + Goto ${${_Switch}Else} ; then go there if all else fails + !undef ${_Switch}Else + !endif + !undef ${_Switch}Tmp + !undef ${_Switch}Var + ${_Break}: ; Place the break label + !insertmacro _PopScope Break + !insertmacro _PopScope Switch + !insertmacro _PopLogic + !verbose pop + !macroend + !define EndSwitch `!insertmacro _EndSwitch` + +!endif ; LOGICLIB +!verbose 3 +!define LOGICLIB_VERBOSITY ${_LOGICLIB_VERBOSITY} +!undef _LOGICLIB_VERBOSITY +!verbose pop diff --git a/cmake/Windows/Include/NsisMultiUser.nsh b/cmake/Windows/Include/NsisMultiUser.nsh new file mode 100644 index 000000000..de0bac8c9 --- /dev/null +++ b/cmake/Windows/Include/NsisMultiUser.nsh @@ -0,0 +1,1154 @@ +/* + +NsisMultiUser.nsh - NSIS plugin that allows "per-user" (no admin required) and "per-machine" (asks elevation *only when necessary*) installations + +Full source code, documentation and demos at https://github.com/Drizin/NsisMultiUser/ + +Copyright 2016-2018 Ricardo Drizin, Alex Mitev + +*/ + +!verbose push +!verbose 3 + +; Standard NSIS header files +!include nsDialogs.nsh +!include LogicLib.nsh +!include x64.nsh +!include WinVer.nsh +!include FileFunc.nsh +!include UAC.nsh +!include StrFunc.nsh + +RequestExecutionLevel user ; will ask elevation only if necessary + +; exit and error codes +!define MULTIUSER_ERROR_INVALID_PARAMETERS 666660 ; invalid command-line parameters +!define MULTIUSER_ERROR_ELEVATION_NOT_ALLOWED 666661 ; elevation is restricted by MULTIUSER_INSTALLMODE_ALLOW_ELEVATION or MULTIUSER_INSTALLMODE_ALLOW_ELEVATION_IF_SILENT +!define MULTIUSER_ERROR_NOT_INSTALLED 666662 ; returned from uninstaller when no version is installed +!define MULTIUSER_ERROR_RUN_UNINSTALLER_FAILED 666663 ; returned from installer if executing the uninstaller failed +!define MULTIUSER_ERROR_ELEVATION_FAILED 666666 ; returned by the outer instance when the inner instance cannot start (user aborted elevation dialog, Logon service not running, UAC is not supported by the OS, user without admin priv. is used in the runas dialog), or started, but was not admin +!define MULTIUSER_INNER_INSTANCE_BACK 666667 ; returned by the inner instance when the user presses the Back button on the first visible page (display outer instance) + +!macro MULTIUSER_INIT_VARS + ; required defines + !ifndef PRODUCT_NAME | VERSION | PROGEXE + !error "Should define all variables: PRODUCT_NAME, VERSION, PROGEXE" + !endif + + ; optional defines + ; COMPANY_NAME - stored in uninstall info in registry + ; CONTACT - stored in uninstall info in registry + ; COMMENTS - stored in uninstall info in registry + ; URL_INFO_ABOUT - stored as the Support Link in the uninstall info of the registry, and when not included, the Help Link as well. + ; URL_HELP_LINK - stored as the Help Link in the uninstall info of the registry. + ; URL_UPDATE_INFO - stored as the Update Information in the uninstall info of the registry. + ; MULTIUSER_INSTALLMODE_NO_HELP_DIALOG - don't show help dialog + + !define /ifndef MULTIUSER_INSTALLMODE_ALLOW_BOTH_INSTALLATIONS 1 ; 0 or 1 - whether user can install BOTH per-user and per-machine; this only affects the texts and the required elevation on the page, the actual uninstall of previous version has to be implemented by script + !define /ifndef MULTIUSER_INSTALLMODE_ALLOW_ELEVATION 1 ; 0 or 1, allow UAC screens in the (un)installer - if set to 0 and user is not admin, per-machine radiobutton will be disabled, or if elevation is always required, (un)installer will exit with an error code (and message if not silent) + !if "${MULTIUSER_INSTALLMODE_ALLOW_ELEVATION}" == "" ; old code - just defined with no value, equivalent to 1 + !define /redef MULTIUSER_INSTALLMODE_ALLOW_ELEVATION 1 + !endif + !define /ifndef MULTIUSER_INSTALLMODE_ALLOW_ELEVATION_IF_SILENT 0 ; 0 or 1, (only available if MULTIUSER_INSTALLMODE_ALLOW_ELEVATION = 1) allow UAC screens in the (un)installer in silent mode; if set to 0 and user is not admin and elevation is always required, (un)installer will exit with an error code + !if ${MULTIUSER_INSTALLMODE_ALLOW_ELEVATION} = 0 + !if ${MULTIUSER_INSTALLMODE_ALLOW_ELEVATION_IF_SILENT} = 1 + !error "MULTIUSER_INSTALLMODE_ALLOW_ELEVATION_IF_SILENT can be set only when MULTIUSER_INSTALLMODE_ALLOW_ELEVATION is set!" + !endif + !endif + !define /ifndef MULTIUSER_INSTALLMODE_DEFAULT_ALLUSERS 0 ; 0 or 1, (only available if MULTIUSER_INSTALLMODE_ALLOW_ELEVATION = 1 and there are 0 or 2 installations on the system) when running as user and is set to 1, per-machine installation is pre-selected, otherwise per-user installation + !if "${MULTIUSER_INSTALLMODE_DEFAULT_ALLUSERS}" == "" ; old code - just defined with no value, equivalent to 1 + !define /redef MULTIUSER_INSTALLMODE_DEFAULT_ALLUSERS 1 + !endif + !define /ifndef MULTIUSER_INSTALLMODE_DEFAULT_CURRENTUSER 0 ; 0 or 1, (only available if there are 0 or 2 installations on the system) when running as admin and is set to 1, per-user installation is pre-selected, otherwise per-machine installation + !if "${MULTIUSER_INSTALLMODE_DEFAULT_CURRENTUSER}" == "" ; old code - just defined with no value, equivalent to 1 + !define /redef MULTIUSER_INSTALLMODE_DEFAULT_CURRENTUSER 1 + !endif + !define /ifndef MULTIUSER_INSTALLMODE_64_BIT 0 ; set to 1 for 64-bit installers + !define /ifndef MULTIUSER_INSTALLMODE_INSTDIR "${PRODUCT_NAME}" ; suggested name of directory to install (under $PROGRAMFILES32/$PROGRAMFILES64 or $LOCALAPPDATA) + + !define /ifndef MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY "${PRODUCT_NAME}" ; registry key for UNINSTALL info, placed under [HKLM|HKCU]\Software\Microsoft\Windows\CurrentVersion\Uninstall (can be ${PRODUCT_NAME} or some {GUID}) + !define /ifndef MULTIUSER_INSTALLMODE_INSTALL_REGISTRY_KEY "Microsoft\Windows\CurrentVersion\Uninstall\${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY}" ; registry key where InstallLocation is stored, placed under [HKLM|HKCU]\Software (can be ${PRODUCT_NAME} or some {GUID}) + !define MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH "Software\Microsoft\Windows\CurrentVersion\Uninstall\${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY}" ; full path to registry key storing uninstall information displayed in Windows installed programs list + !define MULTIUSER_INSTALLMODE_INSTALL_REGISTRY_KEY_PATH "Software\${MULTIUSER_INSTALLMODE_INSTALL_REGISTRY_KEY}" ; full path to registry key where InstallLocation is stored + !define /ifndef UNINSTALL_FILENAME "uninstall.exe" ; name of uninstaller + !define /ifndef MULTIUSER_INSTALLMODE_DISPLAYNAME "${PRODUCT_NAME} ${VERSION}" ; display name in Windows uninstall list of programs + !define /ifndef MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUENAME "InstallLocation" ; name of the registry value containing install directory + + !ifdef MULTIUSER_INSTALLMODE_FUNCTION + !define MULTIUSER_INSTALLMODE_CHANGE_MODE_FUNCTION ${MULTIUSER_INSTALLMODE_FUNCTION} ; old code - changed function name + !undef MULTIUSER_INSTALLMODE_FUNCTION + !endif + + ; Variables + Var MultiUser.Privileges ; Current user level: "Admin", "Power" (up to Windows XP), or else regular user. + Var MultiUser.InstallMode ; Current Install Mode ("AllUsers" or "CurrentUser") + Var IsAdmin ; 0 or 1, initialized via UserInfo::GetAccountType + Var IsInnerInstance ; 0 or 1, initialized via UAC_IsInnerInstance + Var HasPerMachineInstallation ; 0 or 1 + Var HasPerUserInstallation ; 0 or 1 + Var HasCurrentModeInstallation ; 0 or 1 + Var PerMachineInstallationVersion ; contains version number of empty string "" + Var PerUserInstallationVersion ; contains version number of empty string "" + Var PerMachineInstallationFolder + Var PerUserInstallationFolder + Var PerMachineUninstallString + Var PerUserUninstallString + Var PerMachineOptionAvailable ; 0 or 1: 0 means only per-user radio button is enabled on page, 1 means both; will be 0 only when MULTIUSER_INSTALLMODE_ALLOW_ELEVATION = 0 and user is not admin + Var InstallShowPagesBeforeComponents ; 0 or 1, when 0, use it to hide all pages before Components inside the installer when running as inner instance + Var DisplayDialog ; (internal) + Var PreFunctionCalled ; (internal) + Var CmdLineInstallMode ; contains command-line install mode set via /allusers and /currentusers parameters + Var CmdLineDir ; contains command-line directory set via /D parameter + + ; interface variables + Var MultiUser.InstallModePage + Var MultiUser.InstallModePage.Text + Var MultiUser.InstallModePage.AllUsers + Var MultiUser.InstallModePage.CurrentUser + !ifdef UMUI_SYSVERSION + Var MultiUser.InstallModePage.AllUsersLabel + Var MultiUser.InstallModePage.CurrentUserLabel + !endif + Var MultiUser.InstallModePage.Description +!macroend + +!macro MULTIUSER_UNINIT_VARS + !ifdef MULTIUSER_INSTALLMODE_UNFUNCTION + !define MULTIUSER_INSTALLMODE_CHANGE_MODE_FUNCTION ${MULTIUSER_INSTALLMODE_UNFUNCTION} ; old code - changed function name + !undef MULTIUSER_INSTALLMODE_UNFUNCTION + !else ifdef MULTIUSER_INSTALLMODE_CHANGE_MODE_UNFUNCTION + !define MULTIUSER_INSTALLMODE_CHANGE_MODE_FUNCTION ${MULTIUSER_INSTALLMODE_CHANGE_MODE_UNFUNCTION} ; old code - changed function name + !undef MULTIUSER_INSTALLMODE_CHANGE_MODE_UNFUNCTION + !endif + + ; Variables + Var /GLOBAL UninstallShowBackButton ; 0 or 1, use it to show/hide the Back button on the first visible page of the uninstaller +!macroend + +/****** Modern UI 2 page ******/ +!macro MULTIUSER_PAGE UNINSTALLER_PREFIX UNINSTALLER_FUNCPREFIX + !ifdef MULTIUSER_${UNINSTALLER_PREFIX}PAGE_INSTALLMODE + !error "You cannot insert MULTIUSER_${UNINSTALLER_PREFIX}PAGE_INSTALLMODE more than once!" + !endif + !define MULTIUSER_${UNINSTALLER_PREFIX}PAGE_INSTALLMODE + + #${${UNINSTALLER_PREFIX}StrRep} + + !insertmacro MULTIUSER_${UNINSTALLER_PREFIX}INIT_VARS + + !ifmacrodef MUI_${UNINSTALLER_PREFIX}PAGE_INIT + !insertmacro MUI_${UNINSTALLER_PREFIX}PAGE_INIT + !endif + + !insertmacro MULTIUSER_FUNCTION_INSTALLMODEPAGE "${UNINSTALLER_PREFIX}" "${UNINSTALLER_FUNCPREFIX}" + + PageEx ${UNINSTALLER_FUNCPREFIX}custom + PageCallbacks ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallModePre ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallModeLeave + PageExEnd + + !ifmacrodef MUI_${UNINSTALLER_PREFIX}PAGE_END + !insertmacro MUI_${UNINSTALLER_PREFIX}PAGE_END ; MUI1 MUI_UNPAGE_END macro + !endif +!macroend + +!macro MULTIUSER_PAGE_INSTALLMODE ; create install page - called by user script + !insertmacro MULTIUSER_PAGE "" "" +!macroend + +!macro MULTIUSER_UNPAGE_INSTALLMODE ; create uninstall page - called by user script + !ifndef MULTIUSER_PAGE_INSTALLMODE + !error "You have to insert MULTIUSER_PAGE_INSTALLMODE before MULTIUSER_UNPAGE_INSTALLMODE!" + !endif + !insertmacro MULTIUSER_PAGE "UN" "un." +!macroend + +/****** Installer/uninstaller initialization ******/ +!macro MULTIUSER_LANGUAGE_INIT ; called by user script after the last MUI_LANGUAGE call + !include "NsisMultiUserLang.nsh" +!macroend + +!macro MULTIUSER_INIT ; called by user script in .onInit (after MULTIUSER_PAGE_INSTALLMODE) + !ifdef MULTIUSER_INIT + !error "MULTIUSER_INIT already inserted!" + !endif + !define MULTIUSER_INIT + + !ifndef MULTIUSER_PAGE_INSTALLMODE + !error "You have to insert MULTIUSER_PAGE_INSTALLMODE!" + !endif + + Call MultiUser.InitChecks +!macroend + +!macro MULTIUSER_UNINIT ; called by user script in un.onInit (after MULTIUSER_UNPAGE_INSTALLMODE) + !ifdef MULTIUSER_UNINIT + !error "MULTIUSER_UNINIT already inserted!" + !endif + !define MULTIUSER_UNINIT + + !ifndef MULTIUSER_PAGE_INSTALLMODE | MULTIUSER_UNPAGE_INSTALLMODE + !error "You have to insert both MULTIUSER_PAGE_INSTALLMODE and MULTIUSER_UNPAGE_INSTALLMODE!" + !endif + + Call un.MultiUser.InitChecks +!macroend + +!macro MULTIUSER_SET_ERROR ERROR ; only use in MultiUser.InitChecks! + SetErrorLevel ${ERROR} + ${if} ${silent} + Quit + ${else} + StrCpy $InstallShowPagesBeforeComponents 0 + System::Store L + Return + ${endif} +!macroend + +/****** Functions ******/ +!macro MULTIUSER_FUNCTION_INSTALLMODEPAGE UNINSTALLER_PREFIX UNINSTALLER_FUNCPREFIX + Function ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.AllUsers + ${if} $MultiUser.InstallMode == "AllUsers" + Return + ${endif} + + StrCpy $MultiUser.InstallMode "AllUsers" + + SetShellVarContext all + + StrCpy $HasCurrentModeInstallation "$HasPerMachineInstallation" + + ${if} $CmdLineDir != "" + StrCpy $INSTDIR $CmdLineDir + ${elseif} $PerMachineInstallationFolder != "" + ${andif} $PerMachineInstallationVersion == "${VERSION}" + StrCpy $INSTDIR $PerMachineInstallationFolder + ${else} + !if "${UNINSTALLER_FUNCPREFIX}" == "" + ; Set default installation location for installer + ${if} ${MULTIUSER_INSTALLMODE_64_BIT} = 0 + StrCpy $INSTDIR "$PROGRAMFILES32\${MULTIUSER_INSTALLMODE_INSTDIR}" + ${else} + StrCpy $INSTDIR "$PROGRAMFILES64\${MULTIUSER_INSTALLMODE_INSTDIR}" + ${endif} + !endif + ${endif} + + !ifdef MULTIUSER_INSTALLMODE_CHANGE_MODE_FUNCTION + Call "${MULTIUSER_INSTALLMODE_CHANGE_MODE_FUNCTION}" + !endif + FunctionEnd + + Function ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.CurrentUser + ${if} $MultiUser.InstallMode == "CurrentUser" + Return + ${endif} + + StrCpy $MultiUser.InstallMode "CurrentUser" + + SetShellVarContext current + + StrCpy $HasCurrentModeInstallation "$HasPerUserInstallation" + + ${if} $CmdLineDir != "" + StrCpy $INSTDIR $CmdLineDir + ${elseif} $PerUserInstallationFolder != "" + ${andif} $PerUserInstallationVersion == "${VERSION}" + StrCpy $INSTDIR $PerUserInstallationFolder + ${else} + !if "${UNINSTALLER_FUNCPREFIX}" == "" + ; Set default installation location for installer + ${if} "$LOCALAPPDATA" != "" + ; There is a shfolder.dll that emulates CSIDL_LOCAL_APPDATA for older versions of shell32.dll which doesn't support it (pre-Win2k versions) + ; This shfolder.dll is bundeled with IE5 (or as part of Platform SDK Redistributable) that can be installed on NT4 and NSIS (at least since v3.01) will use it instead of shell32.dll if it is available + StrCpy $INSTDIR "$LOCALAPPDATA\${MULTIUSER_INSTALLMODE_INSTDIR}" + ${else} + ; When shfolder.dll is unavailable on NT4 (and so $LOCALAPPDATA returns nothing), local AppData path can still be queried here using registry + ReadRegStr $INSTDIR HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" "Local AppData" + ${if} "$INSTDIR" == "" + StrCpy $INSTDIR "$PROGRAMFILES32\${MULTIUSER_INSTALLMODE_INSTDIR}" ; there's no 64-bit of Windows before 2000 (i.e. NT4) + ${else} + StrCpy $INSTDIR "$INSTDIR\${MULTIUSER_INSTALLMODE_INSTDIR}" + ${endif} + ${endif} + !endif + ${endif} + + !ifdef MULTIUSER_INSTALLMODE_CHANGE_MODE_FUNCTION + Call "${MULTIUSER_INSTALLMODE_CHANGE_MODE_FUNCTION}" + !undef MULTIUSER_INSTALLMODE_CHANGE_MODE_FUNCTION + !endif + FunctionEnd + + Function ${UNINSTALLER_FUNCPREFIX}MultiUser.GetPos + StrCpy $2 $PreFunctionCalled ; if not PreFunctionCalled, we cannot get position + + ${if} $2 = 1 + System::Call "*(i, i, i, i) p .r3" ; allocate RECT struct + + System::Call "User32::GetWindowRect(p $HWNDPARENT, i r3)" + + System::Call '*$3(i .r0, i .r1, i, i)' + + System::Free $3 + ${endif} + FunctionEnd + + Function ${UNINSTALLER_FUNCPREFIX}MultiUser.SetPos + System::Call "User32::SetWindowPos(p $HWNDPARENT, i 0, i $0, i $1, i 0, i 0, i 0x5)" + FunctionEnd + + Function ${UNINSTALLER_FUNCPREFIX}MultiUser.CheckPageElevationRequired + ; check if elevation on page is always required, return result in $0 + ; when this function is called from InitChecks, InstallMode is "" + ; and when called from InstallModeLeave/SetShieldsAndTexts, InstallMode is not empty + StrCpy $0 0 + ${if} $IsAdmin = 0 + ${if} $MultiUser.InstallMode == "AllUsers" + StrCpy $0 1 + ${else} + !if "${UNINSTALLER_FUNCPREFIX}" == "" ; installer + !if ${MULTIUSER_INSTALLMODE_ALLOW_BOTH_INSTALLATIONS} = 0 + ${if} $HasPerMachineInstallation = 1 + ${andif} $HasPerUserInstallation = 0 + ; has to uninstall the per-machine installation, which requires admin rights + ; but signle-user installs of standard users shouldn't be elevated (run as another user) + StrCpy $0 2 + ${endif} + !endif + !endif + ${endif} + ${endif} + FunctionEnd + + Function ${UNINSTALLER_FUNCPREFIX}MultiUser.CheckElevationAllowed + ${if} ${silent} + StrCpy $0 "${MULTIUSER_INSTALLMODE_ALLOW_ELEVATION_IF_SILENT}" + ${else} + StrCpy $0 "${MULTIUSER_INSTALLMODE_ALLOW_ELEVATION}" + ${endif} + FunctionEnd + + Function ${UNINSTALLER_FUNCPREFIX}MultiUser.Elevate + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.CheckElevationAllowed + + ${if} $0 = 0 + Return + ${endif} + + HideWindow + !insertmacro UAC_RunElevated + ${if} $0 = 0 + ; if inner instance was started ($1 = 1), return code of the elevated fork process is in $2 as well as set via SetErrorLevel + ; NOTE: the error level may have a value MULTIUSER_ERROR_ELEVATION_FAILED (but not MULTIUSER_ERROR_ELEVATION_NOT_ALLOWED) + ${if} $1 <> 1 ; process did not start - return MULTIUSER_ERROR_ELEVATION_FAILED + SetErrorLevel ${MULTIUSER_ERROR_ELEVATION_FAILED} + ${endif} + ${else} ; process did not start - return MULTIUSER_ERROR_ELEVATION_FAILED or Win32 error code stored in $0 + ${if} $0 = 1223 ; user aborted elevation dialog - translate to MULTIUSER_ERROR_ELEVATION_FAILED for easier processing + ${orif} $0 = 1062 ; Logon service not running - translate to MULTIUSER_ERROR_ELEVATION_FAILED for easier processing + StrCpy $0 ${MULTIUSER_ERROR_ELEVATION_FAILED} + ${endif} + SetErrorLevel $0 + ${endif} + Quit + FunctionEnd + + Function ${UNINSTALLER_FUNCPREFIX}MultiUser.InitChecks + System::Store S + + ; Installer initialization - check privileges and set default install mode + StrCpy $MultiUser.InstallMode "" + StrCpy $PerMachineOptionAvailable 1 + StrCpy $InstallShowPagesBeforeComponents 1 + StrCpy $DisplayDialog 1 + StrCpy $PreFunctionCalled 0 + StrCpy $CmdLineInstallMode "" + StrCpy $CmdLineDir "" + + ${if} ${RunningX64} ; fix for https://github.com/Drizin/NsisMultiUser/issues/11 + ${if} ${MULTIUSER_INSTALLMODE_64_BIT} = 0 + ; HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall gets redirected to HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall, + ; for HKCU there's no redirection + SetRegView 32 ; someday, when NSIS is 64-bit... + ${else} + SetRegView 64 + ${endif} + ${endif} + + UserInfo::GetAccountType + Pop $MultiUser.Privileges + ${if} $MultiUser.Privileges == "Admin" + ${orif} $MultiUser.Privileges == "Power" ; under XP (and earlier?), Power users can install programs, but UAC_IsAdmin returns false + StrCpy $IsAdmin 1 + ${else} + StrCpy $IsAdmin 0 + ${endif} + + ${if} ${UAC_IsInnerInstance} + StrCpy $IsInnerInstance 1 + ${else} + StrCpy $IsInnerInstance 0 + ${endif} + + ; initialize PerXXXInstallationFolder, PerXXXInstallationVersion, PerXXXUninstallString variables + ReadRegStr $PerMachineInstallationFolder HKLM "${MULTIUSER_INSTALLMODE_INSTALL_REGISTRY_KEY_PATH}" "${MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUENAME}" ; "InstallLocation" + ReadRegStr $PerMachineInstallationVersion HKLM "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}" "DisplayVersion" + ReadRegStr $PerMachineUninstallString HKLM "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}" "UninstallString" ; contains the /currentuser or /allusers parameter + ${if} $PerMachineInstallationFolder == "" + StrCpy $HasPerMachineInstallation 0 + ${else} + StrCpy $HasPerMachineInstallation 1 + ${endif} + + ReadRegStr $PerUserInstallationFolder HKCU "${MULTIUSER_INSTALLMODE_INSTALL_REGISTRY_KEY_PATH}" "${MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUENAME}" ; "InstallLocation" + !insertmacro MULTIUSER_GetCurrentUserString $0 + ReadRegStr $PerUserInstallationVersion HKCU "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}$0" "DisplayVersion" + ReadRegStr $PerUserUninstallString HKCU "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}$0" "UninstallString" ; contains the /currentuser or /allusers parameter + ${if} $PerUserInstallationFolder == "" + StrCpy $HasPerUserInstallation 0 + ${else} + StrCpy $HasPerUserInstallation 1 + ${if} $PerUserInstallationVersion == "" + ${andif} $0 != "" + ; support old versions that did not have MULTIUSER_GetCurrentUserString + ReadRegStr $PerUserInstallationVersion HKCU "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}" "DisplayVersion" + ReadRegStr $PerUserUninstallString HKCU "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}" "UninstallString" ; contains the /currentuser or /allusers parameter + ${endif} + ${endif} + + ; get all parameters + ${GetParameters} $R0 + + ; initialize CmdLineInstallMode and CmdLineDir, needed also if we are the inner instance (UAC passes all parameters from the outer instance) + ; note: the loading of the /D parameter depends on AllowRootDirInstall, see https://sourceforge.net/p/nsis/bugs/1176/ + ${GetOptions} $R0 "/allusers" $R1 + ${ifnot} ${errors} + StrCpy $CmdLineInstallMode "AllUsers" + ${endif} + + ${GetOptions} $R0 "/currentuser" $R1 + ${ifnot} ${errors} + ${if} $CmdLineInstallMode != "" + !insertmacro MULTIUSER_SET_ERROR ${MULTIUSER_ERROR_INVALID_PARAMETERS} + ${endif} + StrCpy $CmdLineInstallMode "CurrentUser" + ${endif} + + !if "${UNINSTALLER_FUNCPREFIX}" == "" + ${if} "$INSTDIR" != "" ; if $INSTDIR is not empty here in the installer, it's initialized with the value of the /D command-line parameter + StrCpy $CmdLineDir "$INSTDIR" + ${endif} + !endif + + ; initialize $InstallShowPagesBeforeComponents and $UninstallShowBackButton + !if "${UNINSTALLER_FUNCPREFIX}" == "" + ${if} $IsInnerInstance = 1 + StrCpy $InstallShowPagesBeforeComponents 0 ; we hide pages only if we're the inner instance (the outer instance always shows them) + ${endif} + !else + ${if} $CmdLineInstallMode == "" + ${andif} $HasPerMachineInstallation = 1 + ${andif} $HasPerUserInstallation = 1 + StrCpy $UninstallShowBackButton 1 ; make sure we show Back button only if dialog was displayed, i.e. uninstaller did not elevate in the beginning (see when MultiUser.Elevate is called) + ${else} + StrCpy $UninstallShowBackButton 0 + ${endif} + !endif + + ${if} $IsInnerInstance = 1 + ; check if the inner instance has admin rights + ${if} $IsAdmin = 0 + SetErrorLevel ${MULTIUSER_ERROR_ELEVATION_FAILED} ; special return value for outer instance so it knows we did not have admin rights + Quit + ${endif} + + !if "${UNINSTALLER_FUNCPREFIX}" == "" + ; set language to the one used in the outer instance (installer only, for uninstaller the outer and inner instance might have different language, + ; or there might be no current user installation when the outer uninstaller invokes the inner instance + !insertmacro UAC_AsUser_GetGlobalVar $LANGUAGE + + !if ${MULTIUSER_INSTALLMODE_ALLOW_BOTH_INSTALLATIONS} = 0 + !insertmacro UAC_AsUser_GetGlobal $0 $MultiUser.InstallMode + ${if} $0 == "CurrentUser" + ; the inner instance was elevated because there is installation per-machine, which needs to be removed and requires admin rights, + ; but the user selected per-user installation in the outer instance, set context to CurrentUser + Call MultiUser.InstallMode.CurrentUser + StrCpy $DisplayDialog 0 + System::Store L + Return + ${endif} + !endif + !endif + + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.AllUsers ; Inner Process (and Admin) - set to AllUsers + StrCpy $DisplayDialog 0 + System::Store L + Return + ${endif} + + ; process /? parameter + !ifndef MULTIUSER_INSTALLMODE_NO_HELP_DIALOG ; define MULTIUSER_INSTALLMODE_NO_HELP_DIALOG to display your own help dialog (new options, return codes, etc.) + ${GetOptions} $R0 "/?" $R1 + ${ifnot} ${errors} + MessageBox MB_ICONINFORMATION "Usage:$\r$\n\ + $\r$\n\ + /allusers$\t- (un)install for all users, case-insensitive$\r$\n\ + /currentuser - (un)install for current user only, case-insensitive$\r$\n\ + /uninstall$\t- (installer only) run uninstaller, requires /allusers or /currentuser, case-insensitive$\r$\n\ + /S$\t- silent mode, requires /allusers or /currentuser, case-sensitive$\r$\n\ + /D$\t- (installer only) set install directory, must be last parameter, without quotes, case-sensitive$\r$\n\ + /?$\t- display this message$\r$\n\ + $\r$\n\ + $\r$\n\ + Return codes (decimal):$\r$\n\ + $\r$\n\ + 0$\t- normal execution (no error)$\r$\n\ + 1$\t- (un)installation aborted by user (Cancel button)$\r$\n\ + 2$\t- (un)installation aborted by script$\r$\n\ + 666660$\t- invalid command-line parameters$\r$\n\ + 666661$\t- elevation is not allowed by defines$\r$\n\ + 666662$\t- uninstaller detected there's no installed version$\r$\n\ + 666663$\t- executing uninstaller from the installer failed$\r$\n\ + 666666$\t- cannot start elevated instance$\r$\n\ + other$\t- Windows error code when trying to start elevated instance" + SetErrorLevel 0 + Quit + ${endif} + !endif + + ; process /uninstall parameter + !if "${UNINSTALLER_FUNCPREFIX}" == "" + ${GetOptions} $R0 "/uninstall" $R1 + ${ifnot} ${errors} + ${if} $CmdLineInstallMode == "" + !insertmacro MULTIUSER_SET_ERROR ${MULTIUSER_ERROR_INVALID_PARAMETERS} + ${elseif} $CmdLineInstallMode == "AllUsers" + ${if} $HasPerMachineInstallation = 0 + !insertmacro MULTIUSER_SET_ERROR ${MULTIUSER_ERROR_NOT_INSTALLED} + ${endif} + StrCpy $0 "$PerMachineInstallationFolder" + ${else} + ${if} $HasPerUserInstallation = 0 + !insertmacro MULTIUSER_SET_ERROR ${MULTIUSER_ERROR_NOT_INSTALLED} + ${endif} + StrCpy $0 "$PerUserInstallationFolder" + ${endif} + + ; NOTES: + ; - the _? param stops the uninstaller from copying itself to the temporary directory, which is the only way for waiting to work + ; - $R0 passes the original parameters from the installer to the uninstaller (together with /uninstall so that uninstaller knows installer is running and skips opitional single instance checks) + ; - using ExecWait fails if the new process requires elevation, see http://forums.winamp.com/showthread.php?p=3080202&posted=1#post3080202, so we use ExecShellWait + ExecShellWait "open" "$0\${UNINSTALL_FILENAME}" "$R0 _?=$0" + ${if} ${errors} + SetErrorLevel ${MULTIUSER_ERROR_RUN_UNINSTALLER_FAILED} + ${else} + SetErrorLevel 0 + ${endif} + Quit + ${endif} + !endif + + ; check for limitations + ${if} ${silent} + ${andif} $CmdLineInstallMode == "" + SetErrorLevel ${MULTIUSER_ERROR_INVALID_PARAMETERS} ; one of the /allusers or /currentuser parameters is required in silent mode + Quit + ${endif} + + !if "${UNINSTALLER_FUNCPREFIX}" != "" + ${if} $HasPerMachineInstallation = 0 + ${andif} $HasPerUserInstallation = 0 + !insertmacro MULTIUSER_SET_ERROR ${MULTIUSER_ERROR_NOT_INSTALLED} + ${endif} + !endif + + ; process /allusers and /currentuser parameters (both silent and non-silent mode, installer and uninstaller) + ${if} $CmdLineInstallMode != "" + ${ifnot} ${IsNT} ; Not running Windows NT, (so it's Windows 95/98/ME), so per-user installation not supported + ${andif} $CmdLineInstallMode == "CurrentUser" + !insertmacro MULTIUSER_SET_ERROR ${MULTIUSER_ERROR_INVALID_PARAMETERS} + ${endif} + + ${if} $CmdLineInstallMode == "AllUsers" + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.AllUsers + ${else} + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.CurrentUser + ${endif} + + !if "${UNINSTALLER_FUNCPREFIX}" != "" + ${if} $HasCurrentModeInstallation = 0 + !insertmacro MULTIUSER_SET_ERROR ${MULTIUSER_ERROR_NOT_INSTALLED} + ${endif} + !endif + + !if "${UNINSTALLER_FUNCPREFIX}" != "" + StrCpy $DisplayDialog 0 ; uninstaller - don't display dialog when there is /allusers or /currentuser parameter + !else + ${if} ${silent} + StrCpy $DisplayDialog 0 + ${endif} + !endif + + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.CheckPageElevationRequired + ${if} $0 = 1 + ${if} $DisplayDialog = 0 ; if we are not displaying the dialog (uninstaller or silent mode) and elevation is required, Elevate now (or Quit with an error) + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.Elevate + ${else} + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.CheckElevationAllowed ; if we are displaying the dialog and elevation is required, check if elevation is allowed + ${endif} + ${if} $0 = 0 + !insertmacro MULTIUSER_SET_ERROR ${MULTIUSER_ERROR_ELEVATION_NOT_ALLOWED} + ${endif} + ${endif} + System::Store L + Return + ${endif} + + ; the rest of the code is executed only when there are no /allusers and /currentuser parameters and in non-silent mode + ${ifnot} ${IsNT} ; Not running Windows NT, (so it's Windows 95/98/ME), so per-user installation not supported + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.AllUsers + StrCpy $DisplayDialog 0 + System::Store L + Return + ${endif} + + ; check if elevation on page is always required (installer only) + !if "${UNINSTALLER_FUNCPREFIX}" == "" + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.CheckPageElevationRequired + ${if} $0 = 1 + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.CheckElevationAllowed + ${if} $0 = 0 + !insertmacro MULTIUSER_SET_ERROR ${MULTIUSER_ERROR_ELEVATION_NOT_ALLOWED} + ${endif} + ${endif} + !endif + + ; if elevation is not allowed and user is not admin, disable the per-machine option + !if ${MULTIUSER_INSTALLMODE_ALLOW_ELEVATION} = 0 + ${if} $IsAdmin = 0 + StrCpy $PerMachineOptionAvailable 0 + ${endif} + !endif + + ; if there's only one installed version + ; when uninstaller is invoked from the "add/remove programs", Windows will automatically start uninstaller elevated if uninstall keys are in HKLM + ${if} $HasPerMachineInstallation = 1 + ${andif} $HasPerUserInstallation = 0 + !if "${UNINSTALLER_FUNCPREFIX}" == "" + ${if} $PerMachineOptionAvailable = 1 + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.AllUsers + ${else} + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.CurrentUser + ${endif} + !else + ${if} $IsAdmin = 0 + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.Elevate ; if $PerMachineOptionAvailable = 0 (i.e. MULTIUSER_INSTALLMODE_ALLOW_ELEVATION = 0), Elevate will call CheckElevationAllowed, which checks if MULTIUSER_INSTALLMODE_ALLOW_ELEVATION = 0 + ${if} $0 = 0 + !insertmacro MULTIUSER_SET_ERROR ${MULTIUSER_ERROR_ELEVATION_NOT_ALLOWED} + ${endif} + ${endif} + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.AllUsers + StrCpy $DisplayDialog 0 + !endif + ${elseif} $HasPerMachineInstallation = 0 + ${andif} $HasPerUserInstallation = 1 + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.CurrentUser + !if "${UNINSTALLER_FUNCPREFIX}" != "" + StrCpy $DisplayDialog 0 + !endif + ${else} ; if there is no installed version (installer only), or there are 2 installations - we always display the dialog + ${if} $IsAdmin = 1 ; If running as admin, default to per-machine installation (unless default is forced by MULTIUSER_INSTALLMODE_DEFAULT_CURRENTUSER) + !if ${MULTIUSER_INSTALLMODE_DEFAULT_CURRENTUSER} = 0 + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.AllUsers + !else + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.CurrentUser + !endif + ${else} ; if not running as admin, default to per-user installation (unless default is forced by MULTIUSER_INSTALLMODE_DEFAULT_ALLUSERS) + !if ${MULTIUSER_INSTALLMODE_DEFAULT_ALLUSERS} = 0 + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.CurrentUser + !else + ${if} $PerMachineOptionAvailable = 1 + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.AllUsers + ${else} + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.CurrentUser + ${endif} + !endif + ${endif} + ${endif} + + System::Store L + FunctionEnd + + Function ${UNINSTALLER_FUNCPREFIX}MultiUser.ShowErrorMessage + Push $0 + + GetErrorLevel $0 + + ${if} $0 = -1 + Pop $0 + Return + ${endif} + + ${Switch} $0 + ${Case} ${MULTIUSER_ERROR_INVALID_PARAMETERS} + MessageBox MB_ICONSTOP "$(MULTIUSER_INVALID_PARAMS)" /SD IDOK + Quit + ${Case} ${MULTIUSER_ERROR_NOT_INSTALLED} + MessageBox MB_ICONSTOP "$(MULTIUSER_NOT_INSTALLED)" /SD IDOK + Quit + ${Case} ${MULTIUSER_ERROR_ELEVATION_NOT_ALLOWED} + MessageBox MB_ICONSTOP "$(MULTIUSER_RUN_AS_ADMIN)" /SD IDOK + Quit + ${EndSwitch} + FunctionEnd + + Function ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallModePre + System::Store S + + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.ShowErrorMessage + + ${if} $IsInnerInstance = 1 + ${if} $PreFunctionCalled = 0 ; inner instance is displayed + ; set position of inner instance + !insertmacro UAC_AsUser_Call Function ${UNINSTALLER_FUNCPREFIX}MultiUser.GetPos ${UAC_SYNCREGISTERS} + ${if} $2 = 1 + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.SetPos + ${endif} + ${else} ; user pressed Back button on the first visible page in the inner instance - display outer instance + ; set position of outer instance + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.GetPos + !insertmacro UAC_AsUser_Call Function ${UNINSTALLER_FUNCPREFIX}MultiUser.SetPos ${UAC_SYNCREGISTERS} + + SetErrorLevel ${MULTIUSER_INNER_INSTANCE_BACK} + Quit + ${endif} + ${endif} + StrCpy $PreFunctionCalled 1 + + ${if} $DisplayDialog = 0 + System::Store L + Abort + ${endif} + + !ifmacrodef MUI_HEADER_TEXT + !if "${UNINSTALLER_FUNCPREFIX}" == "" + !insertmacro MUI_HEADER_TEXT "$(MULTIUSER_PAGE_TITLE)" "$(MULTIUSER_INSTALL_PAGE_SUBTITLE)" + !else + !insertmacro MUI_HEADER_TEXT "$(MULTIUSER_PAGE_TITLE)" "$(MULTIUSER_UNINSTALL_PAGE_SUBTITLE)" + !endif + !endif + + !ifdef MUI_PAGE_CUSTOMFUNCTION_PRE + Call "${MUI_PAGE_CUSTOMFUNCTION_PRE}" + !undef MUI_PAGE_CUSTOMFUNCTION_PRE + !endif + nsDialogs::Create 1018 + Pop $MultiUser.InstallModePage + + ; default was MULTIUSER_TEXT_INSTALLMODE_TITLE "Choose Users" + !if "${UNINSTALLER_FUNCPREFIX}" == "" + ${NSD_CreateLabel} 0 0 100% 24u "$(MULTIUSER_INSTALL_HEADER)" + !else + ${NSD_CreateLabel} 0 0 100% 24u "$(MULTIUSER_UNINSTALL_HEADER)" + !endif + Pop $MultiUser.InstallModePage.Text + + !ifdef UMUI_SYSVERSION + StrCpy $0 "$(MULTIUSER_ALL_USERS_UMUI)" + ${NSD_CreateRadioButton} 30u 30% 10u 8u "" + Pop $MultiUser.InstallModePage.AllUsers + + System::Call "advapi32::GetUserName(t. r1, *i ${NSIS_MAX_STRLEN})" + ${${UNINSTALLER_PREFIX}StrRep} "$1" "$(MULTIUSER_CURRENT_USER_UMUI)" "{USER}" "$1" + ${NSD_CreateRadioButton} 30u 45% 10u 8u "" + Pop $MultiUser.InstallModePage.CurrentUser + + ; We create the radio buttons with empty text and create separate labels, because radio button font color can't be changed with XP Styles turned on, + ; which creates problems with UMUI themes, see http://forums.winamp.com/showthread.php?p=3079742#post3079742 + ; shortcuts (&) for labels don't work and cause strange behaviour in NSIS - going to another page, etc. + ${NSD_CreateLabel} 44u 30% 280u 16u "$0" + Pop $MultiUser.InstallModePage.AllUsersLabel + nsDialogs::SetUserData $MultiUser.InstallModePage.AllUsersLabel $MultiUser.InstallModePage.AllUsers + ${NSD_CreateLabel} 44u 45% 280u 8u "$1" + Pop $MultiUser.InstallModePage.CurrentUserLabel + nsDialogs::SetUserData $MultiUser.InstallModePage.CurrentUserLabel $MultiUser.InstallModePage.CurrentUser + + ${if} $PerMachineOptionAvailable = 0 ; install per-machine is not available + SendMessage $MultiUser.InstallModePage.AllUsersLabel ${WM_SETTEXT} 0 "STR:$0$\r$\n($(MULTIUSER_RUN_AS_ADMIN))" ; only when $PerMachineOptionAvailable = 0, we add that comment to the disabled control itself + ${orif} $CmdLineInstallMode != "" + EnableWindow $MultiUser.InstallModePage.AllUsersLabel 0 ; start out disabled + EnableWindow $MultiUser.InstallModePage.AllUsers 0 ; start out disabled + ${endif} + + ${if} $CmdLineInstallMode != "" + EnableWindow $MultiUser.InstallModePage.CurrentUserLabel 0 + EnableWindow $MultiUser.InstallModePage.CurrentUser 0 + ${endif} + + ; bind to label click + ${NSD_OnClick} $MultiUser.InstallModePage.CurrentUserLabel ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallModeOptionLabelClick + ${NSD_OnClick} $MultiUser.InstallModePage.AllUsersLabel ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallModeOptionLabelClick + !else + StrCpy $0 "$(MULTIUSER_ALL_USERS)" + + System::Call "advapi32::GetUserName(t. r1, *i ${NSIS_MAX_STRLEN})" + ${${UNINSTALLER_PREFIX}StrRep} "$1" "$(MULTIUSER_CURRENT_USER)" "{USER}" "$1" + + ${NSD_CreateRadioButton} 30u 30% 280u 16u "$0" + Pop $MultiUser.InstallModePage.AllUsers + + ${NSD_CreateRadioButton} 30u 45% 280u 8u "$1" + Pop $MultiUser.InstallModePage.CurrentUser + + ${if} $PerMachineOptionAvailable = 0 ; install per-machine is not available + SendMessage $MultiUser.InstallModePage.AllUsers ${WM_SETTEXT} 0 "STR:$0$\r$\n($(MULTIUSER_RUN_AS_ADMIN))" ; only when $PerMachineOptionAvailable = 0, we add that comment to the disabled control itself + ${orif} $CmdLineInstallMode != "" + EnableWindow $MultiUser.InstallModePage.AllUsers 0 ; start out disabled + ${endif} + + ${if} $CmdLineInstallMode != "" + EnableWindow $MultiUser.InstallModePage.CurrentUser 0 + ${endif} + !endif + + ; bind to radiobutton change + ${NSD_OnClick} $MultiUser.InstallModePage.CurrentUser ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallModeOptionClick + ${NSD_OnClick} $MultiUser.InstallModePage.AllUsers ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallModeOptionClick + + ${NSD_CreateLabel} 0u -32u 100% 32u "" ; will hold up to 4 lines of text + Pop $MultiUser.InstallModePage.Description + + ${if} $MultiUser.InstallMode == "AllUsers" ; setting selected radio button + SendMessage $MultiUser.InstallModePage.AllUsers ${BM_SETCHECK} ${BST_CHECKED} 0 ; select radio button + ${else} + SendMessage $MultiUser.InstallModePage.CurrentUser ${BM_SETCHECK} ${BST_CHECKED} 0 ; select radio button + ${endif} + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.SetShieldAndTexts ; simulating click on the control will change $INSTDIR and reset a possible user selection + + !ifmacrodef UMUI_IOPAGEBGTRANSPARENT_INIT ; UMUI, apply theme to controls + !ifndef USE_MUIEx ; for MUIEx, applying themes causes artifacts + !insertmacro UMUI_IOPAGEBGTRANSPARENT_INIT $MultiUser.InstallModePage + !insertmacro UMUI_IOPAGECTLTRANSPARENT_INIT $MultiUser.InstallModePage.Text + !insertmacro UMUI_IOPAGECTLTRANSPARENT_INIT $MultiUser.InstallModePage.AllUsers + !insertmacro UMUI_IOPAGECTLTRANSPARENT_INIT $MultiUser.InstallModePage.AllUsersLabel + !insertmacro UMUI_IOPAGECTLTRANSPARENT_INIT $MultiUser.InstallModePage.CurrentUser + !insertmacro UMUI_IOPAGECTLTRANSPARENT_INIT $MultiUser.InstallModePage.CurrentUserLabel + !insertmacro UMUI_IOPAGECTLTRANSPARENT_INIT $MultiUser.InstallModePage.Description + !endif + !endif + + System::Store L + + !ifdef MUI_PAGE_CUSTOMFUNCTION_SHOW + Call "${MUI_PAGE_CUSTOMFUNCTION_SHOW}" + !undef MUI_PAGE_CUSTOMFUNCTION_SHOW + !endif + + nsDialogs::Show + + !if "${UNINSTALLER_FUNCPREFIX}" == "" + Push $0 + GetDlgItem $0 $HWNDPARENT 1 + SendMessage $0 ${BCM_SETSHIELD} 0 0 ; hide SHIELD on page leave (InstallModeLeave is called only on Next button click) + Pop $0 + !endif + FunctionEnd + + Function ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallModeLeave + System::Store S + + !if ${MULTIUSER_INSTALLMODE_ALLOW_ELEVATION} = 1 ; if elevation is allowed + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.CheckPageElevationRequired + + ${if} $0 = 1 + HideWindow + !insertmacro UAC_RunElevated + ;MessageBox MB_OK "[$0]/[$1]/[$2]/[$3]" + + ; http://nsis.sourceforge.net/UAC_plug-in + ${Switch} $0 + ${Case} 0 + ${Switch} $1 + ${Case} 1 ; Started an elevated child process successfully, exit code is in $2 + ${Switch} $2 + ${Case} ${MULTIUSER_ERROR_ELEVATION_FAILED} ; the inner instance was not admin after all - stay on page + MessageBox MB_ICONSTOP "$(MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED)" /SD IDOK + ${Break} + ${Case} ${MULTIUSER_INNER_INSTANCE_BACK} ; if user pressed Back button on the first visible page of the inner instance - stay on page + ${Break} + ${Default} ; all other cases - Quit + ; return code of the elevated fork process is in $2 as well as set via SetErrorLevel + Quit + ${EndSwitch} + ${Break} + ${Case} 3 ; RunAs completed successfully, but with a non-admin user - stay on page + MessageBox MB_ICONSTOP "$(MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED)" /SD IDOK + ${Break} + ${Default} ; 0 - UAC is not supported by the OS, OR 2 - The process is already running @ HighIL (Member of admin group) - stay on page + MessageBox MB_ICONSTOP "$(MULTIUSER_ELEVATION_NOT_SUPPORTED)" /SD IDOK + ${EndSwitch} + ${Break} + ${Case} 1223 ; user aborted elevation dialog - stay on page + ${Break} + ${Case} 1062 ; Logon service not running - stay on page + MessageBox MB_ICONSTOP "$(MULTIUSER_LOGON_SERVICE_NOT_RUNNING)" /SD IDOK + ${Break} + ${Default} ; anything else should be treated as a fatal error - stay on page + ${${UNINSTALLER_PREFIX}StrRep} "$0" "$(MULTIUSER_ELEVATION_ERROR)" "{ERROR}" "$0" + MessageBox MB_ICONSTOP "$0" /SD IDOK + ${EndSwitch} + + ; clear the error level set by UAC for inner instance, so that outer instance returns its own error level when exits (the error level is not reset by NSIS if once set and >= 0) + ; see http://forums.winamp.com/showthread.php?p=3079116&posted=1#post3079116 + SetErrorLevel -1 + BringToFront + Abort ; Stay on page + ${endif} + !endif + + System::Store L + + !ifdef MUI_PAGE_CUSTOMFUNCTION_LEAVE + Call "${MUI_PAGE_CUSTOMFUNCTION_LEAVE}" + !undef MUI_PAGE_CUSTOMFUNCTION_LEAVE + !endif + FunctionEnd + + Function ${UNINSTALLER_FUNCPREFIX}MultiUser.SetShieldAndTexts + System::Store S + + StrCpy $0 "$MultiUser.InstallMode" + ; if necessary, display text for different install mode rather than the actual one in $MultiUser.InstallMode + !if ${MULTIUSER_INSTALLMODE_ALLOW_BOTH_INSTALLATIONS} = 0 + !if "${UNINSTALLER_FUNCPREFIX}" == "" + ${if} $MultiUser.InstallMode == "AllUsers" ; user selected "all users" + ${if} $HasPerMachineInstallation = 0 + ${andif} $HasPerUserInstallation = 1 + StrCpy $0 "CurrentUser" ; display information for the "current user" installation + ${endif} + ${elseif} $HasPerMachineInstallation = 1 + ${andif} $HasPerUserInstallation = 0 ; user selected "current user" + StrCpy $0 "AllUsers" ; display information for the "all users" installation + ${endif} + !endif + !endif + + ; set label text + StrCpy $1 "" + ${if} $0 == "AllUsers" ; all users + ${if} $HasPerMachineInstallation = 1 + ${${UNINSTALLER_PREFIX}StrRep} "$1" "$(MULTIUSER_INSTALLED_ALL_USERS)" "{VERSION}" "$PerMachineInstallationVersion" + ${${UNINSTALLER_PREFIX}StrRep} "$1" "$1" "{FOLDER}" "$PerMachineInstallationFolder" + + !if "${UNINSTALLER_FUNCPREFIX}" == "" + ${if} $PerMachineInstallationVersion == "${VERSION}" + ${if} $MultiUser.InstallMode == "AllUsers" + ${${UNINSTALLER_PREFIX}StrRep} "$2" "$(MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS)" "{VERSION}" "$PerMachineInstallationVersion" + ${else} + ${${UNINSTALLER_PREFIX}StrRep} "$2" "$(MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER)" "{VERSION}" "$PerMachineInstallationVersion" + ${endif} + ${else} + ${if} $MultiUser.InstallMode == "AllUsers" + ${${UNINSTALLER_PREFIX}StrRep} "$2" "$(MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS)" "{OLD_VERSION}" "$PerMachineInstallationVersion" + ${${UNINSTALLER_PREFIX}StrRep} "$2" "$2" "{VERSION}" "${VERSION}" + ${else} + ${${UNINSTALLER_PREFIX}StrRep} "$2" "$(MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER)" "{OLD_VERSION}" "$PerMachineInstallationVersion" + ${${UNINSTALLER_PREFIX}StrRep} "$2" "$2" "{VERSION}" "${VERSION}" + ${endif} + ${endif} + StrCpy $1 "$1$\r$\n$2" + !endif + ${else} + StrCpy $1 "$(MULTIUSER_NEW_INSTALLATION_ALL_USERS)" + ${endif} + ${else} ; current user + ${if} $HasPerUserInstallation = 1 + ${${UNINSTALLER_PREFIX}StrRep} "$1" "$(MULTIUSER_INSTALLED_CURRENT_USER)" "{VERSION}" "$PerUserInstallationVersion" + ${${UNINSTALLER_PREFIX}StrRep} "$1" "$1" "{FOLDER}" "$PerUserInstallationFolder" + + !if "${UNINSTALLER_FUNCPREFIX}" == "" + ${if} $PerUserInstallationVersion == "${VERSION}" + ${if} $MultiUser.InstallMode == "AllUsers" + ${${UNINSTALLER_PREFIX}StrRep} "$2" "$(MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS)" "{VERSION}" "$PerUserInstallationVersion" + ${else} + ${${UNINSTALLER_PREFIX}StrRep} "$2" "$(MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER)" "{VERSION}" "$PerUserInstallationVersion" + ${endif} + ${else} + ${if} $MultiUser.InstallMode == "AllUsers" + ${${UNINSTALLER_PREFIX}StrRep} "$2" "$(MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS)" "{OLD_VERSION}" "$PerUserInstallationVersion" + ${${UNINSTALLER_PREFIX}StrRep} "$2" "$2" "{VERSION}" "${VERSION}" + ${else} + ${${UNINSTALLER_PREFIX}StrRep} "$2" "$(MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER)" "{OLD_VERSION}" "$PerUserInstallationVersion" + ${${UNINSTALLER_PREFIX}StrRep} "$2" "$2" "{VERSION}" "${VERSION}" + ${endif} + ${endif} + StrCpy $1 "$1$\r$\n$2" + !endif + ${else} + StrCpy $1 "$(MULTIUSER_NEW_INSTALLATION_CURRENT_USER)" + ${endif} + ${endif} + + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.CheckPageElevationRequired + ${if} $0 = 1 + StrCpy $1 "$1 $(MULTIUSER_ADMIN_CREDENTIALS_REQUIRED)" + ${elseif} $0 = 2 + StrCpy $1 "$1 $(MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED)" + StrCpy $0 0 + ${endif} + + SendMessage $MultiUser.InstallModePage.Description ${WM_SETTEXT} 0 "STR:$1" + + GetDlgItem $1 $hwndParent 1 ; get item 1 (next button) at parent window, store in $1 - (0 is back, 1 is next .. what about CANCEL? http://nsis.sourceforge.net/Buttons_Header ) + + SendMessage $1 ${BCM_SETSHIELD} 0 $0 ; display/hide SHIELD (Windows Vista and above) + + System::Store L + FunctionEnd + + !ifdef UMUI_SYSVERSION + Function ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallModeOptionLabelClick + Exch $0 ; get clicked control's HWND, which is on the stack in $0 + nsDialogs::GetUserData $0 + Pop $0 + + ${NSD_Uncheck} $MultiUser.InstallModePage.AllUsers + ${NSD_Uncheck} $MultiUser.InstallModePage.CurrentUser + ${NSD_Check} $0 ; ${NSD_Check} will check both radio buttons without the above 2 lines + ${NSD_SetFocus} $0 + Push $0 + ; ${NSD_Check} doesn't call Click event + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallModeOptionClick + + Pop $0 + FunctionEnd + !endif + + Function ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallModeOptionClick + Exch $0 ; get clicked control's HWND, which is on the stack in $0 + + ; set InstallMode + ${if} $0 = $MultiUser.InstallModePage.AllUsers + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.AllUsers + ${else} + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.CurrentUser + ${endif} + + Call ${UNINSTALLER_FUNCPREFIX}MultiUser.SetShieldAndTexts + + Pop $0 + FunctionEnd +!macroend + +!macro MULTIUSER_GetCurrentUserString VAR + StrCpy ${VAR} "" + !if ${MULTIUSER_INSTALLMODE_ALLOW_BOTH_INSTALLATIONS} <> 0 + ${if} $MultiUser.InstallMode == "CurrentUser" + ${orif} $MultiUser.InstallMode == "" ; called from InitChecks + StrCpy ${VAR} " (current user)" + ${endif} + !endif +!macroend + +!macro MULTIUSER_RegistryAddInstallInfo + Push $0 + Push $1 + Push $2 + Push $3 + Push $4 + + ; Write the installation path into the registry + WriteRegStr SHCTX "${MULTIUSER_INSTALLMODE_INSTALL_REGISTRY_KEY_PATH}" "${MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUENAME}" "$INSTDIR" ; "InstallLocation" + + ; Write the uninstall keys for Windows + ; Workaround for Windows issue: if the uninstall key names are the same in HKLM and HKCU, Windows displays only one entry in the add/remove programs dialog; + ; this will create 2 different keys in HKCU (MULTIUSER_INSTALLMODE_INSTALL_REGISTRY_KEY_PATH and MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH), + ; but that's OK, both will be removed by uninstaller + !insertmacro MULTIUSER_GetCurrentUserString $0 + + ${if} $MultiUser.InstallMode == "AllUsers" ; setting defaults + WriteRegStr SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}" "DisplayName" "${MULTIUSER_INSTALLMODE_DISPLAYNAME}" + WriteRegStr SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}" "UninstallString" '"$INSTDIR\${UNINSTALL_FILENAME}" /allusers' + WriteRegStr SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}" "QuietUninstallString" '"$INSTDIR\${UNINSTALL_FILENAME}" /allusers /S' + ${else} + WriteRegStr SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}$0" "DisplayName" "${MULTIUSER_INSTALLMODE_DISPLAYNAME} (current user)" ; "add/remove programs" will show if installation is per-user + WriteRegStr SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}$0" "UninstallString" '"$INSTDIR\${UNINSTALL_FILENAME}" /currentuser' + WriteRegStr SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}$0" "QuietUninstallString" '"$INSTDIR\${UNINSTALL_FILENAME}" /currentuser /S' + ${endif} + + WriteRegStr SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}$0" "DisplayVersion" "${VERSION}" + WriteRegStr SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}$0" "DisplayIcon" "$INSTDIR\${PROGEXE},0" + !ifdef COMPANY_NAME + WriteRegStr SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}$0" "Publisher" "${COMPANY_NAME}" + !endif + !ifdef CONTACT + WriteRegStr SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}$0" "Contact" "${CONTACT}" + !endif + !ifdef COMMENTS + WriteRegStr SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}$0" "Comments" "${COMMENTS}" + !endif + !ifdef URL_INFO_ABOUT + WriteRegStr SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}$0" "URLInfoAbout" "${URL_INFO_ABOUT}" + !endif + !ifdef URL_HELP_LINK + WriteRegStr SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}$0" "HelpLink" "${URL_HELP_LINK}" + !endif + !ifdef URL_UPDATE_INFO + WriteRegStr SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}$0" "URLUpdateInfo" "${URL_UPDATE_INFO}" + !endif + WriteRegDWORD SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}$0" "NoModify" 1 + WriteRegDWORD SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}$0" "NoRepair" 1 + + ; Write InstallDate string value in 'YYYYMMDD' format. + ; Without it, Windows gets the date from the registry key metadata, which might be inaccurate. + System::Call /NOUNLOAD "*(&i2,&i2,&i2,&i2,&i2,&i2,&i2,&i2) i .r4" + System::Call /NOUNLOAD "kernel32::GetLocalTime(i)i(r4)" + System::Call /NOUNLOAD "*$4(&i2,&i2,&i2,&i2,&i2,&i2,&i2,&i2)i(.r1,.r2,,.r3,,,,)" + System::Free $4 + IntCmp $2 9 0 0 +2 + StrCpy $2 "0$2" + IntCmp $3 9 0 0 +2 + StrCpy $3 "0$3" + WriteRegStr SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}$0" "InstallDate" "$1$2$3" + + Pop $4 + Pop $3 + Pop $2 + Pop $1 + Pop $0 +!macroend + +!macro MULTIUSER_RegistryAddInstallSizeInfo + Push $0 + Push $1 + Push $2 + Push $3 + + !insertmacro MULTIUSER_GetCurrentUserString $0 + + ${GetSize} "$INSTDIR" "/S=0K" $1 $2 $3 ; get folder size, convert to KB + IntFmt $1 "0x%08X" $1 + WriteRegDWORD SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}$0" "EstimatedSize" "$1" + + Pop $3 + Pop $2 + Pop $1 + Pop $0 +!macroend + +!macro MULTIUSER_RegistryRemoveInstallInfo + Push $0 + + ; Remove registry keys + DeleteRegKey SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}" + !insertmacro MULTIUSER_GetCurrentUserString $0 + ${if} "$0" != "" + DeleteRegKey SHCTX "${MULTIUSER_INSTALLMODE_UNINSTALL_REGISTRY_KEY_PATH}$0" + ${endif} + DeleteRegKey SHCTX "${MULTIUSER_INSTALLMODE_INSTALL_REGISTRY_KEY_PATH}" + + Pop $0 +!macroend + +!verbose pop diff --git a/cmake/Windows/Include/NsisMultiUserLang.nsh b/cmake/Windows/Include/NsisMultiUserLang.nsh new file mode 100644 index 000000000..add12a478 --- /dev/null +++ b/cmake/Windows/Include/NsisMultiUserLang.nsh @@ -0,0 +1,2038 @@ +!ifdef LANG_ENGLISH + LangString MULTIUSER_PAGE_TITLE ${LANG_ENGLISH} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_ENGLISH} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_ENGLISH} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_ENGLISH} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_ENGLISH} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_ENGLISH} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_ENGLISH} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_ENGLISH} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_ENGLISH} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_ENGLISH} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_ENGLISH} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_ENGLISH} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_ENGLISH} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_ENGLISH} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_ENGLISH} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_ENGLISH} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_ENGLISH} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_ENGLISH} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_ENGLISH} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_ENGLISH} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_ENGLISH} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_ENGLISH} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_ENGLISH} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_ENGLISH} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_ENGLISH} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_ENGLISH} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_ENGLISH} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_AFRIKAANS + LangString MULTIUSER_PAGE_TITLE ${LANG_AFRIKAANS} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_AFRIKAANS} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_AFRIKAANS} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_AFRIKAANS} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_AFRIKAANS} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_AFRIKAANS} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_AFRIKAANS} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_AFRIKAANS} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_AFRIKAANS} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_AFRIKAANS} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_AFRIKAANS} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_AFRIKAANS} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_AFRIKAANS} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_AFRIKAANS} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_AFRIKAANS} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_AFRIKAANS} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_AFRIKAANS} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_AFRIKAANS} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_AFRIKAANS} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_AFRIKAANS} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_AFRIKAANS} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_AFRIKAANS} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_AFRIKAANS} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_AFRIKAANS} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_AFRIKAANS} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_AFRIKAANS} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_AFRIKAANS} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_ALBANIAN + LangString MULTIUSER_PAGE_TITLE ${LANG_ALBANIAN} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_ALBANIAN} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_ALBANIAN} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_ALBANIAN} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_ALBANIAN} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_ALBANIAN} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_ALBANIAN} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_ALBANIAN} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_ALBANIAN} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_ALBANIAN} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_ALBANIAN} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_ALBANIAN} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_ALBANIAN} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_ALBANIAN} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_ALBANIAN} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_ALBANIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_ALBANIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_ALBANIAN} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_ALBANIAN} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_ALBANIAN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_ALBANIAN} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_ALBANIAN} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_ALBANIAN} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_ALBANIAN} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_ALBANIAN} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_ALBANIAN} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_ALBANIAN} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_ARABIC + LangString MULTIUSER_PAGE_TITLE ${LANG_ARABIC} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_ARABIC} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_ARABIC} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_ARABIC} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_ARABIC} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_ARABIC} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_ARABIC} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_ARABIC} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_ARABIC} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_ARABIC} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_ARABIC} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_ARABIC} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_ARABIC} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_ARABIC} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_ARABIC} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_ARABIC} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_ARABIC} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_ARABIC} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_ARABIC} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_ARABIC} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_ARABIC} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_ARABIC} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_ARABIC} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_ARABIC} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_ARABIC} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_ARABIC} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_ARABIC} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_ARMENIAN + LangString MULTIUSER_PAGE_TITLE ${LANG_ARMENIAN} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_ARMENIAN} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_ARMENIAN} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_ARMENIAN} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_ARMENIAN} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_ARMENIAN} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_ARMENIAN} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_ARMENIAN} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_ARMENIAN} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_ARMENIAN} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_ARMENIAN} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_ARMENIAN} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_ARMENIAN} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_ARMENIAN} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_ARMENIAN} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_ARMENIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_ARMENIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_ARMENIAN} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_ARMENIAN} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_ARMENIAN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_ARMENIAN} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_ARMENIAN} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_ARMENIAN} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_ARMENIAN} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_ARMENIAN} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_ARMENIAN} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_ARMENIAN} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_ASTURIAN + LangString MULTIUSER_PAGE_TITLE ${LANG_ASTURIAN} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_ASTURIAN} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_ASTURIAN} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_ASTURIAN} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_ASTURIAN} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_ASTURIAN} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_ASTURIAN} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_ASTURIAN} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_ASTURIAN} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_ASTURIAN} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_ASTURIAN} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_ASTURIAN} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_ASTURIAN} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_ASTURIAN} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_ASTURIAN} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_ASTURIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_ASTURIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_ASTURIAN} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_ASTURIAN} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_ASTURIAN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_ASTURIAN} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_ASTURIAN} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_ASTURIAN} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_ASTURIAN} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_ASTURIAN} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_ASTURIAN} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_ASTURIAN} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_BASQUE + LangString MULTIUSER_PAGE_TITLE ${LANG_BASQUE} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_BASQUE} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_BASQUE} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_BASQUE} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_BASQUE} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_BASQUE} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_BASQUE} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_BASQUE} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_BASQUE} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_BASQUE} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_BASQUE} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_BASQUE} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_BASQUE} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_BASQUE} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_BASQUE} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_BASQUE} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_BASQUE} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_BASQUE} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_BASQUE} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_BASQUE} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_BASQUE} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_BASQUE} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_BASQUE} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_BASQUE} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_BASQUE} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_BASQUE} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_BASQUE} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_BELARUSIAN + LangString MULTIUSER_PAGE_TITLE ${LANG_BELARUSIAN} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_BELARUSIAN} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_BELARUSIAN} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_BELARUSIAN} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_BELARUSIAN} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_BELARUSIAN} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_BELARUSIAN} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_BELARUSIAN} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_BELARUSIAN} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_BELARUSIAN} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_BELARUSIAN} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_BELARUSIAN} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_BELARUSIAN} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_BELARUSIAN} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_BELARUSIAN} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_BELARUSIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_BELARUSIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_BELARUSIAN} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_BELARUSIAN} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_BELARUSIAN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_BELARUSIAN} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_BELARUSIAN} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_BELARUSIAN} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_BELARUSIAN} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_BELARUSIAN} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_BELARUSIAN} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_BELARUSIAN} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_BOSNIAN + LangString MULTIUSER_PAGE_TITLE ${LANG_BOSNIAN} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_BOSNIAN} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_BOSNIAN} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_BOSNIAN} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_BOSNIAN} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_BOSNIAN} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_BOSNIAN} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_BOSNIAN} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_BOSNIAN} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_BOSNIAN} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_BOSNIAN} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_BOSNIAN} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_BOSNIAN} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_BOSNIAN} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_BOSNIAN} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_BOSNIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_BOSNIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_BOSNIAN} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_BOSNIAN} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_BOSNIAN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_BOSNIAN} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_BOSNIAN} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_BOSNIAN} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_BOSNIAN} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_BOSNIAN} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_BOSNIAN} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_BOSNIAN} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_BRETON + LangString MULTIUSER_PAGE_TITLE ${LANG_BRETON} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_BRETON} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_BRETON} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_BRETON} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_BRETON} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_BRETON} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_BRETON} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_BRETON} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_BRETON} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_BRETON} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_BRETON} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_BRETON} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_BRETON} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_BRETON} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_BRETON} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_BRETON} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_BRETON} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_BRETON} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_BRETON} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_BRETON} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_BRETON} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_BRETON} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_BRETON} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_BRETON} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_BRETON} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_BRETON} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_BRETON} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_BULGARIAN + LangString MULTIUSER_PAGE_TITLE ${LANG_BULGARIAN} "Избор на потребители" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_BULGARIAN} "Изберете за кои потребители да се инсталира $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_BULGARIAN} "Изберете за кои потребители да се премахне $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_BULGARIAN} "Изберете дали да инсталирате $(^NameDA) за всички потребители или за текущия потребител." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_BULGARIAN} "$(^NameDA) е инсталиран едновременно за всички потребители и за текущия потребител.$\r$\nИзберете коя инсталация премахнете." + LangString MULTIUSER_ALL_USERS ${LANG_BULGARIAN} "За &всеки, който използва този компютър (всички потребители)$\r$\n(Забележка: Програмата за инсталиране ще се рестартира с повишени привилегии)" + LangString MULTIUSER_CURRENT_USER ${LANG_BULGARIAN} "За &мен ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_BULGARIAN} "За всеки, който използва този компютър (всички потребители)$\r$\n(Забележка: Програмата за инсталиране ще се рестартира с повишени привилегии)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_BULGARIAN} "За мен ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_BULGARIAN} "Нова инсталация за всички потребители." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_BULGARIAN} "Нова инсталация за текущия потребител." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_BULGARIAN} "Версия {VERSION} е инсталирана за всички потребители в $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_BULGARIAN} "Версия {VERSION} е инсалирана за текущия потребител в $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_BULGARIAN} "Преинсталиране на версия {VERSION} за всички потребители." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_BULGARIAN} "Преинсталиране на версия {VERSION} за текущия потребител." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_BULGARIAN} "Деинсталиране на версия {OLD_VERSION} и инсталиране на версия {VERSION} за всички потребители." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_BULGARIAN} "Деинсталиране на версия {OLD_VERSION} и инсталиране на версия {VERSION} за текущия потребител." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_BULGARIAN} "Трябва да стартирате тази програма като администратор." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_BULGARIAN} "Изисква се администраторска идентификация." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_BULGARIAN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_BULGARIAN} "Невалидна комбинация от параметри." + LangString MULTIUSER_NOT_INSTALLED ${LANG_BULGARIAN} "Няма инсталация на $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_BULGARIAN} "Операционната система не поддържа инсталации за текущия потребител." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_BULGARIAN} "Трябва да влезете с профил, който е член на администраторската група, за да продължите." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_BULGARIAN} "Операционната система не поддържа повишаване на привилегиите." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_BULGARIAN} "Не е възможно повишаване на привилегиите, услугата Secondary Logon не е пусната." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_BULGARIAN} "Не е възможно повишаване на привилегиите, грешка {ERROR}." +!endif + +!ifdef LANG_CATALAN + LangString MULTIUSER_PAGE_TITLE ${LANG_CATALAN} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_CATALAN} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_CATALAN} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_CATALAN} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_CATALAN} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_CATALAN} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_CATALAN} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_CATALAN} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_CATALAN} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_CATALAN} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_CATALAN} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_CATALAN} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_CATALAN} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_CATALAN} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_CATALAN} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_CATALAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_CATALAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_CATALAN} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_CATALAN} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_CATALAN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_CATALAN} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_CATALAN} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_CATALAN} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_CATALAN} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_CATALAN} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_CATALAN} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_CATALAN} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_CORSICAN + LangString MULTIUSER_PAGE_TITLE ${LANG_CORSICAN} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_CORSICAN} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_CORSICAN} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_CORSICAN} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_CORSICAN} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_CORSICAN} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_CORSICAN} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_CORSICAN} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_CORSICAN} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_CORSICAN} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_CORSICAN} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_CORSICAN} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_CORSICAN} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_CORSICAN} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_CORSICAN} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_CORSICAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_CORSICAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_CORSICAN} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_CORSICAN} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_CORSICAN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_CORSICAN} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_CORSICAN} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_CORSICAN} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_CORSICAN} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_CORSICAN} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_CORSICAN} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_CORSICAN} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_CROATIAN + LangString MULTIUSER_PAGE_TITLE ${LANG_CROATIAN} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_CROATIAN} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_CROATIAN} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_CROATIAN} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_CROATIAN} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_CROATIAN} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_CROATIAN} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_CROATIAN} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_CROATIAN} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_CROATIAN} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_CROATIAN} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_CROATIAN} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_CROATIAN} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_CROATIAN} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_CROATIAN} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_CROATIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_CROATIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_CROATIAN} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_CROATIAN} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_CROATIAN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_CROATIAN} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_CROATIAN} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_CROATIAN} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_CROATIAN} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_CROATIAN} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_CROATIAN} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_CROATIAN} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_CZECH + LangString MULTIUSER_PAGE_TITLE ${LANG_CZECH} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_CZECH} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_CZECH} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_CZECH} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_CZECH} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_CZECH} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_CZECH} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_CZECH} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_CZECH} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_CZECH} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_CZECH} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_CZECH} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_CZECH} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_CZECH} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_CZECH} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_CZECH} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_CZECH} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_CZECH} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_CZECH} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_CZECH} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_CZECH} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_CZECH} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_CZECH} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_CZECH} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_CZECH} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_CZECH} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_CZECH} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_DANISH + LangString MULTIUSER_PAGE_TITLE ${LANG_DANISH} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_DANISH} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_DANISH} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_DANISH} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_DANISH} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_DANISH} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_DANISH} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_DANISH} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_DANISH} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_DANISH} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_DANISH} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_DANISH} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_DANISH} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_DANISH} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_DANISH} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_DANISH} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_DANISH} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_DANISH} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_DANISH} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_DANISH} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_DANISH} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_DANISH} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_DANISH} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_DANISH} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_DANISH} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_DANISH} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_DANISH} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_DUTCH + LangString MULTIUSER_PAGE_TITLE ${LANG_DUTCH} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_DUTCH} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_DUTCH} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_DUTCH} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_DUTCH} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_DUTCH} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_DUTCH} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_DUTCH} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_DUTCH} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_DUTCH} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_DUTCH} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_DUTCH} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_DUTCH} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_DUTCH} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_DUTCH} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_DUTCH} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_DUTCH} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_DUTCH} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_DUTCH} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_DUTCH} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_DUTCH} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_DUTCH} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_DUTCH} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_DUTCH} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_DUTCH} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_DUTCH} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_DUTCH} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_ESPERANTO + LangString MULTIUSER_PAGE_TITLE ${LANG_ESPERANTO} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_ESPERANTO} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_ESPERANTO} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_ESPERANTO} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_ESPERANTO} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_ESPERANTO} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_ESPERANTO} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_ESPERANTO} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_ESPERANTO} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_ESPERANTO} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_ESPERANTO} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_ESPERANTO} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_ESPERANTO} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_ESPERANTO} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_ESPERANTO} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_ESPERANTO} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_ESPERANTO} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_ESPERANTO} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_ESPERANTO} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_ESPERANTO} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_ESPERANTO} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_ESPERANTO} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_ESPERANTO} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_ESPERANTO} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_ESPERANTO} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_ESPERANTO} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_ESPERANTO} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_ESTONIAN + LangString MULTIUSER_PAGE_TITLE ${LANG_ESTONIAN} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_ESTONIAN} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_ESTONIAN} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_ESTONIAN} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_ESTONIAN} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_ESTONIAN} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_ESTONIAN} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_ESTONIAN} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_ESTONIAN} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_ESTONIAN} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_ESTONIAN} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_ESTONIAN} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_ESTONIAN} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_ESTONIAN} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_ESTONIAN} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_ESTONIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_ESTONIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_ESTONIAN} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_ESTONIAN} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_ESTONIAN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_ESTONIAN} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_ESTONIAN} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_ESTONIAN} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_ESTONIAN} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_ESTONIAN} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_ESTONIAN} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_ESTONIAN} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_FARSI + LangString MULTIUSER_PAGE_TITLE ${LANG_FARSI} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_FARSI} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_FARSI} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_FARSI} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_FARSI} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_FARSI} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_FARSI} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_FARSI} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_FARSI} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_FARSI} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_FARSI} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_FARSI} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_FARSI} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_FARSI} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_FARSI} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_FARSI} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_FARSI} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_FARSI} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_FARSI} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_FARSI} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_FARSI} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_FARSI} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_FARSI} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_FARSI} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_FARSI} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_FARSI} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_FARSI} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_FINNISH + LangString MULTIUSER_PAGE_TITLE ${LANG_FINNISH} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_FINNISH} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_FINNISH} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_FINNISH} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_FINNISH} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_FINNISH} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_FINNISH} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_FINNISH} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_FINNISH} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_FINNISH} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_FINNISH} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_FINNISH} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_FINNISH} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_FINNISH} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_FINNISH} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_FINNISH} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_FINNISH} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_FINNISH} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_FINNISH} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_FINNISH} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_FINNISH} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_FINNISH} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_FINNISH} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_FINNISH} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_FINNISH} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_FINNISH} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_FINNISH} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_FRENCH + LangString MULTIUSER_PAGE_TITLE ${LANG_FRENCH} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_FRENCH} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_FRENCH} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_FRENCH} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_FRENCH} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_FRENCH} "For &anyone who uses this computer (all users)$\r$\n(Note: Le programme d'installation redémarrera avec des privilèges élevés)" + LangString MULTIUSER_CURRENT_USER ${LANG_FRENCH} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_FRENCH} "For anyone who uses this computer (all users)$\r$\n(Note: Le programme d'installation redémarrera avec des privilèges élevés)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_FRENCH} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_FRENCH} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_FRENCH} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_FRENCH} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_FRENCH} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_FRENCH} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_FRENCH} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_FRENCH} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_FRENCH} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_FRENCH} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_FRENCH} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_FRENCH} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_FRENCH} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_FRENCH} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_FRENCH} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_FRENCH} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_FRENCH} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_FRENCH} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_FRENCH} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_GALICIAN + LangString MULTIUSER_PAGE_TITLE ${LANG_GALICIAN} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_GALICIAN} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_GALICIAN} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_GALICIAN} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_GALICIAN} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_GALICIAN} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_GALICIAN} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_GALICIAN} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_GALICIAN} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_GALICIAN} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_GALICIAN} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_GALICIAN} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_GALICIAN} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_GALICIAN} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_GALICIAN} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_GALICIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_GALICIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_GALICIAN} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_GALICIAN} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_GALICIAN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_GALICIAN} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_GALICIAN} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_GALICIAN} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_GALICIAN} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_GALICIAN} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_GALICIAN} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_GALICIAN} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_GEORGIAN + LangString MULTIUSER_PAGE_TITLE ${LANG_GEORGIAN} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_GEORGIAN} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_GEORGIAN} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_GEORGIAN} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_GEORGIAN} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_GEORGIAN} "For anyone who uses this computer (all users)" + LangString MULTIUSER_ALL_USERS ${LANG_GEORGIAN} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_GEORGIAN} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_GEORGIAN} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_GEORGIAN} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_GEORGIAN} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_GEORGIAN} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_GEORGIAN} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_GEORGIAN} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_GEORGIAN} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_GEORGIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_GEORGIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_GEORGIAN} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_GEORGIAN} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_GEORGIAN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_GEORGIAN} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_GEORGIAN} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_GEORGIAN} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_GEORGIAN} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_GEORGIAN} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_GEORGIAN} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_GEORGIAN} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_GERMAN + ; Translation on 2019-03-29 done by: https://github.com/Tobias-B-Besemer + LangString MULTIUSER_PAGE_TITLE ${LANG_GERMAN} "Wähle Benutzer" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_GERMAN} "Wähle für welche Benutzer $(^NameDA) installiert werden soll." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_GERMAN} "Wähle für welche Benutzer $(^NameDA) entfernt werden soll." + LangString MULTIUSER_INSTALL_HEADER ${LANG_GERMAN} "Selektiere entweder $(^NameDA) zu installieren für alle Benutzer, oder für aktuellen Benutzer." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_GERMAN} "$(^NameDA) ist installiert für beides, für alle Benutzer und für aktuellen Benutzer.$\r$\nWähle, welche Installation entfernt werden soll." + LangString MULTIUSER_ALL_USERS ${LANG_GERMAN} "Für &jeden, der diesen Computer benutzt (alle Benutzer)$\r$\n(Hinweis: Das Installationsprogramm wird mit erhöhten Rechten neu gestartet)" + LangString MULTIUSER_CURRENT_USER ${LANG_GERMAN} "Für &mich ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_GERMAN} "Für jeden, der diesen Computer benutzt (alle Benutzer)$\r$\n(Hinweis: Das Installationsprogramm wird mit erhöhten Rechten neu gestartet)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_GERMAN} "Für mich ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_GERMAN} "Frische Installation für alle Benutzer." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_GERMAN} "Frische Installation für aktuellen Benutzer." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_GERMAN} "Version {VERSION} ist installiert für alle Benutzer in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_GERMAN} "Version {VERSION} ist installiert für aktuellen Benutzer in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_GERMAN} "Neuinstallation Version {VERSION} für alle Benutzer." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_GERMAN} "Neuinstallation Version {VERSION} für aktuellen Benutzer." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_GERMAN} "Deinstallation Version {OLD_VERSION} und Installation Version {VERSION} für alle Benutzer." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_GERMAN} "Deinstallation Version {OLD_VERSION} und Installation Version {VERSION} für aktuellen Benutzer." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_GERMAN} "Du musst dieses Programm als Administrator ausführen." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_GERMAN} "Administrator Anmeldedaten benötigt." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_GERMAN} "Administrator Anmeldedaten benötigt für Deinstallation." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_GERMAN} "Unzulässige Kombination von Parametern." + LangString MULTIUSER_NOT_INSTALLED ${LANG_GERMAN} "Dort ist keine Installation von $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_GERMAN} "Das Betriebssystem unterstützt nicht Aktuelle-Benutzer-Installationen." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_GERMAN} "Du musst Dich mit einem Konto, dass ein Mitglied der Administratoren Gruppe ist, anmelden um fortzufahren." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_GERMAN} "Das Betriebssystem unterstützt nicht Hochstuffung." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_GERMAN} "Hochstuffung nicht möglich, zweiter Anmelde-Service läuft nicht." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_GERMAN} "Hochstuffung nicht möglich, Fehler {ERROR}." +!endif + +!ifdef LANG_GREEK + LangString MULTIUSER_PAGE_TITLE ${LANG_GREEK} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_GREEK} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_GREEK} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_GREEK} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_GREEK} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_GREEK} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_GREEK} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_GREEK} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_GREEK} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_GREEK} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_GREEK} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_GREEK} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_GREEK} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_GREEK} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_GREEK} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_GREEK} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_GREEK} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_GREEK} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_GREEK} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_GREEK} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_GREEK} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_GREEK} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_GREEK} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_GREEK} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_GREEK} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_GREEK} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_GREEK} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_HEBREW + LangString MULTIUSER_PAGE_TITLE ${LANG_HEBREW} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_HEBREW} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_HEBREW} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_HEBREW} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_HEBREW} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_HEBREW} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_HEBREW} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_HEBREW} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_HEBREW} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_HEBREW} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_HEBREW} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_HEBREW} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_HEBREW} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_HEBREW} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_HEBREW} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_HEBREW} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_HEBREW} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_HEBREW} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_HEBREW} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_HEBREW} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_HEBREW} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_HEBREW} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_HEBREW} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_HEBREW} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_HEBREW} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_HEBREW} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_HEBREW} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_HUNGARIAN + LangString MULTIUSER_PAGE_TITLE ${LANG_HUNGARIAN} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_HUNGARIAN} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_HUNGARIAN} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_HUNGARIAN} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_HUNGARIAN} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_HUNGARIAN} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_HUNGARIAN} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_HUNGARIAN} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_HUNGARIAN} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_HUNGARIAN} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_HUNGARIAN} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_HUNGARIAN} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_HUNGARIAN} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_HUNGARIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_HUNGARIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_HUNGARIAN} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_HUNGARIAN} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_HUNGARIAN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_HUNGARIAN} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_HUNGARIAN} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_HUNGARIAN} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_HUNGARIAN} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_HUNGARIAN} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_HUNGARIAN} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_HUNGARIAN} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_ICELANDIC + LangString MULTIUSER_PAGE_TITLE ${LANG_ICELANDIC} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_ICELANDIC} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_ICELANDIC} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_ICELANDIC} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_ICELANDIC} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_ICELANDIC} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_ICELANDIC} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_ICELANDIC} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_ICELANDIC} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_ICELANDIC} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_ICELANDIC} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_ICELANDIC} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_ICELANDIC} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_ICELANDIC} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_ICELANDIC} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_ICELANDIC} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_ICELANDIC} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_ICELANDIC} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_ICELANDIC} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_ICELANDIC} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_ICELANDIC} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_ICELANDIC} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_ICELANDIC} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_ICELANDIC} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_ICELANDIC} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_ICELANDIC} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_ICELANDIC} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_INDONESIAN + LangString MULTIUSER_PAGE_TITLE ${LANG_INDONESIAN} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_INDONESIAN} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_INDONESIAN} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_INDONESIAN} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_INDONESIAN} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_INDONESIAN} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_INDONESIAN} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_INDONESIAN} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_INDONESIAN} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_INDONESIAN} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_INDONESIAN} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_INDONESIAN} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_INDONESIAN} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_INDONESIAN} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_INDONESIAN} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_INDONESIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_INDONESIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_INDONESIAN} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_INDONESIAN} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_INDONESIAN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_INDONESIAN} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_INDONESIAN} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_INDONESIAN} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_INDONESIAN} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_INDONESIAN} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_INDONESIAN} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_INDONESIAN} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_IRISH + LangString MULTIUSER_PAGE_TITLE ${LANG_IRISH} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_IRISH} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_IRISH} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_IRISH} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_IRISH} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_IRISH} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_IRISH} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_IRISH} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_IRISH} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_IRISH} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_IRISH} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_IRISH} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_IRISH} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_IRISH} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_IRISH} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_IRISH} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_IRISH} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_IRISH} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_IRISH} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_IRISH} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_IRISH} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_IRISH} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_IRISH} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_IRISH} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_IRISH} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_IRISH} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_IRISH} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_ITALIAN + LangString MULTIUSER_PAGE_TITLE ${LANG_ITALIAN} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_ITALIAN} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_ITALIAN} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_ITALIAN} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_ITALIAN} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_ITALIAN} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_ITALIAN} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_ITALIAN} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_ITALIAN} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_ITALIAN} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_ITALIAN} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_ITALIAN} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_ITALIAN} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_ITALIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_ITALIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_ITALIAN} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_ITALIAN} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_ITALIAN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_ITALIAN} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_ITALIAN} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_ITALIAN} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_ITALIAN} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_ITALIAN} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_ITALIAN} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_ITALIAN} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_JAPANESE + LangString MULTIUSER_PAGE_TITLE ${LANG_JAPANESE} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_JAPANESE} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_JAPANESE} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_JAPANESE} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_JAPANESE} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_JAPANESE} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_JAPANESE} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_JAPANESE} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_JAPANESE} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_JAPANESE} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_JAPANESE} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_JAPANESE} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_JAPANESE} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_JAPANESE} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_JAPANESE} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_JAPANESE} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_JAPANESE} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_JAPANESE} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_JAPANESE} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_JAPANESE} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_JAPANESE} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_JAPANESE} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_JAPANESE} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_JAPANESE} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_JAPANESE} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_JAPANESE} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_JAPANESE} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_KOREAN + LangString MULTIUSER_PAGE_TITLE ${LANG_KOREAN} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_KOREAN} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_KOREAN} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_KOREAN} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_KOREAN} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_KOREAN} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_KOREAN} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_KOREAN} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_KOREAN} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_KOREAN} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_KOREAN} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_KOREAN} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_KOREAN} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_KOREAN} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_KOREAN} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_KOREAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_KOREAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_KOREAN} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_KOREAN} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_KOREAN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_KOREAN} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_KOREAN} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_KOREAN} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_KOREAN} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_KOREAN} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_KOREAN} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_KOREAN} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_KURDISH + LangString MULTIUSER_PAGE_TITLE ${LANG_KURDISH} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_KURDISH} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_KURDISH} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_KURDISH} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_KURDISH} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_KURDISH} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_KURDISH} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_KURDISH} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_KURDISH} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_KURDISH} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_KURDISH} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_KURDISH} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_KURDISH} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_KURDISH} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_KURDISH} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_KURDISH} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_KURDISH} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_KURDISH} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_KURDISH} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_KURDISH} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_KURDISH} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_KURDISH} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_KURDISH} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_KURDISH} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_KURDISH} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_KURDISH} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_KURDISH} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_LATVIAN + LangString MULTIUSER_PAGE_TITLE ${LANG_LATVIAN} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_LATVIAN} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_LATVIAN} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_LATVIAN} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_LATVIAN} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_LATVIAN} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_LATVIAN} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_LATVIAN} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_LATVIAN} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_LATVIAN} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_LATVIAN} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_LATVIAN} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_LATVIAN} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_LATVIAN} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_LATVIAN} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_LATVIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_LATVIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_LATVIAN} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_LATVIAN} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_LATVIAN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_LATVIAN} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_LATVIAN} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_LATVIAN} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_LATVIAN} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_LATVIAN} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_LATVIAN} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_LATVIAN} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_LITHUANIAN + LangString MULTIUSER_PAGE_TITLE ${LANG_LITHUANIAN} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_LITHUANIAN} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_LITHUANIAN} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_LITHUANIAN} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_LITHUANIAN} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_LITHUANIAN} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_LITHUANIAN} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_LITHUANIAN} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_LITHUANIAN} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_LITHUANIAN} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_LITHUANIAN} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_LITHUANIAN} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_LITHUANIAN} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_LITHUANIAN} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_LITHUANIAN} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_LITHUANIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_LITHUANIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_LITHUANIAN} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_LITHUANIAN} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_LITHUANIAN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_LITHUANIAN} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_LITHUANIAN} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_LITHUANIAN} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_LITHUANIAN} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_LITHUANIAN} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_LITHUANIAN} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_LITHUANIAN} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_LUXEMBOURGISH + LangString MULTIUSER_PAGE_TITLE ${LANG_LUXEMBOURGISH} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_LUXEMBOURGISH} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_LUXEMBOURGISH} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_LUXEMBOURGISH} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_LUXEMBOURGISH} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_LUXEMBOURGISH} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_LUXEMBOURGISH} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_LUXEMBOURGISH} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_LUXEMBOURGISH} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_LUXEMBOURGISH} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_LUXEMBOURGISH} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_LUXEMBOURGISH} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_LUXEMBOURGISH} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_LUXEMBOURGISH} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_LUXEMBOURGISH} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_LUXEMBOURGISH} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_LUXEMBOURGISH} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_LUXEMBOURGISH} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_LUXEMBOURGISH} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_LUXEMBOURGISH} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_LUXEMBOURGISH} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_LUXEMBOURGISH} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_LUXEMBOURGISH} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_LUXEMBOURGISH} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_LUXEMBOURGISH} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_LUXEMBOURGISH} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_LUXEMBOURGISH} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_MACEDONIAN + LangString MULTIUSER_PAGE_TITLE ${LANG_MACEDONIAN} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_MACEDONIAN} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_MACEDONIAN} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_MACEDONIAN} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_MACEDONIAN} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_MACEDONIAN} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_MACEDONIAN} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_MACEDONIAN} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_MACEDONIAN} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_MACEDONIAN} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_MACEDONIAN} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_MACEDONIAN} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_MACEDONIAN} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_MACEDONIAN} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_MACEDONIAN} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_MACEDONIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_MACEDONIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_MACEDONIAN} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_MACEDONIAN} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_MACEDONIAN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_MACEDONIAN} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_MACEDONIAN} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_MACEDONIAN} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_MACEDONIAN} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_MACEDONIAN} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_MACEDONIAN} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_MACEDONIAN} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_MALAY + LangString MULTIUSER_PAGE_TITLE ${LANG_MALAY} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_MALAY} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_MALAY} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_MALAY} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_MALAY} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_MALAY} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_MALAY} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_MALAY} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_MALAY} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_MALAY} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_MALAY} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_MALAY} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_MALAY} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_MALAY} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_MALAY} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_MALAY} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_MALAY} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_MALAY} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_MALAY} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_MALAY} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_MALAY} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_MALAY} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_MALAY} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_MALAY} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_MALAY} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_MALAY} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_MALAY} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_MONGOLIAN + LangString MULTIUSER_PAGE_TITLE ${LANG_MONGOLIAN} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_MONGOLIAN} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_MONGOLIAN} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_MONGOLIAN} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_MONGOLIAN} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_MONGOLIAN} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_MONGOLIAN} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_MONGOLIAN} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_MONGOLIAN} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_MONGOLIAN} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_MONGOLIAN} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_MONGOLIAN} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_MONGOLIAN} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_MONGOLIAN} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_MONGOLIAN} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_MONGOLIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_MONGOLIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_MONGOLIAN} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_MONGOLIAN} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_MONGOLIAN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_MONGOLIAN} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_MONGOLIAN} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_MONGOLIAN} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_MONGOLIAN} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_MONGOLIAN} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_MONGOLIAN} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_MONGOLIAN} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_NORWEGIAN + LangString MULTIUSER_PAGE_TITLE ${LANG_NORWEGIAN} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_NORWEGIAN} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_NORWEGIAN} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_NORWEGIAN} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_NORWEGIAN} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_NORWEGIAN} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_NORWEGIAN} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_NORWEGIAN} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_NORWEGIAN} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_NORWEGIAN} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_NORWEGIAN} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_NORWEGIAN} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_NORWEGIAN} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_NORWEGIAN} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_NORWEGIAN} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_NORWEGIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_NORWEGIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_NORWEGIAN} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_NORWEGIAN} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_NORWEGIAN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_NORWEGIAN} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_NORWEGIAN} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_NORWEGIAN} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_NORWEGIAN} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_NORWEGIAN} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_NORWEGIAN} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_NORWEGIAN} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_NORWEGIANNYNORSK + LangString MULTIUSER_PAGE_TITLE ${LANG_NORWEGIANNYNORSK} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_NORWEGIANNYNORSK} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_NORWEGIANNYNORSK} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_NORWEGIANNYNORSK} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_NORWEGIANNYNORSK} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_NORWEGIANNYNORSK} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_NORWEGIANNYNORSK} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_NORWEGIANNYNORSK} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_NORWEGIANNYNORSK} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_NORWEGIANNYNORSK} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_NORWEGIANNYNORSK} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_NORWEGIANNYNORSK} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_NORWEGIANNYNORSK} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_NORWEGIANNYNORSK} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_NORWEGIANNYNORSK} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_NORWEGIANNYNORSK} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_NORWEGIANNYNORSK} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_NORWEGIANNYNORSK} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_NORWEGIANNYNORSK} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_NORWEGIANNYNORSK} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_NORWEGIANNYNORSK} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_NORWEGIANNYNORSK} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_NORWEGIANNYNORSK} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_NORWEGIANNYNORSK} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_NORWEGIANNYNORSK} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_NORWEGIANNYNORSK} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_NORWEGIANNYNORSK} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_PASHTO + LangString MULTIUSER_PAGE_TITLE ${LANG_PASHTO} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_PASHTO} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_PASHTO} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_PASHTO} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_PASHTO} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_PASHTO} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_PASHTO} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_PASHTO} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_PASHTO} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_PASHTO} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_PASHTO} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_PASHTO} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_PASHTO} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_PASHTO} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_PASHTO} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_PASHTO} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_PASHTO} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_PASHTO} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_PASHTO} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_PASHTO} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_PASHTO} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_PASHTO} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_PASHTO} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_PASHTO} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_PASHTO} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_PASHTO} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_PASHTO} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_POLISH + LangString MULTIUSER_PAGE_TITLE ${LANG_POLISH} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_POLISH} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_POLISH} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_POLISH} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_POLISH} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_POLISH} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_POLISH} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_POLISH} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_POLISH} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_POLISH} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_POLISH} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_POLISH} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_POLISH} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_POLISH} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_POLISH} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_POLISH} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_POLISH} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_POLISH} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_POLISH} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_POLISH} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_POLISH} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_POLISH} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_POLISH} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_POLISH} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_POLISH} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_POLISH} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_POLISH} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_PORTUGUESE + LangString MULTIUSER_PAGE_TITLE ${LANG_PORTUGUESE} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_PORTUGUESE} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_PORTUGUESE} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_PORTUGUESE} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_PORTUGUESE} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_PORTUGUESE} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_PORTUGUESE} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_PORTUGUESE} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_PORTUGUESE} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_PORTUGUESE} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_PORTUGUESE} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_PORTUGUESE} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_PORTUGUESE} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_PORTUGUESE} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_PORTUGUESE} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_PORTUGUESE} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_PORTUGUESE} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_PORTUGUESE} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_PORTUGUESE} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_PORTUGUESE} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_PORTUGUESE} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_PORTUGUESE} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_PORTUGUESE} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_PORTUGUESE} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_PORTUGUESE} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_PORTUGUESE} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_PORTUGUESE} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_PORTUGUESEBR + LangString MULTIUSER_PAGE_TITLE ${LANG_PORTUGUESEBR} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_PORTUGUESEBR} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_PORTUGUESEBR} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_PORTUGUESEBR} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_PORTUGUESEBR} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_PORTUGUESEBR} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_PORTUGUESEBR} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_PORTUGUESEBR} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_PORTUGUESEBR} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_PORTUGUESEBR} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_PORTUGUESEBR} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_PORTUGUESEBR} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_PORTUGUESEBR} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_PORTUGUESEBR} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_PORTUGUESEBR} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_PORTUGUESEBR} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_PORTUGUESEBR} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_PORTUGUESEBR} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_PORTUGUESEBR} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_PORTUGUESEBR} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_PORTUGUESEBR} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_PORTUGUESEBR} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_PORTUGUESEBR} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_PORTUGUESEBR} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_PORTUGUESEBR} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_PORTUGUESEBR} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_PORTUGUESEBR} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_ROMANIAN + LangString MULTIUSER_PAGE_TITLE ${LANG_ROMANIAN} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_ROMANIAN} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_ROMANIAN} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_ROMANIAN} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_ROMANIAN} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_ROMANIAN} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_ROMANIAN} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_ROMANIAN} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_ROMANIAN} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_ROMANIAN} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_ROMANIAN} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_ROMANIAN} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_ROMANIAN} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_ROMANIAN} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_ROMANIAN} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_ROMANIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_ROMANIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_ROMANIAN} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_ROMANIAN} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_ROMANIAN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_ROMANIAN} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_ROMANIAN} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_ROMANIAN} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_ROMANIAN} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_ROMANIAN} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_ROMANIAN} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_ROMANIAN} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_RUSSIAN + LangString MULTIUSER_PAGE_TITLE ${LANG_RUSSIAN} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_RUSSIAN} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_RUSSIAN} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_RUSSIAN} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_RUSSIAN} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_RUSSIAN} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_RUSSIAN} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_RUSSIAN} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_RUSSIAN} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_RUSSIAN} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_RUSSIAN} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_RUSSIAN} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_RUSSIAN} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_RUSSIAN} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_RUSSIAN} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_RUSSIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_RUSSIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_RUSSIAN} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_RUSSIAN} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_RUSSIAN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_RUSSIAN} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_RUSSIAN} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_RUSSIAN} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_RUSSIAN} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_RUSSIAN} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_RUSSIAN} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_RUSSIAN} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_SCOTSGAELIC + LangString MULTIUSER_PAGE_TITLE ${LANG_SCOTSGAELIC} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_SCOTSGAELIC} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_SCOTSGAELIC} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_SCOTSGAELIC} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_SCOTSGAELIC} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_SCOTSGAELIC} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_SCOTSGAELIC} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_SCOTSGAELIC} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_SCOTSGAELIC} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_SCOTSGAELIC} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_SCOTSGAELIC} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_SCOTSGAELIC} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_SCOTSGAELIC} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_SCOTSGAELIC} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_SCOTSGAELIC} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_SCOTSGAELIC} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_SCOTSGAELIC} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_SCOTSGAELIC} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_SCOTSGAELIC} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_SCOTSGAELIC} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_SCOTSGAELIC} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_SCOTSGAELIC} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_SCOTSGAELIC} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_SCOTSGAELIC} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_SCOTSGAELIC} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_SERBIAN + LangString MULTIUSER_PAGE_TITLE ${LANG_SERBIAN} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_SERBIAN} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_SERBIAN} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_SERBIAN} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_SERBIAN} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_SERBIAN} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_SERBIAN} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_SERBIAN} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_SERBIAN} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_SERBIAN} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_SERBIAN} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_SERBIAN} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_SERBIAN} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_SERBIAN} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_SERBIAN} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_SERBIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_SERBIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_SERBIAN} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_SERBIAN} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_SERBIAN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_SERBIAN} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_SERBIAN} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_SERBIAN} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_SERBIAN} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_SERBIAN} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_SERBIAN} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_SERBIAN} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_SERBIANLATIN + LangString MULTIUSER_PAGE_TITLE ${LANG_SERBIANLATIN} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_SERBIANLATIN} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_SERBIANLATIN} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_SERBIANLATIN} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_SERBIANLATIN} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_SERBIANLATIN} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_SERBIANLATIN} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_SERBIANLATIN} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_SERBIANLATIN} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_SERBIANLATIN} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_SERBIANLATIN} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_SERBIANLATIN} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_SERBIANLATIN} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_SERBIANLATIN} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_SERBIANLATIN} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_SERBIANLATIN} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_SERBIANLATIN} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_SERBIANLATIN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_SERBIANLATIN} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_SERBIANLATIN} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_SERBIANLATIN} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_SERBIANLATIN} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_SERBIANLATIN} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_SERBIANLATIN} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_SERBIANLATIN} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_SIMPCHINESE + LangString MULTIUSER_PAGE_TITLE ${LANG_SIMPCHINESE} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_SIMPCHINESE} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_SIMPCHINESE} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_SIMPCHINESE} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_SIMPCHINESE} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_SIMPCHINESE} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_SIMPCHINESE} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_SIMPCHINESE} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_SIMPCHINESE} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_SIMPCHINESE} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_SIMPCHINESE} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_SIMPCHINESE} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_SIMPCHINESE} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_SIMPCHINESE} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_SIMPCHINESE} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_SIMPCHINESE} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_SIMPCHINESE} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_SIMPCHINESE} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_SIMPCHINESE} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_SIMPCHINESE} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_SIMPCHINESE} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_SIMPCHINESE} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_SIMPCHINESE} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_SIMPCHINESE} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_SIMPCHINESE} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_SIMPCHINESE} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_SIMPCHINESE} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_SLOVAK + LangString MULTIUSER_PAGE_TITLE ${LANG_SLOVAK} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_SLOVAK} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_SLOVAK} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_SLOVAK} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_SLOVAK} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_SLOVAK} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_SLOVAK} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_SLOVAK} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_SLOVAK} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_SLOVAK} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_SLOVAK} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_SLOVAK} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_SLOVAK} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_SLOVAK} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_SLOVAK} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_SLOVAK} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_SLOVAK} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_SLOVAK} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_SLOVAK} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_SLOVAK} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_SLOVAK} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_SLOVAK} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_SLOVAK} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_SLOVAK} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_SLOVAK} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_SLOVAK} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_SLOVAK} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_SLOVENIAN + LangString MULTIUSER_PAGE_TITLE ${LANG_SLOVENIAN} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_SLOVENIAN} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_SLOVENIAN} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_SLOVENIAN} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_SLOVENIAN} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_SLOVENIAN} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_SLOVENIAN} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_SLOVENIAN} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_SLOVENIAN} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_SLOVENIAN} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_SLOVENIAN} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_SLOVENIAN} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_SLOVENIAN} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_SLOVENIAN} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_SLOVENIAN} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_SLOVENIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_SLOVENIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_SLOVENIAN} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_SLOVENIAN} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_SLOVENIAN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_SLOVENIAN} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_SLOVENIAN} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_SLOVENIAN} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_SLOVENIAN} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_SLOVENIAN} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_SLOVENIAN} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_SLOVENIAN} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_SPANISH + LangString MULTIUSER_PAGE_TITLE ${LANG_SPANISH} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_SPANISH} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_SPANISH} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_SPANISH} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_SPANISH} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_SPANISH} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_SPANISH} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_SPANISH} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_SPANISH} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_SPANISH} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_SPANISH} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_SPANISH} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_SPANISH} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_SPANISH} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_SPANISH} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_SPANISH} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_SPANISH} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_SPANISH} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_SPANISH} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_SPANISH} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_SPANISH} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_SPANISH} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_SPANISH} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_SPANISH} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_SPANISH} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_SPANISH} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_SPANISH} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_SPANISHINTERNATIONAL + LangString MULTIUSER_PAGE_TITLE ${LANG_SPANISHINTERNATIONAL} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_SPANISHINTERNATIONAL} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_SPANISHINTERNATIONAL} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_SPANISHINTERNATIONAL} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_SPANISHINTERNATIONAL} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_SPANISHINTERNATIONAL} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_SPANISHINTERNATIONAL} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_SPANISHINTERNATIONAL} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_SPANISHINTERNATIONAL} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_SPANISHINTERNATIONAL} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_SPANISHINTERNATIONAL} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_SPANISHINTERNATIONAL} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_SPANISHINTERNATIONAL} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_SPANISHINTERNATIONAL} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_SPANISHINTERNATIONAL} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_SPANISHINTERNATIONAL} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_SPANISHINTERNATIONAL} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_SPANISHINTERNATIONAL} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_SPANISHINTERNATIONAL} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_SPANISHINTERNATIONAL} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_SPANISHINTERNATIONAL} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_SPANISHINTERNATIONAL} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_SPANISHINTERNATIONAL} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_SPANISHINTERNATIONAL} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_SPANISHINTERNATIONAL} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_SPANISHINTERNATIONAL} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_SPANISHINTERNATIONAL} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_SWEDISH + LangString MULTIUSER_PAGE_TITLE ${LANG_SWEDISH} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_SWEDISH} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_SWEDISH} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_SWEDISH} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_SWEDISH} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_SWEDISH} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_SWEDISH} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_SWEDISH} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_SWEDISH} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_SWEDISH} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_SWEDISH} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_SWEDISH} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_SWEDISH} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_SWEDISH} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_SWEDISH} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_SWEDISH} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_SWEDISH} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_SWEDISH} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_SWEDISH} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_SWEDISH} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_SWEDISH} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_SWEDISH} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_SWEDISH} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_SWEDISH} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_SWEDISH} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_SWEDISH} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_SWEDISH} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_TATAR + LangString MULTIUSER_PAGE_TITLE ${LANG_TATAR} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_TATAR} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_TATAR} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_TATAR} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_TATAR} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_TATAR} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_TATAR} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_TATAR} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_TATAR} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_TATAR} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_TATAR} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_TATAR} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_TATAR} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_TATAR} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_TATAR} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_TATAR} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_TATAR} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_TATAR} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_TATAR} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_TATAR} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_TATAR} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_TATAR} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_TATAR} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_TATAR} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_TATAR} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_TATAR} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_TATAR} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_THAI + LangString MULTIUSER_PAGE_TITLE ${LANG_THAI} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_THAI} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_THAI} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_THAI} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_THAI} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_THAI} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_THAI} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_THAI} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_THAI} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_THAI} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_THAI} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_THAI} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_THAI} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_THAI} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_THAI} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_THAI} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_THAI} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_THAI} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_THAI} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_THAI} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_THAI} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_THAI} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_THAI} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_THAI} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_THAI} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_THAI} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_THAI} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_TRADCHINESE + LangString MULTIUSER_PAGE_TITLE ${LANG_TRADCHINESE} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_TRADCHINESE} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_TRADCHINESE} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_TRADCHINESE} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_TRADCHINESE} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_TRADCHINESE} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_TRADCHINESE} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_TRADCHINESE} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_TRADCHINESE} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_TRADCHINESE} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_TRADCHINESE} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_TRADCHINESE} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_TRADCHINESE} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_TRADCHINESE} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_TRADCHINESE} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_TRADCHINESE} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_TRADCHINESE} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_TRADCHINESE} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_TRADCHINESE} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_TRADCHINESE} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_TRADCHINESE} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_TRADCHINESE} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_TRADCHINESE} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_TRADCHINESE} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_TRADCHINESE} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_TRADCHINESE} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_TRADCHINESE} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_TURKISH + LangString MULTIUSER_PAGE_TITLE ${LANG_TURKISH} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_TURKISH} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_TURKISH} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_TURKISH} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_TURKISH} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_TURKISH} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_TURKISH} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_TURKISH} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_TURKISH} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_TURKISH} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_TURKISH} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_TURKISH} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_TURKISH} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_TURKISH} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_TURKISH} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_TURKISH} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_TURKISH} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_TURKISH} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_TURKISH} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_TURKISH} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_TURKISH} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_TURKISH} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_TURKISH} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_TURKISH} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_TURKISH} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_TURKISH} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_TURKISH} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_UKRAINIAN + LangString MULTIUSER_PAGE_TITLE ${LANG_UKRAINIAN} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_UKRAINIAN} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_UKRAINIAN} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_UKRAINIAN} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_UKRAINIAN} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_UKRAINIAN} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_UKRAINIAN} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_UKRAINIAN} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_UKRAINIAN} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_UKRAINIAN} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_UKRAINIAN} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_UKRAINIAN} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_UKRAINIAN} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_UKRAINIAN} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_UKRAINIAN} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_UKRAINIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_UKRAINIAN} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_UKRAINIAN} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_UKRAINIAN} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_UKRAINIAN} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_UKRAINIAN} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_UKRAINIAN} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_UKRAINIAN} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_UKRAINIAN} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_UKRAINIAN} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_UKRAINIAN} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_UKRAINIAN} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_UZBEK + LangString MULTIUSER_PAGE_TITLE ${LANG_UZBEK} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_UZBEK} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_UZBEK} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_UZBEK} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_UZBEK} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_UZBEK} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_UZBEK} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_UZBEK} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_UZBEK} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_UZBEK} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_UZBEK} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_UZBEK} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_UZBEK} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_UZBEK} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_UZBEK} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_UZBEK} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_UZBEK} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_UZBEK} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_UZBEK} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_UZBEK} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_UZBEK} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_UZBEK} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_UZBEK} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_UZBEK} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_UZBEK} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_UZBEK} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_UZBEK} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_VIETNAMESE + LangString MULTIUSER_PAGE_TITLE ${LANG_VIETNAMESE} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_VIETNAMESE} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_VIETNAMESE} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_VIETNAMESE} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_VIETNAMESE} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_VIETNAMESE} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_VIETNAMESE} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_VIETNAMESE} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_VIETNAMESE} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_VIETNAMESE} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_VIETNAMESE} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_VIETNAMESE} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_VIETNAMESE} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_VIETNAMESE} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_VIETNAMESE} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_VIETNAMESE} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_VIETNAMESE} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_VIETNAMESE} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_VIETNAMESE} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_VIETNAMESE} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_VIETNAMESE} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_VIETNAMESE} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_VIETNAMESE} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_VIETNAMESE} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_VIETNAMESE} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_VIETNAMESE} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_VIETNAMESE} "Unable to elevate, error {ERROR}." +!endif + +!ifdef LANG_WELSH + LangString MULTIUSER_PAGE_TITLE ${LANG_WELSH} "Choose Users" + LangString MULTIUSER_INSTALL_PAGE_SUBTITLE ${LANG_WELSH} "Choose for which users to install $(^NameDA)." + LangString MULTIUSER_UNINSTALL_PAGE_SUBTITLE ${LANG_WELSH} "Choose for which users to remove $(^NameDA)." + LangString MULTIUSER_INSTALL_HEADER ${LANG_WELSH} "Select whether to install $(^NameDA) for all users or for current user." + LangString MULTIUSER_UNINSTALL_HEADER ${LANG_WELSH} "$(^NameDA) is installed both for all users and for current user.$\r$\nSelect which installation to remove." + LangString MULTIUSER_ALL_USERS ${LANG_WELSH} "For &anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER ${LANG_WELSH} "For &me ({USER})" + LangString MULTIUSER_ALL_USERS_UMUI ${LANG_WELSH} "For anyone who uses this computer (all users)$\r$\n(Note: The installer will restart with elevated privileges)" + LangString MULTIUSER_CURRENT_USER_UMUI ${LANG_WELSH} "For me ({USER})" + LangString MULTIUSER_NEW_INSTALLATION_ALL_USERS ${LANG_WELSH} "Fresh install for all users." + LangString MULTIUSER_NEW_INSTALLATION_CURRENT_USER ${LANG_WELSH} "Fresh install for current user." + LangString MULTIUSER_INSTALLED_ALL_USERS ${LANG_WELSH} "Version {VERSION} is installed for all users in $\"{FOLDER}$\"." + LangString MULTIUSER_INSTALLED_CURRENT_USER ${LANG_WELSH} "Version {VERSION} is installed for current user in $\"{FOLDER}$\"." + LangString MULTIUSER_REINSTALL_SAME_VERSION_ALL_USERS ${LANG_WELSH} "Reinstall version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_SAME_VERSION_CURRENT_USER ${LANG_WELSH} "Reinstall version {VERSION} for current user." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_ALL_USERS ${LANG_WELSH} "Uninstall version {OLD_VERSION} and install version {VERSION} for all users." + LangString MULTIUSER_REINSTALL_DIFF_VERSION_CURRENT_USER ${LANG_WELSH} "Uninstall version {OLD_VERSION} and install version {VERSION} for current user." + LangString MULTIUSER_RUN_AS_ADMIN ${LANG_WELSH} "You need to run this program as administrator." + LangString MULTIUSER_ADMIN_CREDENTIALS_REQUIRED ${LANG_WELSH} "Administrator credentials required." + LangString MULTIUSER_ADMIN_UNINSTALL_CREDENTIALS_REQUIRED ${LANG_WELSH} "Administrator credentials required for uninstall." + ; error messages - not so important + LangString MULTIUSER_INVALID_PARAMS ${LANG_WELSH} "Invalid combination of paramaters." + LangString MULTIUSER_NOT_INSTALLED ${LANG_WELSH} "There is no installation of $(^NameDA)." + LangString MULTIUSER_INSTALLATION_FOR_CURRENT_USER_NOT_SUPPORTED ${LANG_WELSH} "The operating system doesn't support current user installations." + LangString MULTIUSER_ADMIN_ACCOUNT_LOGIN_REQUIRED ${LANG_WELSH} "You need to login with an account that is a member of the administrators group to continue." + LangString MULTIUSER_ELEVATION_NOT_SUPPORTED ${LANG_WELSH} "The operating system doesn't support elevation." + LangString MULTIUSER_LOGON_SERVICE_NOT_RUNNING ${LANG_WELSH} "Unable to elevate, Secondary Logon service not running." + LangString MULTIUSER_ELEVATION_ERROR ${LANG_WELSH} "Unable to elevate, error {ERROR}." +!endif diff --git a/cmake/Windows/Include/StdUtils.nsh b/cmake/Windows/Include/StdUtils.nsh new file mode 100644 index 000000000..537655da5 --- /dev/null +++ b/cmake/Windows/Include/StdUtils.nsh @@ -0,0 +1,501 @@ +################################################################################# +# StdUtils plug-in for NSIS +# Copyright (C) 2004-2018 LoRd_MuldeR +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# +# http://www.gnu.org/licenses/lgpl-2.1.txt +################################################################################# + +# DEVELOPER NOTES: +# - Please see "https://github.com/lordmulder/stdutils/" for news and updates! +# - Please see "Docs\StdUtils\StdUtils.html" for detailed function descriptions! +# - Please see "Examples\StdUtils\StdUtilsTest.nsi" for usage examples! + +################################################################################# +# FUNCTION DECLARTIONS +################################################################################# + +!ifndef ___STDUTILS__NSH___ +!define ___STDUTILS__NSH___ + +!define StdUtils.Time '!insertmacro _StdU_Time' #time(), as in C standard library +!define StdUtils.GetMinutes '!insertmacro _StdU_GetMinutes' #GetSystemTimeAsFileTime(), returns the number of minutes +!define StdUtils.GetHours '!insertmacro _StdU_GetHours' #GetSystemTimeAsFileTime(), returns the number of hours +!define StdUtils.GetDays '!insertmacro _StdU_GetDays' #GetSystemTimeAsFileTime(), returns the number of days +!define StdUtils.Rand '!insertmacro _StdU_Rand' #rand(), as in C standard library +!define StdUtils.RandMax '!insertmacro _StdU_RandMax' #rand(), as in C standard library, with maximum value +!define StdUtils.RandMinMax '!insertmacro _StdU_RandMinMax' #rand(), as in C standard library, with minimum/maximum value +!define StdUtils.RandList '!insertmacro _StdU_RandList' #rand(), as in C standard library, with list support +!define StdUtils.RandBytes '!insertmacro _StdU_RandBytes' #Generates random bytes, returned as Base64-encoded string +!define StdUtils.FormatStr '!insertmacro _StdU_FormatStr' #sprintf(), as in C standard library, one '%d' placeholder +!define StdUtils.FormatStr2 '!insertmacro _StdU_FormatStr2' #sprintf(), as in C standard library, two '%d' placeholders +!define StdUtils.FormatStr3 '!insertmacro _StdU_FormatStr3' #sprintf(), as in C standard library, three '%d' placeholders +!define StdUtils.ScanStr '!insertmacro _StdU_ScanStr' #sscanf(), as in C standard library, one '%d' placeholder +!define StdUtils.ScanStr2 '!insertmacro _StdU_ScanStr2' #sscanf(), as in C standard library, two '%d' placeholders +!define StdUtils.ScanStr3 '!insertmacro _StdU_ScanStr3' #sscanf(), as in C standard library, three '%d' placeholders +!define StdUtils.TrimStr '!insertmacro _StdU_TrimStr' #Remove whitspaces from string, left and right +!define StdUtils.TrimStrLeft '!insertmacro _StdU_TrimStrLeft' #Remove whitspaces from string, left side only +!define StdUtils.TrimStrRight '!insertmacro _StdU_TrimStrRight' #Remove whitspaces from string, right side only +!define StdUtils.RevStr '!insertmacro _StdU_RevStr' #Reverse a string, e.g. "reverse me" <-> "em esrever" +!define StdUtils.ValidFileName '!insertmacro _StdU_ValidFileName' #Test whether string is a valid file name - no paths allowed +!define StdUtils.ValidPathSpec '!insertmacro _StdU_ValidPathSpec' #Test whether string is a valid full(!) path specification +!define StdUtils.ValidDomainName '!insertmacro _StdU_ValidDomain' #Test whether string is a valid host name or domain name +!define StdUtils.StrToUtf8 '!insertmacro _StdU_StrToUtf8' #Convert string from Unicode (UTF-16) or ANSI to UTF-8 bytes +!define StdUtils.StrFromUtf8 '!insertmacro _StdU_StrFromUtf8' #Convert string from UTF-8 bytes to Unicode (UTF-16) or ANSI +!define StdUtils.SHFileMove '!insertmacro _StdU_SHFileMove' #SHFileOperation(), using the FO_MOVE operation +!define StdUtils.SHFileCopy '!insertmacro _StdU_SHFileCopy' #SHFileOperation(), using the FO_COPY operation +!define StdUtils.AppendToFile '!insertmacro _StdU_AppendToFile' #Append contents of an existing file to another file +!define StdUtils.ExecShellAsUser '!insertmacro _StdU_ExecShlUser' #ShellExecute() as NON-elevated user from elevated installer +!define StdUtils.InvokeShellVerb '!insertmacro _StdU_InvkeShlVrb' #Invokes a "shell verb", e.g. for pinning items to the taskbar +!define StdUtils.ExecShellWaitEx '!insertmacro _StdU_ExecShlWaitEx' #ShellExecuteEx(), returns the handle of the new process +!define StdUtils.WaitForProcEx '!insertmacro _StdU_WaitForProcEx' #WaitForSingleObject(), e.g. to wait for a running process +!define StdUtils.GetParameter '!insertmacro _StdU_GetParameter' #Get the value of a specific command-line option +!define StdUtils.TestParameter '!insertmacro _StdU_TestParameter' #Test whether a specific command-line option has been set +!define StdUtils.ParameterCnt '!insertmacro _StdU_ParameterCnt' #Get number of command-line tokens, similar to argc in main() +!define StdUtils.ParameterStr '!insertmacro _StdU_ParameterStr' #Get the n-th command-line token, similar to argv[i] in main() +!define StdUtils.GetAllParameters '!insertmacro _StdU_GetAllParams' #Get complete command-line, but without executable name +!define StdUtils.GetRealOSVersion '!insertmacro _StdU_GetRealOSVer' #Get the *real* Windows version number, even on Windows 8.1+ +!define StdUtils.GetRealOSBuildNo '!insertmacro _StdU_GetRealOSBld' #Get the *real* Windows build number, even on Windows 8.1+ +!define StdUtils.GetRealOSName '!insertmacro _StdU_GetRealOSStr' #Get the *real* Windows version, as a "friendly" name +!define StdUtils.GetOSEdition '!insertmacro _StdU_GetOSEdition' #Get the Windows edition, i.e. "workstation" or "server" +!define StdUtils.GetOSReleaseId '!insertmacro _StdU_GetOSRelIdNo' #Get the Windows release identifier (on Windows 10) +!define StdUtils.GetOSReleaseName '!insertmacro _StdU_GetOSRelIdStr' #Get the Windows release (on Windows 10), as a "friendly" name +!define StdUtils.VerifyOSVersion '!insertmacro _StdU_VrfyRealOSVer' #Compare *real* operating system to an expected version number +!define StdUtils.VerifyOSBuildNo '!insertmacro _StdU_VrfyRealOSBld' #Compare *real* operating system to an expected build number +!define StdUtils.HashText '!insertmacro _StdU_HashText' #Compute hash from text string (CRC32, MD5, SHA1/2/3, BLAKE2) +!define StdUtils.HashFile '!insertmacro _StdU_HashFile' #Compute hash from file (CRC32, MD5, SHA1/2/3, BLAKE2) +!define StdUtils.NormalizePath '!insertmacro _StdU_NormalizePath' #Simplifies the path to produce a direct, well-formed path +!define StdUtils.GetParentPath '!insertmacro _StdU_GetParentPath' #Get parent path by removing the last component from the path +!define StdUtils.SplitPath '!insertmacro _StdU_SplitPath' #Split the components of the given path +!define StdUtils.GetDrivePart '!insertmacro _StdU_GetDrivePart' #Get drive component of path +!define StdUtils.GetDirectoryPart '!insertmacro _StdU_GetDirPart' #Get directory component of path +!define StdUtils.GetFileNamePart '!insertmacro _StdU_GetFNamePart' #Get file name component of path +!define StdUtils.GetExtensionPart '!insertmacro _StdU_GetExtnPart' #Get file extension component of path +!define StdUtils.TimerCreate '!insertmacro _StdU_TimerCreate' #Create a new event-timer that will be triggered periodically +!define StdUtils.TimerDestroy '!insertmacro _StdU_TimerDestroy' #Destroy a running timer created with TimerCreate() +!define StdUtils.ProtectStr '!insertmacro _StdU_PrtctStr' #Protect a given String using Windows' DPAPI +!define StdUtils.UnprotectStr '!insertmacro _StdU_UnprtctStr' #Unprotect a string that was protected via ProtectStr() +!define StdUtils.GetLibVersion '!insertmacro _StdU_GetLibVersion' #Get the current StdUtils library version (for debugging) +!define StdUtils.SetVerbose '!insertmacro _StdU_SetVerbose' #Enable or disable "verbose" mode (for debugging) + + +################################################################################# +# MACRO DEFINITIONS +################################################################################# + +!macro _StdU_Time out + StdUtils::Time /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_GetMinutes out + StdUtils::GetMinutes /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_GetHours out + StdUtils::GetHours /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_GetDays out + StdUtils::GetDays /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_Rand out + StdUtils::Rand /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_RandMax out max + push ${max} + StdUtils::RandMax /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_RandMinMax out min max + push ${min} + push ${max} + StdUtils::RandMinMax /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_RandList count max + push ${max} + push ${count} + StdUtils::RandList /NOUNLOAD +!macroend + +!macro _StdU_RandBytes out count + push ${count} + StdUtils::RandBytes /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_FormatStr out format val + push `${format}` + push ${val} + StdUtils::FormatStr /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_FormatStr2 out format val1 val2 + push `${format}` + push ${val1} + push ${val2} + StdUtils::FormatStr2 /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_FormatStr3 out format val1 val2 val3 + push `${format}` + push ${val1} + push ${val2} + push ${val3} + StdUtils::FormatStr3 /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_ScanStr out format input default + push `${format}` + push `${input}` + push ${default} + StdUtils::ScanStr /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_ScanStr2 out1 out2 format input default1 default2 + push `${format}` + push `${input}` + push ${default1} + push ${default2} + StdUtils::ScanStr2 /NOUNLOAD + pop ${out1} + pop ${out2} +!macroend + +!macro _StdU_ScanStr3 out1 out2 out3 format input default1 default2 default3 + push `${format}` + push `${input}` + push ${default1} + push ${default2} + push ${default3} + StdUtils::ScanStr3 /NOUNLOAD + pop ${out1} + pop ${out2} + pop ${out3} +!macroend + +!macro _StdU_TrimStr var + push ${var} + StdUtils::TrimStr /NOUNLOAD + pop ${var} +!macroend + +!macro _StdU_TrimStrLeft var + push ${var} + StdUtils::TrimStrLeft /NOUNLOAD + pop ${var} +!macroend + +!macro _StdU_TrimStrRight var + push ${var} + StdUtils::TrimStrRight /NOUNLOAD + pop ${var} +!macroend + +!macro _StdU_RevStr var + push ${var} + StdUtils::RevStr /NOUNLOAD + pop ${var} +!macroend + +!macro _StdU_ValidFileName out test + push `${test}` + StdUtils::ValidFileName /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_ValidPathSpec out test + push `${test}` + StdUtils::ValidPathSpec /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_ValidDomain out test + push `${test}` + StdUtils::ValidDomainName /NOUNLOAD + pop ${out} +!macroend + + +!macro _StdU_StrToUtf8 out str + push `${str}` + StdUtils::StrToUtf8 /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_StrFromUtf8 out trnc str + push ${trnc} + push `${str}` + StdUtils::StrFromUtf8 /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_SHFileMove out from to hwnd + push `${from}` + push `${to}` + push ${hwnd} + StdUtils::SHFileMove /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_SHFileCopy out from to hwnd + push `${from}` + push `${to}` + push ${hwnd} + StdUtils::SHFileCopy /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_AppendToFile out from dest offset maxlen + push `${from}` + push `${dest}` + push ${offset} + push ${maxlen} + StdUtils::AppendToFile /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_ExecShlUser out file verb args + push `${file}` + push `${verb}` + push `${args}` + StdUtils::ExecShellAsUser /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_InvkeShlVrb out path file verb_id + push "${path}" + push "${file}" + push ${verb_id} + StdUtils::InvokeShellVerb /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_ExecShlWaitEx out_res out_val file verb args + push `${file}` + push `${verb}` + push `${args}` + StdUtils::ExecShellWaitEx /NOUNLOAD + pop ${out_res} + pop ${out_val} +!macroend + +!macro _StdU_WaitForProcEx out handle + push `${handle}` + StdUtils::WaitForProcEx /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_GetParameter out name default + push `${name}` + push `${default}` + StdUtils::GetParameter /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_TestParameter out name + push `${name}` + StdUtils::TestParameter /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_ParameterCnt out + StdUtils::ParameterCnt /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_ParameterStr out index + push ${index} + StdUtils::ParameterStr /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_GetAllParams out truncate + push `${truncate}` + StdUtils::GetAllParameters /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_GetRealOSVer out_major out_minor out_spack + StdUtils::GetRealOsVersion /NOUNLOAD + pop ${out_major} + pop ${out_minor} + pop ${out_spack} +!macroend + +!macro _StdU_GetRealOSBld out + StdUtils::GetRealOsBuildNo /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_GetRealOSStr out + StdUtils::GetRealOsName /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_VrfyRealOSVer out major minor spack + push `${major}` + push `${minor}` + push `${spack}` + StdUtils::VerifyRealOsVersion /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_VrfyRealOSBld out build + push `${build}` + StdUtils::VerifyRealOsBuildNo /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_GetOSEdition out + StdUtils::GetOsEdition /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_GetOSRelIdNo out + StdUtils::GetOsReleaseId /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_GetOSRelIdStr out + StdUtils::GetOsReleaseName /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_HashText out type text + push `${type}` + push `${text}` + StdUtils::HashText /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_HashFile out type file + push `${type}` + push `${file}` + StdUtils::HashFile /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_NormalizePath out path + push `${path}` + StdUtils::NormalizePath /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_GetParentPath out path + push `${path}` + StdUtils::GetParentPath /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_SplitPath out_drive out_dir out_fname out_ext path + push `${path}` + StdUtils::SplitPath /NOUNLOAD + pop ${out_drive} + pop ${out_dir} + pop ${out_fname} + pop ${out_ext} +!macroend + +!macro _StdU_GetDrivePart out path + push `${path}` + StdUtils::GetDrivePart /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_GetDirPart out path + push `${path}` + StdUtils::GetDirectoryPart /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_GetFNamePart out path + push `${path}` + StdUtils::GetFileNamePart /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_GetExtnPart out path + push `${path}` + StdUtils::GetExtensionPart /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_TimerCreate out callback interval + GetFunctionAddress ${out} ${callback} + push ${out} + push ${interval} + StdUtils::TimerCreate /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_TimerDestroy out timer_id + push ${timer_id} + StdUtils::TimerDestroy /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_PrtctStr out dpsc salt text + push `${dpsc}` + push `${salt}` + push `${text}` + StdUtils::ProtectStr /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_UnprtctStr out trnc salt data + push `${trnc}` + push `${salt}` + push `${data}` + StdUtils::UnprotectStr /NOUNLOAD + pop ${out} +!macroend + +!macro _StdU_GetLibVersion out_ver out_tst + StdUtils::GetLibVersion /NOUNLOAD + pop ${out_ver} + pop ${out_tst} +!macroend + +!macro _StdU_SetVerbose enable + Push ${enable} + StdUtils::SetVerboseMode /NOUNLOAD +!macroend + + +################################################################################# +# MAGIC NUMBERS +################################################################################# + +!define StdUtils.Const.ShellVerb.PinToTaskbar 0 +!define StdUtils.Const.ShellVerb.UnpinFromTaskbar 1 +!define StdUtils.Const.ShellVerb.PinToStart 2 +!define StdUtils.Const.ShellVerb.UnpinFromStart 3 + +!endif # !___STDUTILS__NSH___ diff --git a/cmake/Windows/Include/UAC.nsh b/cmake/Windows/Include/UAC.nsh new file mode 100644 index 000000000..08979aba9 --- /dev/null +++ b/cmake/Windows/Include/UAC.nsh @@ -0,0 +1,299 @@ +/*** UAC Plug-in *** + +Interactive User (MediumIL) Admin user (HighIL) +***[Setup.exe]************* ***[Setup.exe]************** +* * * * +* +++[.OnInit]+++++++++++ * * +++[.OnInit]++++++++++++ * +* + UAC_RunElevated >---+-+----> * + + * +* + NSIS.Quit + * * + + * +* +++++++++++++++++++++++ * * ++++++++++++++++++++++++ * +* * * * +* * * * +* +++[Section]+++++++++++ * * +++[Section]++++++++++++ * +* + + * /--+-+- +** +** Get integrity level of current process +** +**/ +!macro UAC_GetIntegrityLevel outvar +UAC::_ 6 +!if "${outvar}" != "s" + Pop ${outvar} +!endif +!macroend + + + +/* UAC_IsAdmin +** +** Is the current process running with administrator privileges? Result in $0 +** +** ${If} ${UAC_IsAdmin} ... +** +**/ +!macro UAC_IsAdmin +UAC::_ 2 +!macroend +!define UAC_IsAdmin `"" UAC_IsAdmin ""` +!macro _UAC_IsAdmin _a _b _t _f +!insertmacro _UAC_MakeLL_Cmp _!= 0 2s +!macroend + + + +/* UAC_IsInnerInstance +** +** Does the current process have a NSIS/UAC parent process that is part of the elevation operation? +** +** ${If} ${UAC_IsInnerInstance} ... +** +**/ +!macro UAC_IsInnerInstance +UAC::_ 3 +!macroend +!define UAC_IsInnerInstance `"" UAC_IsInnerInstance ""` +!macro _UAC_IsInnerInstance _a _b _t _f +!insertmacro _UAC_MakeLL_Cmp _!= 0 3s +!macroend + + + +/* UAC_PageElevation_OnInit, UAC_PageElevation_OnGuiInit, +** +** Helper macros for elevation on a custom elevation page, see the DualMode example for more information. +** +**/ +!macro UAC_Notify_OnGuiInit +UAC::_ 4 +!macroend +!macro UAC_PageElevation_OnGuiInit +!insertmacro UAC_Notify_OnGuiInit +!macroend +!macro UAC_PageElevation_OnInit +UAC::_ 5 +${IfThen} ${Errors} ${|} Quit ${|} +!macroend + + + +/* UAC_AsUser_Call +** +** Calls a function or label in the user process instance. +** All the UAC_AsUser_* macros use this helper macro. +** +**/ +!define UAC_SYNCREGISTERS 0x1 +;define UAC_SYNCSTACK 0x2 +!define UAC_SYNCOUTDIR 0x4 +!define UAC_SYNCINSTDIR 0x8 +;define UAC_CLEARERRFLAG 0x10 +!macro UAC_AsUser_Call type name flags +push $0 +Get${type}Address $0 ${name} +!verbose push +!verbose ${UAC_VERBOSE} +!insertmacro _UAC_ParseDefineFlagsToInt _UAC_AsUser_Call__flags ${flags} +!verbose pop +StrCpy $0 "1$0:${_UAC_AsUser_Call__flags}" +!undef _UAC_AsUser_Call__flags +Exch $0 +UAC::_ +!macroend + + + +/* +** UAC_AsUser_GetSection +*/ +!macro UAC_AsUser_GetSection secprop secidx outvar +!insertmacro _UAC_AsUser_GenOp ${outvar} SectionGet${secprop} ${secidx} "" +!macroend + + + +/* +** UAC_AsUser_GetGlobalVar +** UAC_AsUser_GetGlobal +*/ +!macro UAC_AsUser_GetGlobalVar var +!insertmacro _UAC_AsUser_GenOp ${var} StrCpy "" ${var} +!macroend +!macro UAC_AsUser_GetGlobal outvar srcvar +!insertmacro _UAC_AsUser_GenOp ${outvar} StrCpy "" ${srcvar} +!macroend + + + +/* +** UAC_AsUser_ExecShell +** +** Call ExecShell in the user process instance. +** +*/ +!macro UAC_AsUser_ExecShell verb command params workdir show +!insertmacro _UAC_IncL +goto _UAC_L_E_${__UAC_L} +_UAC_L_F_${__UAC_L}: +ExecShell "${verb}" "${command}" '${params}' ${show} +return +_UAC_L_E_${__UAC_L}: +!if "${workdir}" != "" + push $outdir + SetOutPath "${workdir}" +!endif +!insertmacro UAC_AsUser_Call Label _UAC_L_F_${__UAC_L} ${UAC_SYNCREGISTERS}|${UAC_SYNCOUTDIR}|${UAC_SYNCINSTDIR} #|${UAC_CLEARERRFLAG} +!if "${workdir}" != "" + pop $outdir + SetOutPath $outdir +!endif +!macroend + + + +!macro _UAC_MakeLL_Cmp cmpop cmp pluginparams +!insertmacro _LOGICLIB_TEMP +UAC::_ ${pluginparams} +pop $_LOGICLIB_TEMP +!insertmacro ${cmpop} $_LOGICLIB_TEMP ${cmp} `${_t}` `${_f}` +!macroend +!macro _UAC_definemath def val1 op val2 +!define /math _UAC_definemath "${val1}" ${op} ${val2} +!ifdef ${def} + !undef ${def} +!endif +!define ${def} "${_UAC_definemath}" +!undef _UAC_definemath +!macroend +!macro _UAC_ParseDefineFlags_orin parse outflags +!searchparse /noerrors ${${parse}} "" _UAC_ParseDefineFlags_orin_f1 "|" _UAC_ParseDefineFlags_orin_f2 +!define _UAC_ParseDefineFlags_orin_this ${_UAC_ParseDefineFlags_orin_f1} +!undef ${parse} +!define ${parse} ${_UAC_ParseDefineFlags_orin_f2} +!define _UAC_ParseDefineFlags_orin_saveout ${${outflags}} +!undef ${outflags} +!define /math ${outflags} "${_UAC_ParseDefineFlags_orin_saveout}" | "${_UAC_ParseDefineFlags_orin_this}" +!undef _UAC_ParseDefineFlags_orin_saveout +!undef _UAC_ParseDefineFlags_orin_this +!ifdef _UAC_ParseDefineFlags_orin_f1 + !undef _UAC_ParseDefineFlags_orin_f1 +!endif +!ifdef _UAC_ParseDefineFlags_orin_f2 + !undef _UAC_ParseDefineFlags_orin_f2 +!endif +!macroend +!macro _UAC_ParseDefineFlags_Begin _outdef _in +!define _UAC_PDF${_outdef}_parse "${_in}" +!define _UAC_PDF${_outdef}_flags "" +!define _UAC_PDF${_outdef}_r 0 +!insertmacro _UAC_ParseDefineFlags_orin _UAC_PDF${_outdef}_parse _UAC_PDF${_outdef}_flags ;0x1 +!insertmacro _UAC_ParseDefineFlags_orin _UAC_PDF${_outdef}_parse _UAC_PDF${_outdef}_flags ;0x2 +!insertmacro _UAC_ParseDefineFlags_orin _UAC_PDF${_outdef}_parse _UAC_PDF${_outdef}_flags ;0x4 +!insertmacro _UAC_ParseDefineFlags_orin _UAC_PDF${_outdef}_parse _UAC_PDF${_outdef}_flags ;0x8 +!insertmacro _UAC_ParseDefineFlags_orin _UAC_PDF${_outdef}_parse _UAC_PDF${_outdef}_flags ;0x10 +!macroend +!macro _UAC_ParseDefineFlags_End _outdef +!define ${_outdef} ${_UAC_PDF${_outdef}_r} +!undef _UAC_PDF${_outdef}_r +!undef _UAC_PDF${_outdef}_flags +!undef _UAC_PDF${_outdef}_parse +!macroend +!macro _UAC_ParseDefineFlags_IncludeFlag _outdef flag +!if ${_UAC_PDF${_outdef}_flags} & ${flag} + !insertmacro _UAC_definemath _UAC_PDF${_outdef}_r ${_UAC_PDF${_outdef}_r} | ${flag} +!endif +!macroend +!macro _UAC_ParseDefineFlagsToInt _outdef _in +!insertmacro _UAC_ParseDefineFlags_Begin _UAC_ParseDefineFlagsToInt_tmp "${_in}" +!define ${_outdef} ${_UAC_PDF_UAC_ParseDefineFlagsToInt_tmp_flags} +!insertmacro _UAC_ParseDefineFlags_End _UAC_ParseDefineFlagsToInt_tmp +!undef _UAC_ParseDefineFlagsToInt_tmp +!macroend +!macro _UAC_IncL +!insertmacro _UAC_definemath __UAC_L "${__UAC_L}" + 1 +!macroend +!macro _UAC_AsUser_GenOp outvar op opparam1 opparam2 +!define _UAC_AUGOGR_ID _UAC_AUGOGR_OP${outvar}${op}${opparam1}${opparam2} +!ifndef ${_UAC_AUGOGR_ID} ;Has this exact action been done before? + !if ${outvar} == $0 + !define ${_UAC_AUGOGR_ID} $1 + !else + !define ${_UAC_AUGOGR_ID} $0 + !endif + !if "${opparam1}" == "" + !define _UAC_AUGOGR_OPP1 ${${_UAC_AUGOGR_ID}} + !define _UAC_AUGOGR_OPP2 ${opparam2} + !else + !define _UAC_AUGOGR_OPP1 ${opparam1} + !define _UAC_AUGOGR_OPP2 ${${_UAC_AUGOGR_ID}} + !endif + goto ${_UAC_AUGOGR_ID}_C + ${_UAC_AUGOGR_ID}_F: + ${op} ${_UAC_AUGOGR_OPP1} ${_UAC_AUGOGR_OPP2} + return + ${_UAC_AUGOGR_ID}_C: + !undef _UAC_AUGOGR_OPP1 + !undef _UAC_AUGOGR_OPP2 +!endif +push ${${_UAC_AUGOGR_ID}} +!insertmacro UAC_AsUser_Call Label ${_UAC_AUGOGR_ID}_F ${UAC_SYNCREGISTERS} +StrCpy ${outvar} ${${_UAC_AUGOGR_ID}} +pop ${${_UAC_AUGOGR_ID}} +!undef _UAC_AUGOGR_ID +!macroend + + + +!verbose pop +!endif /* UAC_HDR__INC */ \ No newline at end of file diff --git a/cmake/Windows/NSIS.template.in b/cmake/Windows/NSIS.template.in new file mode 100644 index 000000000..bc091df88 --- /dev/null +++ b/cmake/Windows/NSIS.template.in @@ -0,0 +1,756 @@ +############################################ +## see README before running this script! ## +############################################ +## useful resources: +# http://abarinoff-dev.blogspot.com/2010/04/passing-parameters-and-retrieving.html +# http://nsis.sourceforge.net/Inetc_plug-in + +################### +### CPACK config ## +################### +Name "@CPACK_PACKAGE_NAME@" +BrandingText "@CPACK_PACKAGE_FILE_NAME@" +OutFile "@CPACK_TOPLEVEL_DIRECTORY@/@CPACK_OUTPUT_FILE_NAME@" +SetCompressor /SOLID lzma + +!define INST_DIR "@CPACK_TEMPORARY_DIRECTORY@" +## Long version has to have 4 levels... +!define VERSION_LONG "@CPACK_PACKAGE_VERSION@.0" + +################## +### config ### +################## +### These used to live in a separately !include'd Cfg_Settings.nsh, generated by CMake +### as its own file on disk. That file reliably existed right up to (and including) the +### instant before CPack invoked NSIS -- yet NSIS's own !include of it, a fraction of a +### second later in that same CPack run, reported it missing, with none of CPack's own +### file operations (traced with --debug) ever touching it. Defining everything directly +### here instead relies only on CPack's own @CPACK_...@ template substitution when it +### writes this file to project.nsi -- the same mechanism already used above and below +### for absolute paths on the build tree's own drive (OutFile, the installer icon, the +### license page) -- with no separate file needing to survive on disk at packaging time. +# path to visual studio redistributable (has to match your CMake generator; currently unused) +!define VS_REDISTRIBUTABLE_PATH "" +!define VS_REDISTRIBUTABLE_EXE "" +# define your platform: +!define PLATFORM "@CPACK_OPENMS_PLATFORM@" +# path to OpenMS - source tree +!define OPENMSDIRSRC "@CPACK_OPENMS_PROJECT_SOURCE_DIR@" +!define NSISRESOURCES "@CPACK_OPENMS_PROJECT_SOURCE_DIR@/cmake/Windows" +# version string (does not need to be only numbers, in contrast to VERSION_LONG which has to have 4 number levels) +!define VERSION "@CPACK_OPENMS_VERSION@" + +### Paths into CPack's packaging tree. @CPACK_TEMPORARY_DIRECTORY@ always reflects the +### staging directory actually used for this packaging run, whether or not +### CPACK_PACKAGE_DIRECTORY was redirected elsewhere (e.g. to a short path on Windows to +### avoid MAX_PATH issues). +!define OPENMSPACKAGEDIR "@CPACK_TEMPORARY_DIRECTORY@" +!define OPENMSBINDIR "@CPACK_TEMPORARY_DIRECTORY@/@CPACK_OPENMS_INSTALL_BIN_DIR@" +!define OPENMSLIBDIR "@CPACK_TEMPORARY_DIRECTORY@/@CPACK_OPENMS_INSTALL_LIB_DIR@" +!define OPENMSSHAREDIR "@CPACK_TEMPORARY_DIRECTORY@/@CPACK_OPENMS_INSTALL_SHARE_DIR@" +!define OPENMSPLUGINDIR "@CPACK_TEMPORARY_DIRECTORY@/@CPACK_OPENMS_INSTALL_PLUGIN_DIR@" +!define OPENMSDOCDIR "@CPACK_TEMPORARY_DIRECTORY@/@CPACK_OPENMS_INSTALL_DOC_DIR@" +!define THIRDPARTYDIR "@CPACK_TEMPORARY_DIRECTORY@/@CPACK_OPENMS_INSTALL_SHARE_DIR@/THIRDPARTY" + +### NSISRESOURCES now consists of the cmake/Windows directory of the source tree. +!addplugindir ${NSISRESOURCES}\Plugins\x86-unicode +!addincludedir ${NSISRESOURCES}\Include + +# set to "0" for deployment!!! use "1" to build the installer fast (for script debugging) +!define DEBUG_BUILD 0 +!define DEBUG_NO_THIRDPARTY 0 +# set to "0" for deployment!!! use "1" to skip packaging of *.html files (takes ages) +!define DEBUG_SKIP_DOCU 0 + +################## +### SCRIPT ### +################## + +# which extensions to connect to TOPPView and TOPPAS +!macro OpenMSGUIExtensions _action + !insertmacro ${_action} ".mzData" "TOPPView" + !insertmacro ${_action} ".mzXML" "TOPPView" + !insertmacro ${_action} ".mzML" "TOPPView" + !insertmacro ${_action} ".sqMass" "TOPPView" + !insertmacro ${_action} ".dta" "TOPPView" + !insertmacro ${_action} ".dta2D" "TOPPView" + !insertmacro ${_action} ".cdf" "TOPPView" + !insertmacro ${_action} ".idXML" "TOPPView" + !insertmacro ${_action} ".featureXML" "TOPPView" + !insertmacro ${_action} ".consensusXML" "TOPPView" + !insertmacro ${_action} ".toppas" "TOPPAS" +!macroend + +# Defines +!define APPNAME "OpenMS" +!define PRODUCT_NAME "${APPNAME}" +# For the icon used by MultiUser plugin, relative to INSTDIR +!define PROGEXE "bin\TOPPView.exe" +# For our own additional regkeys +!define REGKEY "SOFTWARE\$(^Name)" +# For AdvUninstallLog (matches default of MultiUser) +!define PRODUCT_UNINST_ROOT SHCTX +# For AdvUninstallLog (matches default of MultiUser) +!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" +!define COMPANY "OpenMS Developer Team" +# For MultiUser +!define COMPANY_NAME "${COMPANY}" +!define URL "https://www.OpenMS.de" +# For MultiUser +!define URL_INFO_ABOUT "${URL}" + +# We could also define the following +#CONTACT +#URL_HELP_LINK + + +# MultiUser defines +!define MULTIUSER_INSTALLMODE_INSTDIR "${PRODUCT_NAME}-${VERSION}" # Otherwise it would just be PRODUCT_NAME +!define MULTIUSER_INSTALLMODE_DEFAULT_ALLUSERS 1 # Default to Alluser install even when not an admin +!define MULTIUSER_INSTALLMODE_64_BIT 1 +!define MULTIUSER_INSTALLMODE_NO_HELP_DIALOG 1 # We define our own with additional params later + +# Included files + +# MUI2 somehow crashes with NSIS3.0 release/stable. Switched to MuiEx (belongs to UltraMui) that seems better supported and has legacy option. +#!include MUI2.nsh +!include MUIEx.nsh +!include Sections.nsh +!include Library.nsh +!include FileFunc.nsh + +!define FOLDERLIST_EXE ${NSISRESOURCES}\FolderList.exe + +# Private includes from repo +!include IncludeScript_Misc.nsh +!include IncludeScript_FileLogging.nsh +!include EnvVarUpdate.nsh +!include AdvUninstLog2.nsh +!include NsisMultiUser.nsh + +# For AdvUninstalllog (alternative INTERACTIVE_UNINSTALL will trigger message boxes for each file) +!insertmacro UNATTENDED_UNINSTALL + +# Reserved Files +!insertmacro MUI_RESERVEFILE_LANGDLL + +# Modify the next line to adapt to the plugin for other NSIS versions (currently 3.0 release) +# e.g. NSIS 2.x does not have the subfolders x86-unicode or x86-ansi, so remove them. +ReserveFile "${NSISDIR}\Plugins\x86-unicode\advsplash.dll" + +;-------------------------------- +;Interface Configuration + +!define MUI_HEADERIMAGE +!define MUI_HEADERIMAGE_BITMAP "${NSISRESOURCES}\images\header.bmp" ; optional +!define MUI_HEADERIMAGE_UNBITMAP "${NSISRESOURCES}\images\header-uninstall.bmp" ; optional +!define MUI_HEADERIMAGE_RIGHT +!define MUI_ABORTWARNING +!define MUI_WELCOMEFINISHPAGE_BITMAP "${NSISRESOURCES}\images\wizard.bmp" ; optional +!define MUI_UNWELCOMEFINISHPAGE_BITMAP "${NSISRESOURCES}\images\wizard-uninstall.bmp" ; optional + +!insertmacro RefreshShellIcons +!insertmacro un.RefreshShellIcons +!insertmacro DirState +!insertmacro GetFileName + +# (global) Variables to be set and used during our script +Var StartMenuGroup +Var EnvVarUpdateLoc + +# MUI defines +#!define MUI_ICON OpenMS.ico + +# UI settings +!define MUI_FINISHPAGE_NOAUTOCLOSE +!define UMUI_STARTMENUPAGE_REGISTRY_ROOT SHCTX +!define UMUI_STARTMENUPAGE_REGISTRY_KEY ${PRODUCT_UNINST_KEY} +!define UMUI_STARTMENUPAGE_REGISTRY_VALUENAME StartMenuGroup +!define UMUI_STARTMENUPAGE_DEFAULTFOLDER "${PRODUCT_NAME}" +!define MUI_LICENSEPAGE_RADIOBUTTONS +!define MUI_FINISHPAGE_SHOWREADME $INSTDIR\ReleaseNotes.txt +!define MUI_UNFINISHPAGE_NOAUTOCLOSE + +# Add survey link at the end of the installer +!define MUI_FINISHPAGE_LINK "Join the community - complete our user survey" +!define MUI_FINISHPAGE_LINK_LOCATION "https://tally.so/r/pbV6Qq" +!define MUI_FINISHPAGE_LINK_COLOR "0066CC" + +# Remember the installer language +!define UMUI_LANGUAGE_REGISTRY_ROOT SHCTX +!define UMUI_LANGUAGE_REGISTRY_KEY ${PRODUCT_UNINST_KEY} +!define UMUI_LANGUAGE_REGISTRY_VALUENAME "InstallerLanguage" + + +# Installer pages +!insertmacro MUI_PAGE_WELCOME +!define MUI_PAGE_CUSTOMFUNCTION_SHOW licpageshow +!insertmacro MUI_PAGE_LICENSE ${OPENMSDIRSRC}\License.txt +!insertmacro MULTIUSER_PAGE_INSTALLMODE +!insertmacro MUI_PAGE_DIRECTORY +!insertmacro MUI_PAGE_COMPONENTS +!insertmacro MUI_PAGE_STARTMENU Application $StartMenuGroup +!insertmacro MUI_PAGE_INSTFILES +!insertmacro MUI_PAGE_FINISH + +# Uninstaller pages +!insertmacro MUI_UNPAGE_CONFIRM +!define MULTIUSER_INSTALLMODE_CHANGE_MODE_FUNCTION un.PageInstallModeChangeMode +!insertmacro MULTIUSER_UNPAGE_INSTALLMODE +!insertmacro MUI_UNPAGE_INSTFILES + +# Installer languages +!insertmacro MUI_LANGUAGE German +!insertmacro MUI_LANGUAGE English +!insertmacro MUI_LANGUAGE French +!insertmacro MULTIUSER_LANGUAGE_INIT + +# Installer Language Strings +LangString ^UninstallLink ${LANG_GERMAN} "Uninstall $(^Name)" +LangString ^UninstallLink ${LANG_ENGLISH} "Uninstall $(^Name)" +LangString ^UninstallLink ${LANG_FRENCH} "Uninstall $(^Name)" + +# Custom MUI Function to set font of license display page +# to a mono spaced one. +# from http://stackoverflow.com/questions/8424172/nsis-display-license-with-a-monospace-font +Function licpageshow + FindWindow $0 "#32770" "" $HWNDPARENT + CreateFont $1 "Consolas" "8" + GetDlgItem $0 $0 1000 + SendMessage $0 ${WM_SETFONT} $1 1 +FunctionEnd + + +# predefined installation modes +InstType "Recommended" #1 +InstType "Minimum" #2 +InstType "Full" #3 + +# TODO check what this does +CRCCheck on +ShowInstDetails hide +VIProductVersion ${VERSION_LONG} +VIAddVersionKey /LANG=${LANG_GERMAN} ProductName "${PRODUCT_NAME}" +VIAddVersionKey /LANG=${LANG_GERMAN} ProductVersion "${VERSION}" +VIAddVersionKey /LANG=${LANG_GERMAN} CompanyName "${COMPANY}" +VIAddVersionKey /LANG=${LANG_GERMAN} CompanyWebsite "${URL}" +VIAddVersionKey /LANG=${LANG_GERMAN} FileVersion "${VERSION}" +VIAddVersionKey /LANG=${LANG_GERMAN} FileDescription "" +VIAddVersionKey /LANG=${LANG_GERMAN} LegalCopyright "" + +ShowUninstDetails hide + +; HKLM (all users) vs HKCU (current user) defines +!define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' +!define env_hkcu 'HKCU "Environment"' + +!macro CREATE_SMGROUP_SHORTCUT NAME PATH + Push "${NAME}" + Push "${PATH}" + Call CreateSMGroupShortcut +!macroend + +Function CreateSMGroupShortcut + Exch $R0 ;PATH + Exch + Exch $R1 ;NAME + Push $R2 + StrCpy $R2 $StartMenuGroup 1 + StrCmp $R2 ">" no_smgroup + SetOutPath $SMPROGRAMS\$StartMenuGroup + StrCpy $OUTDIR "$INSTDIR" # execute link target in $OUTDIR + + CreateDirectory "$SMPROGRAMS\${APPNAME}" + CreateShortcut "$SMPROGRAMS\${APPNAME}\$R1.lnk" $R0 + + no_smgroup: + Pop $R2 + Pop $R1 + Pop $R0 +FunctionEnd + + +# Installer sections +Section "OpenMS Library" SEC_Lib + SectionIn 1 2 3 RO + + SetOutPath $INSTDIR\bin + SetOverwrite on + + # open log file + !insertmacro UNINSTALL.LOG_OPEN_INSTALL + + # install files for bin dir + File "${OPENMSLIBDIR}\*.dll" + File "${OPENMSLIBDIR}\*.lib" + + !insertmacro UNINSTALL.LOG_CLOSE_INSTALL + + SetOutPath $INSTDIR\bin\plugins + SetOverwrite on + + !insertmacro UNINSTALL.LOG_OPEN_INSTALL + File /r "${OPENMSPLUGINDIR}\*.*" + !insertmacro UNINSTALL.LOG_CLOSE_INSTALL + + # share dir + SetOutPath $INSTDIR\share\OpenMS + SetOverwrite on + + !insertmacro UNINSTALL.LOG_OPEN_INSTALL + + !if ${DEBUG_BUILD} == 0 + File /r /x "THIRDPARTY" /x "doc" "${OPENMSSHAREDIR}\*.*" + !endif + + # icon for *files* associated with TOPPView + File "${NSISRESOURCES}\OpenMS_TOPPView.ico" + File "${NSISRESOURCES}\OpenMS_TOPPAS.ico" + + !insertmacro UNINSTALL.LOG_CLOSE_INSTALL +SectionEnd + +Section "TOPP tools" SEC_TOPP + SectionIn 1 2 3 RO + + SetOutPath $INSTDIR\bin + SetOverwrite on + + #open uninstall log file + !insertmacro UNINSTALL.LOG_OPEN_INSTALL + + # Since Qt 5.14 we do not need qt.conf if the plugins are in the standard location "plugins" + # Qt is built "-relocatable" since then. + #File "${OPENMSBINDIR}\qt.conf" + + # install every tool exe except for Tutorials (if present) + # skip in installer debug mode + !if ${DEBUG_BUILD} == 0 + File /x "Tutorial_*.exe" "${OPENMSBINDIR}\*.exe" + !endif + + !insertmacro UNINSTALL.LOG_CLOSE_INSTALL +SectionEnd + + +Section "Documentation" SEC_Doc + SectionIn 3 + + SetOverwrite on + SetOutPath $INSTDIR\share\doc\html + + # open uninstall log file + !insertmacro UNINSTALL.LOG_OPEN_INSTALL + + # html docs + !if ${DEBUG_SKIP_DOCU} == 0 + + File /r "${OPENMSDOCDIR}\html\*.*" + #SetOutPath $INSTDIR\share\doc + !endif + + !insertmacro UNINSTALL.LOG_CLOSE_INSTALL +SectionEnd + +## Third party libs +## TODO switch to packagedir +SectionGroup "ThirdParty" SEC_ThirdParty + !if ${DEBUG_NO_THIRDPARTY} == 0 + ## Install every directory in the given (flattened) THIRDPARTY folder. ProteoWizard + ## (pwiz-bin) is not among them: cmake/package_general.cmake does not stage it. + !tempfile filelist + !system 'FOR /D %A IN ("${THIRDPARTYDIR}\*") DO @( (echo Section "%~nA" & echo SectionIn 1 3 & echo !insertmacro UNINSTALL.LOG_OPEN_INSTALL & echo SetOverwrite on & echo CreateDirectory "$INSTDIR\share\OpenMS\THIRDPARTY\%~nA" & echo SetOutPath "$INSTDIR\share\OpenMS\THIRDPARTY\%~nA" & echo File /r "%~A\*.*" & echo Var /GLOBAL %~nAInstalled & echo StrCpy $%~nAInstalled "1" & echo !insertmacro UNINSTALL.LOG_CLOSE_INSTALL & echo SectionEnd) >> "${filelist}")' + !include "${filelist}" + !delfile "${filelist}" + !endif + +SectionGroupEnd + +Section "-License" SEC_License + SectionIn 1 2 3 + SetOutPath $INSTDIR + SetOverwrite on + #open uninstall log file + !insertmacro UNINSTALL.LOG_OPEN_INSTALL + + File "${NSISRESOURCES}\ReleaseNotes.txt" + + !insertmacro UNINSTALL.LOG_CLOSE_INSTALL +SectionEnd + +Function CreateShortcuts + !insertmacro MUI_STARTMENU_WRITE_BEGIN Application + + ## warning: create shortcuts only AFTER installing files, OR renew SetOutPath + ## otherwise all files will be installed to the default install directory + !insertmacro CREATE_SMGROUP_SHORTCUT "OpenMS Documentation (html)" $INSTDIR\share\doc\html\index.html + + !insertmacro CREATE_SMGROUP_SHORTCUT TOPPView $INSTDIR\bin\TOPPView.exe + !insertmacro CREATE_SMGROUP_SHORTCUT TOPPAS $INSTDIR\bin\TOPPAS.exe + !insertmacro CREATE_SMGROUP_SHORTCUT INIFileEditor $INSTDIR\bin\INIFileEditor.exe + !insertmacro CREATE_SMGROUP_SHORTCUT "OpenMS Homepage" "${URL}" + !insertmacro CREATE_SMGROUP_SHORTCUT "TOPP command line" "$INSTDIR\bin\command.bat" + + SetOutPath $SMPROGRAMS\${APPNAME} + CreateShortcut "$SMPROGRAMS\${APPNAME}\$(^UninstallLink).lnk" $INSTDIR\uninstall.exe + !insertmacro MUI_STARTMENU_WRITE_END + +FunctionEnd + + +Section "-Create_StartMenu" SEC_StartMenuCreate + #GetFunctionAddress $0 CreateShortcuts + #UAC::ExecCodeSegment $0 + !insertmacro MUI_STARTMENU_WRITE_BEGIN Application + + ## warning: create shortcuts only AFTER installing files, OR renew SetOutPath + ## otherwise all files will be installed to the default install directory + !insertmacro CREATE_SMGROUP_SHORTCUT "OpenMS Documentation (html)" $INSTDIR\share\doc\html\index.html + + !insertmacro CREATE_SMGROUP_SHORTCUT TOPPView $INSTDIR\bin\TOPPView.exe + !insertmacro CREATE_SMGROUP_SHORTCUT TOPPAS $INSTDIR\bin\TOPPAS.exe + !insertmacro CREATE_SMGROUP_SHORTCUT INIFileEditor $INSTDIR\bin\INIFileEditor.exe + !insertmacro CREATE_SMGROUP_SHORTCUT "OpenMS Homepage" http://www.OpenMS.de/ + !insertmacro CREATE_SMGROUP_SHORTCUT "TOPP command line" "$INSTDIR\bin\command.bat" + + SetOutPath $SMPROGRAMS\${APPNAME} + CreateShortcut "$SMPROGRAMS\${APPNAME}\$(^UninstallLink).lnk" $INSTDIR\uninstall.exe + !insertmacro MUI_STARTMENU_WRITE_END +SectionEnd + +Section "-Create_command_bat" SEC_CmdBat + SectionIn 1 2 3 + #open log file + # Does not work for FileWrite somehow: !insertmacro UNINSTALL.LOG_OPEN_INSTALL + + ## create a command bat (i.e. a TOPP shell) + push $R0 + push $0 + StrCpy $R0 $INSTDIR 2 + fileOpen $0 "$INSTDIR\bin\command.bat" w + fileWrite $0 "$SYSDIR\cmd.exe /k $\"$R0 && cd $INSTDIR\bin && cls && echo on && echo Welcome to the OpenMS TOPP tools command line && echo type 'dir *.exe' to see available commands && echo on $\"" + fileClose $0 + pop $0 + pop $R0 + + # Does not work. Maybe needs to be done later? For now we delete manually in "-Uninstall" section + # FileWrite $UninstallLog "$INSTDIR\bin\command.bat$\r$\n" + + # Does not work for FileWrite somehow: !insertmacro UNINSTALL.LOG_CLOSE_INSTALL +SectionEnd + + +Section "-PathInst" SEC_PathRegister + SectionIn 1 2 3 + # no logging required, as we do not install files in this section + ## HINT: do not forget to also add/modify the un.EnvVarUpdate in the uninstall section! + + ${If} $MultiUser.InstallMode == "AllUsers" + StrCpy $EnvVarUpdateLoc "HKLM" + ${Else} + StrCpy $EnvVarUpdateLoc "HKCU" + ${EndIf} + + # OpenMS binary path + ${EnvVarUpdate} $0 "PATH" "A" "$EnvVarUpdateLoc" "$INSTDIR\bin" + IfErrors 0 +2 + MessageBox MB_OK "Unable to add '$INSTDIR\bin' to PATH environment. Add manually if required. See 'details' for details." + + # Add all folders of all INSTALLED Third Party libraries to PATH that adapters find them + FindFirst $0 $1 $INSTDIR\share\OpenMS\THIRDPARTY\*.* + loop: + StrCmp $1 "" done + StrCmp $1 "." skip + StrCmp $1 ".." skip + IfFileExists "$INSTDIR\share\OpenMS\THIRDPARTY\$1\*.*" IsDir skip + IsDir: + ${EnvVarUpdate} $3 "PATH" "A" "$EnvVarUpdateLoc" "$INSTDIR\share\OpenMS\THIRDPARTY\$1" + IfErrors 0 +2 + MessageBox MB_OK "Unable to add '$1' to PATH environment. Add manually if required. See 'details' for details." + skip: + FindNext $0 $1 + Goto loop + done: + FindClose $0 + + # Note: OPENMS_DATA_PATH is intentionally NOT written anymore. OpenMS now resolves its + # shared data deterministically relative to the executable (see File::getOpenMSDataPath), + # so a stale value from an old or side-by-side install can no longer hijack data resolution. + + # Make sure windows knows about the change (PATH edits above still require this broadcast) + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 + +SectionEnd + +SectionGroup "Register File Extensions" SEC_RegisterExt + # no logging required, as we do not install files in this section + + # windows registry info: http://support.microsoft.com/kb/256986 + !insertmacro OpenMSGUIExtensions RegisterExtensionSection + + Section "-RegFileRefreshInternal" SEC_RegFileRefreshInternal + SectionIn 1 2 3 + ${RefreshShellIcons} + SectionEnd + +SectionGroupEnd + +## This is done by NsisMultiUser plugin now +Section -post SEC0008 + SetOutPath $INSTDIR + # Write uninstaller and registry uninstall info as the last step: + # - Cons: user does not have the option to run the uninstaller if sth. goes wrong + # - Pros: we can use the uninstall logger plugin that avoids boilerplate code + + # defined by NsisMultiUser plugin. default uninstall.exe. + WriteUninstaller "${UNINSTALL_FILENAME}" + # add registry keys like the ones below + !insertmacro MULTIUSER_RegistryAddInstallInfo + +# WriteRegStr SHCTX "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayName "$(^Name)" +# WriteRegStr SHCTX "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayVersion "${VERSION}" +# WriteRegStr SHCTX "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" Publisher "OpenMS Developer Team" +# WriteRegStr SHCTX "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" URLInfoAbout "${URL}" +# WriteRegStr SHCTX "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayIcon $INSTDIR\uninstall.exe +# WriteRegStr SHCTX "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" UninstallString $INSTDIR\uninstall.exe +# WriteRegDWORD SHCTX "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" NoModify 1 +# WriteRegDWORD SHCTX "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" NoRepair 1 +SectionEnd + +# hidden section, write install size as the final step +Section "-Write Install Size" + !insertmacro MULTIUSER_RegistryAddInstallSizeInfo +SectionEnd + +Function parseParameters + ClearErrors + + ; /nothirdparty + ${GetOptions} $cmdLineParams '/nothirdparty' $R0 + IfErrors parsedParams 0 + !insertmacro ClearSectionFlag ${SEC_ThirdParty} ${SF_SELECTED} + + parsedParams: + +FunctionEnd + +# Installer functions +Function .onInit + + ## now our own code: + !insertmacro MULTIUSER_INIT + !insertmacro UNINSTALL.LOG_PREPARE_INSTALL + + # Command line options for silent install (with "/S") + + # Get parameters + Var /GLOBAL cmdLineParams + Push $R0 + ${GetParameters} $cmdLineParams + + # /? param (help) + ClearErrors + ${GetOptions} $cmdLineParams '/?' $R0 + ${ifnot} ${errors} + MessageBox MB_ICONINFORMATION "Usage:$\r$\n\ + $\r$\n\ + /allusers$\t- (un)install for all users, case-insensitive$\r$\n\ + /currentuser$\t- (un)install for current user only, case-insensitive$\r$\n\ + /uninstall$\t- (installer only) run uninstaller, requires /allusers or /currentuser, case-insensitive$\r$\n\ + /nothirdparty$\t- does not install thirdparty tools, case-sensitive$\r$\n\ + /S$\t- silent mode, requires /allusers or /currentuser, case-sensitive$\r$\n\ + /D$\t- (installer only) set install directory, must be last parameter, without quotes, case-sensitive$\r$\n\ + /?$\t- display this message$\r$\n\ + $\r$\n\ + $\r$\n\ + Return codes (decimal):$\r$\n\ + $\r$\n\ + 0$\t- normal execution (no error)$\r$\n\ + 1$\t- (un)installation aborted by user (Cancel button)$\r$\n\ + 2$\t- (un)installation aborted by script$\r$\n\ + 666660$\t- invalid command-line parameters$\r$\n\ + 666661$\t- elevation is not allowed by defines$\r$\n\ + 666662$\t- uninstaller detected there's no installed version$\r$\n\ + 666663$\t- executing uninstaller from the installer failed$\r$\n\ + 666666$\t- cannot start elevated instance$\r$\n\ + other$\t- Windows error code when trying to start elevated instance" + SetErrorLevel 0 + Quit + ${endif} + + Pop $R0 + + # Initialise options + + # Parse Parameters + Push $R0 + Call parseParameters + Pop $R0 + + # show splash screen + InitPluginsDir + Push $R1 + File /oname=$PLUGINSDIR\spltmp.bmp "${NSISRESOURCES}\images\OpenMS_splash.bmp" + advsplash::show 1000 600 400 -1 $PLUGINSDIR\spltmp + Pop $R1 + Pop $R1 + + ## deny starting of x64 installer on an x86 system (will not run) + !if ${PLATFORM} == 64 + ${If} ${RunningX64} + ${else} + MessageBox mb_iconstop "You are running a 32bit operating system. The executables of this setup are 64bit, and thus cannot be run after installation. Use a 64bit OS (there is no 32bit installer for OpenMS anymore)." + Abort + ${EndIf} + !endif + + # check for previous versions + # on install we did: WriteRegStr SHCTX "${REGKEY}" "Path" "$INSTDIR" + ReadRegStr $R0 SHCTX "${REGKEY}" "Path" + StrCmp $R0 "" virgin_install + + ## store, if the old-installer is present ($R8 should be empty then) + ReadRegStr $R8 SHCTX "${REGKEY}" "UninstallString" + + MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \ + "OpenMS has already been installed. $\nThe old version will be removed automatically. \ + Please close all OpenMS applications before continuing!" \ + IDCANCEL quit_installer + + ;Run the uninstaller + ClearErrors + ExecWait '$R0\uninstall.exe _?=$R0' ;; Do not execute the copy of uninstaller (ExecWait won´t work) + Delete "$R0\uninstall.exe" # delete installer manually + + push $R9 + ${DirState} "$R0" $R9 + StrCmp $R9 1 0 virgin_install + pop $R9 + + # look for the very first (and buggy) version of the installer + StrCmp $R8 "" 0 new_installer + # we found the old installer: + ## delete the licenses, share other stuff + RmDir /REBOOTOK "$R0\GUI" + RmDir /REBOOTOK /r "$R0\share" + Delete /REBOOTOK "$R0\*.txt" + ## correct Path settings (they were not properly reset) + ${EnvVarUpdate} $0 "PATH" "R" "HKLM" "$R0\lib" + ${EnvVarUpdate} $0 "PATH" "R" "HKLM" "$R0\TOPP" + ; delete variable + DeleteRegValue ${env_hklm} "OPENMS_DATA_PATH" + ; make sure windows knows about the change + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 + + new_installer: + ## check that all *.dll´s and *.exe files are gone (userfiles are ok)! otherwise force reboot + !insertmacro REBOOT_ON_INCOMPLETE_DELETION $R0 + + virgin_install: + !insertmacro MUI_LANGDLL_DISPLAY + return + + quit_installer: + quit + +FunctionEnd + +Function .onInstFailed + #UAC::Unload ;Must call unload! +FunctionEnd + +Function .onInstSuccess + !insertmacro UNINSTALL.LOG_UPDATE_INSTALL +FunctionEnd + +# set the component descriptions after the Sections have been defined! +!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN +!insertmacro MUI_DESCRIPTION_TEXT ${SEC_Lib} "The core libraries of OpenMS" +!insertmacro MUI_DESCRIPTION_TEXT ${SEC_TOPP} "TOPP (The OpenMS PiPeline) - chainable tools for data analysis" +!insertmacro MUI_DESCRIPTION_TEXT ${SEC_Doc} "Documentation/Tutorials for TOPP, TOPPView and the OpenMS library itself." +!insertmacro MUI_DESCRIPTION_TEXT ${SEC_ThirdParty} "Install third party tools (search engines and ThermoRawFileParser)." +!insertmacro MUI_DESCRIPTION_TEXT ${SEC_RegisterExt} "Register certain file types (e.g., '.mzML') with TOPPView.exe." +!insertmacro MUI_FUNCTION_DESCRIPTION_END + +################ +## UNINSTALL ### +################ + +# Uninstaller sections + +Section "-Uninstall" + !insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuGroup + !insertmacro MUI_UNGETLANGUAGE + + ## undo changes to PATH + ${If} $MultiUser.InstallMode == "AllUsers" + StrCpy $EnvVarUpdateLoc "HKLM" + ${Else} + StrCpy $EnvVarUpdateLoc "HKCU" + ${EndIf} + + # OpenMS binary path + ${un.EnvVarUpdate} $0 "PATH" "R" "$EnvVarUpdateLoc" "$INSTDIR\bin" + + # Third Party library paths + FindFirst $0 $1 $INSTDIR\share\OpenMS\THIRDPARTY\*.* + loopun: + StrCmp $1 "" doneun + StrCmp $1 "." skipun + StrCmp $1 ".." skipun + IfFileExists "$INSTDIR\share\OpenMS\THIRDPARTY\$1\*.*" IsDirun skipun + IsDirun: + ${un.EnvVarUpdate} $3 "PATH" "R" "$EnvVarUpdateLoc" "$INSTDIR\share\OpenMS\THIRDPARTY\$1" + IfErrors 0 +2 + MessageBox MB_OK "Unable to remove '$1' from PATH environment. Remove manually if required. See 'details' for details." + skipun: + FindNext $0 $1 + Goto loopun + doneun: + FindClose $0 + + ## remove OPENMS_DATA_PATH + ${If} $MultiUser.InstallMode == "AllUsers" + DeleteRegValue ${env_hklm} "OPENMS_DATA_PATH" + ${Else} + DeleteRegValue ${env_hkcu} "OPENMS_DATA_PATH" + ${EndIf} + + # remove extension-links to TOPPView + !insertmacro OpenMSGUIExtensions UnRegisterExtensionSection + ${un.RefreshShellIcons} + + ## delete all installed files + !insertmacro UNINSTALL.NEW_UNINSTALL + + # remove directories which are now empty (in case some were forgotten) + Push "$INSTDIR" + Call un.RemoveEmptyDirs + + ## clean up the registry (should be done by the NsisMultiUser plugin) + #DeleteRegKey SHCTX "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" + # delete /Software/OpenMS (with all its content) + DeleteRegKey SHCTX "${REGKEY}" + # somehow our generated bat file is not recorded by AdvUninstallLog + Delete "$INSTDIR\bin\command.bat" + # Remove the uninstaller from registry as the very last step - if sth. goes wrong, let the user run it again + !insertmacro MULTIUSER_RegistryRemoveInstallInfo + + RmDir /REBOOTOK $INSTDIR + + ## delete start menu entries ($SMPROGRAMS depends on the ShellContext) + RmDir /r /REBOOTOK $SMPROGRAMS\${APPNAME} + +SectionEnd + +# UnInstaller functions +Function un.onInit + !insertmacro MULTIUSER_UNINIT + !insertmacro MUI_UNGETLANGUAGE ; we always get the language, since the outer and inner instance might have different language +FunctionEnd + +Function un.PageInstallModeChangeMode + !insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuGroup +FunctionEnd + + diff --git a/cmake/Windows/NSIS_Readme.txt b/cmake/Windows/NSIS_Readme.txt new file mode 100644 index 000000000..cc909958c --- /dev/null +++ b/cmake/Windows/NSIS_Readme.txt @@ -0,0 +1,6 @@ +This folder includes small scripts, executables and a plugin for NSIS. +The plugin was tested with the current NSIS version 3.06.1 If they stop working at some point, please upgrade them. License can be found in the Doc folders. +The plugin in the Contrib, Docs, Examples, Plugins folder is the INetc plugin for downloading stuff. + +Do not forget to globally install the UltraModernUI 2.0b6 plugin (tested with 2021-03-16; not shipped because of its size) and the large String build of NSIS. + diff --git a/cmake/Windows/OpenMS.ico b/cmake/Windows/OpenMS.ico new file mode 100644 index 0000000000000000000000000000000000000000..568c7619db8c7ee3f638d8e314a78e2794013ffe GIT binary patch literal 50534 zcmeEv2V9j$)9)P40S>*`J0jQ%#)bt2M8rbG0s?l$qhJTIgI!Rt3sS_6U7|)&MAT^1 z*bN#*5kg{&T~Vo0=Kl9N=O~)IN#6Ut-@V`Ockk++r|r(p&hF04?#?VkGBPG}b8}o3 z)L2GzkqFO(XC;l-C3=l_>Srq&uORZ$C$h3qr+=zLblONftJCjM674e8K3mZq!1=lw zk)547{dhg1f=1$5lOAb@x70o(y)BWR1CgVnCcPn1(rEFlPT#mHQPoM>XDe##Ow@HT zQDcEKBG4dFkAD@EhGt}>=SU`s(PTc=;-mP-tT;Is#xJhmKooD=^ z70cVyEAiYE6R~_?E2G5C6E`jQ>{os)!RW;Dfp*3x69V?&x%kDh3qJmyt#V&4I5tG- zX~vTu?(?0!jalz?>ORj_D4^)ZaVuPy&CKvq&P2IpL^)`KvvQ&ZBBFgnM8#==z*6%p z-ib74k+ukV%I1GbCp6Yy1R0r-4pl;|N^)6s($_a4T}5@$leZ!>Gc(ecbw}($78VwW z)ydSb4H?MY$v|f?8R_;XL!EJCW-yS9bf%KAd@j|kTbHVs4I)$dA~KOL!F45>$)gZs z$kx`D%oSS@canu-FV(IbOqPmosgfdOLUbTC1sDTL-FV z@g3DNx`*pIs&8?Zn$$T!bxod8ee)c$GW(6{ndFhRY0kdfEpy}k^V?Pb{oK8c0$0ClWAwHAIwS5734_rsygVvG{;_#ut)YHBI z_v>inh{@#Ev495kK1aj6*O7a-S2SkSEb7~}fK;jpH2CZDW`sN}HoU(6&v#({>T#KG43zpXu1qAO51Z{{K(^-4u{p)Tv*$vZ3HKB2?|>)T(u} z<}DkWNRO6%+9w64xF)>G`~^c7IfMUG!|q*2EnZ!F;B@bqO=}qt zP4ehIA|hns*bTmOTGXpV6f>dsh)pglW<`#k+s3*EQ9_uPUt*P2%L0Pub!bqNXk*;$ z@$0*cQ4Lr)&)&8=(cm3XGdcx1IF9TY+PM*!oALH7LzFAqeYM{i(3{&+=I-ZHfQ%Dl(`LLp4#{TOs~U zP}B#nP6FR8121LpPX<3_@LmR=E(1SLBGRe=>FJkaxhWuc4T_h~5AQQ^KqZz!L!7~~Biot^z zGKIl=8N83dZy9_Kb@`4VZ$OXkWyo!Xr~=<)@M{(@zTJe9$78N7?Zry0DG zA!8Wwi6PS2GGq}$=AkXNF=Qn} z{xW2|mVQF^CxK5h_%_;UEEE+phAd#nTZa5)$O(pyz>seY8OV_347~z;H>zpTx}h`xLV=)AB|r| zD}1KU$v)|GLVx=*3VlxKej<;^EA(Dbm?Pp}>Af;tJ?Li6(2);Pvu0mWby+qws2vM^ z2KtECSQ_+o0{QkWqO!RR&xa$Mu{G12KqAV$BbYIOAq3O*@sHIZKmDxBu z+xGvMR@cSF#oF3h`+{8k{9Ig|tvx-Y9Jw{(Q=`pa*d#7~t6LoMc9FV#cS*jvW2_ly&5p?H(Zb(2x-S>xp6#_K$-%=oR!FU}!; zYLIxg?$2zn!7t7zfpYF2H{M_k07lV%ah*@;KiVsvttUz}-`t2o=-i!;gQcra-j&|LI9~UR!pOyL0&SZmX zlD=`Wi=!FmhGadV&MMalcE)#I#KgknA<<=(pZ`=c@Dl{f&CY(660K6DWhIXk^vQL| z%1ViiRjHy?A~{}UrKP5(#Hw5zrAN-y&&oOz&xXX5z;wP@Ce zYMZR1rj0s~8GTRH=scO|AEw&Io2Uw1r{*nNP$m6SRN3$do*z&ns|lDFrBfZVy;RHO z2xeu!QM)#+sCBEZREvJ6y7DZlDtkuN^|FyZk80Cear8MvMrcQGTOokoz&}(>;rZ4BSb*9P+7ux0mESU_bS9{+-5-Q;}Dn zD>Q240`llqK>fPE#e8QbdG-B?2Dy~b0L+2B-SWv_wUUPPEh0a!pJ_<{0tyNWrJxzp zX}CujO`Woqf`gXQ=s|@PG;tfLyi3X7H=ibtyNtQe9-1Avn^Z%KX!i6SG--G-O&L{6 zix!8|WWOSs=KqprO}GO0vi7ENe2TJ+2j7}zhpi{?~&ZfSmQzr}Q%qga;7k{N6F1?}~m&@qxgADpD zo9Xvo%jwN4rcxFv!+&ph`gxFj{#fw|Y(S=OVs2(6)1f~}CZkF=9a^_&)7GYbEi)Na z%!zx_sp07A=-8nbQq;F^P|y7H6uR=RJv}@;x^;4J?9j4JM|(RvtgC$jLDhrfcOBd` z*JtRo055k{#MW)mvw9ePLP9=fvfJ>9gZ+ZT=S*J_5ZHg*#8F)Wn|=IFU55lNuO{;i z2|N2$(fN45u5ol~cANSQ z>X?ZFXzARcuCA*$Ry`a3z*y&rPFh&fR5}&fx=H;yHAMlsyXN`#?74bl<3BY= zy*~c%4EkniZQ`QdeAy`5LbRsG@Y4BGo(Vc+8?kU!k9b*qN;^qxM|8Sw4q zxkEkH#V9j=txVYm4#|GJGF9i)JjV`A>en?u0V6N$Ug6(o^+tC|G^?ycL{p!}!056^!SHFr~7)h9ZYGyI*VU7$zvb-r8d>d>K$t)P!A z<<{xl>vqRgzD7X@JO=hW*f(K5om%GHt!s;V5`l-^xpZQ4()QZ(=}4rjlk>V5tCc$6 zEpl~j*V-J}v0$3<p97qoou=KEjgX~BdAoLRp{Bpig!@1K_;{7Bu4n4d zflf|CzwK>oyyxaz2iGbRc(lN|`!^uaWNV_vc=UAk*sxp-sntDOXg)uEs=S|>^-Ip( zli}06#&~;=-JEtKZOb$dxhP!(-w;sF1lL#G8#8`IP9WB)=L<(Z!@ zUpVp2f!&+eg$EDyc6Dm^DYpQj10?TUy>#L92>_Yv)3c_|$HJu&M2eBe?%%$0un|_#$7$Pygs1TGT8}LWL)8ZX-fn)Mq(0VLh26=FfdtSJnm3Hqv|bce;mp zy|+4}v`!>xW9sLB{HwuT(H%Jo0FRY2AI!P;W8RyNcm?z4b6DF*!Mj6jF5ic^jg56e zfKON8B1fcRXC!D{r91cQ^84jz5K~Djsn)-KV(bVBVXBx$}L*JHX=_SCR`n zj$@5Q;IM_wbYj^=XEo^KB5)9KpBe|lzr{fzuOcOt$#j3y*Q>$x%{nPUD_7&c;7OfGr64SO)ck1qe|J`p@>`7e#b3p=dx4lJa%sL z7WYrNQPmvo);gO$ou_>1h>_ZT;?zlja>8;CX$IEe69bl5GIRps`! zAGnY6F}82-!JdOgv6t5fc5@xVy`0x#Eu)xy`V_P8pdIYhKZ=KZUBF#izF`m7iFVvbqO+_Gg0u357(Z;xf}>+p^TyIvOYa zjj`r3f!$q>a}Bd~Qr{Ht)qV2g`e{Wh3aXgQEVHpF;l@?pbB}gKymcdU!ls?9tEa<{ zvKeb&MLfv0kk6zR0glwS_|U-zSli0uK3(z|dKmkS9VvY~o%TI1o|^^wAK=Oc(QK-- zPTMCjE~HSg9Xw?+IomfbD7UTrmg^Yiv6bn29_v%Wp>ua}wd$34XFP+>@7Zr~39ks> z&U$)!tgEYF=*c``#0UP$`aLh3$5<;HBbC2z&jlXnc89Afk6@iD0c%}rH0xbrY-;&~ z1{0z?4Xq}WJGU<3W;Nb(J>xvCrF_rBJxX{+;4ZFOtrBls$>@{sIbtC*v?^98bfv3Z z>z2G`8FQEB?|H#==AlDIOXcs_a*@Aw&gLq5XQj0|QytJiz83t!L3{^~`Yf>b*SAaE zI_7a}E36Tr?sbhmFF$4#OLRVY6x(w8I#L;BWo6PeA^I(QIOp-AnV-tvzV#wwKEl=X zu7f`ulX!zD-$-Ysl&3=Jef0GWIb<4_59*P}_Kot`#!}D#<@eXrziK7kw4OOoRm58o zzLWCz>eW-46I)w1;J`^+c;d(+ULN|X{2f~_0jC#SU3nM0@+`{Vi#{M|umSn?5p}fk zVyaDp&Kw>h`d2gLGb=^D-pZWkkxt$v{utwj& zLIP;9bDO4o{kJIpIoco-ZE#i6+3;QHauve>Jn)eNAIc9T7GdqY7;E0eEcOH9V)wF* zjSabvVA^aOTU;fB^%f@{cE9;qgQBxKS01LH!rd zokSnJgl{rLNuR7(zPNusXuyopgK>oeFI50ty;B`4}vE+wtj~_te0r3C)lr$#s>6BDO8ky z;)Nq3Z;8t;$Jz!TJM>(thj^!rfm7B&))ixqCl7ld@411+dua^VR?g#*154Ro75Oo( zHqYpR%r=!?pzSYfz6qUHqaGvC7h$Kdu>~JL{DIR>2s!@>Jm)oEx%7&Y55It%D~3!g zU`M-r$m%?9Ym*QCOYG0&VH{wOWlS;0u7A!+dtdVAjW2n6z%#TBc)9r-=zx}@e4*2d z@Mrpu`U}x7jT*KsOF8m^Q;vS%qe&&acY6s(ul&FZW)z|R*k1w;gL@TlKgR-g?U2u% zF$UY&Kz23Ghh8Y&6>|5s1wx+yo$^>;{uRoW|E4M6OS)^zt$6)K&|yn#wlpRZHy81y z4aK}}c`=8F7V-RGHJ_S_G2%D4kUe`AKsU(ewhi*7cByOpmTT#kpwDHNV+rSD**aAJ zuj*Z~d~v@M5jxz=(nI@-%MXD+?%Gm}u~Eoz>x#fDi+R=3B3?ABh^P7$uutDS=xll1 z#`*)>TIQFVDrSgeFL2d3%o|pFV}OY~dwZG^?1RqYlyD?H}mgy;p#YPVsjE`i*p`tuz_Pa>BmrSCjoWrl{igUAwZozNQ3n zU4trhjNKX$yB;_C*4Ujy$kp-MxR~r`C!94*!HqIZgKKV8uL;?9H)0d)j8i7Oq^{}K z)=~jL(&x0@i|EsK%KQG=bmIt66@X+aPp^apnW~2*&s3eFmDbJ@pj;jC-fq8t2H9Oz zow8erT}}Zgw}#5oGr{hD{B8N!i0IR_Qcwx+X?FBjulP3m zq|Z!PVEoiD1@Jdu%hnv}Q;|NQ&Hl6nrZ1JLfP-C4Q8PJq7)7}cscV)zQ%Z01@qN5q z)GA&zRkg>bTxJB^@p@F%EiVS@AWgWxtU;>^hka+_SQN!K@cBAW!?#R~OZnT7XuKy$3;gsnG_-qXcd z(8mOT(%PJt-yiGgf2*tX-bT>b@Kt7NTARhn`<|ZuCyeb@Mh|jv#(PvCD>J)|opG|K zr`IVZt&H{@j=G5VX?C>g{#X~OqlkUoYb4T%b|&M!e$sX@=PI+YBTNy| zo?c!P7NB2^9U#C9Ko1XGyOtU41%ysqTQPgA1P1Rry?Xr$Tg3hVQpWvB~VD zfi9thBC-&W;j{55a;y;Vk58+ZT4c#3x&5q4f5IkMuaJp${@j^wQD~ z3Dk5wtD&!G6wpr!YWoyBfEtM??8*OSkhC*>(vewUk+3T1=;?q=waLU#PC7c)q^~qX z{uZQfq$FK=Q_{o!y;8Rk=~5@8sYMoM24rkzBJJawnpH+q^d<937O+=#gON%tGLns; z8r3YRO0_CvKmpjp_oJ#+>tV0IxwNNmM8Vjb?@K1Kg;dw78r7-Yh>XOZK5UdNDVpln zYl(gRt<=!QifZV_;QkizUb!Vz!J{Rv&r2YIR&6-k8Wg^wmNkL7{QOo8H z$wGEP+SfNRID&3-3-_5+NAC(XtrtiZy6Mywd-;{IkKd+^1KH?2mGqaN3S#_o^b_b{# z_W9kqPo`e3{?yj`IrVT{LapnTW4|AJ?jA$1r;q*hzSE!wl+hs10W@gfc=GZdD(&lc zYL!Qr7gG1uOkN&Q!hWDfDfZ|y$-7qp?3TCC)M=AxV!%oo*6%g>eEpuL z1Y6Q}j(a?dgTOOKCV?2v#`jpKyd-f8VH3Rm~*u$SNv=Fw;OjE~Z z)9g9XGig8a*9 zVQ8|n$3J^gv9!lOcWNnYoG;SKm9f&^eq`8jnm--VB=Q?tvwAl+Pv6k8*=4k1aTYC` zS4`_yWKj5`B3d7Lo7SzlLTi=?duXP(*i*D++fLfF@dt|8@Dn9$N}=c#unWMx|E8!c zidtPr3Go@UX~TPp#S-_H4Id~js*HB+xB;8#d=mToJK}}i^gY_Y_d4y}`j+WpT(wQFwKc$}24X$9w*T z|K%Vnl<8sk%M>!bLfPL#13Qu%nO3fBX>6h+Qz-sA3%Hh1b?fGxTDNZ9sYN5}+LpS6 zEdMePS=x5%(xpqsj`poPHE-UcMU#frVe@G-_mx8SWo4=uq8W{*%W|oER|J$H~X1 zdrt%h?~$X1AT(=fruZU*LRN41l7#(7jvS1cKhZB>;;i}OdJY&KvT@tKJv-OW9Me)? z_E`pn!esc8jXS@)c=5ZPE9M8zTD^2*MBup4r8|sobUrIVCTkbG8kD!t zQ&5kX`I}GC(327K*EE(XEX>Vivhg#U)sj^plT2YXIv{NPs(uP(hedND)?C@3XmIt& z!ZkA%brFG!>=zW$?Hwl z>>z|W(POF+znzBMl$4h+0`Ku@V?@Y~*iz_fejik0_QcsIATZP?I2Q)PwTn27T4_TT6mZ)wb=8m=)09L*P^6Z0hmH{S+2Y^1i2eR}#(x{<4hFo?U=YqefOb zB7>sU$wRAW1^D?$_+LGL^Jfd0DrYbMcu(LT(Y;IO_RU)~vNe$4k9}}5am{qU{sBl|>C&Uu z!xW0|FDIUlmBrr9$*uwT3w*kCacGV7rV{)~4^F0TT8Lf@`qa4l{8<~BAQ3kO(4OSdFI?YcPM6Iz{Hq4&NZGDtd!{;xD)6%|MEOadH=**HurXzk5lh%_MMtH zF&6L(zsh)UEiEA;aC*WWXY)7t{bWt=9trZ8c=#K=2?b9o0snDIcPm4uE`G3oKcTUU<7tlpo2^drdd zUTTnsi^ufiNwn*Yo^0-eFyP|@7FJo^e-w@HKg{?sEivJEPTxAe){(XOEoL&(2W+}+ zKH}G!3eab?hX*R$TtXimLbm;J&W$Unht5Cm+jOmk-dX^}q`Uv}TNCsy)X-b}Fv7>f z!>L@=rD<%&1=qPnI0lu(MM)Mv&e!4+{MQc69s#^>F z{Cs@+dyJlbW|f{y56pJvbRQS1iVRL6OM3qN?$!fGcOQs9wLffPfS+G~KcArJee2>6 zY>k}}9yGdnMgCT(pgNZxKYxYr`~kYg{8@n$g8~Blf|egVfAf6mrX~LEbt{5LmFcUC zPk(#-DCfsBsrxsri3nRbYgSOe#EH|V&zdzoXmo4i&yyDxDiw8-K-HgaT{&~?(Eh}P znAHpCPY(+48|~xM=j(PRG97hIKm95cvU!=09^Jli>&oRbX{pB!CB!VmsP5zUwUaeu z>!*a;JB32=RZ_;|hdGo-+oP4)-zFBB zlt`rsf2|B?OZbmowezL_KTn0O^?!YyYV|LtssDu!Vuq_r@H(y-40I;Rl`=0q1DUVB zfzB8ue7BSavSCVnnTNi<%uP>U)*rL`ilMo9035M;@P90PfrFkc8VNQ8vUp%{6Y&LN zAz}%lSW*yCEHS)9#D1eJ0VsQbjW(2#t`=``{Q@rD{6~W>_M2u&5cOq!1sfN86MGQf zA&Mmq?2T2HY}#~Xov=6WD(#W#$-1+G+Df)?eiZ?M0ej6L>~h{7)J8`xWH zgU!bV>^UzhH`ECzL!C->sCLD=Tt%DsenLks%G0*Zr`P}XodQlGq8JejTY*+7xWNlK z=<6iepj1{|m-eKq>OREY{5{D&KBiTHt>#z&?)%JmA@;J#x&_HJ#`d58T9pJD*Iu-WKM86f` zpVt9CZQ8a&Ci!AyW*wOkn<^HR)=>V8{qjQCBM2M9r`VH!hW+~|unqVfb$N`duyOna z_Db1^56~vUzVQa)MXs!y#+CHGMcj|Loh|iZ*+OrFbT!jm3SYdwW$*{p)I+`uUKmYvv9Oi?E;kR*LN!=E4Tx4feg?U~l_1*ENQ( zs_{$s_C3d5`xDp>J?46*zrt_zA>vP5&-^Ags&SE9)H}m=HYd1s!$XLBxs~m9ZdQK_ zH>|adYgkMxSL)Yedr`=fbYCO@rs$xcXzswz7>)7P~vfOLiaz`c2B4)xB2k z?!fFnB8TS$UF5YZFLV6HONbYFP2?q>9e9aHc;1ISCiefEz2}~=0~j?ZpN9@S!()d$ zVDCPKut|8y?QEYT%@ZCu_#)4lo`$@qIUz2MH*ZSijZw+4Z#g9S#P)OB#dZz1b5)aB z@C&V??Ms^RAn~QYYycS^J9g|S*;@)*)P{|$dBm`3l0B+7{C$P(fv`ypoEpgrU6SllH$~rtFR$7*)zj@A zdwOh?>{A;zX$0Fzg=C{Dm&@4KcbH_SI-t)^_*L(fY*mF{F>Jdv_6vfyitv%Qs2|n8 zTIM8V6C3E+ms?vrhFuJ72y4ERY{+I$Wd1INIrG7Du3N8;M8h3B_VCTi%+tp+_lCWn zpLZUgN@n;gyGizKGT4|!t=}Wnseku(?9%QX&qZDC{RkV3#64_eWF*-jcJ0=gALSJA z&V={e&-Ju4j;k6)K}M{Bz3rk3y!E4u`-84wpkGsr+sm+fW}9lqN}E<=@RVG(fo)F{ z*Z}tGQ~t)tqW*BST=8xmpDYk+ZKWMnM$vwHPv@R5VBB-`Hh4d25r{hegr`^|xCY+1=% zYR8EaC-DBnT*=PYy2>fY>V0ZkU+5gdw_QZ&NK#tV!&}{DB)wI0EAge>0{^y6_m?=@ zF}JAm7WS{gt}RcpuM=$`?0`2%m2#V}x=6Ob>sH?7AQkMrS_!%q^EZ2#$El`B<|drTf!f9`VDdOzLI529_X4|2A@UP{|K8m*oB$EJ`VPYTKp3> z2>cx+{MSYR|8b1I^&WPd%=;1_aoe`7q;lG}ZOa=rY+!Q>Lmo6x#hW*vpE#Mmu(d7V#7)ezW-XFv zFPF=C$r2bcBMcfeh>eYncu`0y&qrEccl7_ce?tFFMXJSn?85dGO3@-^>=bIisgQk{kmSs?Mz@k8Hne>(6#k2W}pHrR=Auo3l$1}~ilJ35JH-PV)2Yk8>PKQD#t__B~!<+CPz zknG3%bb;NU=tJl?Vhpsvc^blwT#LW3CEu|6u4L~m?8%QFy3ZyiYJT1tw*2?*lu35w zhY!5Qdt=GAJZ5z+>RK$>m+#$Gar~nHZ~6fI-$*)N6@{2bT){Xv3H${w687fN(6yI> z4_OO(yu=(xPtyQGb``a6GYGbgr5rlF5O&7}(AU(q&w_8(hYh?qGeX#*f5acQ$g%71 z@)r1J2wT;~i`KHSiQ4upFmNV+d!U?GFDsGkxw|_JLYwIE%J7>U9m!Ij{d+5pUqSy8 z;Qto*Kf&DLA$09qXoK(2hrU4_wn}YaB43U9hn>K`NMF_qDeOXuao zKcJ9@xWg8*9r_UXkZmRK|9YR}U%7H6*tp)6>~%A4GxzAxi*;aA4o=M5ww#vyEc}P% zOFk7rQ?^KbC^&Ev@7=}{pFNcHuke3{dBiW0owb-Vd>qH}ShT@L$xlq+tCS7Y8URT6 z3)}moM25X_o@9SN7H58Z-7Wv44SpMIp;v18zk_6pzh~#YkM{UYn>Lnk6gK$>_xu8# zqFl1epEH?x?TY&>Z1cNyb%#xDsbrs@eC*Hge+QW(Y?OZk{`aMEEcpv)v(W6yTn|Qj3x{Ed|=M9m$+^M50^fejA$z#5o4!6eB*Km$X1^FfQpZCE3 z74XMg4)bZr)*f?DbsyS>aj;2C{}QFlQ;Wao|An194wCeg%~7ytU81(D9W|%`_V)#n zEa(io;<1B2pzo^jw*>x|E@VnP5*vyV?L{A7wj`dnM#J9PE?2Tg7H7@~TkYXP)Vy`= zn*EGDVZQvs7x*WXqW=q@7ue}5;A5woBh5X;aT`L=<3PgPv$Mv`O4KRk}bT*C+QEHwD`XP{ul%Bbr5{0 zlKc|zKaMsy0Q}c#`Ogb|Sx+th0SLNTxl%2TkIpJTxQk)qT!=O(hTlOUkMdNvLGR85 z@a-vqExsCmY*zEDS1&m|UG4WG@Nnqj$Y)P7eBspcLdZQ~7d~o`u;quZK%K^tZ$NQz z3IF)xE$M8YKjIHR1;q=j0sMwKsAZYpqn22MG0|C}<^MO8GG8tK7w*Sm?GI=594$S1 zkfDndarCNUX&g)$Qz+Sp5A0C@U8j^2Hw*lszg4Zmj~_qg$Vj!Vyn&&D=geLv@i4cJ z?=W}B5BwYyu=5w|8Sv4p ztho7c{l!RUx<>v=_#&%1z?NC~K(UAW)Y4<$Fbn^WEgOr$zl$Uvkg?vv*1b^j1KGR1 z4El2y$rmI$I~#nnhlGQvsgn2axhnaDbZ!Qj4Zktr7b0YLSB=iOWWL&WMEHl~_| zrIL+$%$j29>?0u${D&4oZ!86mDr5T&UAR`Qnw*xF2HmVSbOz!UEgJLDZ}NDYZ!z0J z=1G1X@GGeS-BrjC|DmOjQ3Y&fYR=fWbrlw{K^m{v~#quS2CwyW=6m8JBY90^5{6Ngr2KFB=@!Euh1gY*K zZ$N-Qd>hK(Qz`rggg=qMAHFgQjA5*QiM2f8Q!LUViZx?|k8AhZ`Ioe2(!On@4A1vl=St$`#*8c=-8^MIVHL7I2ytIFZksES3Ch+S!6{nZVx;zBbjcMp;!_ zQ@sRVH_6uv=|B41h<$^Pp>7@QMiPCG^S8k3j+LE48yrY1L>)fxw%B6H&*0V-=J)T^ zKCfcznV6VJ^V}9K8^YHlo8fyP@lD|~SyNy5YboE?m9Z&Eeu^uUOf6e^&BIK`jEnG`?Q3r_^fe%S-U~Aj1 ze9!h5eDq)`i+1?-U^(yI`70mXca4`VTOr{s@HaIzmFVZ~Jq+Wb96FPb)$qB5zAEOO z!v9tH7S%RT&wmE@DnTFn06*kmQa(`!F;6xzHNrZ@7GApGdmcXEsid8K|>mwq36O9-Y@1rjWC8gG|b~+{Yr73Ulvaeh~YW2 zqIvPcjT|y}Bc9{f%VRAM?vu?9&{b?Ki@`GwVEs)g>WH;_rC1k4P-xex)Q^Au`!!y3 zwQ5%7(d(|2pNBu^xwLYIjT@)mP)Feh`WSiTL%89_JtDbL_+852Hz~56%g6 zRr_`I>Xa|lNAm3g{oC29{kyug67^L3c=fSq6V{aIuoBSQ;Guc%(Fe)&@LB{3e3902Y+3MK!@O&dN)zF;dB6!F5DMbept)BOwK zhgHY{!{HO=U4S`r0ehk@!Y^LvfI^=WXETcR0MV~(Fiz^5a191N3hyh|9xB$Lo`7Fjr%Q`~We=GUO*EL}9$;WIY zTZpl$Uem@>zeIO68V3KQ&ws)gcVE;&j0dr=i*q#Fl|#=f6TWa_-n$?EnZh4#YiuFr z#zm4(+{RT!EabNEixYL37bx1K0J>~G_wTOuj}v{RRUMXmpug}J%t?^wGh z!N)bhpdu}`FaPZ;bi9^Y-YUo5j*!!{gAbJK-u9;a$bR%I#H8H}c~>T_g=~&4K)d9l z9{KRA6YWtVty7QjV(4jQSYLWmW?gk(iLqW^;H{;(Si6_@AAp~<5A+|wy<%lGGVXi4 zlX!y_biRIlrM5!*7ENe+Vg`MmNvY1Z`zd{!$ ze{S1)kmOrvYVz5hweW`&YsQ|sI?~!bZvT&j&t$jIy~X@NGY7f}4F1;sK`vK%U=6t; zbf1d-Zy(5`LELB^Z$E6S_nYTWfsnq;z~4MT)~CwiEAz_ zW5hKFgcR2Wppm!=QqBM5Pb3&$MZcmV@oe_VKL=nw`4eH)BS$==Wxl+g74OkX|LJRv zfcq!qeTmnXcnigm>iw~v+WLQ_M~;R*T6$^ehlCP6KhjrF9Q2cd+Mmb~MJz!4OTSfp zJ^T%VUhup527asUsJc!L{?_SqOCrq`IzmUFP9RMP#5y-6`?x*rkn~IW81NF?9<);8;owYRz5CF($*)rAg1iO$E z%i#)4*JE%o-Y;4~azuvLa`-aUc;t`8QJ}_CQ9+cSX(Rf9$e$}q33qi}o{IA0Z0G%*DonEMdXK z3ex`6m~g*vXc zvtA?rGBH+c#rK17dkshVp>X1T5wrXxWxo{l1AI;SB7b<=)X>**G_HRd-4OXj`I`J$ zsVOlcKe`PXR{%o!OZ?!IF3~3>GczS77Wtn5?6UFkXH7Nvwcn9HR%Ao0!PhaF;2CsK((Szaan+X8OKNWq)RTX;=6K2p~g$jCz z_QUDXs6p1$uA+MAsVBwv`%C;#0nveT<$#|m;KL6c-~H3cPX=4TBW@Bn9Pb#*aWC>m_8^^%Jg0fZ;*(Dka>dhXfu7IAmp= z6+9s`W|^y-YI&NtH;8dn7cVG~EqzDz!o^UHw*xGrC9Z1l_>LMpzj5Q*b#&D5aPWdt z*RJf_8$R|UgCgVX?AO_Xip!B8d^w!3Q)8BC*#{8NcuA*#2Z{uO7l!xHf)^y}^y-yx z$rcG>L?Pkfs*mhTd>2)OUv_E=QiO*uTjGbqzANxwCUN3-R;uvbj>m9art&k_R9;Y6 z0O*A8!h;)SU^oMM#q6SvA_1Jg1rp)m^(%634TL$O2mvED7R>$g>;RBU9Ylh()Rbd? z6hCSlXy(3y5B609^}oz56#)UL4!P3fAAg`WiSVbH|CsuJ`^{GM=^2uu0w7N{C7y*M zB47#>aKUFNcKEYRnyZApKGa3=3l0Jy5lpQLN=GskjttWv4U=1;} z&*JQL5%hELgJ6~;T}WShJxfy1&rx6HXaAe7U%=PbJb%PTgQpf>ac;Z_+N-uc+WL0W z&||*#Dv?(ZSjqr=dTbC)3#vDh^S0jZ|7ryDWNiK)ax=s^P8sq$VJu9q0w!+#L{*IPT zJ5tIz!w|}u3}j!ExmkT&y|8jHn)G#tQf1Rll3#lD>hNi|{EGAyW6474iF4#9!5=-C zYSgZYv*s5fMpAW)K`3Q;_Io=mdTzeKHCb(DP9#aZ-K2tMZ3V#pll&(}7-OjUI9sh%>M>fl<#;AiU4(ViOB z+)a(^#Ytz;TbZX*J)BA3viUUXZ0|;ms-GfT{Q~M}?@100J*l}-0ohdgom$jCN?$eE zLe`bvkX_^5*!G8+{1YBnvI{|zl)9!0`meewL$ z6dAS+--~GV+I1AR^fWCC&7jDLBi)98TDx? zWpw`RD>`$!gf3ltNte%+!GHZ0UAt65>9@-0c6yQI$DVPojIwgF>F1wc(&L;mdhxVO z?aQ89PKCwg@MYI# zE$Y^)WNIjfiLLA(0uZI?SE|$2u5H_YdBK#X;a}R=<_Ky<^v| zJ-T*n)v9glCQTaHw6LvjAsI3MH2_gfGn-!h92^|+-?2Slv~AnEwLrnvrmm%-AjV%n z0OrPZom|{qTza|mbLfSC4)$HU+DQ-^*w|Xt5q|IgIzI}x?BUkW&Ap$mdp|&Na_Hsg z=xE>G&aU-q=d-oaAw{Q0@HFWUz4*m>)j?id`lY2)#<%a<=7-@STeNMJ~0{OZ;FBIisCT)I5^z?mOz|M2~> z&5LIG^tHgsbyiFe|^g2G4jwYK=O z718dN0|P>$AigCxP?=(RL}cQH7=_W)>-!=jR(689ECPH=DSSeA>pCVR`wRhik$vs! zJ1HV52YCE$vOT?WuvDjmWD;@l%o#n7iGRt1J8Jzgv--TPH?=%m2-2lqjkUBB+1(Gi2e%C@d$MG{iI zIROKG-Q3-LLz6OxDm^oj!h*w+-_#aOp~yNB85|guejD}Q`Y3kB0Q{K+%;4+d@49L! zAfr)%!72c78;A<@S9;z_3JYAH{u?=8?rCMQ-<M;+cs{}poOir1&GF+PD+TJGZF+G zF(>Jcr;%sIxfAKn(Rj5B-#oizr1)93EYGisD^;X)?bPq{NYKCqXIBPiIU0eGP{|IrJllj0&n zf=3M0l>ay<=Ur{|*O%9mk}m8~D$d`zlXD-v0qqw!*ukMany`V5O&v{s*`@2}lDDr4 z3s(86!azTT=d;JJeh0Vc{p>_kT=IjeikO^?SNBE#%S;ID*U!Pxu5AYp@MHd)cP^Yr zN?0{#k}4ofs{fle?{}fO4`w8Wg>An+)u`LEr*DwoXlq9Nw0=%54((gDZqUH$WB#*u z($5`^0|Eh)LX$H3D~G;&SB#FY{5d@;7%XA4LYejI{V!7gNeJ|Hcd%D?0d0QzCIblU zi;9>NFiG@3#n6JHJW#*Ut5adBfQaOq3dNz^!rwuUt@q-B`?*6Zi9T$jrJroWy*n39 z9gbfW8XO#%jQ%sUxa1;O$KuEP=BT6|Y2;r}{F?&w%h*20*U8C6v|yVSIIT@;KUq*t zM!JMRNXV+gB7aE*mzU!M;b^#G=SMB{?q(!&V!8W=ME<(>^t{( zsM7zn#CH#eqIe(>b~v-D(YoIS{j%fc_&U1-|E{f?z?4*w4}oY6^5026oxCsk%Cn)$ zp}Q1D=&OmM`mXK+=Om`jR`!<4&q4ojb$4>=Y2T{WClN+82!}CbT)%MQ#JP;;!xh89 z`IHaS*9QQ75HL9E!Xc&dD$3vWI62JM*WJCBqkUVGkHrH4*`A!7%#8H(D|en2`YSw9 z`jOu)1AA@TYY`w>mCcWzJ$v=$)tfiZ9^JWcI3Y50&Ya*$BLl{&pjbp~ zPdax6Yz~UqSl&^cpAH2bphY8;Fd%{RlkR}6*g=T00>icg4&S``@?DnS@IDL5cFcv3*X2=|VL zB-dhH@rvb*Dl2jxJ-Ubd0Faz~I4LPUE-q?SL`Y!pB$ZHbL~~jj{CRd!2cq%kbF$Ho z($gh>sKzEI|n?H;-l6J z0A48H%J?s`3pnW2gAQOUU^LuGzjHkuAd-{!#i1=GdHJ@1#M3G*9}E5B2JmHr*51v0 zkeMm4xO4r&g%gMOMMZ{A>rw;2|IqGVWCsxh8JY*}xpyxoBSS#Aat>`Vp>ySbl35K+ zq@*f?g4TZX-Hl7BTNaLKXMkBp#R2<=Qonp5fvETcy#B55+4S}AYyEG*{!b?Uv|{-2 z?tis+F7P(i=^l66Zi#XU6^i7NE@w0qqNxMY?dxNs$yI%)}&024 zJ-^n8RcXzP7XN_b`oiy*iT(Zmq)vQNMBT6d{>p)WJqIq-Pmb2URQp=(+zH9mPSKLP zAnd&6J^qi+@L9gYcmEx?9=d3ro!_WE(0I5<&cV4j=P!9v=v!=@_I2{fg=j5NtcH61 znpxQrUGxlpU-f_gQGFESy%)BU`Y*md=;35!Sl z!Spx7lkz2cIW|!eJ`%sdZ}FS|*IRF0z-QWHbf;+j+G>3tP_M~y^((E>zDm0=ds6&cM6>F^eu(%`!1L%@LT|v&&WiK&3-4=p+Ea@ER@e53 zKl5Kb1?(npo7kg%DaUUThEoAw*6KBU`839lRpPe?3%c?pL6S~lYgz}s~zj5LMipVm3`YzEWb5j-=f!>?Syih zglV19@}%wnrncD_|D zGfT%bt6DbIs+66geWLd9R=Lbrt5kZRl`VO`Uklg7wQ1)Xe~ztZsgl)wj@8jeoocnJ zjI|~wWT`hQOFfxc!iL(ZzB(|Xc4}7M4)ui4bG_Z?gq~D!i+WI_y>^97ntioVvqQht z{tvzW#%fhqueqUL+VSN-7B<#ut6k|mt5zsadS&5oSPFXji4isvg_IPCIF~uv?gKsa{U? zX)>ShI$`RtU(;^4dhK_4zdy5=&TWw8d}>f_hx$2p2zzC_@DH|YR@^rAFKyPmyiL}q zrtrb4d?UPzwN}5{=XOS&Pprl1AK9hN*I4`3@7q;ZysKHB%dKm>Ozlgo^A(G%-6iwv zlJjR;v$LjJTB?sjyd`~t;It1TJ3V0`wCZJ z=v{lfCxtm!^w~Tza<7dTyvGLi*&~br`o(vtN9a4BkA|GII4w(QdAf0(x$y?)21%6DU)Ba zQ6pzt|GrbLdzVM8L)$ra_Gzhha`lN;sca9ee}u&lyLM$)e=?t1SyJ*-9TS9e(I{d-_HXdaW%6F2g{FXEr=d+S`ycVt%CcfvK>VQrdiQ=i;6 zYt*21{4+(JH@wI7-Ej3{$v~Q&a{MH#R{ml4#o@YjgoeY}dKWJq`S+t!dN~HbS#@@+ z=dFPLa194LcE56|dMqQ{0p_97Ti5?i&EAdit5e5b_T-~`T@J2nEqsAiJFQ2joz}SF zkD$NX>vn$A>7xHJ(GNz{XvK{!Vr!Jb@o-`!kL${%oU8f6vd6+epii;IX}j&p*4aLj zbH>zM%UJrA&zB7JaAe-(8_Tw+*DKe1{rUX0?e}=^{41K>*ZShNarzrJY^3>(>Isw0 zxVHUn+0^eOFTz&qw@ZD{dn|p~`|7c87XN(sow;-8+p^cbwUI+tTc^ukwWf`xTb*k1 zkL4b5`j0AcS7LksEk9->ws!v2tTaizjhg)``sv-LUz6U=n>6DOT#PrC=Bp2Vzc36= zh+pHnueJ#TDbMa7v{!Nsc1*VVKlj-9QG0Fqn_J_b3$!eLWtDmra~TcET}_D=r{bd`SBkkC6f$ zI{wgnf!vDx!u={fo_UGTU%$#OYg9er0hmh6{(U|**YS~50rzX<_`hrN)u*59^MCmq z`|Uk*ykC9#^9u^m0uKfZxZCE<%Cr8xqZzBn&=2+jJFl5@iC&Kyw%1;JInOQh3&zL(&kegBx8aqAnT5Us{jV?DsowLi6eGMRjKEhFBhI#CQ^+5| z>I0(;th+HWthjj21Z{`f*69OQvq~q$IGSH6I?;P{fEn1#I0a7uIiSD%-rFUI!ewaH zvW;IONB(AJ?|-!tZk4dlItst)f&2E_yKm(e(vv_x$HgzNwK0E`zQ{*3YlNKvZz$Vm zY`!q7F#W@Zjj*{hcUqsG>#W6@D}}8I#+=$WVYA01%r!D4`Z`nB7fmo1!$9AV7l3hyRbe~#dP-F;h*>plL0e(A@@=NfvR zNOPiH8$N7;e+H~6> zmB6=3l!0zeQ>-r2;~)%hyoaile`6h6Z}9cS-lGGocim$m8Azs|nY@Yg^EdQk_nF6f z$4xm}FX?x`fraP?QxIDQPxMfjdbe|h%M-~Be7m8O_%=@1CCT&;9ci=EgadQ^2F1yr zsmK3a<&8_l1L`T{j8Dh%#mEj&Z%U}4K;!pq)Y|Mnn)G*!9qcx9ZCwY19hayBiR)h! z{pdTg%v@w<)c!d={{TO>X3d&Hwtf24&Hh=wN4#`nmq>1kqJNgtze)73wb~U|dmSNQ zI|Uht>IRV=C|&$_F&XfhWKr~A7|S88<7M;ww^={pJ#>KB4;=_L0C@=VpG-gcF!+uf zVLgFgx5x8>bj1mYvJc)2+xi&x5dSx5;57HCy`%$Ogq6h+y(xdMrct@5!aTfbf#JZ@nfuyM>CM+aDQYyem+hoT=_-bc6( z$N_QEgAYDhi2i{C2Ri+EdHe00bE5dBWBXea3r0Es?}!)qyJ-5smDsL)LAcVDK2zO5 zH8$1N3d=z71rMo)_6Ow!%pLZ)23nIhYVLM=-Fb74>t6@WRChn1ImXPN4>}O1 zUwWRr{@~J#{QX|#fI03Tmo3hV>v@oYmtK0wwrt*SYd_y-*goE`QT=%L9q0?RgE#T? zq=V6~-0}2pMgLmS|DouAJ8lOGd_ll{9izHglR!VTCU4w#ur?PD5~gf)?bu@GIA3~B zqyuNvigW-OfEVD&VgHlqXT2YiFC+dVu3P>_;h2wDar4Ig_TCEc|ME2#{r$LXj2@Zp zIW+!rh-SVMM-{#P!s56-OZ0D64Tbs|^~IH<|4qrjLfOIDvV+u7sU=f89HX4z;y^#N zCU4w(u^X;Q^=rSce>7K{_!Yc2@MGeBpptR{*+Zwli1k;$vd^L>-o@@ud!}&Ahs|I4 zPQGTU=ecf>6V$8M$a!#0w*m6`xgIYNGvE_u&rI@vZvXc>{Vh-5D*C~P`$F`8AQ_;J zxFi-2fX`px3(J)Ve$ekTCDYISC%dO#y2t6P9q}!Chz)) zzZ|#U*kW{mS?VDc;)q-%)8DFPTaR#~=6-o>W@_%5%gw|dR zu_rXE9-B)Y3p>>J#vIin_C&F4%nzXZ*aG7E1LuhoXO@*W1AujC5c{f)1pKe(LAkM;RID=a{_t|D`^* z$z_*11^Nel*g-Iuf*oY-!9XRxXZ;f6-wRr`wRe{1`~LYS`;1&A*nEz9T1&BOuJe`n zs>4Ou!sE$toyY(2nX}G3&uaqY(Adc2{HH+v@y$DhnG`S+NZdX-YlxgZuO&;jlv ziRiE=)9>;>aqOp_rxJIdo52ne$FbhT0@MJ0TYtC5_fEg!{Sg0Ncwt-n=!1O*?c2BQ zKOp8?_|huZFJ!8fVtnvGkpblG-T_nNyjn1Kt*!WTzUS6Um%I^wAO1i;JiP7t-MXHv z82v#9xUcfQ=*JI`6BPJ?3MGdG+KZBZw|^ssrMnMC_o(OM$MM5lV~7WZQQ^39*hTyl z`A(pp{P&yn`)uo${e@yXuA7(-nnny3zO%jyABnB;vBJ8rw5K=6=^Q<3n)C5*f8BRL z{$D^p>jC{+CI9FE7=z4i34VZ?GcU$-BJMrM*1stG=l<``KFL2ii8W47$HKzU(wvgNLKKsLS! z+zwug!Utp53dukZVOh6}d;xO6YvO!jl%nVlbcEyTzvO$316xWhnLL7g>TJc<0huw;B49sP5%zjj}62ItQY->Hh@@A_tljXC)7cTihn)-sZqVIO`p2S=FEs< zvmgV+#K-`3Os*eWz5p(~BO5?0NKOoPKX}J4X#FRt1`uYr__IaH@*mHChYns4`CsgSY+LXJtTnX^ z@ON1+WEQ?)i+^`PVfjz4^AYo*C*;G}4`N6#NvWk!S0%m#TaVc5+U^6Ke)5Ea(T`1P zdAf4aN;|dw!3Gcu2OCHnfDN3h=WF@}-RD?T{tG|6{-J(jVH@VT9iWznU7GZe;sMn( zi3!2)W$nq)h!ctNFS;LYs;t$&0Q9NB;kTK^CSMKuv};n=JJcyO@#SC0}UqWWk5zSG=SQJ2RSlA~}x2TVw8 zKD0y6pkJEP@RrAI_BQ_m8c;KO@oO`xZa;{yH7){N`6V{fT;jE%dlpdO!^G z@cmJK`u@B5?)O-8)<3bX%X^C!u5v#@9hkTgc~7LD*Z4wwA~jDinkSAg$eEMl2>82n zQJ%{Rvx*wm%#ttJAwC8lKrTd0D5Ae~@s=_Ai$U9=HtrEPmhzB$=Qs~M7jbOOC?-G- zuv7R))}9y*x}i0hcI*K80Ctl50Mro^bwBWd_oy!rQ;~a9FAX}B97jO^hpY2FUVx`O zUvO&Goj!Ao8FB@=;3|K1tN;_!pB+3D{qg%>En9Sv4akY>0Xj!qM12dNw|IfD>sRJm zcJ_XcZNv2@9`OU%2Wnw$&W&QefaQ$bhdr^TNGu4?yL9Oq=Rx8*;m5`e`&=)%pAIfA z&*3ny;DmCCaq!B-n$Hit{{??0gj(?Jw>|E8JaH>E3+w?qv=hs(`*NSp21>lX#Me(h zIp5<*d8jkBy__3e7j zh&VX%fz&*a<=Fm1?|(u+o8SL#*r1tB8n@bcz&dgdkGyo^xb*M6wnX}0nZMa>Cccdt z8npxNAL9Sfd1{H+19-xFNf{8p$e%5KiWuCQ%{#O@n z@n?OWoto+O**Py}*!+1Js#Rs!^ye~67$i1%+?T%g#7V@=+}9({A>JqVg%{M3$N|X( z(GB8&@Qg*jTXJl~kS}cXpVIA#$1*H!YKA?Zmg%pl6A!#2UC$9Mv#ys%b%4e-BdmJv zcX8dZ9U2aIi$DKVt!gbBe9sJ*ee{kR*7D4Jw*lC9?(I_V;(cm%#7yLK#528x`1loCa>!&>b1mFDmHy!QN`c3sb*2|v9;D3<=c)@GzA+Z9v05$s%FH;{OR>Y80 zQ)Gi$D12Z|(GBQCAA+sKPU0i*7m5C}QmIi^vUn}OwpfmPq@RBcJn-kA;Q==BKQFu0 zeIs%o>ea+W8-Ogp2W$cIfKCuIQ&Wv* zuquga`Nw z>;b+KJ*aV%X04X$9RJ-|4+cK&r`q`<$UNj*#1)@~SUE*=R>>Rt-9A67R|z_TPeV800s4TQ#KvO}S~Srt%H#A*OSw*>+h_O&`ibifH?}z>aX;b% z#Ma~&;kxXUx=oEb(vW)>*mJ3yJYRQSs186q0bT??AP>j__gkm+&({derU z)ay7G=lplvsI^jCr{>Om2kyOa|HIh$W&3pVGpW(B7hwuKn{mOx#jRSszq3}P$ zBiz~i2&UH7lR|47&f}xnxD*}q-~NFdj&%xfZrAg-zL3dLIJm<(>Wduo#n_GKVd3bf z(TV&tI#D>H2-@Pfyy5Tl{&ul4$;ZrMz8!$;@N>PtKKi{f$;WV=$;UufI0m`{AHp&4 sDbBY{en@=u9}-{v#KIHy6N&F(9m2ZA*GXUSb<+nf(0XYlioz5AC+n$MbN~PV literal 0 HcmV?d00001 diff --git a/cmake/Windows/Plugins/amd64-unicode/INetC.dll b/cmake/Windows/Plugins/amd64-unicode/INetC.dll new file mode 100755 index 0000000000000000000000000000000000000000..fad7ad42e2daa0d74110a77acfbd5c73768e934f GIT binary patch literal 27136 zcmeHw3w%`7wfCMR2SQ*tARJUMGH4Ji0)YS~43Qi-17~!A0D+*Q5Rwd}gd|PQ@UT8Y zC#fXIX|>n3`e|Ejz16l}Yi)}W&?W>(c!!{Xf;Hfy6GjCeh2Vp8|7-6vnFOg-``z#N zyWg*aGkfo~*IIk6wbx$zaZa|gZn>YuGsY6|wJgT!kkTiM|9<&T8>;&b-PD);sn_0N zbq?R&VL2;`DqLmdrOV6nR=M)?N=ix%*Rn!ad7#8qRN~U+%y+FSEhrr0bS9q1^yL6u2WD8>>Ap)ys>@<>p`GaPgZ4ocVYm8C2)rqK<-;QsWPZr#0OnF6lK44te7G#p}U5am) zPZsdH6#t$5e`taJqOHnklTR-YxtHv8mz}oR=}9|1Z>N3jQ8n03Q|)w`ozAw?MRrcfZ}f zpl0k2yZ%u-ecDd9*y%nyZL`z&?ex5zCM^=2Ty{FfPH(W&96K$r)75rbWv7qY=`(g( zZ>M|gw9QUGwo`VqXs@50USX#r?R0{jYIZu$PM6tfiJkgw`R}vSs68IC>z}gIdOJO2 zrzh?76FcpDi=e#9PAA#vjdr@!PFLIM{dW3GJKbofyX^EWJ3ViwS0awmC)G|xDfYX7 zl_AcSvOEO#B38nd+f`qLyV!76(MjlHBbkSl<6kD=1?*b8=4zJ4#Uzu^9jII;k0(QB+)5lDDdGvTHbRY%KG0tU{ZA_Yz}c!Lbx_ z8Q_x7R(8sFAv_;gC2Vz<`W29dv@V1W#HSp&e0+<5MRFFgRY*%&0C}nx97u(-!5bS`{LIWDDT z$Q2-6gSu$XP3@xBcfhfbTcikBC3X$TPuxhuV(=@3q(ZM{98P)(I~ZK%5^$iNAx!!R z`;fF`6)Kl;SprB!eF-mjwLuI{wkt*N6oFRw&{)V)+D#_ThV#t>P6hNUg(UWJ1MsLl zOCXhyLGUNN${=S~ZArd0Xe$qGQZM9lD;EJv^bXZmfT9?6qG!m5C&QCd;k{jRLMnkz zd|bA#x{xD3cG(CtItuU|ZkK7SxY%fX#i$X#3?=IIS!`M-9+g*KP+kT($?~!BHkHvo z)@>Bg$PK`|MnjWmKTpK?qmj1&kd@rVcS-C*Dj%m` z4xAO7l58nH7h-nhPyJ3dDB^w;^?y7NDv-In$egc|H(&Q*en}(V)Tzj-Pfa~#&twfm1&)Fz}_

S*D?khWBr;t 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 aU_$N^{lp#lvHt0m@GK$x`}6;)1^yc=lV!^Q literal 0 HcmV?d00001 diff --git a/cmake/Windows/Plugins/x86-ansi/INetC.dll b/cmake/Windows/Plugins/x86-ansi/INetC.dll new file mode 100755 index 0000000000000000000000000000000000000000..d064bc1ac3474b84ae9c4ef12a043900738d1987 GIT binary patch literal 22016 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ðW2GbL*x>joG;o*WKF1!%BaWXqo^U+v zc;0c`@dsF=vyOAn!^uvyv%q<^^LnSw>2u!bEO)MSu62f;QD>*~Zs&c@JlxLf ndP}|4-dgVt@9o~Zyx;f!5SsinH2HYix%}U{=KZT*LlXGEWT(rI literal 0 HcmV?d00001 diff --git a/cmake/Windows/Plugins/x86-ansi/StdUtils.dll b/cmake/Windows/Plugins/x86-ansi/StdUtils.dll new file mode 100644 index 0000000000000000000000000000000000000000..5317b6d401c321200b7a3be87ce02381e333ff22 GIT binary patch literal 95744 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 literal 0 HcmV?d00001 diff --git a/cmake/Windows/Plugins/x86-ansi/UAC.dll b/cmake/Windows/Plugins/x86-ansi/UAC.dll new file mode 100755 index 0000000000000000000000000000000000000000..57a58c5399a54f964a69cff764f505ef2b7c8c16 GIT binary patch literal 14848 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 literal 0 HcmV?d00001 diff --git a/cmake/Windows/Plugins/x86-unicode/INetC.dll b/cmake/Windows/Plugins/x86-unicode/INetC.dll new file mode 100755 index 0000000000000000000000000000000000000000..b766595f2e8004898c52cb6fdea257ee186b1b3a GIT binary patch literal 25088 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 literal 0 HcmV?d00001 diff --git a/cmake/Windows/Plugins/x86-unicode/StdUtils.dll b/cmake/Windows/Plugins/x86-unicode/StdUtils.dll new file mode 100644 index 0000000000000000000000000000000000000000..6c852f4c46038befa5b37a9fb6f85977d84dcf24 GIT binary patch literal 102400 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 + CONTENT + ) +====================================================================================================================]]# +function(toolchain_update_file) + set(OPTIONS) + set(ONE_VALUE_KEYWORDS CONTENT PATH) + set(MULTI_VALUE_KEYWORDS) + + cmake_parse_arguments(PARSE_ARGV 0 UPDATE_FILE "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}") + + if(NOT (EXISTS ${UPDATE_FILE_PATH})) + message(VERBOSE "update_file: Creating ${UPDATE_FILE_PATH}") + file(WRITE ${UPDATE_FILE_PATH} ${UPDATE_FILE_CONTENT}) + else() + file(READ ${UPDATE_FILE_PATH} CURRENT_CONTENT) + if(NOT (CURRENT_CONTENT STREQUAL UPDATE_FILE_CONTENT)) + message(VERBOSE "update_file: Updating ${UPDATE_FILE_PATH}") + file(WRITE ${UPDATE_FILE_PATH} ${UPDATE_FILE_CONTENT}) + endif() + endif() +endfunction() + +#[[==================================================================================================================== + toolchain_find_powershell + ------------------------- + Searches for PowerShell. + + toolchain_find_powershell( + + ) + + If the POWERSHELL_PATH value is set, that will be preferred. The VARIABLE_NAME will be set in the parent scope + with the result. +====================================================================================================================]]# +function(toolchain_find_powershell VARIABLE_NAME) + if(NOT EXISTS ${POWERSHELL_PATH}) + find_program( + POWERSHELL_PATH + NAMES pwsh.exe powershell.exe + DOC "The path to PowerShell" + REQUIRED + ) + endif() + message(VERBOSE "toolchain_find_powershell: Using PowerShell from: ${POWERSHELL_PATH}") + set(${VARIABLE_NAME} ${POWERSHELL_PATH} PARENT_SCOPE) +endfunction() + +#[[==================================================================================================================== + toolchain_download_file + ----------------------- + Downloads a file to the given path. + + toolchain_download_file( + URL + PATH + EXPECTED_HASH = + ) + + The URL and EXPECTED_HASH values will be written to ".key" forcing a re-download if the values change. +====================================================================================================================]]# +function(toolchain_download_file) + set(OPTIONS) + set(ONE_VALUE_KEYWORDS URL PATH EXPECTED_HASH) + set(MULTI_VALUE_KEYWORDS) + + cmake_parse_arguments(PARSE_ARGV 0 DOWNLOAD_FILE "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}") + + toolchain_update_file( + PATH "${DOWNLOAD_FILE_PATH}.key" + CONTENT "URL ${DOWNLOAD_FILE_URL}:EXPECTED_HASH ${DOWNLOAD_FILE_EXPECTED_HASH}" + ) + + if("${DOWNLOAD_FILE_PATH}.key" IS_NEWER_THAN ${DOWNLOAD_FILE_PATH}) + message(VERBOSE "download_file: ${DOWNLOAD_FILE_URL} --> ${DOWNLOAD_FILE_PATH}") + file(REMOVE ${DOWNLOAD_FILE_PATH}) + file(DOWNLOAD + ${DOWNLOAD_FILE_URL} + ${DOWNLOAD_FILE_PATH} + EXPECTED_HASH ${DOWNLOAD_FILE_EXPECTED_HASH} + ) + endif() +endfunction() \ No newline at end of file diff --git a/cmake/Windows/UAC_License.txt b/cmake/Windows/UAC_License.txt new file mode 100644 index 000000000..8f5ef7ece --- /dev/null +++ b/cmake/Windows/UAC_License.txt @@ -0,0 +1,14 @@ +This software is provided 'as-is', without any express or implied warranty. + +ZLIB/LIBPNG LICENSE +------------------- + +This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source distribution. diff --git a/cmake/Windows/VSWhere.cmake b/cmake/Windows/VSWhere.cmake new file mode 100644 index 000000000..7957bfcf8 --- /dev/null +++ b/cmake/Windows/VSWhere.cmake @@ -0,0 +1,144 @@ +#---------------------------------------------------------------------------------------------------------------------- +# MIT License +# +# Copyright (c) 2021 Mark Schofield +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +#---------------------------------------------------------------------------------------------------------------------- +include_guard() + +include("${CMAKE_CURRENT_LIST_DIR}/ToolchainCommon.cmake") + +#[[==================================================================================================================== + toolchain_ensure_vswhere + ------------------------ + + Ensures that 'vswhere' is available and the VSWHERE_PATH variables is set in the cache. The following steps will be + taken: + + 1. If `VSWHERE_PATH` is set, then that value will be used. + 2. If 'vswhere' is found through `find_program`, that path will be used. + 3. 'vswhere' will be downloaded - specified by `VSWHERE_VERSION` and `VSWHERE_HASH` - into the + `TOOLCHAIN_TOOLS_PATH` and `VSWHERE_PATH` will be set to the download location. If `TOOLCHAIN_TOOLS_PATH` is + not set, then it will default to `${CMAKE_BINARY_DIR}/__tools`. + + Note: Since `CMAKE_BINARY_DIR` is platform specific, the default download location will change by platform, + resulting in the tool being downloaded once for each platform that is built. Setting + `TOOLCHAIN_TOOLS_PATH` to a platform-independent path (e.g. relative to the root of the repository) will + allow 'vswhere' to be downloaded once for all platforms. +====================================================================================================================]]# +function(toolchain_ensure_vswhere) + find_program(VSWHERE_PATH + NAMES vswhere vswhere.exe + HINTS "$ENV{ProgramFiles\(x86\)}/Microsoft Visual Studio/Installer" + ) + + # If vswhere isn't found, download it. + # + # vswhere.exe will be downloaded to `TOOLCHAIN_TOOLS_PATH`. If `TOOLCHAIN_TOOLS_PATH` is not set then it will be downloaded to '${CMAKE_BINARY_DIR}/__tools'. + if(VSWHERE_PATH STREQUAL "VSWHERE_PATH-NOTFOUND") + if(NOT VSWHERE_VERSION) + set(VSWHERE_VERSION "2.8.4") + set(VSWHERE_HASH "SHA256=E50A14767C27477F634A4C19709D35C27A72F541FB2BA5C3A446C80998A86419") + else() + if(NOT VSWHERE_HASH) + message(FATAL_ERROR "VSWHERE_VERSION is set to ${VSWHERE_VERSION}. VSWHERE_HASH must be set if VSWHERE_VERSION is set.") + endif() + endif() + + if(NOT TOOLCHAIN_TOOLS_PATH) + set(TOOLCHAIN_TOOLS_PATH "${CMAKE_BINARY_DIR}/__tools") + endif() + + set(VSWHERE_PATH "${TOOLCHAIN_TOOLS_PATH}/vswhere.exe" CACHE FILEPATH "The location of 'vswhere.exe'" FORCE) + + toolchain_download_file( + URL "https://github.com/microsoft/vswhere/releases/download/${VSWHERE_VERSION}/vswhere.exe" + PATH ${VSWHERE_PATH} + EXPECTED_HASH ${VSWHERE_HASH} + ) + endif() +endfunction() + +#[[==================================================================================================================== + findVisualStudio + ---------------- + + Finds a Visual Studio instance, and sets CMake variables based on properties of the found instance. + + findVisualStudio( + [VERSION ] + [PRERELEASE ] + [PRODUCTS ] + [REQUIRES ...] + PROPERTIES + < > + ) +====================================================================================================================]]# +function(findVisualStudio) + set(OPTIONS) + set(ONE_VALUE_KEYWORDS VERSION PRERELEASE PRODUCTS) + set(MULTI_VALUE_KEYWORDS REQUIRES PROPERTIES) + + cmake_parse_arguments(PARSE_ARGV 0 FIND_VS "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}") + + toolchain_ensure_vswhere() + + set(VSWHERE_COMMAND ${VSWHERE_PATH} -latest) + + if(FIND_VS_PRERELEASE) + list(APPEND VSWHERE_COMMAND -prerelease) + endif() + + if(FIND_VS_PRODUCTS) + list(APPEND VSWHERE_COMMAND -products ${FIND_VS_PRODUCTS}) + endif() + + if(FIND_VS_REQUIRES) + list(APPEND VSWHERE_COMMAND -requires ${FIND_VS_REQUIRES}) + endif() + + if(FIND_VS_VERSION) + list(APPEND VSWHERE_COMMAND -version "${FIND_VS_VERSION}") + endif() + + message(VERBOSE "findVisualStudio: VSWHERE_COMMAND = ${VSWHERE_COMMAND}") + + execute_process( + COMMAND ${VSWHERE_COMMAND} + OUTPUT_VARIABLE VSWHERE_OUTPUT + ) + + message(VERBOSE "findVisualStudio: VSWHERE_OUTPUT = ${VSWHERE_OUTPUT}") + + # Matches `VSWHERE_PROPERTY` in the `VSWHERE_OUTPUT` text in the format written by vswhere. + # The matched value is assigned to the variable `VARIABLE_NAME` in the parent scope. + function(getVSWhereProperty VSWHERE_OUTPUT VSWHERE_PROPERTY VARIABLE_NAME) + string(REGEX MATCH "${VSWHERE_PROPERTY}: [^\r\n]*" VSWHERE_VALUE "${VSWHERE_OUTPUT}") + string(REPLACE "${VSWHERE_PROPERTY}: " "" VSWHERE_VALUE "${VSWHERE_VALUE}") + set(${VARIABLE_NAME} "${VSWHERE_VALUE}" PARENT_SCOPE) + endfunction() + + while(FIND_VS_PROPERTIES) + list(POP_FRONT FIND_VS_PROPERTIES VSWHERE_PROPERTY) + list(POP_FRONT FIND_VS_PROPERTIES VSWHERE_CMAKE_VARIABLE) + getVSWhereProperty("${VSWHERE_OUTPUT}" ${VSWHERE_PROPERTY} VSWHERE_VALUE) + set(${VSWHERE_CMAKE_VARIABLE} ${VSWHERE_VALUE} PARENT_SCOPE) + endwhile() +endfunction() \ No newline at end of file diff --git a/cmake/Windows/images/OpenMS_splash.bmp b/cmake/Windows/images/OpenMS_splash.bmp new file mode 100644 index 0000000000000000000000000000000000000000..1be232b6d8c30c27e3b23cd89f3fc7a2c5360d79 GIT binary patch literal 94458 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 literal 0 HcmV?d00001 diff --git a/cmake/Windows/images/example_header.png b/cmake/Windows/images/example_header.png new file mode 100644 index 0000000000000000000000000000000000000000..d0ee63278d1c1869b31327ea68babab6ec9444c1 GIT binary patch literal 46526 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 literal 0 HcmV?d00001 diff --git a/cmake/Windows/images/example_wizard.png b/cmake/Windows/images/example_wizard.png new file mode 100644 index 0000000000000000000000000000000000000000..ab644e09950520130f2ab4af215288e6413565b1 GIT binary patch literal 47620 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%0D)abU5q=hU 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 DqGN2- literal 0 HcmV?d00001 diff --git a/cmake/Windows/images/header-uninstall.bmp b/cmake/Windows/images/header-uninstall.bmp new file mode 100644 index 0000000000000000000000000000000000000000..1672afa6d3ba4625690277187b4bab8bd0abd738 GIT binary patch literal 9744 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 efrWO~fTg?l9=u0j%#SJP-%)k=;!n0_x#@H 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 ZFOR=x{}X6%)qjCq_FrH<{|k(e{{zaz4F~`L literal 0 HcmV?d00001 diff --git a/cmake/Windows/images/wizard.bmp b/cmake/Windows/images/wizard.bmp new file mode 100644 index 0000000000000000000000000000000000000000..196a5b7a7e0179fb9ac572b4c0dea3b6c9801687 GIT binary patch literal 52576 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 ICon?(A1_5If&c&j literal 0 HcmV?d00001 diff --git a/cmake/Windows/install.exe b/cmake/Windows/install.exe new file mode 100644 index 0000000000000000000000000000000000000000..711936298ffdf8efa15e7ea66df661aff666e77c GIT binary patch literal 41713 zcmeFaeSA|@wm-bnq-`i^Q=ruUVHC#PAl$ulo=UgCIn4mY#)B<;}GBf>#sg!XH5KK z276}2pC|1zEd2ANCH~rGTVqqhy-n3?ZL6#6>l-B7Jw98LTyLwbx0T-EwykZb@y$q2 zPs@!r?fq=+h%pZt?@EN9J-qC$QAj`f@QS;V1U%`kZTP)n+p@c^#_zF*op+5Ezop`L zaqVh9)%{ycT~5Xp8j@Mh=@$^wKmE*V7->jNV=Iu}mLvu}^+v=q5gMtCLyzlO1Q2u) zkw-x#A`(8x#s`(C-i6@s{2 zel*rN-iV2hjj>fTnrf=0YQ}bC1B5o&6$tkrT=H>%AT#u0Y)LgbeH5A0_l8RfA?jeP zb4Go;v6)&Le4B55sQ}X0wS86r5#h8+*H`Yt=rdYnx<@Cs!2X=-ApZeA!@aEqKZ_d zwpaoNZ;$h2CUEU>a$-=lfCAdOrCu$23B}|rb=FcuyxIxB4JG2E4ru;e98^Im(W3?V zqTdT-S_=5e6$PDlA3Bi9)P=dG-Mt{A`bO=WIgnCyNs@W!K$2AD@rHk7DA4S)4kNd@ zR6SCAi1Ndw2D4i=4|OF;#`)0+LtQ3mg!=j&?S~{=G;^pcQy!_lQ}C|x7em22p`5a0 zs-id1^y=L!R~#@gOm}6aT7^c&Q@b=$|AEP`kA`O-1_krnwUd|&?0m6#0C0z3Wk(# zY|S?n3VN)Y5q6oqYSNP_a#n#h|JY~k_YX_SO0OYmRQk_{lFC{STr%>v69ZQUEW3$k z72h!UH+cu<)vFc}ULj{pb;b(bE6kB@w|~^^RA&)!ly0+n#n6Eid7A1pw|4@|xjUIO zR;?H==yV+GR~HQ{pBSd}s$GB_`^0`g9$C`bEjs?FsoVaMl#anG&X@@UwKe^l>KqmW zH-YF#Bil-UO9ei!eBbQOUHTcqap&XzHbuKu*=87pCVy_NjA zVg@diQ_z1|G__nkq7LSDDVuUFOqy*--VV;&-G;A%L+zc`9bExt?5*_Y%V6JGl&57+ z|B-{a{7IN^P0G#DvK?T?_91InLVpFFD=;bhsORX{YH6-XO($XnP_(s3VkWQhu~nP74Wmi! z*abmMJu6=UceV~#Kma%R-#P3GmCv=Yq;%0wEu25$ mHD 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 literal 0 HcmV?d00001 diff --git a/cmake/add_library_macros.cmake b/cmake/add_library_macros.cmake new file mode 100644 index 000000000..74b1966a2 --- /dev/null +++ b/cmake/add_library_macros.cmake @@ -0,0 +1,316 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Julianus Pfeuffer $ +# $Authors: Stephan Aiche, Chris Bielow, Julianus Pfeuffer $ +# -------------------------------------------------------------------------- + +# required modules +include(CMakeParseArguments) +include(GenerateExportHeader) +include(CheckLibArchitecture) + +#------------------------------------------------------------------------------ +## export a single option indicating if libraries should be build as unity +## build +option(ENABLE_UNITYBUILD "Enables unity builds for all libraries." OFF) +option(OPENMS_VERIFY_INTERFACE_HEADER_SETS + "Compile OpenMS public headers individually with the all_verify_interface_header_sets target" OFF) + +#------------------------------------------------------------------------------ +## Unity Build of a set of cpp files +## i.e., make one large compilation unit which usually compiles a lot faster +## +## pros: +## - compiles a lot faster +## - reveals double definitions of internal classes in different cpp files +## - reveals weird variable names (like 'IN'), which are defined as macro in certain headers which are now part of the compilation unit +## cons: +## - not desirable for developing, since a small change will trigger recreation of the whole lib +function(convert_to_unity_build UB_SUFFIX SOURCE_FILES_NAME) + set(files ${${SOURCE_FILES_NAME}}) + # generate a unique file name for the unity build translation unit + set(unit_build_file ${CMAKE_CURRENT_BINARY_DIR}/ub_${UB_SUFFIX}.cpp) + # exclude all translation units from compilation + set_source_files_properties(${files} PROPERTIES HEADER_FILE_ONLY true) + # open the unity build file + file(WRITE ${unit_build_file} "// Unity Build generated by CMake\n") + # add include statement for each translation unit + foreach(source_file ${files}) + # we have headers in there as well, which should not be included explicitly + if (${source_file} MATCHES "\\.cpp|\\.cxx") # cxx for moc's; + if (IS_ABSOLUTE ${source_file}) + file(APPEND ${unit_build_file} "#include<${source_file}>\n") + else() + file(APPEND ${unit_build_file} "#include<${CMAKE_CURRENT_SOURCE_DIR}/${source_file}>\n") + endif() + endif() + endforeach(source_file) + # add unity build aggregate as source file + set(${SOURCE_FILES_NAME} ${${SOURCE_FILES_NAME}} ${unit_build_file} PARENT_SCOPE) +endfunction(convert_to_unity_build) + +#------------------------------------------------------------------------------ +## Copy the dll produced by the given target to the test/doc binary path. +## @param targetname The target to modify. +## @note This macro will do nothing outside of Windows since the linker will find the libs. +macro(copy_dll_to_extern_bin targetname) + if (WIN32) + get_property(_copy_dll_is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + if(_copy_dll_is_multi_config) + file(TO_NATIVE_PATH "${OPENMS_HOST_BINARY_DIRECTORY}/src/tests/class_tests/bin/$/$" DLL_TEST_TARGET) + file(TO_NATIVE_PATH "${OPENMS_HOST_BINARY_DIRECTORY}/src/tests/class_tests/bin/$" DLL_TEST_TARGET_PATH) + + file(TO_NATIVE_PATH "${OPENMS_HOST_BINARY_DIRECTORY}/doc/doxygen/parameters/$/$" DLL_DOC_TARGET) + file(TO_NATIVE_PATH "${OPENMS_HOST_BINARY_DIRECTORY}/doc/doxygen/parameters/$" DLL_DOC_TARGET_PATH) + else() + file(TO_NATIVE_PATH "${OPENMS_HOST_BINARY_DIRECTORY}/src/tests/class_tests/bin/$" DLL_TEST_TARGET) + file(TO_NATIVE_PATH "${OPENMS_HOST_BINARY_DIRECTORY}/src/tests/class_tests/bin/" DLL_TEST_TARGET_PATH) + + file(TO_NATIVE_PATH "${OPENMS_HOST_BINARY_DIRECTORY}/doc/doxygen/parameters/$" DLL_DOC_TARGET) + file(TO_NATIVE_PATH "${OPENMS_HOST_BINARY_DIRECTORY}/doc/doxygen/parameters/" DLL_DOC_TARGET_PATH) + endif() + add_custom_command(TARGET ${targetname} + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory "${DLL_TEST_TARGET_PATH}" + COMMAND ${CMAKE_COMMAND} -E copy_if_different $ ${DLL_TEST_TARGET} + COMMAND ${CMAKE_COMMAND} -E make_directory "${DLL_DOC_TARGET_PATH}" + COMMAND ${CMAKE_COMMAND} -E copy_if_different $ ${DLL_DOC_TARGET} + ) + endif() +endmacro() + +#------------------------------------------------------------------------------ +# openms_add_library() +# Create an OpenMS library, install it, register for export of targets, and +# export all required variables for later usage in the build system. +# +# Signature: +# openms_add_library(TARGET_NAME OpenMS +# SOURCE_FILES +# HEADER_FILES

+# (will be installed with the library) +# BASE_DIRS +# PRIVATE_INCLUDES +# EXTERNAL_INCLUDES +# (will be added with -isystem if available) +# LINK_LIBRARIES +# PRIVATE_LINK_LIBRARIES +# ALLOWED_PUBLIC_INCLUDES +# DLL_EXPORT_PATH +# EXPORT_SET ) +# +# Besides TARGET_NAME the library is available as OpenMS::TARGET_NAME, the name +# under which it is exported (install(EXPORT ... NAMESPACE OpenMS::)), so +# in-tree code and consumers of the installed package can link the same name. +# The library and its export go into the install components of EXPORT_SET; the +# headers always go into the component TARGET_NAME_headers. +function(openms_add_library) + #------------------------------------------------------------------------------ + # parse arguments to function + set(options ) + set(oneValueArgs TARGET_NAME DLL_EXPORT_PATH EXPORT_SET) + set(multiValueArgs BASE_DIRS PRIVATE_INCLUDES EXTERNAL_INCLUDES SOURCE_FILES HEADER_FILES LINK_LIBRARIES PRIVATE_LINK_LIBRARIES + ALLOWED_PUBLIC_INCLUDES) + ## make above arguments available as variables, e.g. ${openms_add_library_PRIVATE_LINK_LIBRARIES} + cmake_parse_arguments(openms_add_library "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) + + #------------------------------------------------------------------------------ + # Status message for configure output + message(STATUS "Adding library ${openms_add_library_TARGET_NAME}") + + #------------------------------------------------------------------------------ + # Preserve the include-directory cache consumed by class tests. + set(${openms_add_library_TARGET_NAME}_INCLUDE_DIRECTORIES ${openms_add_library_BASE_DIRS} + ${openms_add_library_EXTERNAL_INCLUDES} + CACHE INTERNAL "${openms_add_library_TARGET_NAME} include directories" FORCE) + + #------------------------------------------------------------------------------ + # Check if we want a unity build + if (ENABLE_UNITYBUILD) + message(STATUS "Enabled Unity Build for ${openms_add_library_TARGET_NAME}") + convert_to_unity_build(${openms_add_library_TARGET_NAME}_UnityBuild openms_add_library_SOURCE_FILES) + endif() + + #------------------------------------------------------------------------------ + # Add the library + add_library(${openms_add_library_TARGET_NAME} ${openms_add_library_SOURCE_FILES}) + add_library(OpenMS::${openms_add_library_TARGET_NAME} ALIAS ${openms_add_library_TARGET_NAME}) + + set_target_properties(${openms_add_library_TARGET_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) + set_target_properties(${openms_add_library_TARGET_NAME} PROPERTIES VISIBILITY_INLINES_HIDDEN 1) + # AUTOMOC is chosen by the library's own CMakeLists.txt. Merely finding Qt + # elsewhere must not enable Qt code generation for non-GUI libraries. + + #------------------------------------------------------------------------------ + # Include directories + # Public include directories come from the header file set and its install destination. + + # TODO actually we shouldn't need to add these external includes. They should propagate through target_link_library if they are public + target_include_directories(${openms_add_library_TARGET_NAME} SYSTEM PUBLIC + "$" + ) + target_include_directories(${openms_add_library_TARGET_NAME} SYSTEM PRIVATE ${openms_add_library_PRIVATE_INCLUDES}) + + target_compile_features(${openms_add_library_TARGET_NAME} PUBLIC cxx_std_23) + + # Add compiler flags using the new helper function + openms_add_library_compiler_flags(${openms_add_library_TARGET_NAME}) + + if(ADDRESS_SANITIZER) + add_asan_to_target(${openms_add_library_TARGET_NAME}) + endif() + + + set_target_properties(${openms_add_library_TARGET_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) + set_target_properties(${openms_add_library_TARGET_NAME} PROPERTIES VISIBILITY_INLINES_HIDDEN 1) + + #------------------------------------------------------------------------------ + # Generate export header if requested + if(openms_add_library_DLL_EXPORT_PATH) + ## this snipped creates 'OpenMSConfig.h' in the build tree + set(_CONFIG_H "include/${openms_add_library_DLL_EXPORT_PATH}${openms_add_library_TARGET_NAME}Config.h") + string(TOUPPER ${openms_add_library_TARGET_NAME} _TARGET_UPPER_CASE) + include(GenerateExportHeader) + generate_export_header(${openms_add_library_TARGET_NAME} + EXPORT_MACRO_NAME ${_TARGET_UPPER_CASE}_DLLAPI + EXPORT_FILE_NAME ${_CONFIG_H}) + + string(REGEX REPLACE "/" "\\\\" _fixed_path ${openms_add_library_DLL_EXPORT_PATH}) + + # add generated header to visual studio + source_group("Header Files\\${_fixed_path}" FILES ${_CONFIG_H}) + list(APPEND openms_add_library_HEADER_FILES "${CMAKE_CURRENT_BINARY_DIR}/${_CONFIG_H}") + endif() + + # Both configured headers and generate_export_header() output belong to the + # public interface. Listing them here also makes them visible to IDEs/AUTOMOC. + list(REMOVE_DUPLICATES openms_add_library_HEADER_FILES) + openms_validate_public_headers(${openms_add_library_HEADER_FILES} + ALLOW ${openms_add_library_ALLOWED_PUBLIC_INCLUDES}) + target_sources(${openms_add_library_TARGET_NAME} PUBLIC FILE_SET HEADERS + BASE_DIRS ${openms_add_library_BASE_DIRS} + FILES ${openms_add_library_HEADER_FILES}) + if(OPENMS_VERIFY_INTERFACE_HEADER_SETS) + set_target_properties(${openms_add_library_TARGET_NAME} PROPERTIES + VERIFY_INTERFACE_HEADER_SETS ON) + endif() + + #------------------------------------------------------------------------------ + # Link library against other libraries + if(openms_add_library_LINK_LIBRARIES) + ## check for consistent lib arch (e.g. all 64bit)? + check_lib_architecture(openms_add_library_LINK_LIBRARIES) + target_link_libraries(${openms_add_library_TARGET_NAME} PUBLIC ${openms_add_library_LINK_LIBRARIES}) + list(LENGTH openms_add_library_LINK_LIBRARIES _library_count) + endif() + + if (openms_add_library_PRIVATE_LINK_LIBRARIES) + ## check for consistent lib arch (e.g. all 64bit)? + check_lib_architecture(openms_add_library_PRIVATE_LINK_LIBRARIES) + target_link_libraries(${openms_add_library_TARGET_NAME} PRIVATE ${openms_add_library_PRIVATE_LINK_LIBRARIES}) + list(LENGTH openms_add_library_PRIVATE_LINK_LIBRARIES _private_library_count) + endif() + + #------------------------------------------------------------------------------ + # Export libraries (self + dependencies) + set(${openms_add_library_TARGET_NAME}_LIBRARIES + ${openms_add_library_TARGET_NAME} + ${openms_add_library_LINK_LIBRARIES} + CACHE + INTERNAL "${openms_add_library_TARGET_NAME} libraries" FORCE) + + #------------------------------------------------------------------------------ + # we also want to install the library (into the components of its export set) + if(NOT openms_add_library_EXPORT_SET) + set(openms_add_library_EXPORT_SET ${OPENMS_EXPORT_SET}) + endif() + install_library(${openms_add_library_TARGET_NAME} HEADERS EXPORT_SET ${openms_add_library_EXPORT_SET}) + + #------------------------------------------------------------------------------ + # register for the build-tree export of the same export set + openms_register_export_target(${openms_add_library_TARGET_NAME} ${openms_add_library_EXPORT_SET}) + + #------------------------------------------------------------------------------ + # On Windows copy DLLs and dependencies of them to other locations of executables that need them (tests, documenter) + # TODO Find something that does not copy 100s of MB three times. + # TODO I think this should ideally go to the tests and docs CMakeLists separately. + # Copy target DLLs themselves + copy_dll_to_extern_bin(${openms_add_library_TARGET_NAME}) + # Copy dependencies + if(WIN32) + # with newer CMakes we can also easily copy dependencies like Qt + # This stores the command as a list + set(has_dll_dep + $> + ) + set(none_command + ${CMAKE_COMMAND} -E echo + ) + ## TODO check if we can use create_symlink instead + set(copy_dlls_to_output_folder + ${CMAKE_COMMAND} -E copy_if_different + $ + $ + ) + + get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + if(is_multi_config) + file(TO_NATIVE_PATH "${OPENMS_HOST_BINARY_DIRECTORY}/src/tests/class_tests/bin/$/" DLL_TEST_TARGET_PATH) + file(TO_NATIVE_PATH "${OPENMS_HOST_BINARY_DIRECTORY}/doc/doxygen/parameters/$/" DLL_DOC_TARGET_PATH) + else() + file(TO_NATIVE_PATH "${OPENMS_HOST_BINARY_DIRECTORY}/src/tests/class_tests/bin/" DLL_TEST_TARGET_PATH) + file(TO_NATIVE_PATH "${OPENMS_HOST_BINARY_DIRECTORY}/doc/doxygen/parameters/" DLL_DOC_TARGET_PATH) + endif() + + set(copy_dlls_to_test_folder + ${CMAKE_COMMAND} -E copy_if_different + $ + ${DLL_TEST_TARGET_PATH} + ) + + foreach(command IN ITEMS "${copy_dlls_to_output_folder}" "${copy_dlls_to_test_folder}") + set(if_runtime_dlls_copy + $ + ) + add_custom_command(TARGET ${openms_add_library_TARGET_NAME} POST_BUILD + COMMAND "${if_runtime_dlls_copy}" + COMMAND_EXPAND_LISTS + ) + endforeach() + + if(ENABLE_DOCS) + set(copy_dlls_to_doc_folder + ${CMAKE_COMMAND} -E copy_if_different + $ + ${DLL_DOC_TARGET_PATH} + ) + set(if_runtime_dlls_copy + $ + ) + add_custom_command(TARGET ${openms_add_library_TARGET_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory "${DLL_DOC_TARGET_PATH}" + COMMAND "${if_runtime_dlls_copy}" + COMMAND_EXPAND_LISTS + ) + endif() + + ## another fix for APPLE, see https://github.com/OpenMS/OpenMS/pull/7525 + if(APPLECLANG) + if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "15.0.0") + target_link_options(${openms_add_library_TARGET_NAME} PRIVATE -ld_classic) + set_target_properties(${openms_add_library_TARGET_NAME} PROPERTIES + QT_NO_DISABLE_WARN_DUPLICATE_LIBRARIES TRUE) + endif() + endif() + endif() + #------------------------------------------------------------------------------ + # Status message for configure output + message(STATUS "Adding library ${openms_add_library_TARGET_NAME} - SUCCESS") +endfunction() diff --git a/cmake/build_system_macros.cmake b/cmake/build_system_macros.cmake new file mode 100644 index 000000000..f06f6672a --- /dev/null +++ b/cmake/build_system_macros.cmake @@ -0,0 +1,51 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Stephan Aiche, Chris Bielow $ +# $Authors: Chris Bielow, Stephan Aiche $ +# -------------------------------------------------------------------------- + +#------------------------------------------------------------------------------ +## export a single option indicating if Arrow/Parquet static libs should be preferred +option(ARROW_USE_STATIC "Use Arrow/Parquet static libraries." ON) + +#------------------------------------------------------------------------------ +## Wraps the common find boost code into a single call +## @param .. simply add all required components to the call +## @note This macro will define BOOST_MOC_ARGS that should be added to all moc +## calls (see https://bugreports.qt-project.org/browse/QTBUG-22829) +macro(find_boost) + set(Boost_USE_MULTITHREADED ON) + set(Boost_USE_STATIC_RUNTIME OFF) + add_definitions(/DBOOST_ALL_NO_LIB) ## disable auto-linking of boost libs (boost tends to guess wrong lib names) + set(Boost_COMPILER "") + + # help boost finding it's packages + set(Boost_ADDITIONAL_VERSIONS + "1.87.1" "1.87.0" "1.87" + "1.86.1" "1.86.0" "1.86" + "1.85.1" "1.85.0" "1.85" + "1.84.1" "1.84.0" "1.84" + "1.83.1" "1.83.0" "1.83" + "1.82.1" "1.82.0" "1.82" + "1.81.1" "1.81.0" "1.81") + + find_package(Boost 1.81.0 COMPONENTS ${ARGN} REQUIRED CONFIG) + +endmacro(find_boost) + +#------------------------------------------------------------------------------ +## Checks if the user supplied package type is valid and aborts if not +## @param package_type The given package type +macro(is_valid_package package_type) + list(FIND VALID_PACKAGE_TYPES ${package_type} list_pos) + if( ${list_pos} EQUAL -1 ) + message(STATUS "The PACKAGE_TYPE ${package_type} is invalid") + message(STATUS "Valid PACKAGE_TYPEs are:") + foreach( _vpt ${VALID_PACKAGE_TYPES} ) + message(STATUS " * ${_vpt}") + endforeach() + message(FATAL_ERROR "Aborting ...") + endif() +endmacro() diff --git a/cmake/compiler_flags.cmake b/cmake/compiler_flags.cmake new file mode 100644 index 000000000..2a22c00a7 --- /dev/null +++ b/cmake/compiler_flags.cmake @@ -0,0 +1,220 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Stephan Aiche, Chris Bielow $ +# $Authors: Andreas Bertsch, Chris Bielow, Stephan Aiche $ +# -------------------------------------------------------------------------- + + +#------------------------------------------------------------------------------ +# This cmake file handles all the project specific compiler flags +# It defines variables and options and provides functions to apply flags to targets + +#------------------------------------------------------------------------------ +# PART 1: Define variables and options +#------------------------------------------------------------------------------ + +# Custom compile flags +if (MY_CXX_FLAGS) ## do not change this name! it's used in configh.cmake + message(STATUS "Custom compile flags: '${MY_CXX_FLAGS}' will be added to targets") +endif() + +# SIMD extensions +set(x64_CPU "x86|AMD64") ## CMake returns 'x86-64' on Linux and 'AMD64' on Windows.. +message(STATUS "Processor is : ${CMAKE_SYSTEM_PROCESSOR}") + +# ARM processors: SIMDe will do the right thing upon detecting ARM +# https://github.com/simd-everywhere/simde/blob/master/simde/simde-arch.h#L117 +# (neon instructions compile without error even if no compile flag is given -- as opposed to x64 intrinsics) + +# Compiler-specific options +if(CMAKE_COMPILER_IS_GNUCXX) + # GCC options + option(ENABLE_GCC_WERROR "Enable -Werror on gcc compilers" OFF) + if(ENABLE_GCC_WERROR) + message(STATUS "Enable -Werror for gcc - note that this may not work on all compilers and system settings!") + endif() +elseif(MSVC) + # MSVC options +elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + # Clang options + set(CMAKE_COMPILER_IS_CLANG true CACHE INTERNAL "Is CLang compiler (clang++)") +else() + # Intel compiler options + set(CMAKE_COMPILER_IS_INTELCXX true CACHE INTERNAL "Is Intel C++ compiler (icpc)") +endif() + +# Platform-dependent options +include(CheckCXXCompilerFlag) +if(NOT WIN32) # we only want fPIC on non-windows systems (fPIC is implicitly true there) + CHECK_CXX_COMPILER_FLAG("-fPIC" WITH_FPIC) + if(WITH_FPIC) + message(STATUS "Position-independent code (-fPIC) is supported and will be applied to targets") + endif() +endif() + +# Conversion warnings +set(CXX_WARN_CONVERSION OFF CACHE BOOL "Enables warnings for type conversion problems (GCC only)") +message(STATUS "Compiler checks for conversion: ${CXX_WARN_CONVERSION}") + +#------------------------------------------------------------------------------ +# PART 2: Functions to apply compiler flags to targets +#------------------------------------------------------------------------------ + +# Function to add compiler flags to a target with proper PUBLIC/PRIVATE visibility +function(openms_add_compiler_flags target_name) + #------------------------------------------------------------------------------ + # PUBLIC flags (propagated to dependent targets) + #------------------------------------------------------------------------------ + + # Language standard + target_compile_features(${target_name} PUBLIC cxx_std_23) + + # Position-independent code + if(NOT WIN32 AND WITH_FPIC) + target_compile_options(${target_name} PUBLIC -fPIC) + endif() + + # Essential preprocessor definitions + if(MSVC) + target_compile_definitions(${target_name} PUBLIC + NOMINMAX # keep windows.h from defining min/max macros + ) + endif() + + # C++23 workaround for ARM: std::float16_t/float32_t/float64_t + # conflict with ARM NEON typedefs of the same name when 'using namespace std;' + # is active. Suppress only the three macros that conflict with NEON typedefs. + # Do NOT suppress __STDCPP_FLOAT128_T__ or __STDCPP_BFLOAT16_T__ as those + # have no NEON conflict and are needed by Boost.Math. + if(NOT MSVC AND CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64|ARM64") + target_compile_options(${target_name} PUBLIC + -U__STDCPP_FLOAT16_T__ -U__STDCPP_FLOAT32_T__ -U__STDCPP_FLOAT64_T__ + ) + endif() + + # SIMD extensions (PUBLIC for binary compatibility) + # MSVC x64 defaults to SSE2 (128-bit); do NOT use /arch:AVX here because + # AVX's 256-bit reductions change Eigen's floating-point evaluation order + # vs the 128-bit paths used by GCC/Clang, causing cross-platform numeric + # divergence in sensitive algorithms (e.g. normalizedCrossCorrelation). + if(NOT MSVC AND ${CMAKE_SYSTEM_PROCESSOR} MATCHES "${x64_CPU}") + target_compile_options(${target_name} PUBLIC -mssse3) + endif() + + # When full OpenMP isn't available (typically Apple clang without libomp), + # multithreading.cmake sets OPENMS_OMP_SIMD_FALLBACK_FLAG to -fopenmp-simd + # so #pragma omp simd vectorization still works inside OpenMS. Applied PRIVATE: + # no installed public OpenMS header contains `#pragma omp simd`, so downstream + # consumers don't need this flag. Propagating it PUBLIC could break downstream + # builds whose compiler doesn't accept -fopenmp-simd. + # Not gated on architecture: -fopenmp-simd is useful on ARM too (NEON). + if(DEFINED OPENMS_OMP_SIMD_FALLBACK_FLAG) + target_compile_options(${target_name} PRIVATE ${OPENMS_OMP_SIMD_FALLBACK_FLAG}) + endif() + + #------------------------------------------------------------------------------ + # PRIVATE flags (not propagated to dependent targets) + #------------------------------------------------------------------------------ + + # Warning controls + if(CMAKE_COMPILER_IS_GNUCXX) + target_compile_options(${target_name} PRIVATE + -Wall -Wextra + -Wno-unknown-pragmas + -ffp-contract=off + -Wno-unused-function + -Wno-psabi + ) + + if(ENABLE_GCC_WERROR) + target_compile_options(${target_name} PRIVATE -Werror) + endif() + + if(CMAKE_GENERATOR STREQUAL "Eclipse CDT4 - Unix Makefiles") + target_compile_options(${target_name} PRIVATE -fmessage-length=0) + endif() + elseif(MSVC) + target_compile_options(${target_name} PRIVATE + /wd4251 /wd4275 # disable dll-interface warning + /wd4996 # disable deprecated functions warning + /wd4661 # disable explicit template instantiation request warning + /wd4503 # disable decorated name length exceeded warning9 + /bigobj # for large object files + /MP # use multiple CPU cores + ) + + target_compile_definitions(${target_name} PRIVATE + _SCL_SECURE_NO_WARNINGS + _CRT_SECURE_NO_WARNINGS + _CRT_SECURE_NO_DEPRECATE + ) + elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + target_compile_options(${target_name} PRIVATE + -ffp-contract=off + -Wall -Wextra + -Wno-sign-conversion + -Wno-global-constructors + -Wno-exit-time-destructors + -Wno-weak-vtables + -Wno-documentation-unknown-command + -Wno-undef + -Wno-documentation + -Wno-source-uses-openmp + -Wno-old-style-cast + -Wno-unknown-warning-option + -Wno-double-promotion + -Wno-unused-template + -Wno-conversion + -Wno-float-equal + -Wno-switch-enum + -Wno-missing-prototypes + -Wno-missing-variable-declarations + -Wno-deprecated + -Wno-covered-switch-default + -Wno-date-time + -Wno-missing-noreturn + ) + endif() + + # Conversion warnings + if(CXX_WARN_CONVERSION AND CMAKE_COMPILER_IS_GNUCXX) + target_compile_options(${target_name} PRIVATE -Wconversion) + endif() + + # Custom flags + if(MY_CXX_FLAGS) + separate_arguments(MY_CXX_FLAGS_LIST UNIX_COMMAND "${MY_CXX_FLAGS}") + target_compile_options(${target_name} PRIVATE ${MY_CXX_FLAGS_LIST}) + endif() +endfunction() + +# Function to add library-specific compiler flags +function(openms_add_library_compiler_flags target_name) + # Add common flags first (both PUBLIC and PRIVATE) + openms_add_compiler_flags(${target_name}) + + # Library-specific PRIVATE flags + if(CMAKE_COMPILER_IS_GNUCXX) + target_compile_options(${target_name} PRIVATE -Wno-non-virtual-dtor) + endif() + + # Address sanitizer (PRIVATE) + if(ADDRESS_SANITIZER) + add_asan_to_target(${target_name}) + endif() +endfunction() + +# Function to add executable-specific compiler flags +function(openms_add_executable_compiler_flags target_name) + # Add common flags first (both PUBLIC and PRIVATE) + openms_add_compiler_flags(${target_name}) + + # Executable-specific PRIVATE flags can be added here + + # Address sanitizer (PRIVATE) + if(ADDRESS_SANITIZER) + add_asan_to_target(${target_name}) + endif() +endfunction() diff --git a/cmake/cpack_clean_runpath.cmake b/cmake/cpack_clean_runpath.cmake new file mode 100644 index 000000000..8d7c5e2ad --- /dev/null +++ b/cmake/cpack_clean_runpath.cmake @@ -0,0 +1,85 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Timo Sachsenberg $ +# $Authors: Timo Sachsenberg $ +# -------------------------------------------------------------------------- + +# Removes empty entries from the RUNPATH (or RPATH) of every ELF file in the CPack +# staging directory. CPack runs this script (CPACK_PRE_BUILD_SCRIPTS, set in +# cmake/package_deb.cmake) after it has installed the files and before it builds +# the package; it is not included at configure time. +# +# The dynamic loader reads an empty entry as the current working directory, so no +# packaged file may carry one. They appear when the binaries were linked under a +# different configuration than the one being packaged, which is what the release +# workflow does: it builds and tests with PACKAGE_TYPE=none, then reconfigures with +# the package type and runs cpack without relinking. CMake pads a build-tree RPATH +# with ':' to the length of the install RPATH, and the install RPATH of +# PACKAGE_TYPE=none also names the vcpkg directory of the build tree (top-level +# CMakeLists.txt), so it is far longer than that of a package. When installing, +# CMake replaces only the padding it now expects and keeps the rest: a library that +# links nothing outside the system, such as libOpenSwathAlgo, was packaged with +# $ORIGIN/../lib/ followed by about 90 empty entries. Relinking before packaging +# would avoid the padding, but 'all' also contains the documentation target, which +# is always out of date and would regenerate the whole documentation. + +## Without it the glob below would start at the file system root. +if(NOT IS_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}") + message(FATAL_ERROR "cpack_clean_runpath.cmake: CPACK_TEMPORARY_DIRECTORY ('${CPACK_TEMPORARY_DIRECTORY}') " + "is not a directory; this script is meant to be run by CPack (CPACK_PRE_BUILD_SCRIPTS).") +endif() + +cmake_policy(PUSH) +## Unset policies take their OLD behavior in a CPack script: CMP0009 NEW keeps +## GLOB_RECURSE from following symlinks out of the staging directory. +cmake_policy(VERSION 3.24) + +## A function, so that none of its variables reach the CPack generator code that +## runs in this scope afterwards. +function(_openms_clean_runpath _staging_dir) + file(GLOB_RECURSE _staged_files LIST_DIRECTORIES false "${_staging_dir}/*") + foreach(_file IN LISTS _staged_files) + ## Editing through a symlink could reach a file outside the staging directory; + ## a staged target is edited under its own name. + if(IS_SYMLINK "${_file}") + continue() + endif() + + ## READ_ELF only sets the variables it finds something for. + unset(_not_elf) + unset(_rpath) + unset(_runpath) + file(READ_ELF "${_file}" RPATH _rpath RUNPATH _runpath CAPTURE_ERROR _not_elf) + if(_not_elf) + continue() + endif() + ## The loader ignores RPATH when RUNPATH is present. + if(DEFINED _runpath) + set(_old "${_runpath}") + elseif(DEFINED _rpath) + set(_old "${_rpath}") + else() + continue() + endif() + + ## READ_ELF returns the entries as a list; compare them as the loader sees them. + string(REPLACE ";" ":" _old "${_old}") + string(REGEX REPLACE "::+" ":" _new "${_old}") + string(REGEX REPLACE "^:|:$" "" _new "${_new}") + if(_new STREQUAL _old) + continue() + endif() + + if(_new STREQUAL "") + file(RPATH_REMOVE FILE "${_file}") + else() + file(RPATH_SET FILE "${_file}" NEW_RPATH "${_new}") + endif() + endforeach() +endfunction() + +_openms_clean_runpath("${CPACK_TEMPORARY_DIRECTORY}") + +cmake_policy(POP) diff --git a/cmake/cpack_deb_t64_dependencies.cmake b/cmake/cpack_deb_t64_dependencies.cmake new file mode 100644 index 000000000..107144adf --- /dev/null +++ b/cmake/cpack_deb_t64_dependencies.cmake @@ -0,0 +1,275 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Julianus Pfeuffer $ +# $Authors: Julianus Pfeuffer $ +# -------------------------------------------------------------------------- + +# Adds the pre-t64 name of each renamed library package to the Depends of every DEB. +# CPack runs this script (CPACK_POST_BUILD_SCRIPTS, set in cmake/package_deb.cmake) +# after it has written the packages and before it copies them to the build tree; it +# is not included at configure time. +# +# Debian and Ubuntu (from 24.04) renamed the library packages whose ABI involves +# time_t when they moved their 32-bit architectures to a 64-bit time_t: libqt6core6 +# became libqt6core6t64, and so on. dpkg-shlibdeps names the packages installed on the +# build host, so a package built on such a release depends on the new names, which +# older releases do not have. Later releases went back to the old names for many of +# these libraries: Debian 13 and Ubuntu 25.10 and 26.04 ship libqt6gui6 and +# libqt6openglwidgets6, with no t64 package. On architectures whose time_t was 64-bit +# already (amd64, arm64, ...) the ABI did not change, and the renamed package provides +# and replaces its old name. There this script adds the old name as an alternative, +# with the same version constraint: +# libqt6core6t64 (>= 6.2.2) -> libqt6core6t64 (>= 6.2.2) | libqt6core6 (>= 6.2.2) +# The old names come from the build host's dpkg database, which dpkg-shlibdeps has +# just read. On armhf, where the ABI changed, the renamed packages do not provide +# their old names, and the dependencies stay as they are. A package built on a release +# before the renaming needs nothing: on those architectures the renamed packages +# provide the names it depends on. +# +# Only the control member of the package is replaced, in place; the data member is +# kept byte for byte. + +cmake_policy(PUSH) +cmake_policy(VERSION 3.24) + +## The name that the installed package : was renamed from: one it both +## provides and replaces, and that starts with without its t64 suffix. Some +## packages also provide and replace names from earlier renames (libext2fs2t64 those of +## libext2fs2 and of e2fslibs, which it replaced in 2018); only the t64 rename's own +## old names are wanted. Empty if there is none. +function(_openms_deb_renamed_from _dpkg_query _name _arch _out) + set(${_out} "" PARENT_SCOPE) + execute_process( + COMMAND "${_dpkg_query}" --show "--showformat=\${Provides}\\n\${Replaces}" "${_name}:${_arch}" + OUTPUT_VARIABLE _value + RESULT_VARIABLE _result + ERROR_VARIABLE _error + ) + ## dpkg-shlibdeps found the package in this database moments ago, so this should + ## not happen; it leaves the dependency strict rather than failing the package. + if(NOT _result EQUAL 0 OR NOT _value MATCHES "^([^\n]*)\n([^\n]*)") + message(WARNING "cpack_deb_t64_dependencies.cmake: cannot query ${_name}:${_arch}, so its dependency stays as it is: ${_error}") + return() + endif() + set(_provides_field "${CMAKE_MATCH_1}") + set(_replaces_field "${CMAKE_MATCH_2}") + + ## Relations are comma-separated; drop the version and architecture qualifiers. + set(_replaces) + string(REPLACE "," ";" _entries "${_replaces_field}") + foreach(_entry IN LISTS _entries) + if(_entry MATCHES "^[ \t]*([^ \t(:]+)") + list(APPEND _replaces "${CMAKE_MATCH_1}") + endif() + endforeach() + + string(REGEX REPLACE "t64$" "" _stem "${_name}") + set(_names) + string(REPLACE "," ";" _entries "${_provides_field}") + foreach(_entry IN LISTS _entries) + if(_entry MATCHES "^[ \t]*([^ \t(:]+)") + set(_provided "${CMAKE_MATCH_1}") + string(FIND "${_provided}" "${_stem}" _position) + if(_position EQUAL 0 AND _provided IN_LIST _replaces) + list(APPEND _names "${_provided}") + endif() + endif() + endforeach() + set(${_out} "${_names}" PARENT_SCOPE) +endfunction() + +## Adds the alternatives to the package , using as scratch space. +## Uses the tools found by _openms_deb_add_t64_alternatives(). +function(_openms_deb_rewrite _package _work_dir) + get_filename_component(_package_name "${_package}" NAME) + file(MAKE_DIRECTORY "${_work_dir}/control") + + execute_process( + COMMAND "${_dpkg_deb}" --ctrl-tarfile "${_package}" + OUTPUT_FILE "${_work_dir}/control.tar" + RESULT_VARIABLE _result + ERROR_VARIABLE _error + ) + if(NOT _result EQUAL 0) + message(FATAL_ERROR "Could not read the control archive of ${_package}: ${_error}") + endif() + ## The members in their order, so that the rebuilt archive lists them the same way. + execute_process( + COMMAND "${_tar}" --list --file "${_work_dir}/control.tar" + OUTPUT_VARIABLE _control_members + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE _result + ERROR_VARIABLE _error + ) + if(NOT _result EQUAL 0) + message(FATAL_ERROR "Could not list the control archive of ${_package}: ${_error}") + endif() + string(REPLACE "\n" ";" _control_members "${_control_members}") + execute_process( + COMMAND "${_tar}" --extract --preserve-permissions --file "${_work_dir}/control.tar" -C "${_work_dir}/control" + RESULT_VARIABLE _result + ERROR_VARIABLE _error + ) + if(NOT _result EQUAL 0) + message(FATAL_ERROR "Could not extract the control archive of ${_package}: ${_error}") + endif() + + set(_control_file "${_work_dir}/control/control") + file(READ "${_control_file}" _control) + if(NOT _control MATCHES "(^|\n)Architecture:[ \t]*([^\r\n]*)") + message(FATAL_ERROR "No Architecture field in the control file of ${_package}") + endif() + set(_arch "${CMAKE_MATCH_2}") + if(NOT _control MATCHES "(^|\n)Depends:[ \t]*([^\r\n]*)") + return() + endif() + set(_depends_field "${CMAKE_MATCH_0}") + set(_depends_prefix "${CMAKE_MATCH_1}") + set(_depends "${CMAKE_MATCH_2}") + + string(REPLACE "," ";" _dependencies "${_depends}") + set(_new_dependencies) + foreach(_dependency IN LISTS _dependencies) + string(STRIP "${_dependency}" _dependency) + ## dpkg-shlibdeps writes "name" or "name (op version)"; entries that already have + ## alternatives are left alone. + if(_dependency MATCHES "^([a-z0-9][a-z0-9+.-]*t64)([ \t]*\\([^)]*\\))?$") + set(_version "${CMAKE_MATCH_2}") + _openms_deb_renamed_from("${_dpkg_query}" "${CMAKE_MATCH_1}" "${_arch}" _old_names) + foreach(_old_name IN LISTS _old_names) + string(APPEND _dependency " | ${_old_name}${_version}") + endforeach() + endif() + list(APPEND _new_dependencies "${_dependency}") + endforeach() + list(JOIN _new_dependencies ", " _new_depends) + if(_new_depends STREQUAL _depends) + return() + endif() + + string(REPLACE "${_depends_field}" "${_depends_prefix}Depends: ${_new_depends}" _control "${_control}") + file(WRITE "${_control_file}" "${_control}") + + ## CPack writes the control archive as control.tar.gz. Rebuild it the same way: + ## same members in the same order, owned by root, dated no later than + ## SOURCE_DATE_EPOCH if that is set, and compressed without a time stamp. tar takes + ## anything after --mtime=@ without an error, so a value that is not a number of + ## seconds is left out rather than passed on. + set(_mtime) + set(_epoch "$ENV{SOURCE_DATE_EPOCH}") + if(_epoch MATCHES "^[0-9]+$") + set(_mtime "--mtime=@${_epoch}" --clamp-mtime) + elseif(NOT _epoch STREQUAL "") + message(WARNING "cpack_deb_t64_dependencies.cmake: SOURCE_DATE_EPOCH ('${_epoch}') is not a number of seconds; " + "the control archive of ${_package_name} keeps the times of its files.") + endif() + file(MAKE_DIRECTORY "${_work_dir}/member") + execute_process( + COMMAND "${_tar}" --create --file "${_work_dir}/member/control.tar" --format=gnu + --owner=0 --group=0 --numeric-owner ${_mtime} --no-recursion + -C "${_work_dir}/control" ${_control_members} + RESULT_VARIABLE _result + ERROR_VARIABLE _error + ) + if(NOT _result EQUAL 0) + message(FATAL_ERROR "Could not rebuild the control archive of ${_package}: ${_error}") + endif() + execute_process( + COMMAND "${_gzip}" -9 --no-name "${_work_dir}/member/control.tar" + RESULT_VARIABLE _result + ERROR_VARIABLE _error + ) + if(NOT _result EQUAL 0) + message(FATAL_ERROR "Could not compress the control archive of ${_package}: ${_error}") + endif() + + execute_process( + COMMAND "${_ar}" t "${_package}" + OUTPUT_VARIABLE _members + RESULT_VARIABLE _result + ERROR_VARIABLE _error + ) + if(NOT _result EQUAL 0) + message(FATAL_ERROR "Could not list the members of ${_package}: ${_error}") + endif() + if(NOT _members MATCHES "(^|\n)control\\.tar\\.gz\n") + message(FATAL_ERROR "${_package} has no control.tar.gz member; its members are:\n${_members}") + endif() + + ## 'ar r' replaces the member in place, keeping the order dpkg requires. ar writes the + ## new archive to a temporary file of its own and renames it over the package, so an + ## interrupted run leaves the package as it was. D: no time stamps or owners; S: no + ## symbol table, which would become the first member. + execute_process( + COMMAND "${_ar}" rDS "${_package}" control.tar.gz + WORKING_DIRECTORY "${_work_dir}/member" + RESULT_VARIABLE _result + ERROR_VARIABLE _error + ) + if(NOT _result EQUAL 0) + message(FATAL_ERROR "Could not replace the control archive of ${_package}: ${_error}") + endif() + + ## Check the result as dpkg reads it. + execute_process( + COMMAND "${_ar}" t "${_package}" + OUTPUT_VARIABLE _new_members + RESULT_VARIABLE _members_result + ERROR_VARIABLE _members_error + ) + execute_process( + COMMAND "${_dpkg_deb}" --field "${_package}" Depends + OUTPUT_VARIABLE _written_depends + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE _field_result + ERROR_VARIABLE _field_error + ) + if(NOT _members_result EQUAL 0 OR NOT _new_members STREQUAL _members + OR NOT _field_result EQUAL 0 OR NOT _written_depends STREQUAL _new_depends) + message(FATAL_ERROR "The rewritten ${_package} does not read back as expected.\n" + "Members: ${_new_members}${_members_error}\nDepends: ${_written_depends}${_field_error}") + endif() + message(STATUS "cpack_deb_t64_dependencies.cmake: ${_package_name}: Depends: ${_new_depends}") +endfunction() + +## A function, so that none of its variables reach the CPack generator code that +## runs in this scope afterwards. +function(_openms_deb_add_t64_alternatives) + ## CPack also runs post-build scripts for the source package and other generators; + ## without a DEB there is nothing to do, and none of the tools below is needed. + set(_debs) + foreach(_package IN LISTS ARGN) + if(_package MATCHES "\\.deb$") + list(APPEND _debs "${_package}") + endif() + endforeach() + if(NOT _debs) + return() + endif() + + find_program(_dpkg_deb dpkg-deb REQUIRED NO_CACHE) + find_program(_dpkg_query dpkg-query REQUIRED NO_CACHE) + find_program(_ar ar REQUIRED NO_CACHE) + find_program(_tar tar REQUIRED NO_CACHE) + find_program(_gzip gzip REQUIRED NO_CACHE) + + foreach(_package IN LISTS _debs) + ## CPack passes the packages with their full path in its own scratch directory; the + ## working directory goes next to them, so it never lands outside that directory. + if(NOT IS_ABSOLUTE "${_package}" OR NOT EXISTS "${_package}") + message(FATAL_ERROR "cpack_deb_t64_dependencies.cmake: '${_package}' is not the full path of a package; " + "this script is meant to be run by CPack (CPACK_POST_BUILD_SCRIPTS).") + endif() + get_filename_component(_work_dir "${_package}" DIRECTORY) + string(APPEND _work_dir "/_openms_deb_t64") + file(REMOVE_RECURSE "${_work_dir}") + _openms_deb_rewrite("${_package}" "${_work_dir}") + file(REMOVE_RECURSE "${_work_dir}") + endforeach() +endfunction() + +_openms_deb_add_t64_alternatives(${CPACK_PACKAGE_FILES}) + +cmake_policy(POP) diff --git a/cmake/doc_macros.cmake b/cmake/doc_macros.cmake new file mode 100644 index 000000000..66d5add91 --- /dev/null +++ b/cmake/doc_macros.cmake @@ -0,0 +1,27 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Stephan Aiche $ +# $Authors: Stephan Aiche $ +# -------------------------------------------------------------------------- + +# clear variable to avoid accumulation +set(OPENMS_DOCUMENTATION_DIRECTORIES "" + CACHE + INTERNAL + "List of paths to be searched when the API documentation is generated") + + +#------------------------------------------------------------------------------ +# Registers the given path in the documentation system +# +# @param path_to_document Path containing header files that should be documented +macro(openms_doc_path path_to_document) + set(OPENMS_DOCUMENTATION_DIRECTORIES + ${path_to_document} + ${OPENMS_DOCUMENTATION_DIRECTORIES} + CACHE + INTERNAL + "List of paths to be searched when the API documentation is generated") +endmacro() diff --git a/cmake/export_macros.cmake b/cmake/export_macros.cmake new file mode 100644 index 000000000..5f5f2ff69 --- /dev/null +++ b/cmake/export_macros.cmake @@ -0,0 +1,98 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Stephan Aiche $ +# $Authors: Stephan Aiche $ +# -------------------------------------------------------------------------- + + +include(CMakePackageConfigHelpers) + +# a collection of wrapper for export functions that allows easier usage +# througout the OpenMS build system +# +# The export sets (core, CLI, GUI; see cmake/install_macros.cmake) each get one +# target file, .cmake, in the build tree and in the installation. +# OpenMSConfig.cmake includes the core file and then the files of the layers +# that are present. +set(_OPENMS_EXPORT_FILE "${OPENMS_EXPORT_SET}.cmake") +set(_OPENMS_CLI_EXPORT_FILE "${OPENMS_CLI_EXPORT_SET}.cmake") +set(_OPENMS_GUI_EXPORT_FILE "${OPENMS_GUI_EXPORT_SET}.cmake") + +# clear the lists before we refill them (one list of targets per export set) +foreach(_export_set IN LISTS OPENMS_EXPORT_SETS) + set(_OPENMS_EXPORT_TARGETS_${_export_set} "" CACHE INTERNAL "Targets exported in ${_export_set}.") +endforeach() + +# openms_register_export_target( []) +# Records that the export set (the core set OpenMSTargets when omitted) has +# targets. What a set contains is install_library()'s association through +# install(TARGETS ... EXPORT ), which export(EXPORT) below reuses; this +# list only says which sets exist, since exporting an empty or unknown set is +# an error. +macro(openms_register_export_target target_name) + set(_export_set ${ARGN}) + if("${_export_set}" STREQUAL "") + set(_export_set ${OPENMS_EXPORT_SET}) + endif() + if(NOT "${_export_set}" IN_LIST OPENMS_EXPORT_SETS) + message(FATAL_ERROR "openms_register_export_target(${target_name}): unknown export set '${_export_set}' (known: ${OPENMS_EXPORT_SETS})") + endif() + set(_OPENMS_EXPORT_TARGETS_${_export_set} ${_OPENMS_EXPORT_TARGETS_${_export_set}} ${target_name} + CACHE INTERNAL "Targets exported in ${_export_set}.") + unset(_export_set) +endmacro() + +macro(openms_export_targets ) + + # configure OpenMSConfig.cmake + configure_package_config_file( + "${OPENMS_HOST_DIRECTORY}/cmake/OpenMSConfig.cmake.in" + "${PROJECT_BINARY_DIR}/OpenMSConfig.cmake" + INSTALL_DESTINATION ${INSTALL_CMAKE_DIR} + PATH_VARS INSTALL_SHARE_DIR INSTALL_LIB_DIR INSTALL_DOC_DIR INSTALL_BIN_DIR INSTALL_INCLUDE_DIR + ) + + # write OpenMSConfigVersion.cmake + write_basic_package_version_file( + "${PROJECT_BINARY_DIR}/OpenMSConfigVersion.cmake" + VERSION ${OPENMS_PACKAGE_VERSION} + COMPATIBILITY SameMinorVersion + ) + + # create the corresponding target files for the build tree, one per export + # set that has targets, with the same OpenMS:: namespace as the installed + # export (install_export_targets), so a project configured against the build + # tree sees the same target names. export(EXPORT) exports exactly the targets + # of the installation export set, so the build tree describes the same layers + # as an installation. A target of one set refers to targets of another set + # through that set's file, which CMake resolves across the export() calls of + # this project. A set without targets (the GUI set of a WITH_GUI=OFF + # configuration) must not leave the file of an earlier configuration of this + # build directory behind: OpenMSConfig.cmake takes the presence of a layer's + # file as the layer being available. + foreach(_export_set IN LISTS OPENMS_EXPORT_SETS) + if(_OPENMS_EXPORT_TARGETS_${_export_set}) + export(EXPORT ${_export_set} + NAMESPACE OpenMS:: + FILE ${OPENMS_HOST_BINARY_DIRECTORY}/${_export_set}.cmake) + else() + file(REMOVE "${OPENMS_HOST_BINARY_DIRECTORY}/${_export_set}.cmake") + endif() + endforeach() + + # install the generated config file + install_file(${PROJECT_BINARY_DIR}/OpenMSConfig.cmake + ${INSTALL_CMAKE_DIR} + cmake) + + # .. and ConfigVersion.cmake + install_file(${PROJECT_BINARY_DIR}/OpenMSConfigVersion.cmake + ${INSTALL_CMAKE_DIR} + cmake) + + # No export(PACKAGE OpenMS): with cmake_minimum_required(VERSION 3.24) policy + # CMP0090 makes it a no-op, and consumers select an installation explicitly + # through OpenMS_DIR or CMAKE_PREFIX_PATH rather than via the user package registry. +endmacro() diff --git a/cmake/find_installed_openms.cmake b/cmake/find_installed_openms.cmake new file mode 100644 index 000000000..073176400 --- /dev/null +++ b/cmake/find_installed_openms.cmake @@ -0,0 +1,82 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Julianus Pfeuffer $ +# $Authors: Julianus Pfeuffer $ +# -------------------------------------------------------------------------- + +#------------------------------------------------------------------------------ +# Build the applications against an installed OpenMS library +# (OPENMS_USE_INSTALLED_LIBRARY=ON), used instead of cmake/cmake_findExternalLibs.cmake. +# +# The libraries OpenSwathAlgo, OpenMS and OpenMS_CLI, their headers and the shared +# data come from an installation of this same source tree (built with e.g. +# BUILD_TOPP_TOOLS=OFF WITH_GUI=OFF); this build adds the TOPP tools +# (BUILD_TOPP_TOOLS) and/or the GUI library with the GUI applications (WITH_GUI). +# That is how OpenMS is packaged in layers, e.g. for Homebrew: +# libopenms the libraries, headers, CMake package and share/OpenMS +# openms the TOPP tools (install component Applications) +# openms-gui OpenMS_GUI + TOPPView, TOPPAS, ... (install components +# library_gui and GUIApplications) +# +# Only what the applications themselves need is searched here: the dependencies of +# the libraries' public link interface are found by OpenMSConfig.cmake. +#------------------------------------------------------------------------------ + +if(NOT BUILD_TOPP_TOOLS AND NOT WITH_GUI) + message(FATAL_ERROR "OPENMS_USE_INSTALLED_LIBRARY builds only the applications, so it needs BUILD_TOPP_TOOLS and/or WITH_GUI.") +endif() +if(NOT "${PACKAGE_TYPE}" STREQUAL "none") + message(FATAL_ERROR "OPENMS_USE_INSTALLED_LIBRARY does not support packaging (PACKAGE_TYPE=${PACKAGE_TYPE}).") +endif() + +## The applications are compiled from the same sources as the library they link, so +## the installation has to be of this very version. +find_package(OpenMS ${OPENMS_PACKAGE_VERSION} EXACT CONFIG REQUIRED COMPONENTS CLI) +## The GUI library is built here (src/openms_gui), so it must not come from the +## installation as well: its imported target would clash with the one built here and +## its installed headers would compete with those of the source tree. +if(WITH_GUI AND OpenMS_WITH_GUI) + message(FATAL_ERROR "The OpenMS installation in ${OpenMS_DIR} already includes the GUI library. " + "Build the GUI (WITH_GUI=ON) against an installation without it (built with WITH_GUI=OFF, " + "or installed without the components library_gui and cmake_gui).") +endif() +message(STATUS "Building against the installed OpenMS ${OpenMS_VERSION} in ${OpenMS_DIR}") +message(STATUS " shared data of that installation: ${OPENMS_DATA_DIR}") + +## options of the installed library that decide which applications exist +set(WITH_WNETALIGN ${OpenMS_WITH_WNETALIGN}) + +#------------------------------------------------------------------------------ +# nlohmann::json: DIAuditor and OpenNuXL use it directly. It is a private dependency of +# libOpenMS, so the installation does not provide it; take it from where the library +# build does (src/openms/extern/CMakeLists.txt): the vendored copy, or an external one +# with USE_EXTERNAL_JSON. +if(BUILD_TOPP_TOOLS) + option(USE_EXTERNAL_JSON "Use an external nlohmann::json library" OFF) + if(USE_EXTERNAL_JSON) + find_package(nlohmann_json REQUIRED GLOBAL) + target_compile_definitions(nlohmann_json::nlohmann_json INTERFACE JSON_USE_IMPLICIT_CONVERSIONS=0) + else() + ## header-only: the include directory of the vendored copy, as its own CMakeLists.txt + ## (which expects the setup of src/openms/extern/CMakeLists.txt) exports it + add_library(nlohmann_json INTERFACE) + add_library(nlohmann_json::nlohmann_json ALIAS nlohmann_json) + target_include_directories(nlohmann_json SYSTEM INTERFACE + "${OPENMS_HOST_DIRECTORY}/src/openms/extern/nlohmann_json/include") + endif() +endif() + +#------------------------------------------------------------------------------ +# Boost (header-only): a few TOPP tools (FileInfo, FileMerger, TextExporter, ...; the +# list in src/topp/CMakeLists.txt) and the GUI library use it directly. It is a private +# dependency of libOpenMS, so the installation does not provide it; find it as the +# library build does. +find_boost() + +#------------------------------------------------------------------------------ +# Qt for the GUI library and applications +if(WITH_GUI) + include(${OPENMS_HOST_DIRECTORY}/cmake/cmake_findQt.cmake) +endif() diff --git a/cmake/install_macros.cmake b/cmake/install_macros.cmake new file mode 100644 index 000000000..91772d83d --- /dev/null +++ b/cmake/install_macros.cmake @@ -0,0 +1,430 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Julianus Pfeuffer $ +# $Authors: Stephan Aiche, Julianus Pfeuffer $ +# -------------------------------------------------------------------------- + +# a collection of wrapper for install functions that allows easier usage +# throughout the OpenMS build system + +#------------------------------------------------------------------------------ +# The installed package is layered. Each layer is one export set (the file +# OpenMSConfig.cmake includes) and one pair of install components, so an +# installation may stop at any layer and the package of what is installed stays +# consistent (CMake refuses an export whose library files are missing): +# +# layer export set libraries cmake files targets +# core OpenMSTargets library cmake OpenMS::OpenMS, OpenMS::OpenSwathAlgo +# and the bundled third-party libraries +# CLI OpenMSCLITargets library_cli cmake_cli OpenMS::OpenMS_CLI (links the core layer) +# GUI OpenMSGUITargets library_gui cmake_gui OpenMS::OpenMS_GUI (links the CLI layer) +# +# Headers keep their own components (OpenMS_headers, OpenMS_CLI_headers, +# OpenMS_GUI_headers, OpenSwathAlgo_headers, thirdparty_headers). A core-only +# installation (e.g. the one the pyOpenMS wheels are built against) is +# library + the core header components + share + cmake. +set(OPENMS_EXPORT_SET "OpenMSTargets") +set(OPENMS_CLI_EXPORT_SET "OpenMSCLITargets") +set(OPENMS_GUI_EXPORT_SET "OpenMSGUITargets") +set(OPENMS_EXPORT_SETS ${OPENMS_EXPORT_SET} ${OPENMS_CLI_EXPORT_SET} ${OPENMS_GUI_EXPORT_SET}) + +# the install components of each export set: _LIBRARY_COMPONENT holds the +# libraries, _CMAKE_COMPONENT the exported target files +set(${OPENMS_EXPORT_SET}_LIBRARY_COMPONENT library) +set(${OPENMS_EXPORT_SET}_CMAKE_COMPONENT cmake) +set(${OPENMS_CLI_EXPORT_SET}_LIBRARY_COMPONENT library_cli) +set(${OPENMS_CLI_EXPORT_SET}_CMAKE_COMPONENT cmake_cli) +set(${OPENMS_GUI_EXPORT_SET}_LIBRARY_COMPONENT library_gui) +set(${OPENMS_GUI_EXPORT_SET}_CMAKE_COMPONENT cmake_gui) + +#------------------------------------------------------------------------------ +# Installs the library lib_target_name into the library component of its export +# set and adds it to that export set. +# +# install_library( [HEADERS] [EXPORT_SET ]) +# +# @param lib_target_name The target name of the library that should be installed +# @param EXPORT_SET One of ${OPENMS_EXPORT_SETS}; the core set OpenMSTargets +# (component 'library') when omitted +# @param HEADERS Install the public HEADERS file set in _headers +function(install_library lib_target_name) + cmake_parse_arguments(_install_library "HEADERS" "EXPORT_SET" "" ${ARGN}) + if(_install_library_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "install_library(${lib_target_name}): unexpected arguments ${_install_library_UNPARSED_ARGUMENTS}") + endif() + if(NOT _install_library_EXPORT_SET) + set(_install_library_EXPORT_SET ${OPENMS_EXPORT_SET}) + endif() + if(NOT _install_library_EXPORT_SET IN_LIST OPENMS_EXPORT_SETS) + message(FATAL_ERROR "install_library(${lib_target_name}): unknown export set '${_install_library_EXPORT_SET}' (known: ${OPENMS_EXPORT_SETS})") + endif() + set(_component ${${_install_library_EXPORT_SET}_LIBRARY_COMPONENT}) + set(_header_install_args) + if(_install_library_HEADERS) + set(_header_install_args FILE_SET HEADERS DESTINATION ${INSTALL_INCLUDE_DIR} + COMPONENT ${lib_target_name}_headers) + endif() + install(TARGETS ${lib_target_name} + RUNTIME_DEPENDENCY_SET OPENMS_DEPS + EXPORT ${_install_library_EXPORT_SET} + LIBRARY DESTINATION ${INSTALL_LIB_DIR} COMPONENT ${_component} + ARCHIVE DESTINATION ${INSTALL_LIB_DIR} COMPONENT ${_component} + RUNTIME DESTINATION ${INSTALL_LIB_DIR} COMPONENT ${_component} + ${_header_install_args} + ) + # MSVC writes the debug information of a DLL to a .pdb file next to it (in a Debug + # or RelWithDebInfo build; a Release build has none, hence OPTIONAL). It ships with + # the DLL, so a consumer of the Windows Debug SDK can step into OpenMS code. + # TARGET_PDB_FILE is only defined for shared libraries and executables. + get_target_property(_type ${lib_target_name} TYPE) + if(MSVC AND _type STREQUAL "SHARED_LIBRARY") + install(FILES $ + DESTINATION ${INSTALL_LIB_DIR} COMPONENT ${_component} OPTIONAL) + endif() +endfunction() + +#------------------------------------------------------------------------------ +# What every installed header may include, as regular expressions matched against the +# whole include name. A library adds the headers of its own PUBLIC dependencies with +# openms_add_library(... ALLOWED_PUBLIC_INCLUDES ...), e.g. Qt for the GUI layer. +set(OPENMS_PUBLIC_INCLUDE_ALLOWLIST + "OpenMS/.*" # OpenMS' own headers + "[a-z_]+" # the C++ standard library: , , ... + "sys/.*" "windows\\.h" "winternl\\.h" # operating-system headers + "omp\\.h" # OpenMP, a PUBLIC dependency of libOpenMS + "CrawdadWrapper\\.h") # Crawdad, a PUBLIC dependency of WITH_CRAWDAD builds + +#------------------------------------------------------------------------------ +# Reject every include of an installed header that is not on the allowlist above. +# openms_validate_public_headers(
... [ALLOW ...]) +# +# All dependencies of OpenMS are installed into one prefix, so an include of a PRIVATE +# dependency resolves through a sibling package's include directory on the machine that +# builds OpenMS, and the compiler header checks pass. It only fails downstream, where the +# package is missing. An allowlist rather than a list of known private dependencies means +# that a dependency added later is rejected too, without anyone having to list it. +# Keep this configure-time guard independent of the header installation method. +function(openms_validate_public_headers) + cmake_parse_arguments(PARSE_ARGV 0 _validate "" "" "ALLOW") + set(_allowed ${OPENMS_PUBLIC_INCLUDE_ALLOWLIST} ${_validate_ALLOW}) + list(JOIN _allowed "|" _allowed_regex) + set(_allowed_regex "^(${_allowed_regex})$") + foreach(_header IN LISTS _validate_UNPARSED_ARGUMENTS) + # Header lists are relative to the calling source directory. + # Generated headers in the build tree may not exist yet at this point; they come from OpenMS' + # own templates, so only what is already on disk is scanned. + set(_header_to_scan "${_header}") + if (NOT IS_ABSOLUTE "${_header_to_scan}") + set(_header_to_scan "${CMAKE_CURRENT_SOURCE_DIR}/${_header_to_scan}") + endif() + if (EXISTS "${_header_to_scan}" AND NOT IS_DIRECTORY "${_header_to_scan}") + file(STRINGS "${_header_to_scan}" _include_lines REGEX "^[ \t]*#[ \t]*include[ \t]*[<\"]") + set(_rejected) + foreach(_line IN LISTS _include_lines) + string(REGEX REPLACE "^[ \t]*#[ \t]*include[ \t]*[<\"]([^>\"]*)[>\"].*$" "\\1" _include "${_line}") + if (NOT _include MATCHES "${_allowed_regex}") + list(APPEND _rejected "${_include}") + endif() + endforeach() + if (_rejected) + list(JOIN _rejected ", " _rejected) + message(FATAL_ERROR "Installed header ${_header} includes ${_rejected}, which downstream " + "builds cannot rely on. For a PRIVATE dependency, add the header to " + "OpenMS_private_headers or expose OpenMS types instead. For a PUBLIC one, " + "which OpenMSConfig.cmake finds for consumers, allow its headers with " + "openms_add_library(... ALLOWED_PUBLIC_INCLUDES ).") + endif() + endif() + endforeach() +endfunction() + +#------------------------------------------------------------------------------ +# Installs the tool tool_target_name +# +# install_tool( [COMPONENT ]) +# +# @param tool_target_name The target name of the tool that should be installed +# @param COMPONENT The install component; 'Applications' (the TOPP tools) when +# omitted. The GUI applications use +# ${OPENMS_GUI_APPLICATIONS_COMPONENT} (see the top-level CMakeLists.txt). +function(install_tool tool_target_name) + cmake_parse_arguments(_install_tool "" "COMPONENT" "" ${ARGN}) + if(_install_tool_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "install_tool(${tool_target_name}): unexpected arguments ${_install_tool_UNPARSED_ARGUMENTS}") + endif() + if(NOT _install_tool_COMPONENT) + set(_install_tool_COMPONENT Applications) + endif() + install(TARGETS ${tool_target_name} RUNTIME_DEPENDENCY_SET OPENMS_DEPS + RUNTIME DESTINATION ${INSTALL_BIN_DIR} COMPONENT ${_install_tool_COMPONENT} + BUNDLE DESTINATION ${INSTALL_BIN_DIR} COMPONENT ${_install_tool_COMPONENT} + ) +endfunction() + +#------------------------------------------------------------------------------ +# Installs a given directory +# @param directory The directory to install +# @param destination The destination (relative to the prefix) where it should be installed +# @param component The component to which to the directory belongs +macro(install_directory directory destination component) + install(DIRECTORY ${directory} + DESTINATION ${destination} + COMPONENT ${component} + FILE_PERMISSIONS OWNER_WRITE OWNER_READ + GROUP_READ + WORLD_READ + DIRECTORY_PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ + GROUP_EXECUTE GROUP_READ + WORLD_EXECUTE WORLD_READ + REGEX "^\\..*" EXCLUDE ## Exclude hidden files (svn, git, DSStore) + REGEX ".*\\/\\..*" EXCLUDE ## Exclude hidden files in subdirectories + ) +endmacro() + +#------------------------------------------------------------------------------ +# Installs a given file +# @param directory The file to install +# @param destination The destination (relative to the prefix) where it should be installed +# @param component The component to which to the file belongs +macro(install_file file destination component) + install(FILES ${file} + DESTINATION ${destination} + COMPONENT ${component}) +endmacro() + +#------------------------------------------------------------------------------ +# Execute the given code while executing the install target +# @param code_snippet The code to execute +# @param component The component to which the code will be associated +macro(install_code code_snippet component) + install(CODE ${code_snippet} + COMPONENT ${component}) +endmacro() + +#------------------------------------------------------------------------------ +# Installs the exported target information of every export set that has +# targets: one .cmake file per layer in the cmake component of that layer +# (cmake, cmake_cli, cmake_gui), so an installation without a layer has no file +# claiming its libraries. Consumers see every target as OpenMS:: +# (OpenMS::OpenMS, OpenMS::OpenSwathAlgo, OpenMS::OpenMS_CLI, ...); a target of +# one layer refers to the targets of the layer below by these names, and +# OpenMSConfig.cmake includes the files in layer order and adds un-namespaced +# aliases for the OpenMS libraries. +macro(install_export_targets ) + foreach(_export_set IN LISTS OPENMS_EXPORT_SETS) + if(_OPENMS_EXPORT_TARGETS_${_export_set}) + install(EXPORT ${_export_set} + NAMESPACE OpenMS:: + DESTINATION ${INSTALL_CMAKE_DIR} + COMPONENT ${${_export_set}_CMAKE_COMPONENT}) + endif() + endforeach() +endmacro() + +#------------------------------------------------------------------------------ +# Returns in ${out_var} the .NET runtime identifiers (RIDs) whose native assets +# this build can load, spelled as NuGet spells them, -: +# https://learn.microsoft.com/dotnet/core/rid-catalog +function(openms_target_dotnet_rids out_var) + if(WIN32) + set(_os "win") + elseif(APPLE) + set(_os "osx") + else() + set(_os "linux") + endif() + + ## CMAKE_SYSTEM_PROCESSOR spells the same architecture differently per + ## platform (x86_64 vs AMD64, aarch64 vs arm64). On macOS + ## CMAKE_OSX_ARCHITECTURES overrides it and may name more than one. + set(_processors "${CMAKE_SYSTEM_PROCESSOR}") + if(APPLE AND CMAKE_OSX_ARCHITECTURES) + set(_processors ${CMAKE_OSX_ARCHITECTURES}) + endif() + + set(_rids) + foreach(_processor IN LISTS _processors) + string(TOLOWER "${_processor}" _processor) + if(_processor MATCHES "^(x86_64|amd64|x64)$") + set(_arch "x64") + elseif(_processor MATCHES "^(aarch64|arm64)$") + set(_arch "arm64") + elseif(_processor MATCHES "^(i[3-6]86|x86)$") + set(_arch "x86") + elseif(_processor MATCHES "^arm") + set(_arch "arm") + else() + ## Unknown architecture: pass it through rather than guess. A RID nothing + ## matches only means nothing is kept, which install_thirdparty_folder + ## reports below. + set(_arch "${_processor}") + endif() + list(APPEND _rids "${_os}-${_arch}") + endforeach() + + ## An arm64 Mac runs x86_64 processes under Rosetta, so an x86_64 mono on one + ## still asks for the osx-x64 helper. Mach-O files never reach dpkg-shlibdeps, + ## so keeping it costs nothing where the exclusion below actually matters. + if(APPLE AND "osx-arm64" IN_LIST _rids) + list(APPEND _rids "osx-x64") + endif() + + list(REMOVE_DUPLICATES _rids) + set(${out_var} "${_rids}" PARENT_SCOPE) +endfunction() + +#------------------------------------------------------------------------------ +# Installs Thirdparty folders with executables +macro(install_thirdparty_folder foldername) + if(EXISTS ${SEARCH_ENGINES_DIRECTORY}/${foldername}) + ## The .NET tools here (ThermoRawFileParser) carry NuGet's 'runtimes//' + ## layout: one folder of native helper libraries per runtime identifier the + ## NuGet package supports. Mono.Unix ships nine of them -- android-arm, + ## android-arm64, android-x64, android-x86, linux-arm, linux-arm64, + ## linux-x64, osx-arm64 and osx-x64 -- and at most the one matching the + ## machine can ever be loaded. ThermoRawFileParser's own Mono.Unix.dll.config + ## maps the library to runtimes/linux-x64, runtimes/osx-x64 and + ## runtimes/osx-arm64, and to nothing else. + ## + ## The selection below goes by the target architecture, not by that file, so a + ## linux-arm64 build keeps runtimes/linux-arm64 although the config does not + ## map it: the helper is native to that host, which is all dpkg-shlibdeps + ## needs, and a later ThermoRawFileParser whose config maps it will find it. + ## + ## Seven of the nine carry a .so, so CPackDeb hands all seven to + ## dpkg-shlibdeps and five are foreign on any given host; the two osx ones + ## are Mach-O and never reach it. + ## + ## The rest is not merely dead weight. Any foreign-architecture ELF in the + ## staging tree makes dpkg-shlibdeps fail with "cannot find library + ## libc.so.6 needed by ... (ELF format: ...)", an error --ignore-missing-info + ## does not cover, so CPack aborts before writing the .deb. That is what + ## forced CPACK_DEBIAN_PACKAGE_SHLIBDEPS off once already (on in #10202, + ## reverted in #10207). Install the RIDs this build targets and leave the + ## others behind; cmake/package_deb.cmake depends on that. + openms_target_dotnet_rids(_target_rids) + set(_foreign_rid_excludes) + set(_present_rids) + set(_kept_rids) + set(_runtimes_dir "${SEARCH_ENGINES_DIRECTORY}/${foldername}/runtimes") + file(GLOB _rid_entries RELATIVE "${_runtimes_dir}" "${_runtimes_dir}/*") + foreach(_rid IN LISTS _rid_entries) + if(NOT IS_DIRECTORY "${_runtimes_dir}/${_rid}") + continue() + endif() + list(APPEND _present_rids "${_rid}") + if("${_rid}" IN_LIST _target_rids) + list(APPEND _kept_rids "${_rid}") + else() + ## Matches the RID directory itself, so install() never descends into + ## it. The (/|$) tail is what keeps 'android-arm' from also matching + ## 'android-arm64'. + list(APPEND _foreign_rid_excludes REGEX "/runtimes/${_rid}(/|$)" EXCLUDE) + endif() + endforeach() + if(_present_rids AND NOT _kept_rids) + ## Nothing here this build could load, so drop the tree instead of leaving + ## an empty runtimes/ behind. Windows is that case: Mono.Unix is a Unix + ## helper and the vendored tool carries no win-* runtime at all. + set(_foreign_rid_excludes REGEX "/runtimes(/|$)" EXCLUDE) + endif() + if(_foreign_rid_excludes) + message(STATUS "${foldername}: installing .NET runtimes ${_kept_rids} of ${_present_rids}") + endif() + + install(DIRECTORY ${SEARCH_ENGINES_DIRECTORY}/${foldername} + DESTINATION ${INSTALL_SHARE_DIR}/THIRDPARTY + COMPONENT ${foldername} + FILE_PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE + DIRECTORY_PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE + ${_foreign_rid_excludes} + REGEX "^\\..*" EXCLUDE ## Exclude hidden files (svn, git, DSStore) + REGEX ".*\\/\\..*" EXCLUDE ## Exclude hidden files in subdirectories + ) + list(APPEND THIRDPARTY_COMPONENT_GROUP ${foldername}) + endif() +endmacro() + +#------------------------------------------------------------------------------ +# Installs Qt plugins. Prefix can be the usual CMAKE_INSTALL_PREFIX or +# if you install to a bundle, the app folder +# Fills _qt_plugins_var with paths to be used e.g. with fixup_bundle at INSTALL time. +macro(install_qt6_plugin_installdir _qt_plugin_name _qt_plugins_var _targetpath _component) + get_target_property(_qt_plugin_path "${_qt_plugin_name}" LOCATION) + if(EXISTS "${_qt_plugin_path}") + get_filename_component(_qt_plugin_file "${_qt_plugin_path}" NAME) + get_filename_component(_qt_plugin_type "${_qt_plugin_path}" PATH) + get_filename_component(_qt_plugin_type "${_qt_plugin_type}" NAME) + set(_qt_plugin_dest "${_targetpath}/${_qt_plugin_type}") + install(FILES "${_qt_plugin_path}" + DESTINATION "${_qt_plugin_dest}" + COMPONENT ${_component}) + set(${_qt_plugins_var} + "${${_qt_plugins_var}};\${CMAKE_INSTALL_PREFIX}/${_qt_plugin_dest}/${_qt_plugin_file}") + else() + message(FATAL_ERROR "Qt plugin ${_qt_plugin_name} not found") + endif() +endmacro() + +#------------------------------------------------------------------------------ +# Installs Qt plugins. Prefix can be the usual CMAKE_INSTALL_PREFIX or +# if you install to a bundle, the app folder +# Fills _qt_plugins_var with paths to be used e.g. with fixup_bundle at BUILD time. +macro(install_qt6_plugin_builddir _qt_plugin_name _qt_plugins_var _targetpath _component) + get_target_property(_qt_plugin_path "${_qt_plugin_name}" LOCATION) + if(EXISTS "${_qt_plugin_path}") + # Resolve symlinks to get the actual file + get_filename_component(_qt_plugin_path "${_qt_plugin_path}" REALPATH) + get_filename_component(_qt_plugin_file "${_qt_plugin_path}" NAME) + get_filename_component(_qt_plugin_type "${_qt_plugin_path}" PATH) + get_filename_component(_qt_plugin_type "${_qt_plugin_type}" NAME) + set(_qt_plugin_dest "${_targetpath}/${_qt_plugin_type}") + install(FILES "${_qt_plugin_path}" + DESTINATION "${_qt_plugin_dest}" + COMPONENT ${_component}) + set(${_qt_plugins_var} + "${${_qt_plugins_var}};${_qt_plugin_dest}/${_qt_plugin_file}") + else() + message(FATAL_ERROR "Qt plugin ${_qt_plugin_name} not found") + endif() +endmacro() + +#------------------------------------------------------------------------------ +# Installs QT6 libraries to CMAKE_INSTALL_PREFIX based on given components +macro(install_qt6_libs _qt_components _targetpath _install_component) + foreach (_qt_component ${_qt_components}) + get_target_property(_qt_lib_path "Qt6::${_qt_component}" LOCATION) + if(_qt_lib_path MATCHES "^.*\\/.*${_qt_component}\\.framework\\/.*$") + ## we could use if Mac but this is more general + get_filename_component(_qt_lib_path "${_qt_lib_path}" PATH) + if(EXISTS "${_qt_lib_path}") + install(DIRECTORY "${_qt_lib_path}" + DESTINATION "${_targetpath}" + COMPONENT ${_install_component}) + else() + message(FATAL_ERROR "Qt lib ${_qt_component} not found at imported location ${_qt_lib_path} for install/package") + endif() + else() + if(EXISTS "${_qt_lib_path}") + if (UNIX AND "${_qt_lib_path}" MATCHES ".*\\.[0-9]+\\.[0-9]+\\.[0-9]+$") + string(REGEX REPLACE "\\.[0-9]+\\.[0-9]+$" "" _qt_lib_path_tgt ${_qt_lib_path}) + else() + set(_qt_lib_path_tgt ${_qt_lib_path}) + endif() + get_filename_component(_qt_lib_path_tgt "${_qt_lib_path_tgt}" NAME) + install(FILES "${_qt_lib_path}" + DESTINATION "${_targetpath}" + RENAME "${_qt_lib_path_tgt}" + COMPONENT ${_install_component}) + else() + message(FATAL_ERROR "Qt lib ${_qt_component} not found at imported location ${_qt_lib_path} for install/package") + endif() + endif() + endforeach(_qt_component) +endmacro() diff --git a/cmake/messages.cmake b/cmake/messages.cmake new file mode 100644 index 000000000..81eaddf22 --- /dev/null +++ b/cmake/messages.cmake @@ -0,0 +1,104 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Julianus Pfeuffer $ +# $Authors: Stephan Aiche, Chris Bielow, Julianus Pfeuffer $ +# -------------------------------------------------------------------------- + + + +# Optional targets +# -------------------------------------------------------------------------- +if (PYOPENMS) + set(pyopenms_targets + COMMAND ${CMAKE_COMMAND} -E echo " pyopenms builds pyOpenMS inplace" + COMMAND ${CMAKE_COMMAND} -E echo " pyopenms_bdist_egg builds pyOpenMS bdist_egg" + COMMAND ${CMAKE_COMMAND} -E echo " pyopenms_bdist builds pyOpenMS bdist as zip file" + COMMAND ${CMAKE_COMMAND} -E echo " pyopenms_rpm builds pyOpenMS rpm" + + ) +else() + set(pyopenms_targets + COMMAND ${CMAKE_COMMAND} -E echo "" + COMMAND ${CMAKE_COMMAND} -E echo " (Disabled) pyopenms targets are not enabled (to enable use -D PYOPENMS=ON)." + COMMAND ${CMAKE_COMMAND} -E echo "" + ) +endif() + +if (OPENMS_COVERAGE) + set(coverage_target + COMMAND ${CMAKE_COMMAND} -E echo " OpenMS_coverage generates a coverage report in html format." + COMMAND ${CMAKE_COMMAND} -E echo " Requires the test target to be executed at least once." + ) +else() + set(coverage_target + COMMAND ${CMAKE_COMMAND} -E echo "" + COMMAND ${CMAKE_COMMAND} -E echo " (Disabled) OpenMS_coverage reporting target is not enabled (to enable use -D OPENMS_COVERAGE=ON)." + COMMAND ${CMAKE_COMMAND} -E echo " Caution: Building with debug and coverage info uses a lot of disk space (>40GB)" + COMMAND ${CMAKE_COMMAND} -E echo "" + ) +endif() + + + +# -------------------------------------------------------------------------- +# Main targets list +if (MSVC) + add_custom_target(targets + COMMAND ${CMAKE_COMMAND} -E echo "" + COMMAND ${CMAKE_COMMAND} -E echo "==========================================================================" + COMMAND ${CMAKE_COMMAND} -E echo "" + COMMAND ${CMAKE_COMMAND} -E echo "The following make targets are available:" + COMMAND ${CMAKE_COMMAND} -E echo " ALL_BUILD [Visual Studio only] builds the OpenMS library, TOPP tools" + COMMAND ${CMAKE_COMMAND} -E echo " [no target] [NMake only] builds the OpenMS library, TOPP tools" + COMMAND ${CMAKE_COMMAND} -E echo " OpenMS builds the OpenMS library" + COMMAND ${CMAKE_COMMAND} -E echo " TOPP builds the TOPP tools" + COMMAND ${CMAKE_COMMAND} -E echo " GUI builds the GUI tools (TOPPView,...)" + COMMAND ${CMAKE_COMMAND} -E echo " RUN_TESTS [Visual Studio only] executes OpenMS and TOPP tests (*)" + COMMAND ${CMAKE_COMMAND} -E echo " test [NMake only] executes OpenMS and TOPP tests (*)" + COMMAND ${CMAKE_COMMAND} -E echo " *) make sure they are built using the ALL_BUILD/all target." + COMMAND ${CMAKE_COMMAND} -E echo " Tutorials_build builds the code snippets of the tutorials in source/EXAMPLES" + COMMAND ${CMAKE_COMMAND} -E echo " doc builds the doxygen and class documentation and the" + COMMAND ${CMAKE_COMMAND} -E echo " parameters documentation" + COMMAND ${CMAKE_COMMAND} -E echo " doc_class_only builds only the doxygen and class documentation" + COMMAND ${CMAKE_COMMAND} -E echo " (faster then doc and very useful when writing" + COMMAND ${CMAKE_COMMAND} -E echo " documentation)." + ${pyopenms_targets} + ${coverage_target} + COMMAND ${CMAKE_COMMAND} -E echo "" + COMMAND ${CMAKE_COMMAND} -E echo "Single TOPP tools have their own target, e.g. TOPPView" + COMMAND ${CMAKE_COMMAND} -E echo "" + COMMAND ${CMAKE_COMMAND} -E echo "==========================================================================" + COMMAND ${CMAKE_COMMAND} -E echo "" + COMMENT "The most important targets for OpenMS" + VERBATIM) +else() + add_custom_target(targets + COMMAND ${CMAKE_COMMAND} -E echo "" + COMMAND ${CMAKE_COMMAND} -E echo "==========================================================================" + COMMAND ${CMAKE_COMMAND} -E echo "" + COMMAND ${CMAKE_COMMAND} -E echo "The following make targets are available:" + COMMAND ${CMAKE_COMMAND} -E echo " [no target] builds the OpenMS library, TOPP tools" + COMMAND ${CMAKE_COMMAND} -E echo " OpenMS builds the OpenMS library" + COMMAND ${CMAKE_COMMAND} -E echo " TOPP builds the TOPP tools" + COMMAND ${CMAKE_COMMAND} -E echo " GUI builds the GUI tools (TOPPView,...)" + COMMAND ${CMAKE_COMMAND} -E echo " test executes OpenMS and TOPP tests" + COMMAND ${CMAKE_COMMAND} -E echo " make sure they are built using the 'all' target" + COMMAND ${CMAKE_COMMAND} -E echo " Tutorials_build builds the code snippets of the tutorials in source/EXAMPLES" + COMMAND ${CMAKE_COMMAND} -E echo " doc builds the doxygen and class documentation and the" + COMMAND ${CMAKE_COMMAND} -E echo " parameters documentation" + COMMAND ${CMAKE_COMMAND} -E echo " doc_class_only builds only the doxygen and class documentation" + COMMAND ${CMAKE_COMMAND} -E echo " (faster then doc and very useful when writing" + COMMAND ${CMAKE_COMMAND} -E echo " documentation)." + COMMAND ${CMAKE_COMMAND} -E echo " help list all available targets (very verbose)" + ${pyopenms_targets} + ${coverage_target} + COMMAND ${CMAKE_COMMAND} -E echo "" + COMMAND ${CMAKE_COMMAND} -E echo "Single TOPP tools have their own target, e.g. TOPPView" + COMMAND ${CMAKE_COMMAND} -E echo "" + COMMAND ${CMAKE_COMMAND} -E echo "==========================================================================" + COMMAND ${CMAKE_COMMAND} -E echo "" + COMMENT "The most important targets for OpenMS" + VERBATIM) +endif() diff --git a/cmake/mimalloc.cmake b/cmake/mimalloc.cmake new file mode 100644 index 000000000..456ab96ed --- /dev/null +++ b/cmake/mimalloc.cmake @@ -0,0 +1,97 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# -------------------------------------------------------------------------- +# $Maintainer: Oliver Kohlbacher $ +# $Authors: Oliver Kohlbacher $ +# -------------------------------------------------------------------------- +# WITH_MIMALLOC: the TOPP tools allocate through mimalloc instead of the NT heap (Windows, MSVC). +# +# mimalloc's documented dynamic override for Windows (its readme, "Dynamic Override on Windows"): the +# executable links mimalloc's import library ahead of every other library (/INCLUDE:mi_version keeps +# the import), and mimalloc.dll and mimalloc-redirect.dll sit next to it. At load time the redirect +# patches the heap entry points of the UCRT, so the allocations of OpenMS.dll and of the static +# dependencies go to mimalloc as well, not only the executable's own. Measured with ProSE (HeLa, +# 3 files, Ryzen 9 7900X, MSVC 14.44): 12 threads 57 -> 42 s (-26 %, the NT heap's page faults and +# system time under contention), 1 thread -5 %, outputs identical. +# +# mimalloc comes from its upstream release through FetchContent, pinned by hash: the vcpkg port cannot +# provide the override under OpenMS's x64-windows-static-md triplet (its 'override' feature supports +# "!windows | !static": a static mimalloc has no DLL to redirect through), and a per-port linkage +# override in the triplet would change the ABI hash of every cached package. pyOpenMS keeps the NT +# heap: the override needs the executable's import table. + +option(WITH_MIMALLOC "Windows/MSVC x64 only: the TOPP tools allocate through mimalloc (mimalloc.dll and mimalloc-redirect.dll next to the executables)." OFF) + +## openms_link_mimalloc(): a no-op unless WITH_MIMALLOC is in effect. Tested through a global +## property, not `TARGET mimalloc`: other packages (e.g. vcpkg's mimalloc wrapper, pulled in by arrow) may +## define a target of that name. +function(openms_link_mimalloc target) + get_property(_active GLOBAL PROPERTY OPENMS_MIMALLOC_ACTIVE) + if(NOT _active) + return() + endif() + target_link_libraries(${target} mimalloc) # build order + ## Link options precede the libraries on the link line, so mimalloc.dll becomes the first import of + ## the executable, as the override requires (check with mimalloc's minject -l ). + target_link_options(${target} PRIVATE /INCLUDE:mi_version $) +endfunction() + +if(NOT WITH_MIMALLOC) + return() +endif() +## x64 only: the redirect DLL name and the undecorated /INCLUDE:mi_version symbol are x64-specific +## (mimalloc-redirect-arm64.dll, mimalloc-redirect32.dll, _mi_version on x86). +if(NOT (WIN32 AND MSVC AND CMAKE_CXX_COMPILER_ARCHITECTURE_ID STREQUAL "x64")) + message(STATUS "WITH_MIMALLOC is Windows/MSVC x64-only; ignored on this platform.") + return() +endif() +if(NOT BUILD_TOPP_TOOLS) + message(STATUS "WITH_MIMALLOC: no TOPP tools in this build, nothing to link.") + return() +endif() + +include(FetchContent) +FetchContent_Declare(mimalloc + URL https://github.com/microsoft/mimalloc/archive/refs/tags/v3.6.1.tar.gz + URL_HASH SHA256=2672e6a99d4579fb4bb32d9de0d63aa424ce600d31fbfaf06eb74d940d2e07a6 + ## A subdirectory without a CMakeLists.txt: FetchContent_MakeAvailable() then only downloads, and the + ## add_subdirectory() below adds mimalloc with EXCLUDE_FROM_ALL, which drops its install rules + ## (headers, import library, CMake package); OpenMS installs the two DLLs and the license itself. + SOURCE_SUBDIR cmake +) +if(TARGET mimalloc) + message(FATAL_ERROR "WITH_MIMALLOC: a target 'mimalloc' already exists (e.g. from vcpkg's mimalloc wrapper); " + "the fetched mimalloc cannot be added next to it.") +endif() +## Settings for the mimalloc subproject only: normal variables in the top-level scope, restored afterwards +## (same pattern as HiGHS in cmake_findExternalLibs.cmake). +set(_openms_mimalloc_vars MI_BUILD_SHARED MI_BUILD_STATIC MI_BUILD_OBJECT MI_BUILD_TESTS MI_OVERRIDE MI_WIN_REDIRECT) +foreach(_var IN LISTS _openms_mimalloc_vars) + if(DEFINED ${_var}) + set(_openms_mimalloc_saved_${_var} "${${_var}}") + endif() +endforeach() +set(MI_BUILD_SHARED ON) +set(MI_BUILD_STATIC OFF) +set(MI_BUILD_OBJECT OFF) +set(MI_BUILD_TESTS OFF) +set(MI_OVERRIDE ON) +set(MI_WIN_REDIRECT ON) +FetchContent_MakeAvailable(mimalloc) +add_subdirectory(${mimalloc_SOURCE_DIR} ${mimalloc_BINARY_DIR} EXCLUDE_FROM_ALL) +foreach(_var IN LISTS _openms_mimalloc_vars) + if(DEFINED _openms_mimalloc_saved_${_var}) + set(${_var} "${_openms_mimalloc_saved_${_var}}") + unset(_openms_mimalloc_saved_${_var}) + else() + unset(${_var}) + endif() +endforeach() +set_property(GLOBAL PROPERTY OPENMS_MIMALLOC_ACTIVE TRUE) + +## mimalloc.dll is built into CMAKE_RUNTIME_OUTPUT_DIRECTORY next to the TOPP tools, and mimalloc's own +## post-build step copies mimalloc-redirect.dll (x64) there. Installed next to the executables; the license +## goes to LICENSES/vendored/mimalloc (openms_install_vendored_licenses()). +install(FILES $ $/mimalloc-redirect.dll + DESTINATION ${INSTALL_BIN_DIR} COMPONENT library) +message(STATUS "WITH_MIMALLOC: the TOPP tools allocate through mimalloc 3.6.1 (${mimalloc_SOURCE_DIR})") diff --git a/cmake/min_compiler_versions.cmake b/cmake/min_compiler_versions.cmake new file mode 100644 index 000000000..06add630c --- /dev/null +++ b/cmake/min_compiler_versions.cmake @@ -0,0 +1,108 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Chris Bielow $ +# $Authors: Chris Bielow $ +# -------------------------------------------------------------------------- + +#------------------------------------------------------------------------------ +# Single source of truth for the minimum supported compiler versions. +# +# The values below are consumed in two places, so they only ever need to be +# edited here: +# 1. the checks at the bottom of this file, which abort configuration with a +# readable message on an unsupported compiler +# 2. doc/doxygen/Doxyfile.in, which turns them into doxygen ALIASES +# (@minMSVC, @minGCC, ...) so that the install documentation quotes these +# exact numbers instead of hardcoding its own copy +# +# Note that the Windows check is additionally duplicated -- deliberately and +# with a pointer back here -- as an early guard in the top-level CMakeLists.txt +# ahead of project(). See the comment there for why. +#------------------------------------------------------------------------------ + +# --- MSVC --------------------------------------------------------------------- +# Several spellings of the same release, because each consumer needs a different one: +# OPENMS_MIN_MSVC_VERSION - the MSVC_VERSION integer, for the check below +# OPENMS_MIN_MSVC_TOOLSET - the toolset number, as reported by %VCToolsVersion% +# OPENMS_MIN_MSVC_IDE - the VS release, which is what users actually install +# OPENMS_MIN_MSVC_YEAR - the VS product year, as it appears in the product name +# and in the default install path +# OPENMS_MIN_MSVC_GENERATOR - the matching CMake generator name +# +# The binding constraint is Apache Arrow. Toolsets older than +# 14.44 carry a bug in the standard library's formatter for zoned_time +# durations coarser than seconds (LWG-4124, fixed by microsoft/STL#5155), which +# Arrow's std::chrono backend trips over while compiling strftime for Date32. +# The failure surfaces as an unreadable template error inside , hence +# the explicit guard. +set(OPENMS_MIN_MSVC_VERSION 1944) +set(OPENMS_MIN_MSVC_TOOLSET "14.44") +set(OPENMS_MIN_MSVC_IDE "17.14") +set(OPENMS_MIN_MSVC_YEAR "2022") +# The generator name embeds the VS major version (the "17" of 17.14) and the product +# year, so it changes whenever either does. Derived rather than spelled out, so there +# is still only one place to edit. +string(REGEX REPLACE "\\..*$" "" _openms_msvc_major "${OPENMS_MIN_MSVC_IDE}") +set(OPENMS_MIN_MSVC_GENERATOR "Visual Studio ${_openms_msvc_major} ${OPENMS_MIN_MSVC_YEAR}") +unset(_openms_msvc_major) + +# --- GCC / Clang / AppleClang ------------------------------------------------- +# Driven by C++23 feature support. +set(OPENMS_MIN_GCC "13") +set(OPENMS_MIN_CLANG "17") +# AppleClang reports its own version scheme; 16 is what ships with Xcode 16. +set(OPENMS_MIN_APPLECLANG "16") +set(OPENMS_MIN_XCODE "16") + +# --- CMake -------------------------------------------------------------------- +# Not a compiler, but the same "documentation must not drift from the build +# system" problem, and the reason for the sync comment on cmake_minimum_required() +# in the top-level CMakeLists.txt. Read it back from CMake itself rather than +# repeating the number, so it can never disagree. +# +# This is captured at top-level scope, which is also the only scope that declares +# a cmake_minimum_required() -- see the note there on why subdirectories must not +# declare their own. +set(OPENMS_MIN_CMAKE "${CMAKE_MINIMUM_REQUIRED_VERSION}") + +#------------------------------------------------------------------------------ +# Enforcement +#------------------------------------------------------------------------------ +# Test CMAKE_CXX_COMPILER_ID rather than the MSVC variable: MSVC is also true +# for clang-cl, which has its own version scheme and is covered by the Clang +# branch below. +if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + if(MSVC_VERSION LESS OPENMS_MIN_MSVC_VERSION) + message(FATAL_ERROR + "OpenMS requires Visual Studio ${OPENMS_MIN_MSVC_YEAR} version ${OPENMS_MIN_MSVC_IDE} or later " + "(MSVC toolset ${OPENMS_MIN_MSVC_TOOLSET}+, MSVC_VERSION >= ${OPENMS_MIN_MSVC_VERSION}), " + "but found MSVC_VERSION ${MSVC_VERSION} (cl.exe ${CMAKE_CXX_COMPILER_VERSION}).\n" + "\n" + "Please update Visual Studio.") + endif() +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS OPENMS_MIN_GCC) + message(FATAL_ERROR + "OpenMS requires GCC ${OPENMS_MIN_GCC} or later for C++23 support, " + "but found ${CMAKE_CXX_COMPILER_VERSION}.") + endif() +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS OPENMS_MIN_APPLECLANG) + message(FATAL_ERROR + "OpenMS requires Apple Clang ${OPENMS_MIN_APPLECLANG} or later " + "(ships with Xcode ${OPENMS_MIN_XCODE}) for C++23 support, " + "but found ${CMAKE_CXX_COMPILER_VERSION}.") + endif() +elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS OPENMS_MIN_CLANG) + message(FATAL_ERROR + "OpenMS requires Clang ${OPENMS_MIN_CLANG} or later for C++23 support, " + "but found ${CMAKE_CXX_COMPILER_VERSION}.") + endif() +else() + message(STATUS + "Compiler '${CMAKE_CXX_COMPILER_ID}' (${CMAKE_CXX_COMPILER_VERSION}) is not one of the " + "officially supported compilers. No minimum version is enforced; the build may or may not work.") +endif() diff --git a/cmake/multithreading.cmake b/cmake/multithreading.cmake new file mode 100644 index 000000000..1cd85977c --- /dev/null +++ b/cmake/multithreading.cmake @@ -0,0 +1,76 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Timo Sachsenberg $ +# $Authors: Andreas Bertsch, Chris Bielow, Stephan Aiche $ +# -------------------------------------------------------------------------- + +#------------------------------------------------------------------------------ +# OpenMP +#------------------------------------------------------------------------------ +message(STATUS "OpenMP support requested: ${MT_ENABLE_OPENMP}") + +if (MT_ENABLE_OPENMP) + find_package(OpenMP COMPONENTS CXX) + + if (NOT OPENMP_FOUND AND MT_REQUIRE_OPENMP) + # The CI presets require the runtime: the fallback below went unnoticed in CI and + # built the macOS packages single-threaded (#10326). + message(FATAL_ERROR + "OpenMP is required (MT_REQUIRE_OPENMP=ON), but find_package(OpenMP) found no " + "OpenMP runtime. On macOS, install Homebrew's libomp (`brew install libomp`) and " + "reconfigure with -DOpenMP_ROOT=$(brew --prefix libomp). Pass -DMT_REQUIRE_OPENMP=OFF " + "to build without parallel regions instead.") + endif() + + if (NOT OPENMP_FOUND) + # Full OpenMP runtime not found (typical on macOS with stock Apple clang). + # Fall back to -fopenmp-simd, which enables `#pragma omp simd` vectorization + # WITHOUT requiring libgomp/libomp at link time and WITHOUT defining _OPENMP. + # Existing OpenMP::OpenMP_CXX consumers are gated by OPENMP_FOUND, so this + # fallback does not activate any OpenMP-runtime-dependent code path. + # Note: CHECK_CXX_COMPILER_FLAG caches OPENMS_HAS_FOPENMP_SIMD as an + # INTERNAL cache variable (standard CMake behavior). If you upgrade the + # compiler and want the probe to re-run, delete that cache entry or pass + # -UOPENMS_HAS_FOPENMP_SIMD on the next configure. + include(CheckCXXCompilerFlag) + CHECK_CXX_COMPILER_FLAG("-fopenmp-simd" OPENMS_HAS_FOPENMP_SIMD) + if (OPENMS_HAS_FOPENMP_SIMD) + # Plain (non-CACHE) variable on purpose: we want it to reset to undefined + # on every reconfigure, so that if the user later installs libomp and + # find_package(OpenMP) starts succeeding, the fallback flag stops being + # applied. A CACHE INTERNAL value would persist and silently combine with + # full OpenMP on subsequent reconfigures. + set(OPENMS_OMP_SIMD_FALLBACK_FLAG "-fopenmp-simd") + message(STATUS + "Full OpenMP not found; falling back to -fopenmp-simd. " + "#pragma omp simd will vectorize, but #pragma omp parallel will not. " + "On macOS, install Homebrew's libomp (`brew install libomp`) and " + "reconfigure with -DOpenMP_ROOT=$(brew --prefix libomp) for full OpenMP. " + "On Linux this fallback is uncommon (libgomp/libomp ship with GCC and " + "Clang); if it fires here, check that your toolchain installation is " + "complete and that find_package(OpenMP) can locate it.") + else() + message(FATAL_ERROR + "OpenMP was requested (MT_ENABLE_OPENMP=ON) but neither full OpenMP " + "nor the -fopenmp-simd fallback is supported by this compiler. " + "Pass -DMT_ENABLE_OPENMP=OFF to skip OpenMP entirely.") + endif() + endif() +endif() + +if (OPENMP_FOUND) + set(CMAKE_INSTALL_OPENMP_LIBRARIES TRUE) # will install the MSVC OpenMP runtime libraries + + # MSVC requires /openmp:experimental to support #pragma omp simd directives. + # The /openmp:experimental flag is a superset of /openmp, so it replaces + # rather than appends to the standard OpenMP flag. + if (MSVC) + set(OpenMP_CXX_FLAGS "/openmp:experimental") + # Update the imported target to use the experimental flag instead of /openmp + if (TARGET OpenMP::OpenMP_CXX) + set_property(TARGET OpenMP::OpenMP_CXX PROPERTY INTERFACE_COMPILE_OPTIONS "/openmp:experimental") + endif() + endif() +endif() diff --git a/cmake/package_components.cmake b/cmake/package_components.cmake new file mode 100644 index 000000000..3fe9c214e --- /dev/null +++ b/cmake/package_components.cmake @@ -0,0 +1,99 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Julianus Pfeuffer $ +# $Authors: Julianus Pfeuffer $ +# -------------------------------------------------------------------------- + +cpack_add_install_type(recommended DISPLAY_NAME "Recommended") +cpack_add_install_type(full DISPLAY_NAME "Full") +cpack_add_install_type(minimal DISPLAY_NAME "Minimal") + +## TODO group some components like "OpenMS_header", "OpenSWATH_header", "thirdparty_headers"... +## TODO do components more fine-grained, so you can install only OpenSwath parts, or only TOPPView but not TOPPAS, etc +cpack_add_component(share + DISPLAY_NAME "OpenMS shared files" + DESCRIPTION "OpenMS shared files" + INSTALL_TYPES recommended full minimal + ) +cpack_add_component(library + DISPLAY_NAME "Libraries" + DESCRIPTION "The OpenMS core libraries" + INSTALL_TYPES recommended full minimal + ) +## the layers above the core library (see cmake/install_macros.cmake) +cpack_add_component(library_cli + DISPLAY_NAME "TOPP tool framework library" + DESCRIPTION "The TOPP tool framework library (OpenMS_CLI), needed by the TOPP tools" + DEPENDS library + INSTALL_TYPES recommended full minimal + ) +if(WITH_GUI) + cpack_add_component(library_gui + DISPLAY_NAME "GUI library" + DESCRIPTION "The GUI library (OpenMS_GUI), needed by TOPPView, TOPPAS and the other GUI applications" + DEPENDS library_cli + INSTALL_TYPES recommended full minimal + ) +endif() +## Every TOPP tool links the TOPP tool framework, so the binaries do not start +## without the CLI layer; TOPPView, TOPPAS and the other GUI applications need the +## GUI layer on top of it (library_gui DEPENDS library_cli). Selecting the +## binaries without their libraries installs tools that fail at startup with a +## loader error for libOpenMS_CLI. +## The GUI applications have a component of their own, GUIApplications, except in +## the productbuild installer, which keeps them in Applications +## (OPENMS_GUI_APPLICATIONS_COMPONENT in the top-level CMakeLists.txt). +if(WITH_GUI AND OPENMS_GUI_APPLICATIONS_COMPONENT STREQUAL "Applications") + set(_openms_applications_depends library_gui) + set(_openms_applications_description "OpenMS binaries including TOPP tools, TOPPView and TOPPAS.") +else() + set(_openms_applications_depends library_cli) + set(_openms_applications_description "The TOPP tools.") +endif() +## The macOS pkg hands pkgbuild a component plist for the app bundles, which keeps the +## installer from relocating them (cmake/generate_applications_component_plist.cmake). +set(_openms_applications_plist) +if(APPLICATIONS_COMPONENT_PLIST) + set(_openms_applications_plist PLIST "${APPLICATIONS_COMPONENT_PLIST}") +endif() +## Capitalized to match the name install_tool() registers (cmake/install_macros.cmake). +## CPack folds the name to upper case for the CPACK_COMPONENT__* metadata below, +## but compares it verbatim when selecting what to install, so the two must agree. +cpack_add_component(Applications + DISPLAY_NAME "OpenMS binaries" + DESCRIPTION "${_openms_applications_description}" + DEPENDS ${_openms_applications_depends} + INSTALL_TYPES recommended full minimal + ${_openms_applications_plist} + ) +unset(_openms_applications_depends) +unset(_openms_applications_description) +unset(_openms_applications_plist) +if(WITH_GUI AND NOT OPENMS_GUI_APPLICATIONS_COMPONENT STREQUAL "Applications") + cpack_add_component(${OPENMS_GUI_APPLICATIONS_COMPONENT} + DISPLAY_NAME "OpenMS GUI applications" + DESCRIPTION "TOPPView, TOPPAS and the other GUI applications, and the TOPP tools that need the GUI library." + DEPENDS library_gui + INSTALL_TYPES recommended full minimal + ) +endif() +cpack_add_component(doc + DISPLAY_NAME "Documentation" + DESCRIPTION "Class and tool documentation. With tutorials." + INSTALL_TYPES recommended full + ) +cpack_add_component_group(thirdparty + DISPLAY_NAME "Thirdparty binaries" + DESCRIPTION "Binaries and files for thirdparty tools and engines." + EXPANDED + ) +foreach(component IN LISTS ${THIRDPARTY_COMPONENT_GROUP}) + cpack_add_component(${component} + DISPLAY_NAME ${component} + DESCRIPTION "Thirdparty engine ${component}" + GROUP thirdparty + INSTALL_TYPES recommended full + ) +endforeach() diff --git a/cmake/package_deb.cmake b/cmake/package_deb.cmake new file mode 100644 index 000000000..b800a15c9 --- /dev/null +++ b/cmake/package_deb.cmake @@ -0,0 +1,112 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Julianus Pfeuffer $ +# $Authors: Julianus Pfeuffer $ +# -------------------------------------------------------------------------- + + +set(CPACK_DEBIAN_PACKAGE_MAINTAINER "OpenMS Inc ") +if((DEFINED ENV{CPACK_PACKAGE_FILE_NAME}) AND (NOT "$ENV{CPACK_PACKAGE_FILE_NAME}" STREQUAL "")) + set(CPACK_PACKAGE_FILE_NAME "$ENV{CPACK_PACKAGE_FILE_NAME}") +else() + # Use CMAKE_SYSTEM_PROCESSOR to detect actual architecture + set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${OPENMS_PACKAGE_VERSION_FULLSTRING}-Debian-Linux-${CMAKE_SYSTEM_PROCESSOR}") +endif() + +## A package built from anything but a release (a nightly, a branch) carries its +## prerelease identifier in the control version too, after a '~': 3.6.0~nightly.2026.09.27. +## dpkg sorts '~' before everything, even the end of the string, so the package sorts +## below the release 3.6.0 and a later nightly above an earlier one. With the plain +## 3.6.0 of before, apt treated a nightly and the release as the same version. +## Without a Debian revision the version may not contain '-', so every character +## outside [A-Za-z0-9.+~] becomes '.'. +if(OPENMS_PACKAGE_VERSION_PRERELEASE_IDENTIFIER) + string(REGEX REPLACE "[^A-Za-z0-9.+~]" "." _openms_deb_prerelease "${OPENMS_PACKAGE_VERSION_PRERELEASE_IDENTIFIER}") + set(CPACK_DEBIAN_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION}~${_openms_deb_prerelease}") +endif() + +## CPack issues when building the package. +## https://bugs.launchpad.net/ubuntu/+source/cmake/+bug/972419 +## https://ubuntuforums.org/showthread.php?t=2316865 +## Workaround after packaging: https://cmake.org/pipermail/cmake/2012-May/050483.html +set(CPACK_DEBIAN_ARCHIVE_TYPE "gnutar") + +## We usually do not want to ship things like stdlib or glibc. Could mess up a system slighlty, when installed system wide +#include(InstallRequiredSystemLibraries) + +## Some libraries reach the staging tree with empty RUNPATH entries, which the loader +## reads as the current working directory: the release workflow links the binaries +## under PACKAGE_TYPE=none and packages them after reconfiguring (the script explains +## how that leaves them behind). The script removes them before the package is built. +list(APPEND CPACK_PRE_BUILD_SCRIPTS "${CMAKE_CURRENT_LIST_DIR}/cpack_clean_runpath.cmake") + +## dpkg-shlibdeps names the packages of the build host, which in Ubuntu 24.04 carry +## the t64 suffix of the 64-bit time_t transition (libqt6gui6t64). Older releases, and +## also Debian 13 and Ubuntu 25.10 and 26.04, name most Qt libraries without it +## (libqt6gui6). After CPack has written the package, the script adds the old name as an +## alternative wherever the renamed package provides it (libqt6gui6t64 (>= X) | +## libqt6gui6 (>= X)), keeping the version constraint. It has to edit the derived entries: a hand-written +## "t64 | non-t64" entry would be ANDed with the derived plain t64 one. +list(APPEND CPACK_POST_BUILD_SCRIPTS "${CMAKE_CURRENT_LIST_DIR}/cpack_deb_t64_dependencies.cmake") + +## Derive dependencies from the built binaries; a hand-written list goes stale and +## installs on systems the binaries cannot run on. A library the package ships itself +## (SQLite, in lib/) needs no Debian package. Apart from the alternatives the +## post-build script above adds, Depends is what dpkg-shlibdeps derives. +## +## This was on once before (#10202) and had to come off again (#10207), because the +## staging tree carried foreign-architecture binaries: ThermoRawFileParser's NuGet +## runtimes// tree ships a libMono.Unix.so for seven runtime identifiers +## (android-arm, android-arm64, android-x64, android-x86, linux-arm, linux-arm64, +## linux-x64), and on any one host five of the seven are foreign -- see the binary +## list in the failing run 35434550390, where they are the only such files. +## dpkg-shlibdeps answers each with "cannot find library libc.so.6 needed by +## ... (ELF format: ...; abi: ...)", an error --ignore-missing-info does not cover, so +## CPack aborted before writing the package. install_thirdparty_folder() +## (cmake/install_macros.cmake) now installs only the runtime identifiers this build +## targets, so nothing foreign reaches the staging tree. The private libraries the tool +## still cannot resolve (libOpenMS_CLI.so and its siblings) are same-architecture, and +## those come back as warnings rather than errors, so they do not stop it. +set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) + +## Debug for now. Not much output. +set(CPACK_DEBIAN_PACKAGE_DEBUG ON) + +## TODO also install headers? make a dev package configuration? +## The libraries come in layers (cmake/install_macros.cmake): library (core), +## library_cli (TOPP tool framework, needed by the TOPP tools) and library_gui. +## 'Applications' as install_tool() registers it: CPack installs a component by +## name and a mismatch would package none of the TOPP tools. +set(CPACK_COMPONENTS_ALL Applications doc library library_cli share ${THIRDPARTY_COMPONENT_GROUP}) +if(WITH_GUI) + ## the GUI applications (install_tool() in src/openms_gui/CMakeLists.txt) + list(APPEND CPACK_COMPONENTS_ALL library_gui ${OPENMS_GUI_APPLICATIONS_COMPONENT}) +endif() + +SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") +SET(CPACK_DEBIAN_PACKAGE_SECTION "science") +SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "package for LC/MS data management and analysis") +SET(CPACK_PACKAGE_DESCRIPTION " + OpenMS is a package for LC/MS data management and analysis. OpenMS + offers an infrastructure for the development of mass + spectrometry-related software and powerful 2D and 3D visualization + solutions. + . + TOPP (the OpenMS PiPeline) is a pipeline for the analysis + of HPLC/MS data. It consists of a set of numerous small applications + that can be chained together to create analysis pipelines tailored + for a specific problem." + ) + +## Create own target because you cannot "depend" on the internal target 'package' +add_custom_target(dist + COMMAND cpack -G ${CPACK_GENERATOR} + COMMENT "Building ${CPACK_GENERATOR} package" +) + +## TODO make postinstall script that sets OPENMS_DATA_PATH + +# For source packages add build dependencies. Not used and not tested. +#set(CPACK_DEBIAN_PACKAGE_BUILDS_DEPENDS "debhelper (>= 9), dpkg-dev (>= 1.16.1~), cmake (>= 2.6.3), imagemagick, doxygen (>= 1.8.1.2), graphviz, texlive-extra-utils, texlive-latex-extra, latex-xcolor, texlive-font-utils, texlive-fonts-recommended" diff --git a/cmake/package_dragndrop_dmg.cmake b/cmake/package_dragndrop_dmg.cmake new file mode 100644 index 000000000..a04d7cbe7 --- /dev/null +++ b/cmake/package_dragndrop_dmg.cmake @@ -0,0 +1,134 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Julianus Pfeuffer $ +# $Authors: Stephan Aiche, Julianus Pfeuffer $ +# -------------------------------------------------------------------------- + +## Very useful for debugging purposes: Disables the dependency on the "make install" target. +## In our case e.g. "make install" always builds the documentation etc. +#set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY On) +## Or reduce the set of components to package +#set(CPACK_COMPONENTS_ALL Applications Dependencies zzz-fixing-dependencies) + + +## We want to package the whole top-level dir so a user can drag'n'drop it via the image. +set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 0) ## dmg seems to be component-aware and makes an ALL-IN-ONE package +set(CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY 1) ## Therefore _only_ use the second.. weird stuff. + +set(MACOS_TARGET_ARCHS ${CMAKE_OSX_ARCHITECTURES}) +if (NOT MACOS_TARGET_ARCHS) + # Warning: if cmake is a subprocess of a process that is run under Rosetta, it will yield + # x86_64 (but probably also build for it. Therefore it should be fine.) + set(MACOS_TARGET_ARCHS ${CMAKE_HOST_SYSTEM_PROCESSOR}) +endif() +if (MACOS_TARGET_ARCHS STREQUAL "x86_64") + set(ARCH_SUFFIX "Intel") +elseif (MACOS_TARGET_ARCHS STREQUAL "arm64") + set(ARCH_SUFFIX "Silicon") +elseif ("x86_64" IN_LIST MACOS_TARGET_ARCHS AND "arm64" IN_LIST MACOS_TARGET_ARCHS) + set(ARCH_SUFFIX "Universal") +else () + set(ARCH_SUFFIX "Unknown") + message(WARNING "Couldn't determine MACOS_TARGET_ARCHS.") +endif() + +if((DEFINED ENV{CPACK_PACKAGE_FILE_NAME}) AND (NOT "$ENV{CPACK_PACKAGE_FILE_NAME}" STREQUAL "")) + set(CPACK_PACKAGE_FILE_NAME "$ENV{CPACK_PACKAGE_FILE_NAME}") +else() + set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${OPENMS_PACKAGE_VERSION_FULLSTRING}-macOS-${ARCH_SUFFIX}") +endif() + +## Note: That the mac app bundles (TOPPView) take care of themselves +## when installed as dmg (see src/openms_gui/add_mac_bundle.cmake) + +## Fix OpenMS dependencies for all executables in the install directory under bin. +## That affects everything but the bundles (which have their own structure and are fixed up in add_mac_bundle.cmake) +########################################################### Fix Dependencies +install(CODE "execute_process(COMMAND ${PROJECT_SOURCE_DIR}/cmake/MacOSX/fix_dependencies.rb -b \${CMAKE_INSTALL_PREFIX}/${INSTALL_BIN_DIR}/ -l \${CMAKE_INSTALL_PREFIX}/${INSTALL_LIB_DIR}/)" + COMPONENT zzz-fixing-dependencies +) # not applicable as long as we dont use Qt plugins in the TOPP tools: -p \${CMAKE_INSTALL_PREFIX}/${INSTALL_PLUGIN_DIR}) + +if(DEFINED CPACK_BUNDLE_APPLE_CERT_APP) + install(CODE "execute_process(COMMAND ${PROJECT_SOURCE_DIR}/cmake/MacOSX/sign_bins_and_libs.rb -d \${CMAKE_INSTALL_PREFIX}/ -s ${CPACK_BUNDLE_APPLE_CERT_APP})" + COMPONENT zzz-sign-bins-and-libs + ) +endif() + +## Additionally install TOPPShell into root of install folder + +########################################################### TOPPShell +install(FILES ${PROJECT_SOURCE_DIR}/cmake/MacOSX/TOPP-shell.command + DESTINATION . + RENAME "TOPP Shell" + PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE + COMPONENT TOPPShell) + +install(FILES ${PROJECT_SOURCE_DIR}/cmake/MacOSX/TOPP_bash_profile + DESTINATION . + RENAME .TOPP_bash_profile + PERMISSIONS OWNER_WRITE OWNER_READ + GROUP_READ + WORLD_READ + COMPONENT TOPPShell) + +install(FILES ${PROJECT_SOURCE_DIR}/cmake/MacOSX/README.md + DESTINATION . + PERMISSIONS OWNER_WRITE OWNER_READ + GROUP_READ + WORLD_READ + COMPONENT TOPPShell) + +## ---------- +## No need to for this at the moment: no Qt plugins for the general CLI tools required anymore. Left here for reference. +## ---------- +## Install the qt.conf file so we can find the libraries +## add qt.conf to the bin directory for DMGs +#file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/qt.conf" +#"[Paths]\nPlugins = ../${INSTALL_PLUGIN_DIR}/\n") +#install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qt.conf +# DESTINATION ${INSTALL_BIN_DIR} +# PERMISSIONS OWNER_WRITE OWNER_READ +# GROUP_READ +# WORLD_READ +# COMPONENT Dependencies) + + +## Create own target because you cannot "depend" on the internal target 'package' +add_custom_target(dist + COMMAND cpack -G ${CPACK_GENERATOR} + COMMENT "Building ${CPACK_GENERATOR} package" +) + +########################################################### Create dmg with background image +set(OPENMS_DMG_FOLDER_NAME "${CPACK_PACKAGE_NAME}-${OPENMS_PACKAGE_VERSION_FULLSTRING}") ## The name of the OpenMS folder on the DMG +configure_file(${PROJECT_SOURCE_DIR}/cmake/MacOSX/setup_applescript.scpt.in ${PROJECT_BINARY_DIR}/macOS_bundle_setup/setup_applescript.scpt) +set(CPACK_DMG_DS_STORE_SETUP_SCRIPT ${PROJECT_BINARY_DIR}/macOS_bundle_setup/setup_applescript.scpt) +#Next line could overcome a script but since we do not have a fixed name of the OpenMS-$VERSION folder, it probably won't work +#set(CPACK_DMG_DS_STORE ${PROJECT_SOURCE_DIR}/cmake/MacOSX/DS_store_new) +set(CPACK_DMG_BACKGROUND_IMAGE ${PROJECT_SOURCE_DIR}/cmake/MacOSX/background.png) +set(CPACK_DMG_FORMAT UDBZ) ## Try bzip2 to get slightly smaller images + +## Sign the DMG image. CPACK_BUNDLE_APPLE_CERT_APP needs to be unique and found in one of the +## keychains in the search list (which needs to be unlocked). +## Note: The executables/bundles inside should already be signed with hardened runtime and timestamp. +## For notarization, SIGNING_EMAIL must also be set. +if (DEFINED CPACK_BUNDLE_APPLE_CERT_APP AND NOT "${SIGNING_EMAIL}" STREQUAL "") + add_custom_target(signed_dist + COMMAND codesign --deep --force --timestamp --sign ${CPACK_BUNDLE_APPLE_CERT_APP} ${CPACK_PACKAGE_FILE_NAME}.dmg + COMMAND ${OPENMS_HOST_DIRECTORY}/cmake/MacOSX/notarize.sh ${CPACK_PACKAGE_FILE_NAME}.dmg de.openms ${SIGNING_EMAIL} APPLE_APP_SPECIFIC_NOTARIZATION_PASSWORD ${OPENMS_HOST_BINARY_DIRECTORY} + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + COMMENT "Signing and notarizing ${CPACK_PACKAGE_FILE_NAME}.dmg as ${CPACK_BUNDLE_APPLE_CERT_APP}" + DEPENDS dist) +elseif(DEFINED CPACK_BUNDLE_APPLE_CERT_APP) + message(STATUS "SIGNING_EMAIL not set. DMG will be signed but not notarized.") + add_custom_target(signed_dist + COMMAND codesign --deep --force --timestamp --sign ${CPACK_BUNDLE_APPLE_CERT_APP} ${CPACK_PACKAGE_FILE_NAME}.dmg + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + COMMENT "Signing ${CPACK_PACKAGE_FILE_NAME}.dmg as ${CPACK_BUNDLE_APPLE_CERT_APP} (not notarized)" + DEPENDS dist) +endif() + diff --git a/cmake/package_general.cmake b/cmake/package_general.cmake new file mode 100644 index 000000000..0c4546dad --- /dev/null +++ b/cmake/package_general.cmake @@ -0,0 +1,222 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Julianus Pfeuffer $ +# $Authors: Stephan Aiche, Julianus Pfeuffer $ +# -------------------------------------------------------------------------- + + + +# -------------------------------------------------------------------------- +# general definitions used for building OpenMS packages +set(CPACK_PACKAGE_NAME "OpenMS") +set(CPACK_PACKAGE_VENDOR "OpenMS.de") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "OpenMS - A framework for mass spectrometry") +set(CPACK_PACKAGE_VERSION "${OPENMS_PACKAGE_VERSION}") +set(CPACK_PACKAGE_VERSION_MAJOR "${OPENMS_PACKAGE_VERSION_MAJOR}") +set(CPACK_PACKAGE_VERSION_MINOR "${OPENMS_PACKAGE_VERSION_MINOR}") +set(CPACK_PACKAGE_VERSION_PATCH "${OPENMS_PACKAGE_VERSION_PATCH}") +set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}-${OPENMS_PACKAGE_VERSION}") +set(CPACK_PACKAGE_DESCRIPTION_FILE ${PROJECT_SOURCE_DIR}/cmake/OpenMSPackageDescriptionFile.txt) +set(CPACK_RESOURCE_FILE_LICENSE ${PROJECT_SOURCE_DIR}/License.txt) +set(CPACK_RESOURCE_FILE_WELCOME ${PROJECT_SOURCE_DIR}/cmake/OpenMSPackageResourceWelcomeFile.txt) +set(CPACK_RESOURCE_FILE_README ${PROJECT_SOURCE_DIR}/cmake/OpenMSPackageResourceReadme.txt) +set(CPACK_STRIP_FILES TRUE) # to save some space in the installers + +set(OPENMS_LOGO_NAME openms_logo_large_transparent.png) ## The filename of the logo to be used for the OpenMS folder e.g. on the DMG +set(OPENMS_LOGO ${PROJECT_SOURCE_DIR}/cmake/MacOSX/${OPENMS_LOGO_NAME}) ## The logo to be used for the OpenMS folder e.g. on the DMG + +set(OPENMS_LOGOSMALL_NAME openms_logo_corner_small.png) ## The filename of the logo to be used for the OpenMS folder e.g. on the PKG +set(OPENMS_LOGOSMALL ${PROJECT_SOURCE_DIR}/cmake/MacOSX/${OPENMS_LOGOSMALL_NAME}) ## The logo to be used for the OpenMS folder e.g. on the PKG + +########################################################### Fixing dynamic dependencies +## Qt Plugins needed for the CL tools should have been installed before (such as QSqliteDriverPlugin) +## This currently works because our libs and TOPP tools include all dependencies. For macOS, +## the app bundles need to have a different RUNTIME_DEPENDENCY_SET (TOPPView_DEPS, ...) due +## to CMake assuming you want standalone bundles. But we want to share libs between them. + +# Add CMAKE_PREFIX_PATH directories to search for runtime dependencies. +# We need this because TARGET_RUNTIME_DLLS (used during build stage copy) has limitations: +# - Incomplete CMake configs from third-party libraries that don't properly export targets +# - Private shared library dependencies not tracked in the dependency graph +# - Manual find_library() results without imported targets +# By adding these paths, we ensure all dependencies are found during installation even if +# they were missed during the build-time copy step. +list(TRANSFORM CMAKE_PREFIX_PATH APPEND "/bin" OUTPUT_VARIABLE DEP_BIN_DIRS) +list(TRANSFORM CMAKE_PREFIX_PATH APPEND "/lib" OUTPUT_VARIABLE DEP_LIB_DIRS) + +# Also include our own runtime directory where dependencies were copied during build. +# This serves as the primary source, with CMAKE_PREFIX_PATH directories as fallback. +list(APPEND DEP_BIN_DIRS $) + +# Combine all search directories for comprehensive dependency resolution +set(RUNTIME_DEP_SEARCH_DIRS ${DEP_BIN_DIRS} ${DEP_LIB_DIRS}) + +# Ensure Arrow/Parquet shared libs are discoverable during install() dependency collection. +# This feeds RUNTIME_DEP_SEARCH_DIRS so install(RUNTIME_DEPENDENCY_SET ...) can locate Arrow libs +# that are not always in the main build tree. It is required for packaging (CPack installers and +# pyOpenMS wheels) to bundle Arrow runtime deps like libarrow_compute/libarrow_dataset, which are +# loaded by OpenMS/pyOpenMS at runtime. Without these search paths, the install step can miss those +# shared libs and the resulting binaries/wheels fail to link or import on user machines. +foreach(_arrow_dep IN ITEMS OPENMS_ARROW_TARGET OPENMS_ARROW_COMPUTE_TARGET OPENMS_PARQUET_TARGET OPENMS_ARROW_DATASET_TARGET) + if(DEFINED ${_arrow_dep} AND NOT "${${_arrow_dep}}" STREQUAL "") + if(TARGET ${${_arrow_dep}}) + list(APPEND RUNTIME_DEP_SEARCH_DIRS $) + else() + get_filename_component(_arrow_dep_dir "${${_arrow_dep}}" DIRECTORY) + if(_arrow_dep_dir) + list(APPEND RUNTIME_DEP_SEARCH_DIRS "${_arrow_dep_dir}") + endif() + endif() + endif() +endforeach() + + +## Info on excluding dependencies: +# PRE_EXCLUDE_REGEXES: Excludes dependencies at the beginning of the dependency analysis. +# This means that any dependency matching these patterns will be excluded before +# CMake traverses its own dependencies. This can prevent CMake from spending +# time analyzing entire dependency chains that you know you want to exclude. +# POST_EXCLUDE_REGEXES: Excludes dependencies after the complete dependency analysis is done. +# This is applied to the final list of all found dependencies. + +# On Windows we need to tell CMake where to look for. +# We also do not need API sets. So exclude them. + + +if(WIN32) + # exclude dll's which are system dll's and should not be shipped (bloats installer and leads to incompatibilities) + set(PRE_EXCLUDE + ## these two are direct systems deps of TOPPView etc. Exclude to save time + "api-ms" "ext-ms" + ## "HvsiFileTrust" "PdmUtilities" are detected as a dependency by CMake which cannot be resolved (and would lead to errors), so ignore it + "hvsi" "pdmutilities" ## make all lower case, since this is what CMake extracts from the targets and the regex is case sensitive + ## MSVC runtime DLLs are handled separately by InstallRequiredSystemLibraries (in package_nsis.cmake). + ## Exclude them here to avoid "Multiple conflicting paths" errors when the same DLL + ## exists in multiple search directories (e.g. a Conda env and another prefix's bin/). CMake 4.x + ## treats such conflicts as fatal errors. + "vcruntime" "msvcp" "concrt" "vccorlib" "ucrtbase" + ) + ## exclude every Dll from c:\Windows\System32 + ## Note: CMake extracts Dll names and will have a list like + ##-- Resolved runtime dependencies: + ##-- C:/WINDOWS/system32/aclui.dll + ##-- C:/WINDOWS/system32/activeds.dll + ## ,i.e. folder names have weird cases (and the CMake regex engine is case sensitive) + set(POST_EXCLUDE ".*[\\/][Ss][Yy][Ss][Tt][Ee][Mm]32[\\/].*") # skip system32 DLLs completely (no matter how CMake names the path, could be 'System32', 'system32', 'SYSTEM32' etc) +elseif(APPLE) + set(PRE_EXCLUDE "/usr/lib" "/System/") + set(POST_EXCLUDE "") +else() + set(PRE_EXCLUDE "") + set(POST_EXCLUDE ".*/ld-linux-.*" ".*/linux-vdso.*" ".*/libm\\..*" ".*/libc\\..*" ".*/libpthread\\..*" ".*/libdl\\..*" ".*/libstdc\\+\\+\\..*" ".*/libgcc_s.*" ".*/libgomp\\..*" ".*/libQt6.*") +endif() + +## The bundled libraries are writable by their owner only (0755), like any installed +## library. With GROUP_WRITE and WORLD_WRITE they were world-writable: the DEB's in +## /usr/lib, where any local user could replace code that the OpenMS tools load, also when +## root runs them, and the files of the Qt frameworks in the macOS package. The packaging +## steps that modify the staged libraries (code signing on macOS, the RUNPATH clean-up of +## the DEB) run as their owner. +install(RUNTIME_DEPENDENCY_SET OPENMS_DEPS + DESTINATION ${INSTALL_LIB_DIR} + PERMISSIONS + OWNER_READ OWNER_WRITE OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE + COMPONENT Dependencies + PRE_EXCLUDE_REGEXES ${PRE_EXCLUDE} + POST_EXCLUDE_REGEXES ${POST_EXCLUDE} + DIRECTORIES ${RUNTIME_DEP_SEARCH_DIRS}) + +#install(RUNTIME_DEPENDENCY_SET TOPPView_DEPS) # I think without giving DESTINATION and COMPONENT it will be inferred +#install(RUNTIME_DEPENDENCY_SET TOPPAS_DEPS) +#... + +########################################################### OpenMP runtime (macOS) +## Apple's Clang ships no OpenMP runtime, so the build takes libomp from Homebrew +## (tools/ci/deps-macos.sh; keg-only, found through OpenMP_ROOT). The runtime dependency +## set above bundles libomp.dylib. Its omp.h goes next to the OpenMS headers, some of which +## include it: OpenMSConfig.cmake points FindOpenMP of a consuming project at that header +## and the bundled library, so that a program built against the package or the SDK loads +## the bundled runtime only. Two OpenMP runtimes in one process abort ("OMP: Error #15"). +set(_openms_omp_libraries "") +if(APPLE AND OPENMP_FOUND) + set(_openms_omp_libraries ${OpenMP_CXX_LIBRARIES}) + foreach(_openms_omp_include_dir IN LISTS OpenMP_CXX_INCLUDE_DIRS) + if(EXISTS "${_openms_omp_include_dir}/omp.h") + install(FILES "${_openms_omp_include_dir}/omp.h" + DESTINATION ${INSTALL_INCLUDE_DIR} + COMPONENT thirdparty_headers) + break() + endif() + endforeach() +endif() + +########################################################### Third-party licenses +## The license texts of what only the packages bundle: Qt and, on macOS, the Homebrew +## formulae (cmake/third_party_licenses.cmake). Those of the vcpkg ports are installed for +## every installation (CMakeLists.txt). The DEB depends on the distribution's Qt (libQt6 is +## excluded above); the Windows and macOS packages bundle theirs. +set(_openms_bundled_qt_version "") +## On macOS Qt and libomp come from Homebrew (tools/ci/deps-macos.sh): the formulae of Qt are +## the kegs that hold its CMake packages, that of libomp the keg that holds the library. +set(_openms_homebrew_paths ${_openms_omp_libraries}) +if(WITH_GUI AND Qt6Core_FOUND AND (WIN32 OR APPLE)) + set(_openms_bundled_qt_version "${Qt6Core_VERSION}") + if(APPLE) + foreach(_openms_qt_component IN ITEMS Core ${OpenMS_GUI_QT_COMPONENTS}) + list(APPEND _openms_homebrew_paths "${Qt6${_openms_qt_component}_DIR}") + endforeach() + endif() +endif() +set(_openms_homebrew_formulae "") +set(_openms_homebrew_prefix "") +if(APPLE) + openms_homebrew_formulae_of(_openms_homebrew_formulae _openms_homebrew_prefix ${_openms_homebrew_paths}) +endif() +openms_install_third_party_licenses(QT_VERSION "${_openms_bundled_qt_version}" + HOMEBREW_PREFIX "${_openms_homebrew_prefix}" + HOMEBREW_FORMULAE ${_openms_homebrew_formulae}) +## On Linux, the runtime dependency set also bundles the libraries of the build machine that +## vcpkg's libraries need and the exclusions above keep (currently none: libgfortran, which +## the LAPACK of the removed COIN-OR solver needed, was the only one). Their licenses come +## from the Debian packages that installed them, so only the DEB does this. +if("${PACKAGE_TYPE}" STREQUAL "deb" + AND OPENMS_USE_VCPKG AND VCPKG_INSTALLED_DIR AND VCPKG_TARGET_TRIPLET) + file(GLOB _openms_vcpkg_shared_libraries LIST_DIRECTORIES false + "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib/*.so" + "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib/*.so.*") + openms_install_system_library_licenses(ROOTS ${_openms_vcpkg_shared_libraries} + EXCLUDE_REGEXES ${POST_EXCLUDE}) +endif() + +########################################################### SEARCHENGINES +set(THIRDPARTY_COMPONENT_GROUP) +## populates the THIRDPARTY_COMPONENT_GROUP list +if(EXISTS ${SEARCH_ENGINES_DIRECTORY}) + ## Automatically recurse over all subfolders in SEARCH_ENGINES_DIRECTORY + file(GLOB THIRDPARTY_SUBDIRS RELATIVE ${SEARCH_ENGINES_DIRECTORY} ${SEARCH_ENGINES_DIRECTORY}/*) + foreach(SUBDIR ${THIRDPARTY_SUBDIRS}) + ## Not shipped, although THIRDPARTY has them: + ## - ProteoWizard (pwiz-bin, Windows only). OpenMS does not use it, and it carries the + ## libraries of several instrument vendors, each under its own license terms. Users get + ## msconvert from ProteoWizard itself. + ## - X!Tandem (XTandem). No OpenMS tool runs it since XTandemAdapter was removed in 3.4.0, + ## and its Linux build embeds expat 2.0.1, which Critical CVEs affect. + if(SUBDIR STREQUAL "pwiz-bin" OR SUBDIR STREQUAL "XTandem") + continue() + endif() + if(IS_DIRECTORY ${SEARCH_ENGINES_DIRECTORY}/${SUBDIR}) + install_thirdparty_folder("${SUBDIR}") + ## The license and notice files the tool ships with, for THIRD-PARTY-NOTICES.txt. + openms_third_party_notice_files_of_tool(_openms_tool_notices + "${SEARCH_ENGINES_DIRECTORY}/${SUBDIR}") + foreach(_openms_tool_notice IN LISTS _openms_tool_notices) + openms_add_third_party_notice("THIRDPARTY/${SUBDIR}/${_openms_tool_notice}" + "${SEARCH_ENGINES_DIRECTORY}/${SUBDIR}/${_openms_tool_notice}") + endforeach() + endif() + endforeach() +endif() diff --git a/cmake/package_mac_productbuild.cmake b/cmake/package_mac_productbuild.cmake new file mode 100644 index 000000000..cc4e2ff0e --- /dev/null +++ b/cmake/package_mac_productbuild.cmake @@ -0,0 +1,185 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Julianus Pfeuffer $ +# $Authors: Julianus Pfeuffer $ +# -------------------------------------------------------------------------- + + +## Very useful for debugging purposes: Disables the dependency on the "make install" target. +## In our case e.g. "make install" always builds the documentation etc. +#set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY On) + +# For info about this CPack generator and its capabilities, see the CMake documentation +# For info about productbuild and the flat package format see https://matthew-brett.github.io/docosx/flat_packages.html + +# Set the install prefix before generating the plist (needed for RootRelativeBundlePath) +set(CPACK_PACKAGING_INSTALL_PREFIX "/Applications/${CPACK_PACKAGE_NAME}-${OPENMS_PACKAGE_VERSION_FULLSTRING}") + +# Generate ApplicationsComponent.plist for CPack component +# Variable APPLICATIONS_COMPONENT_PLIST is set by the included script and visible +# to package_components.cmake since both are include()'d from the top-level CMakeLists.txt. +include(${PROJECT_SOURCE_DIR}/cmake/generate_applications_component_plist.cmake) +set(CPACK_PRODUCTBUILD_IDENTIFIER "de.openms") +set(CPACK_PRODUCTBUILD_RESOURCES_DIR ${PROJECT_SOURCE_DIR}/cmake/MacOSX) +set(CPACK_PRODUCTBUILD_BACKGROUND ${OPENMS_LOGOSMALL_NAME}) +set(CPACK_PRODUCTBUILD_BACKGROUND_ALIGNMENT "bottomleft") +set(CPACK_PRODUCTBUILD_BACKGROUND_SCALING "none") + +# Allow installing to every Domain (https://gitlab.kitware.com/cmake/cmake/-/merge_requests/6825). +set(CPACK_PRODUCTBUILD_DOMAINS TRUE) # system-wide +set(CPACK_PRODUCTBUILD_DOMAINS_USER TRUE) # user folder + +# The installer refuses a macOS older than the deployment target, which package builds set +# through MACOSX_DEPLOYMENT_TARGET (.github/actions/build/action.yml). The Distribution file +# comes from cmake/Modules/CPack.distribution.dist.in: CPack looks for that template in +# CMAKE_MODULE_PATH before its own, and ours is CMake's plus a , the only +# parent Apple's Distribution XML reference allows for ; its script +# attribute is required. Setting CPACK_APPLE_PKG_INSTALLER_CONTENT instead does not work: +# CPack generates that variable. +# TODO the template could also declare hostArchitectures, which CMake does not support +# (https://gitlab.kitware.com/cmake/cmake/-/issues/21734). +# Single quotes: CPack copies CPACK_* values into CPackConfig.cmake without escaping them. +if(CMAKE_OSX_DEPLOYMENT_TARGET) + set(CPACK_OPENMS_ALLOWED_OS_VERSIONS + "") +else() + set(CPACK_OPENMS_ALLOWED_OS_VERSIONS "") + message(WARNING "CMAKE_OSX_DEPLOYMENT_TARGET is not set, so the installer will not check the macOS version. Set MACOSX_DEPLOYMENT_TARGET to the macOS the build and its bundled libraries target.") +endif() + +if(NOT DEFINED CPACK_PRODUCTBUILD_IDENTITY_NAME) + message(WARNING "CPACK_PRODUCTBUILD_IDENTITY_NAME not set. PKG will not be signed. Make sure to specify an identity with a Developer ID: Installer certificate (not Application certificate).") +endif() + +set(MACOS_TARGET_ARCHS ${CMAKE_OSX_ARCHITECTURES}) +if (NOT MACOS_TARGET_ARCHS) + # Warning: if cmake is a subprocess of a process that is run under Rosetta, it will yield + # x86_64 (but probably also build for it. Therefore it should be fine.) + set(MACOS_TARGET_ARCHS ${CMAKE_HOST_SYSTEM_PROCESSOR}) +endif() +if (MACOS_TARGET_ARCHS STREQUAL "x86_64") + set(ARCH_SUFFIX "Intel") +elseif (MACOS_TARGET_ARCHS STREQUAL "arm64") + set(ARCH_SUFFIX "Silicon") +elseif ("x86_64" IN_LIST MACOS_TARGET_ARCHS AND "arm64" IN_LIST MACOS_TARGET_ARCHS) + set(ARCH_SUFFIX "Universal") +else () + set(ARCH_SUFFIX "Unknown") + message(WARNING "Couldn't determine MACOS_TARGET_ARCHS.") +endif() + +if((DEFINED ENV{CPACK_PACKAGE_FILE_NAME}) AND (NOT "$ENV{CPACK_PACKAGE_FILE_NAME}" STREQUAL "")) + set(CPACK_PACKAGE_FILE_NAME "$ENV{CPACK_PACKAGE_FILE_NAME}") +else() + set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${OPENMS_PACKAGE_VERSION_FULLSTRING}-macOS-${ARCH_SUFFIX}") +endif() + +## Additionally install TOPPShell into root of install folder +########################################################### TOPPShell +install(FILES ${PROJECT_SOURCE_DIR}/cmake/MacOSX/TOPP-shell.command + DESTINATION . + RENAME "TOPP Shell" + PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE + COMPONENT TOPPShell) + +install(FILES ${PROJECT_SOURCE_DIR}/cmake/MacOSX/TOPP_bash_profile + DESTINATION . + RENAME .TOPP_bash_profile + PERMISSIONS OWNER_WRITE OWNER_READ + GROUP_READ + WORLD_READ + COMPONENT TOPPShell) + +install(FILES ${PROJECT_SOURCE_DIR}/cmake/MacOSX/README.md + DESTINATION . + PERMISSIONS OWNER_WRITE OWNER_READ + GROUP_READ + WORLD_READ + COMPONENT TOPPShell) + +## bin/qt.conf, which ExecutePipeline needs to find the Qt platform plugin, is installed in +## src/openms_gui/CMakeLists.txt. + +## Fix OpenMS dependencies for all executables in the install directory under bin. +## That affects everything but the bundles (whose Framework folders are symlinked to lib anyway). +########################################################### Fix Dependencies +# Use --no-copy and assume CMake correctly collected all necessary libs already (therefore only fix links to dylibs) +install(CODE "execute_process(COMMAND ${OPENMS_HOST_DIRECTORY}/cmake/MacOSX/fix_dependencies.rb -b \${CMAKE_INSTALL_PREFIX}/../../../Applications${CPACK_PACKAGING_INSTALL_PREFIX}/${INSTALL_BIN_DIR}/ -l \${CMAKE_INSTALL_PREFIX}/${INSTALL_LIB_DIR}/ -p \${CMAKE_INSTALL_PREFIX}/${INSTALL_PLUGIN_DIR} -e @rpath/ -n -c)" + COMPONENT Dependencies + ) +# We have to do signing after fixing, otherwise signature will be invalidated. +# We have to choose COMPONENT Dependencies, otherwise it would be performed at the end of installing Applications, which +# comes first (alphabetically per component, then order of install calls) +# If the install CODE is not in the same component though, we need to navigate from the component specific install +# prefix to the other prefix. This is unfortunately very unrobust. +# TODO find better order or rewrite fix_dependencies script to be called separately +install(CODE " + execute_process(COMMAND find \${CMAKE_INSTALL_PREFIX}/../../../Applications${CPACK_PACKAGING_INSTALL_PREFIX}/${INSTALL_BIN_DIR}/ -type f -execdir codesign --force --options runtime --timestamp -i de.openms.TOPP.{} --sign \"${CPACK_BUNDLE_APPLE_CERT_APP}\" {} \\; OUTPUT_VARIABLE topp_sign_out ERROR_VARIABLE topp_sign_out) + execute_process(COMMAND find \${CMAKE_INSTALL_PREFIX}/${INSTALL_LIB_DIR}/ -type f -execdir codesign --force --options runtime --timestamp -i de.openms.TOPP.libs.{} --sign \"${CPACK_BUNDLE_APPLE_CERT_APP}\" {} \\; OUTPUT_VARIABLE topp_sign_out ERROR_VARIABLE topp_sign_out) + message('\${topp_sign_out}')" + COMPONENT Dependencies + ) +## The libraries come in layered components (cmake/install_macros.cmake): +## library, library_cli and library_gui. productbuild stages each component in +## its own prefix, so each one fixes and signs the libraries it holds. +set(_openms_library_components library library_cli) +if(WITH_GUI) + list(APPEND _openms_library_components library_gui) +endif() +foreach(_library_component IN LISTS _openms_library_components) + install(CODE "execute_process(COMMAND ${OPENMS_HOST_DIRECTORY}/cmake/MacOSX/fix_dependencies.rb -l \${CMAKE_INSTALL_PREFIX}/${INSTALL_LIB_DIR}/ -e @rpath/ -n -c)" + COMPONENT ${_library_component} + ) + install(CODE " + execute_process(COMMAND find \${CMAKE_INSTALL_PREFIX}/${INSTALL_LIB_DIR}/ -type f -execdir codesign --force --options runtime --timestamp -i de.openms.TOPP.libs.{} --sign \"${CPACK_BUNDLE_APPLE_CERT_APP}\" {} \\; OUTPUT_VARIABLE lib_sign_out ERROR_VARIABLE lib_sign_out) + message('\${lib_sign_out}')" + COMPONENT ${_library_component} + ) +endforeach() +unset(_openms_library_components) + +## Sign thirdparty components +foreach(component IN LISTS THIRDPARTY_COMPONENT_GROUP) + install(CODE " + if(EXISTS \${CMAKE_INSTALL_PREFIX}/${INSTALL_SHARE_DIR}/THIRDPARTY/${component}/) + execute_process(COMMAND find \${CMAKE_INSTALL_PREFIX}/${INSTALL_SHARE_DIR}/THIRDPARTY/${component}/ -type f -execdir codesign --force --options runtime --timestamp -i de.openms.thirdparty.${component}.{} --sign \"${CPACK_BUNDLE_APPLE_CERT_APP}\" {} \\; OUTPUT_VARIABLE thirdparty_sign_out ERROR_VARIABLE thirdparty_sign_out) + message('\${thirdparty_sign_out}') + endif()" + COMPONENT ${component} + ) +endforeach() + +## When Applications are installed (which is the FIRST in alphabetical order AND the main component), +## a postinstall script runs to set file icon +install(FILES ${PROJECT_SOURCE_DIR}/cmake/MacOSX/openms_logo_large_transparent.png + DESTINATION . + COMPONENT Applications) +configure_file(${OPENMS_HOST_DIRECTORY}/cmake/MacOSX/setIcon.sh.in ${OPENMS_HOST_BINARY_DIRECTORY}/cmake/MacOSX/setIcon.sh) +set(CPACK_POSTFLIGHT_APPLICATIONS_SCRIPT ${OPENMS_HOST_BINARY_DIRECTORY}/cmake/MacOSX/setIcon.sh) + +## The pyopenms Python extension modules (COMPONENT python_modules, see +## src/pyOpenMS/CMakeLists.txt) are not meant to be bundled into the desktop +## application installer - they are shipped separately as Python wheels (see +## .github/workflows/pyopenms-wheels-cibuildwheel.yml). productbuild packages +## every known component into its own sub-pkg by default, and since these were +## never signed, notarization rejected the whole installer. Exclude them here +## instead of signing them, so they no longer get packaged at all. This must +## run after all install(... COMPONENT ...) calls in the project have been +## processed, so it picks up every real component. +get_cmake_property(CPACK_COMPONENTS_ALL COMPONENTS) +list(REMOVE_ITEM CPACK_COMPONENTS_ALL python_modules) +## Drop the class-test framework archive and its headers (dev tool, not product +## payload). Both install rules are EXCLUDE_FROM_ALL, but productbuild enumerates +## components explicitly and installs each one by name, which ignores that flag. +list(REMOVE_ITEM CPACK_COMPONENTS_ALL OpenMSTestFramework OpenMSTestFramework_headers) + +## Create own target because you cannot "depend" on the internal target 'package' +add_custom_target(dist + COMMAND cpack -G ${CPACK_GENERATOR} + COMMENT "Building ${CPACK_GENERATOR} package" +) + diff --git a/cmake/package_nsis.cmake b/cmake/package_nsis.cmake new file mode 100644 index 000000000..4e8cb79dd --- /dev/null +++ b/cmake/package_nsis.cmake @@ -0,0 +1,128 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Julianus Pfeuffer $ +# $Authors: Julianus Pfeuffer, Chris Bielow $ +# -------------------------------------------------------------------------- + + +## Windows installer + +# Check if nsis is actually run or if only the configuration is used +if("${CPACK_GENERATOR}" STREQUAL "NSIS") + find_program(MAKENSIS_EXE makensis) + + if (NOT MAKENSIS_EXE) + MESSAGE(FATAL_ERROR "Could not find 'makensis.exe'. Please make sure it's in $PATH!") + endif() + + ## check for correct NSIS version + execute_process(COMMAND ${MAKENSIS_EXE} /HDRINFO + OUTPUT_VARIABLE NSIS_INFO + COMMAND_ERROR_IS_FATAL ANY) + STRING(FIND ${NSIS_INFO} "Size of each section is 16408 bytes" NSIS_IS_8K) ## the 1k version gives "2072 bytes" + + if (NSIS_IS_8K EQUAL -1) + MESSAGE(FATAL_ERROR "NSIS (makensis.exe) needs to be the 'special build', which allows for 8k-length strings. This seems to be the 1k version. Please update NSIS. See https://github.com/OpenMS/NSIS") + else() + MESSAGE(STATUS "Found 8k version of NSIS. Great!") + endif() +endif() + + +## With VS2019 the architecture HAS TO BE specified with the "–A" option or CMAKE_GENERATOR_PLATFORM var. +## Therefore the legacy way of adding a suffix to the Generator is not valid anymore. +## Read value of CMAKE_VS_PLATFORM_NAME instead +if (CMAKE_VS_PLATFORM_NAME MATCHES ".*Win32.*" OR CMAKE_GENERATOR MATCHES ".*Win32.*") + set(PLATFORM "32") + set(ARCH "x86") +else() + set(PLATFORM "64") + set(ARCH "x64") +endif() + + +#### Install System runtime libraries into /bin, so NSIS picks them up; this saves us from shipping a VC-Redist.exe with the installer +set(CMAKE_INSTALL_OPENMP_LIBRARIES TRUE) +set (CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION ${INSTALL_LIB_DIR}) +include(InstallRequiredSystemLibraries) + + +## All NSIS.template.in settings that used to live in a separately !include'd +## Cfg_Settings.nsh are now defined directly in NSIS.template.in via CPack's own +## @CPACK_...@ template substitution (the same proven mechanism already used +## elsewhere in that file for e.g. @CPACK_TOPLEVEL_DIRECTORY@, @CPACK_PACKAGE_ICON@- +## derived paths, and the license page path -- all of which are absolute paths on +## the build tree's own drive and substitute reliably). +## +## Cfg_Settings.nsh was previously generated in two stages: an @ONLY configure_file() +## into a ".in.conf" file, then a second configure_file() deferred into an +## install(CODE ...) block (to substitute a PACKAGING_DIR only known once CPack +## starts staging files), and finally !include'd by NSIS.template.in via an +## absolute path. That worked right up until CPack actually ran makensis: CPack's +## own --debug trace confirmed the file existed, correctly populated, right up to +## (and including) the "if exist" check made microseconds before invoking cpack -- +## yet NSIS's !include, running a fraction of a second later inside that same cpack +## invocation, reported it missing, with nothing in CPack's own instrumented file +## operations ever touching it. Whatever removes it, it is specific to a *separate* +## file surviving from CMake-configure-time through to NSIS-compile-time; values +## substituted directly into project.nsi by CPack's own template engine (as done +## here) never depend on any such file existing on disk at packaging time at all. +## +## Only CPACK_-prefixed variables are persisted into CPackConfig.cmake and thus +## visible to CPack's template substitution at packaging time. +set(CPACK_OPENMS_PROJECT_SOURCE_DIR "${PROJECT_SOURCE_DIR}") +set(CPACK_OPENMS_VERSION "${OPENMS_PACKAGE_VERSION_FULLSTRING}") +set(CPACK_OPENMS_PLATFORM "${PLATFORM}") +set(CPACK_OPENMS_INSTALL_BIN_DIR "${INSTALL_BIN_DIR}") +set(CPACK_OPENMS_INSTALL_LIB_DIR "${INSTALL_LIB_DIR}") +set(CPACK_OPENMS_INSTALL_SHARE_DIR "${INSTALL_SHARE_DIR}") +set(CPACK_OPENMS_INSTALL_PLUGIN_DIR "${INSTALL_PLUGIN_DIR}") +set(CPACK_OPENMS_INSTALL_DOC_DIR "${INSTALL_DOC_DIR}") + +## Remove the next three lines if you use the NSIS autogeneration feature at some point! +## For now it makes sure everything is merged into the usual folders bin/share/include +set(CPACK_COMPONENT_ALL_IN_ONE 1) +set(CPACK_COMPONENTS_ALL_GROUPS_IN_ONE_PACKAGE 1) +set(CPACK_MONOLITHIC_INSTALL 1) +## + +if((DEFINED ENV{CPACK_PACKAGE_FILE_NAME}) AND (NOT "$ENV{CPACK_PACKAGE_FILE_NAME}" STREQUAL "")) + set(CPACK_PACKAGE_FILE_NAME "$ENV{CPACK_PACKAGE_FILE_NAME}") +else() + set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${OPENMS_PACKAGE_VERSION_FULLSTRING}-Win${PLATFORM}") +endif() +set(CPACK_PACKAGE_ICON "${PROJECT_SOURCE_DIR}/cmake/Windows/OpenMS.ico") + +## Create own target because you cannot "depend" on the internal target 'package' +add_custom_target(dist + COMMAND cpack -G ${CPACK_GENERATOR} + COMMENT "Building ${CPACK_GENERATOR} package" +) + +## TODO maybe find signtool and maybe check existence of ID in the beginning. +## ID needs to be installed beforehand. Rightclick a p12 file that has a cert for codesigning. +if (DEFINED SIGNING_IDENTITY AND NOT "${SIGNING_IDENTITY}" STREQUAL "") + add_custom_target(signed_dist + COMMAND signtool sign /v /n "${SIGNING_IDENTITY}" /t http://timestamp.digicert.com ${CPACK_PACKAGE_FILE_NAME}.exe + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + COMMENT "Signing ${CPACK_PACKAGE_FILE_NAME}.exe with '${SIGNING_IDENTITY}'" + DEPENDS dist + ) +endif() + +## For now we fully rely only on our NSIS template. Later we could use +## the following to let CMake generate snippets for the NSIS script +## Plus an additional entry in the nsis template (see CPack-NSIS docu) + +# set(CPACK_NSIS_MUI_ICON "${PROJECT_SOURCE_DIR}/cmake/Windows/OpenMS.ico") +# set(CPACK_NSIS_MUI_UNIICON "${PROJECT_SOURCE_DIR}/cmake/Windows/OpenMS.ico") +# set(CPACK_NSIS_HELP_LINK "https://www.openms.de/getting-started") +# set(CPACK_NSIS_URL_INFO_ABOUT "https://www.openms.de") +# set(CPACK_NSIS_CONTACT "open-ms-general@lists.sourceforge.net") +# set(CPACK_NSIS_MENU_LINKS +# "https://www.openms.de" "OpenMS Web Site") + + + diff --git a/cmake/package_rpm.cmake b/cmake/package_rpm.cmake new file mode 100644 index 000000000..9c7295494 --- /dev/null +++ b/cmake/package_rpm.cmake @@ -0,0 +1,56 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Julianus Pfeuffer $ +# $Authors: Julianus Pfeuffer $ +# -------------------------------------------------------------------------- + + + +set(CPACK_RPM_PACKAGE_VENDOR "OpenMS Inc ") +if((DEFINED ENV{CPACK_PACKAGE_FILE_NAME}) AND (NOT "$ENV{CPACK_PACKAGE_FILE_NAME}" STREQUAL "")) + set(CPACK_PACKAGE_FILE_NAME "$ENV{CPACK_PACKAGE_FILE_NAME}") +else() + # Use CMAKE_SYSTEM_PROCESSOR to detect actual architecture + set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${OPENMS_PACKAGE_VERSION_FULLSTRING}-RedHat-Linux-${CMAKE_SYSTEM_PROCESSOR}") +endif() + +## Debug for now. +set(CPACK_RPM_PACKAGE_DEBUG ON) + +## TODO also install headers? make a dev package configuration? +## The libraries come in layers (cmake/install_macros.cmake): library (core), +## library_cli (TOPP tool framework, needed by the TOPP tools) and library_gui. +## 'Applications' as install_tool() registers it: CPack installs a component by +## name and a mismatch would package none of the TOPP tools. +set(CPACK_COMPONENTS_ALL Applications doc library library_cli share ${THIRDPARTY_COMPONENT_GROUP}) +if(WITH_GUI) + ## the GUI applications (install_tool() in src/openms_gui/CMakeLists.txt) + list(APPEND CPACK_COMPONENTS_ALL library_gui ${OPENMS_GUI_APPLICATIONS_COMPONENT}) +endif() + +SET(CPACK_RPM_PACKAGE_LICENSE "BSD clause 3") +#SET(CPACK_RPM_PACKAGE_AUTOREQ ON) +#SET(CPACK_RPM_PACKAGE_AUTOPROV ON) +SET(CPACK_RPM_PACKAGE_AUTOREQPROV ON) +SET(CPACK_RPM_COMPRESSION_TYPE xz) +SET(CPACK_RPM_INSTALL_WITH_EXEC ON) +SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "package for LC/MS data management and analysis") +SET(CPACK_PACKAGE_DESCRIPTION " + OpenMS is a package for LC/MS data management and analysis. OpenMS + offers an infrastructure for the development of mass + spectrometry-related software and powerful 2D and 3D visualization + solutions. + . + TOPP (the OpenMS PiPeline) is a pipeline for the analysis + of HPLC/MS data. It consists of a set of numerous small applications + that can be chained together to create analysis pipelines tailored + for a specific problem." + ) + +## Create own target because you cannot "depend" on the internal target 'package' +add_custom_target(dist + COMMAND cpack -G ${CPACK_GENERATOR} + COMMENT "Building ${CPACK_GENERATOR} package" +) diff --git a/cmake/setup_lib_find_paths.cmake b/cmake/setup_lib_find_paths.cmake new file mode 100644 index 000000000..1a6305ebf --- /dev/null +++ b/cmake/setup_lib_find_paths.cmake @@ -0,0 +1,31 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Stephan Aiche, Chris Bielow $ +# $Authors: Chris Bielow, Stephan Aiche $ +# -------------------------------------------------------------------------- + + +#------------------------------------------------------------------------------ +# This cmake file only handles the customization of internal path variables +# where the build system expects to find external libraries. Note that the +# actual libraries are found in the CMake files of the individual componenents. +#------------------------------------------------------------------------------ + +#------------------------------------------------------------------------------ +# OPENMS_CONTRIB_LIBS pointed the build at a contrib build (OpenMS/contrib). The +# option went away after OpenMS 3.6, together with the contrib (#10327). Stop +# instead of ignoring it: a build that silently dropped the prefix would pick up +# other libraries than the ones the user asked for. +if(DEFINED OPENMS_CONTRIB_LIBS) + message(FATAL_ERROR + "OPENMS_CONTRIB_LIBS was removed after OpenMS 3.6, together with the contrib. " + "Add the prefix of the dependencies to CMAKE_PREFIX_PATH, or let vcpkg build them " + "(cmake --preset -release, see 'cmake --list-presets'). " + "A build directory that still has the option cached needs 'cmake -U OPENMS_CONTRIB_LIBS'.") +endif() + +#------------------------------------------------------------------------------ +# Ensure Qt includes it's libs as SYSTEM +set(QT_INCLUDE_DIRS_NO_SYSTEM Off) \ No newline at end of file diff --git a/cmake/stl_debug.cmake b/cmake/stl_debug.cmake new file mode 100644 index 000000000..21387bf83 --- /dev/null +++ b/cmake/stl_debug.cmake @@ -0,0 +1,22 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Stephan Aiche, Chris Bielow $ +# $Authors: Andreas Bertsch, Chris Bielow, Stephan Aiche $ +# -------------------------------------------------------------------------- + +#------------------------------------------------------------------------------ +# This cmake file enables the STL debug mode + +if (CMAKE_COMPILER_IS_GNUCXX) + if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + # add compiler flag + add_compile_options(/D_GLIBCXX_DEBUG) + message(STATUS "STL debug mode: ${STL_DEBUG}") + else() + message(WARNING "STL debug mode is supported for OpenMS debug mode only") + endif() +else() + message(WARNING "STL debug mode is supported for compiler GCC only") +endif() diff --git a/cmake/third_party_licenses.cmake b/cmake/third_party_licenses.cmake new file mode 100644 index 000000000..2a8f1ad30 --- /dev/null +++ b/cmake/third_party_licenses.cmake @@ -0,0 +1,561 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Timo Sachsenberg $ +# $Authors: Timo Sachsenberg $ +# -------------------------------------------------------------------------- + +## The packages and the pyOpenMS wheels bundle third-party libraries, and most of their +## licenses require the license text to accompany the binaries. The functions below install +## these texts under share/OpenMS/LICENSES, in the component 'share' that every installation +## type includes. +## +## openms_install_vcpkg_licenses() installs vcpkg/.txt: the license text of every vcpkg +## port of the target triplet, which vcpkg installs as share//copyright, except the +## build helpers such as vcpkg-cmake. An installation carries the code of each port: as a +## library next to libOpenMS (install(RUNTIME_DEPENDENCY_SET) in package_general.cmake), +## linked into it (the Windows triplets and those of the Linux wheels are static), or +## compiled in (header-only ports). +## The top-level CMakeLists.txt calls it in every configuration, so that the wheels built +## with vcpkg carry the texts too. +## +## openms_install_third_party_licenses() installs the texts of what only the packages bundle; +## cmake/package_general.cmake calls it: +## - Qt/: Qt is not a vcpkg port. The Windows and macOS packages bundle it; the DEB depends +## on the distribution's Qt instead. OpenMS uses Qt under the LGPL version 3, which +## requires its text, the text of the GPL version 3 that it supplements, and a note on +## where to get the source code of the bundled Qt. +## - homebrew//: on macOS, Qt and the libraries it needs (glib, ICU, freetype, ...) +## and the OpenMP runtime libomp come from Homebrew, and the package bundles them. Homebrew +## installs the license files of a formula into its keg, and these are installed for the +## given formulae and every installed formula they depend on. +## +## openms_install_system_library_licenses() installs system//: on Linux, the +## libraries the package takes from the build machine's distribution rather than from vcpkg +## (none at the moment; it was libgfortran for the LAPACK of the removed COIN-OR solver), +## with the copyright file of the Debian package each comes from; cmake/package_general.cmake +## calls it. +## +## openms_install_vendored_licenses() installs the licenses of the third-party code that +## OpenMS carries in its own source tree and compiles into its libraries (vendored//). +## Every installation of libOpenMS contains that code, the Python wheels too, so the +## top-level CMakeLists.txt calls it in every configuration, not only for packages. +## +## Each of them also records the files it installs, for share/OpenMS/THIRD-PARTY-NOTICES.txt, +## which gathers the texts in one file (cmake/third_party_notices.cmake). + +## Sets to the Homebrew formulae whose kegs hold the given paths, and +## to the prefix of the Homebrew installation they belong to. +function(openms_homebrew_formulae_of formulae_var prefix_var) + set(_formulae) + set(_prefixes) + foreach(_path IN LISTS ARGN) + if(NOT EXISTS "${_path}") + continue() + endif() + ## /opt/ and the files linked into /lib resolve to the keg, + ## /Cellar//. + file(REAL_PATH "${_path}" _real) + if(_real MATCHES "^(.*)/Cellar/([^/]+)/[^/]+(/|$)") + list(APPEND _prefixes "${CMAKE_MATCH_1}") + list(APPEND _formulae "${CMAKE_MATCH_2}") + endif() + endforeach() + list(REMOVE_DUPLICATES _formulae) + list(REMOVE_DUPLICATES _prefixes) + list(LENGTH _prefixes _count) + if(_count GREATER 1) + ## A Mac can have two Homebrew installations, /opt/homebrew and /usr/local. + message(FATAL_ERROR "The paths ${ARGN} belong to more than one Homebrew installation: " + "${_prefixes}") + endif() + set(${formulae_var} "${_formulae}" PARENT_SCOPE) + set(${prefix_var} "${_prefixes}" PARENT_SCOPE) +endfunction() + +## Installs share/OpenMS/LICENSES/vcpkg/.txt for every port of the target triplet, if +## the build takes its dependencies from vcpkg. Left out are the build helpers such as +## vcpkg-cmake: ports that install nothing but their own share/ folder (CMake scripts +## for the builds of other ports), so no installation contains anything of them. They are in +## the target triplet's tree when it is also the host triplet, as in the Linux builds. vcpkg +## lists the files of each port in vcpkg/info/__.list, one +## / per line and folders with a trailing slash; a port without such a list +## keeps its license. +function(openms_install_vcpkg_licenses) + if(NOT (OPENMS_USE_VCPKG AND VCPKG_INSTALLED_DIR AND VCPKG_TARGET_TRIPLET)) + return() + endif() + file(GLOB _copyrights LIST_DIRECTORIES false + "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/share/*/copyright") + set(_count 0) + set(_helpers) + foreach(_copyright IN LISTS _copyrights) + get_filename_component(_port_dir "${_copyright}" DIRECTORY) + get_filename_component(_port "${_port_dir}" NAME) + ## Port and triplet names consist of lowercase letters, digits and dashes, so they need + ## no escaping in the patterns. + file(GLOB _lists "${VCPKG_INSTALLED_DIR}/vcpkg/info/${_port}_*_${VCPKG_TARGET_TRIPLET}.list") + if(_lists) + set(_files) + foreach(_list IN LISTS _lists) + file(STRINGS "${_list}" _entries REGEX "[^/]$") + list(APPEND _files ${_entries}) + endforeach() + list(FILTER _files EXCLUDE REGEX "^${VCPKG_TARGET_TRIPLET}/share/${_port}/") + if(NOT _files) + list(APPEND _helpers "${_port}") + continue() + endif() + endif() + install(FILES "${_copyright}" + DESTINATION "${INSTALL_SHARE_DIR}/LICENSES/vcpkg" + RENAME "${_port}.txt" + COMPONENT share) + openms_add_third_party_notice("LICENSES/vcpkg/${_port}.txt" "${_copyright}") + math(EXPR _count "${_count} + 1") + endforeach() + message(STATUS "Installing the license texts of ${_count} vcpkg ports") + if(_helpers) + list(JOIN _helpers ", " _helpers) + message(STATUS "Not installing those of the build helpers ${_helpers}, which install " + "nothing but their share folder") + endif() +endfunction() + +## openms_install_third_party_licenses([QT_VERSION ] +## [HOMEBREW_PREFIX HOMEBREW_FORMULAE ...]) +## QT_VERSION the version of the Qt the package bundles; empty if it bundles none +## HOMEBREW_PREFIX the prefix of the Homebrew installation the formulae come from +## HOMEBREW_FORMULAE the Homebrew formulae the package bundles libraries of; their +## dependencies are added +function(openms_install_third_party_licenses) + cmake_parse_arguments(PARSE_ARGV 0 arg "" "QT_VERSION;HOMEBREW_PREFIX" "HOMEBREW_FORMULAE") + set(_licenses_dir "${INSTALL_SHARE_DIR}/LICENSES") + + if(arg_QT_VERSION) + set(_qt_licenses "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/third_party_licenses/Qt") + ## The variables README.txt.in refers to. + set(QT_LICENSE_VERSION "${arg_QT_VERSION}") + string(REGEX MATCH "^[0-9]+\\.[0-9]+" QT_LICENSE_MAJOR_MINOR "${arg_QT_VERSION}") + set(QT_LICENSE_HOMEBREW_NOTE "") + if(arg_HOMEBREW_FORMULAE) + string(CONCAT QT_LICENSE_HOMEBREW_NOTE + "\nOn macOS, Qt comes from Homebrew. The Homebrew formulae, including any patches\n" + "Homebrew applies to Qt, are at https://github.com/Homebrew/homebrew-core; ../homebrew\n" + "holds the license files of the formulae whose libraries this package bundles.\n") + endif() + configure_file("${_qt_licenses}/README.txt.in" + "${PROJECT_BINARY_DIR}/third_party_licenses/Qt/README.txt" @ONLY) + set(_qt_files "${_qt_licenses}/LGPL-3.0-only.txt" + "${_qt_licenses}/GPL-3.0-only.txt" + "${PROJECT_BINARY_DIR}/third_party_licenses/Qt/README.txt") + install(FILES ${_qt_files} + DESTINATION "${_licenses_dir}/Qt" + COMPONENT share) + foreach(_file IN LISTS _qt_files) + get_filename_component(_name "${_file}" NAME) + openms_add_third_party_notice("LICENSES/Qt/${_name}" "${_file}") + endforeach() + message(STATUS "Packaging the Qt ${arg_QT_VERSION} licenses") + endif() + + if(arg_HOMEBREW_FORMULAE) + ## The package bundles libraries of these formulae and their dependencies, so configuring + ## fails rather than leave their license files out. The brew of the installation the + ## formulae come from is used, not the one on the PATH: a brew answers for its own + ## installation only, and a Mac can have two. + set(_brew "${arg_HOMEBREW_PREFIX}/bin/brew") + if(NOT arg_HOMEBREW_PREFIX OR NOT EXISTS "${_brew}") + message(FATAL_ERROR "The package bundles libraries of the Homebrew formulae " + "${arg_HOMEBREW_FORMULAE}, but '${_brew}', which is needed to collect " + "their license files, does not exist.") + endif() + ## --union: the dependencies of any of the formulae, not only those they all share. + ## Both the dependencies recorded in the installed kegs (--installed) and those the + ## formulae declare are collected. The recorded ones alone miss formulae: in the Release + ## run of 2026-10-08, 'brew deps --installed' left out exactly the dependencies that + ## 'brew install qtbase' had upgraded in the same run (glib, harfbuzz, pcre2, libpng, + ## cairo, ...), although the package bundles their libraries. homebrew-core's CI checks + ## that a formula declares every formula it links against, so the declared ones cover + ## what is bundled. + set(_dependencies) + foreach(_installed_only "--installed" "") + execute_process(COMMAND "${_brew}" deps ${_installed_only} --union ${arg_HOMEBREW_FORMULAE} + OUTPUT_VARIABLE _deps + RESULT_VARIABLE _result + ERROR_VARIABLE _error + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_STRIP_TRAILING_WHITESPACE) + if(NOT _result EQUAL 0) + message(FATAL_ERROR "'brew deps ${_installed_only} --union' failed (${_error}), so the " + "license files of the dependencies of the Homebrew formulae " + "${arg_HOMEBREW_FORMULAE}, whose libraries the package bundles, " + "cannot be collected.") + endif() + string(REGEX REPLACE "[ \t\r\n]+" ";" _deps "${_deps}") + list(APPEND _dependencies ${_deps}) + endforeach() + set(_formulae ${arg_HOMEBREW_FORMULAE} ${_dependencies}) + list(REMOVE_DUPLICATES _formulae) + list(SORT _formulae) + + set(_without_license) + set(_not_installed) + foreach(_formula IN LISTS _formulae) + execute_process(COMMAND "${_brew}" --prefix "${_formula}" + OUTPUT_VARIABLE _prefix + RESULT_VARIABLE _result + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + ## 'brew --prefix' names the opt link of a formula whether or not it is installed. A + ## declared dependency that is not installed (an optional one, or one the formula + ## gained after it was installed) cannot have a library in the package. + if(NOT _result EQUAL 0 OR NOT IS_DIRECTORY "${_prefix}") + list(APPEND _not_installed "${_formula}") + continue() + endif() + file(REAL_PATH "${_prefix}" _keg) + ## Homebrew copies a formula's top-level license files (COPYING, LICENSE.md, ...) + ## into the root of its keg; some formulae install them to share/doc/ or + ## share/licenses/ instead. The first of these folders that has any is used, + ## as tools/ci/collect_wheel_licenses.py does for the wheels. + set(_license_files) + foreach(_folder "${_keg}" "${_keg}/share/doc/${_formula}" "${_keg}/share/licenses/${_formula}") + file(GLOB _keg_files LIST_DIRECTORIES false "${_folder}/*") + foreach(_file IN LISTS _keg_files) + get_filename_component(_name "${_file}" NAME) + string(TOUPPER "${_name}" _name) + if(_name MATCHES "^(COPYING|COPYRIGHT|LICENSE|LICENCE|NOTICE)") + list(APPEND _license_files "${_file}") + endif() + endforeach() + if(_license_files) + break() + endif() + endforeach() + if(_license_files) + install(FILES ${_license_files} + DESTINATION "${_licenses_dir}/homebrew/${_formula}" + COMPONENT share) + foreach(_file IN LISTS _license_files) + get_filename_component(_name "${_file}" NAME) + openms_add_third_party_notice("LICENSES/homebrew/${_formula}/${_name}" "${_file}") + endforeach() + else() + list(APPEND _without_license "${_formula}") + endif() + endforeach() + list(LENGTH _formulae _count) + list(LENGTH _not_installed _count_not_installed) + math(EXPR _count "${_count} - ${_count_not_installed}") + message(STATUS "Packaging the license files of ${_count} Homebrew formulae") + if(_not_installed) + message(STATUS "Declared Homebrew dependencies that are not installed: ${_not_installed}") + endif() + if(_without_license) + ## Expected for Qt's own formulae, whose keg holds its licenses only in a LICENSES + ## directory; the Qt licenses are installed above. + message(STATUS "No license file in the Homebrew kegs of: ${_without_license}") + endif() + endif() +endfunction() + +## Sets to the libraries needs (the NEEDED entries of its dynamic section). +function(_openms_needed_libraries var objdump library) + execute_process(COMMAND "${objdump}" -p "${library}" + OUTPUT_VARIABLE _output + RESULT_VARIABLE _result + ERROR_QUIET) + if(NOT _result EQUAL 0) + message(FATAL_ERROR "'${objdump} -p ${library}' failed, so the libraries it needs, whose " + "licenses the package has to ship, are unknown.") + endif() + string(REGEX MATCHALL "NEEDED +[^ \t\r\n]+" _entries "${_output}") + list(TRANSFORM _entries REPLACE "^NEEDED +" "") + set(${var} "${_entries}" PARENT_SCOPE) +endfunction() + +## openms_install_system_library_licenses(ROOTS ... [EXCLUDE_REGEXES ...]) +## ROOTS shared libraries that the package bundles and that come with their +## licenses, i.e. those of the vcpkg tree; what they need, directly or +## through each other, is followed +## EXCLUDE_REGEXES paths of libraries the package does not bundle, the +## POST_EXCLUDE_REGEXES of its runtime dependency set (the C and C++ +## runtime, Qt, ...) +## The libraries the roots need that neither another root provides nor an exclusion drops +## come from the build machine's distribution, and the package bundles them (none at the +## moment; it was the GCC Fortran runtime libgfortran for the LAPACK of the removed COIN-OR +## solver). They are found as the compiler finds them (-print-file-name), and the libraries +## they need are followed in turn. +## For each Debian package that installed one, its copyright file goes to +## LICENSES/system//copyright. Debian's copyright files refer to the full texts of +## common licenses in /usr/share/common-licenses instead of including them, so the texts +## they name go next to it. LICENSES/system/INDEX.txt lists the +## libraries with the package, version and source package each comes from. Configuring +## fails rather than leave a license out: without dpkg, for a library the compiler cannot +## find, or for one no package owns. +function(openms_install_system_library_licenses) + cmake_parse_arguments(PARSE_ARGV 0 arg "" "" "ROOTS;EXCLUDE_REGEXES") + set(_provided) + set(_queue) + foreach(_root IN LISTS arg_ROOTS) + get_filename_component(_name "${_root}" NAME) + list(APPEND _provided "${_name}") + if(NOT IS_SYMLINK "${_root}") + list(APPEND _queue "${_root}") + endif() + endforeach() + if(NOT _queue) + return() + endif() + set(_objdump "${CMAKE_OBJDUMP}") + if(NOT _objdump) + find_program(OPENMS_OBJDUMP_EXECUTABLE objdump) + set(_objdump "${OPENMS_OBJDUMP_EXECUTABLE}") + endif() + if(NOT _objdump) + message(FATAL_ERROR "objdump is needed to find the libraries of the build machine that " + "the package bundles, whose licenses it has to ship.") + endif() + + ## Walk the dependencies: | for every library of the build machine. + set(_seen ${_provided}) + set(_system) + set(_unresolved) + while(_queue) + list(POP_FRONT _queue _library) + _openms_needed_libraries(_needed "${_objdump}" "${_library}") + foreach(_name IN LISTS _needed) + if(_name IN_LIST _seen) + continue() + endif() + list(APPEND _seen "${_name}") + execute_process(COMMAND "${CMAKE_CXX_COMPILER}" "-print-file-name=${_name}" + OUTPUT_VARIABLE _path + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET) + if(IS_ABSOLUTE "${_path}" AND EXISTS "${_path}") + file(REAL_PATH "${_path}" _real) + set(_candidates "${_path}" "${_real}") + else() + ## Not where the compiler looks, but the install step may still find and bundle it + ## (through a RUNPATH, ld.so.conf or its DIRECTORIES), so only an exclusion that + ## matches the name lets it pass. + set(_real) + set(_candidates "/${_name}") + endif() + set(_excluded FALSE) + foreach(_regex IN LISTS arg_EXCLUDE_REGEXES) + foreach(_candidate IN LISTS _candidates) + if(_candidate MATCHES "${_regex}") + set(_excluded TRUE) + endif() + endforeach() + endforeach() + if(_excluded) + continue() + elseif(NOT _real) + list(APPEND _unresolved "${_name} (needed by ${_library})") + continue() + endif() + list(APPEND _system "${_name}|${_real}") + list(APPEND _queue "${_real}") + endforeach() + endwhile() + if(_unresolved) + list(JOIN _unresolved ", " _list) + message(FATAL_ERROR "The compiler (-print-file-name) cannot find ${_list}, so whether the " + "package bundles them, and the licenses it then has to ship, cannot be " + "checked.") + endif() + if(NOT _system) + return() + endif() + + find_program(OPENMS_DPKG_QUERY_EXECUTABLE dpkg-query) + set(_dpkg_query "${OPENMS_DPKG_QUERY_EXECUTABLE}") + if(NOT _dpkg_query) + string(REPLACE "|" " from " _list "${_system}") + message(FATAL_ERROR "The package bundles libraries of the build machine (${_list}), but " + "without dpkg-query the packages they come from, and so their " + "licenses, cannot be found.") + endif() + set(_system_dir "${INSTALL_SHARE_DIR}/LICENSES/system") + set(_packages) + set(_index) + foreach(_entry IN LISTS _system) + string(REPLACE "|" ";" _entry "${_entry}") + list(GET _entry 0 _name) + list(GET _entry 1 _real) + ## With a merged /usr, dpkg may know the file under /lib instead of /usr/lib. + set(_package) + set(_architecture) + foreach(_candidate "${_real}" "") + if(NOT _candidate) + string(REGEX REPLACE "^/usr/" "/" _candidate "${_real}") + endif() + execute_process(COMMAND "${_dpkg_query}" -S "${_candidate}" + OUTPUT_VARIABLE _owner + RESULT_VARIABLE _result + ERROR_QUIET) + ## "libgfortran5:amd64: /usr/lib/x86_64-linux-gnu/libgfortran.so.5.0.0" + if(_result EQUAL 0 AND _owner MATCHES "^([^:, \n]+)(:[^: \n]+)?: ") + set(_package "${CMAKE_MATCH_1}") + set(_architecture "${CMAKE_MATCH_2}") + break() + endif() + endforeach() + if(NOT _package) + message(FATAL_ERROR "The package bundles ${_name} (${_real}), which no Debian package " + "owns, so its license cannot be found.") + endif() + ## With the architecture qualifier, as -W lists every installed architecture of a + ## multiarch package otherwise. + execute_process(COMMAND "${_dpkg_query}" -W + "-f=\${Version}|\${source:Package}|\${source:Version}" + "${_package}${_architecture}" + OUTPUT_VARIABLE _versions + RESULT_VARIABLE _result + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET) + if(NOT _result EQUAL 0 OR NOT _versions MATCHES "^[^|\n]+\\|[^|\n]+\\|[^|\n]+$") + message(FATAL_ERROR "'dpkg-query -W ${_package}${_architecture}' failed or returned " + "'${_versions}', so the version of ${_name}'s package cannot be " + "recorded.") + endif() + string(REPLACE "|" ";" _versions "${_versions}") + list(GET _versions 0 _version) + list(GET _versions 1 _source) + list(GET _versions 2 _source_version) + list(APPEND _index "${_name}\t${_package} ${_version} (source package ${_source} ${_source_version})") + if(_package IN_LIST _packages) + continue() + endif() + list(APPEND _packages "${_package}") + ## The doc folder of a library package is often a link to that of its source package's + ## base package (libgfortran5 -> gcc-14-base). + set(_copyright "/usr/share/doc/${_package}/copyright") + if(NOT EXISTS "${_copyright}") + message(FATAL_ERROR "The package bundles ${_name} from the Debian package ${_package}, " + "which has no ${_copyright}.") + endif() + file(REAL_PATH "${_copyright}" _copyright) + install(FILES "${_copyright}" + DESTINATION "${_system_dir}/${_package}" + COMPONENT share) + openms_add_third_party_notice("LICENSES/system/${_package}/copyright" "${_copyright}") + file(READ "${_copyright}" _text) + string(REGEX MATCHALL "/usr/share/common-licenses/[A-Za-z0-9.+-]*[A-Za-z0-9+]" _references "${_text}") + list(REMOVE_DUPLICATES _references) + foreach(_reference IN LISTS _references) + if(NOT EXISTS "${_reference}") + message(FATAL_ERROR "The copyright file of the Debian package ${_package} refers to " + "${_reference}, which does not exist.") + endif() + get_filename_component(_text_name "${_reference}" NAME) + ## GPL is a link to GPL-3; it is installed as a file under the name the text uses. + file(REAL_PATH "${_reference}" _text_file) + install(FILES "${_text_file}" + DESTINATION "${_system_dir}/${_package}" + RENAME "${_text_name}" + COMPONENT share) + openms_add_third_party_notice("LICENSES/system/${_package}/${_text_name}" "${_text_file}") + endforeach() + endforeach() + + list(SORT _index) + list(JOIN _index "\n" _index) + set(_index_file "${PROJECT_BINARY_DIR}/third_party_licenses/system/INDEX.txt") + file(WRITE "${_index_file}" + "Libraries of the build machine's distribution that this package bundles, and the Debian\n" + "package each comes from. LICENSES/system// holds the package's copyright file\n" + "and the texts in /usr/share/common-licenses that it refers to. The source code of a\n" + "package is in the archive of the distribution: apt-get source =.\n\n" + "${_index}\n") + install(FILES "${_index_file}" + DESTINATION "${_system_dir}" + COMPONENT share) + openms_add_third_party_notice("LICENSES/system/INDEX.txt" "${_index_file}") + list(JOIN _packages ", " _packages) + message(STATUS "Packaging the licenses of the libraries the package takes from the build " + "machine, from the Debian packages ${_packages}") +endfunction() + +## Installs the licenses of the libraries under src/openms/extern and src/openms/thirdparty, +## of the third-party code in other OpenMS source files (libkdtree++ in KDTree.h, +## MSNumpress), and of HiGHS when the build fetches it and links it into libOpenMS +## (cmake_findExternalLibs.cmake), under share/OpenMS/LICENSES/vendored. A library of src/openms/extern that the +## build takes from vcpkg or the system instead (USE_EXTERNAL_) is left out; for a vcpkg +## port, openms_install_vcpkg_licenses() installs its license. +## Installs to share/OpenMS/LICENSES/vendored/ and records them for +## THIRD-PARTY-NOTICES.txt. +function(_openms_install_vendored_license library) + install(FILES ${ARGN} + DESTINATION "${INSTALL_SHARE_DIR}/LICENSES/vendored/${library}" + COMPONENT share) + foreach(_file IN LISTS ARGN) + get_filename_component(_name "${_file}" NAME) + openms_add_third_party_notice("LICENSES/vendored/${library}/${_name}" "${_file}") + endforeach() +endfunction() + +function(openms_install_vendored_licenses) + set(_licenses_dir "${INSTALL_SHARE_DIR}/LICENSES/vendored") + set(_openms "${OPENMS_HOST_DIRECTORY}/src/openms") + set(_texts "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/third_party_licenses") + + ## Percolator is under the Apache License 2.0, whose NOTICE file has to accompany it. The + ## NOTICE file also holds the license of the LIBLINEAR code that Percolator contains. + _openms_install_vendored_license(percolator + "${_openms}/thirdparty/percolator/LICENSE-Apache-2.0.txt" + "${_openms}/thirdparty/percolator/NOTICE-percolator.txt") + _openms_install_vendored_license(libkdtree + "${_texts}/libkdtree/README.txt" + "${_texts}/libkdtree/Artistic-2.0.txt") + _openms_install_vendored_license(MSNumpress "${_texts}/MSNumpress/LICENSE.txt") + if(OPENMS_ENABLE_MZPEAK) + _openms_install_vendored_license(mzpeak "${_openms}/thirdparty/mzpeak/LICENSE") + endif() + ## HiGHS fetched by FetchContent is linked statically, so no other step installs its + ## license: openms_install_vcpkg_licenses() covers vcpkg ports, and the wheel's license + ## collection covers shared libraries. A HiGHS from vcpkg or the system is found by + ## find_package() instead, which leaves highs_SOURCE_DIR undefined. + if(DEFINED highs_SOURCE_DIR) + _openms_install_vendored_license(HiGHS "${highs_SOURCE_DIR}/LICENSE.txt") + endif() + ## mimalloc fetched for WITH_MIMALLOC (cmake/mimalloc.cmake); its DLLs ship with the TOPP tools. + get_property(_mimalloc_active GLOBAL PROPERTY OPENMS_MIMALLOC_ACTIVE) + if(_mimalloc_active) + _openms_install_vendored_license(mimalloc "${mimalloc_SOURCE_DIR}/LICENSE") + endif() + + ## / + set(_extern_licenses evergreen/LICENSE GTE/LICENSE Quadtree/LICENSE) + if(NOT USE_EXTERNAL_JSON) + list(APPEND _extern_licenses nlohmann_json/LICENSE.MIT) + endif() + if(NOT USE_EXTERNAL_SQLITECPP) + list(APPEND _extern_licenses SQLiteCpp/LICENSE.txt) + endif() + if(NOT USE_EXTERNAL_SIMDE) + list(APPEND _extern_licenses simde/COPYING) + endif() + if(NOT USE_EXTERNAL_ISOSPEC) + list(APPEND _extern_licenses IsoSpec/LICENSE) + endif() + if(NOT USE_EXTERNAL_EOLBSPLINE) + list(APPEND _extern_licenses eol-bspline/LICENSE) + endif() + foreach(_license IN LISTS _extern_licenses) + get_filename_component(_library "${_license}" DIRECTORY) + _openms_install_vendored_license("${_library}" "${_openms}/extern/${_license}") + endforeach() + if(ENABLE_TDL) + install(DIRECTORY "${_openms}/extern/tool_description_lib/LICENSES/" + DESTINATION "${_licenses_dir}/tool_description_lib" + COMPONENT share) + openms_add_third_party_notice_directory("LICENSES/vendored/tool_description_lib" + "${_openms}/extern/tool_description_lib/LICENSES") + endif() +endfunction() diff --git a/cmake/third_party_licenses/Qt/GPL-3.0-only.txt b/cmake/third_party_licenses/Qt/GPL-3.0-only.txt new file mode 100644 index 000000000..f288702d2 --- /dev/null +++ b/cmake/third_party_licenses/Qt/GPL-3.0-only.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + 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 Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/cmake/third_party_licenses/Qt/LGPL-3.0-only.txt b/cmake/third_party_licenses/Qt/LGPL-3.0-only.txt new file mode 100644 index 000000000..0a041280b --- /dev/null +++ b/cmake/third_party_licenses/Qt/LGPL-3.0-only.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/cmake/third_party_licenses/Qt/README.txt.in b/cmake/third_party_licenses/Qt/README.txt.in new file mode 100644 index 000000000..964dab1a1 --- /dev/null +++ b/cmake/third_party_licenses/Qt/README.txt.in @@ -0,0 +1,14 @@ +The Qt @QT_LICENSE_VERSION@ libraries and plugins in this package (the modules Core, Gui, +Widgets, Svg and the others OpenMS needs) are Copyright (C) The Qt Company Ltd. and +other contributors. OpenMS uses them under the GNU Lesser General Public License, +version 3 (LGPL-3.0-only.txt in this directory), which supplements the GNU General +Public License, version 3 (GPL-3.0-only.txt in this directory). + +The source code of Qt @QT_LICENSE_VERSION@ is available from + https://download.qt.io/official_releases/qt/@QT_LICENSE_MAJOR_MINOR@/@QT_LICENSE_VERSION@/submodules/ +or, once that release has been archived, from + https://download.qt.io/archive/qt/@QT_LICENSE_MAJOR_MINOR@/@QT_LICENSE_VERSION@/submodules/ + +Qt contains third-party code under other licenses; they are listed at +https://doc.qt.io/qt-6/licenses-used-in-qt.html. +@QT_LICENSE_HOMEBREW_NOTE@ \ No newline at end of file diff --git a/cmake/third_party_licenses/homebrew/boost/LICENSE_1_0.txt b/cmake/third_party_licenses/homebrew/boost/LICENSE_1_0.txt new file mode 100644 index 000000000..36b7cd93c --- /dev/null +++ b/cmake/third_party_licenses/homebrew/boost/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/cmake/third_party_notices.cmake b/cmake/third_party_notices.cmake new file mode 100644 index 000000000..3a9c280fa --- /dev/null +++ b/cmake/third_party_notices.cmake @@ -0,0 +1,319 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Timo Sachsenberg $ +# $Authors: Timo Sachsenberg $ +# -------------------------------------------------------------------------- + +## share/OpenMS/THIRD-PARTY-NOTICES.txt holds the license, copyright and notice texts of the +## third-party software an installation contains, in one file. It first lists the components, +## grouped by where they come from, each with the numbers of the texts that apply to it. The +## texts follow, each only once: components whose texts are identical (the same license and +## the same copyright holders) share a number. The files the texts come from stay where +## they are installed, in share/OpenMS/LICENSES and in the tool folders under +## share/OpenMS/THIRDPARTY. +## +## The code that installs these files records them with openms_add_third_party_notice(): +## cmake/third_party_licenses.cmake, the Thermo bridge in cmake_findExternalLibs.cmake, the +## PeptDeep models in src/openms/CMakeLists.txt and the THIRDPARTY tools in +## package_general.cmake. openms_install_third_party_notices(), which +## the top-level CMakeLists.txt calls last, writes the list of recorded files when +## configuring, and the notices from that list when installing, in the component 'share'. +## The notices cannot be written when configuring, since some of the files (the Thermo +## bridge's) exist only after the build. They cannot be made from the installed tree either, +## because the package generators install each component into a folder of its own. The DEB +## also installs the notices, after the OpenMS license, as /usr/share/doc/openms/copyright, +## the file Debian's policy asks every package to have. +## +## The wheel builds add the licenses of the libraries that the wheel repair tools bundle +## after installing OpenMS (tools/ci/collect_wheel_licenses.py). They then run this file as a +## script, which writes the notices again, from the installed tree: +## cmake -DSHARE_DIR=/share/OpenMS -P cmake/third_party_notices.cmake + +## The functions below keep these policies wherever they are called from: in script mode, +## and in the install script, which sets none. include() gives this file a policy scope of +## its own, so the setting does not leak into the including project. +cmake_policy(VERSION 3.24) + +## openms_add_third_party_notice( ) +## Records that the installation contains as share/OpenMS/. +function(openms_add_third_party_notice path file) + set_property(GLOBAL APPEND PROPERTY OPENMS_THIRD_PARTY_NOTICES "${path}|${file}") +endfunction() + +## openms_add_third_party_notice_directory( ) +## Records every file under , which is installed as share/OpenMS/. +function(openms_add_third_party_notice_directory path directory) + file(GLOB_RECURSE _files LIST_DIRECTORIES false RELATIVE "${directory}" "${directory}/*") + foreach(_file IN LISTS _files) + openms_add_third_party_notice("${path}/${_file}" "${directory}/${_file}") + endforeach() +endfunction() + +## Sets to the license, copyright and notice files at the top of a tool folder, such as +## LICENSE, License.txt, NOTICE, COPYING or THIRD-PARTY-NOTICES.txt; READMEs are left out. +function(openms_third_party_notice_files_of_tool var directory) + file(GLOB _files LIST_DIRECTORIES false RELATIVE "${directory}" "${directory}/*") + set(_notices) + foreach(_file IN LISTS _files) + string(TOUPPER "${_file}" _name) + if(_name MATCHES "(^|[-_])(LICEN[CS]E|COPYING|COPYRIGHT|NOTICES?|EULA)") + list(APPEND _notices "${_file}") + endif() + endforeach() + set(${var} "${_notices}" PARENT_SCOPE) +endfunction() + +## openms_install_third_party_notices() +## Installs share/OpenMS/THIRD-PARTY-NOTICES.txt, made from the files recorded so far. +function(openms_install_third_party_notices) + set(_dir "${PROJECT_BINARY_DIR}/third_party_notices") + get_property(_notices GLOBAL PROPERTY OPENMS_THIRD_PARTY_NOTICES) + list(JOIN _notices "\n" _list) + file(WRITE "${_dir}/files.txt" "${_list}\n") + set(_debian_copyright "") + ## PACKAGE_TYPE, not CPACK_GENERATOR: include(CPack) resets the latter to its defaults. + if("${PACKAGE_TYPE}" STREQUAL "deb") + set(_debian_copyright "LICENSE \"${OPENMS_HOST_DIRECTORY}/License.txt\" LICENSE_OUTPUT \"${_dir}/copyright\"") + endif() + install(CODE " + include(\"${CMAKE_CURRENT_FUNCTION_LIST_FILE}\") + openms_write_third_party_notices(\"${_dir}/THIRD-PARTY-NOTICES.txt\" + FILE_LIST \"${_dir}/files.txt\" ${_debian_copyright})" + COMPONENT share) + install(FILES "${_dir}/THIRD-PARTY-NOTICES.txt" + DESTINATION "${INSTALL_SHARE_DIR}" + COMPONENT share) + if(_debian_copyright) + ## Debian policy 12.5: /usr/share/doc//copyright, neither compressed nor a + ## symbolic link. + string(TOLOWER "${CPACK_PACKAGE_NAME}" _package) + install(FILES "${_dir}/copyright" + DESTINATION "share/doc/${_package}" + COMPONENT share) + endif() + list(LENGTH _notices _count) + message(STATUS "THIRD-PARTY-NOTICES.txt: ${_count} license, copyright and notice files") +endfunction() + +## Sets to the content of with Unix line ends and without trailing +## whitespace, and to TRUE if is not a text file, i.e. has a NUL byte in +## its first 8 KiB (the Thermo license is a Word document). file(READ) drops carriage +## returns, so the length of what it reads says nothing. +function(_openms_third_party_notice_text text_var binary_var file) + file(READ "${file}" _head LIMIT 8192 HEX) + ## " ...", so that " 00" can only match a whole byte. + string(REGEX REPLACE "(..)" " \\1" _head "${_head}") + string(FIND "${_head}" " 00" _nul) + if(NOT _nul EQUAL -1) + set(${binary_var} TRUE PARENT_SCOPE) + set(${text_var} "" PARENT_SCOPE) + return() + endif() + file(READ "${file}" _text) + string(REPLACE "\r" "" _text "${_text}") + string(REGEX REPLACE "[ \t\n]+$" "" _text "${_text}") + set(${binary_var} FALSE PARENT_SCOPE) + set(${text_var} "${_text}" PARENT_SCOPE) +endfunction() + +## Sets to the number of the group belongs to (the order of the groups in +## the notices) and to the name of its component. +function(_openms_third_party_notice_component group_var component_var path) + get_filename_component(_name "${path}" NAME) + get_filename_component(_stem "${path}" NAME_WLE) + if(path MATCHES "^LICENSES/Qt/") + set(_group 1) + set(_component "Qt") + elseif(path MATCHES "^LICENSES/(vcpkg|homebrew|system|vendored)/(.+)$") + set(_folder "${CMAKE_MATCH_1}") + set(_rest "${CMAKE_MATCH_2}") + set(_folders vcpkg homebrew system vendored) + list(FIND _folders "${_folder}" _index) + math(EXPR _group "${_index} + 2") + get_filename_component(_component "${_rest}" DIRECTORY) + if(_name STREQUAL "INDEX.txt" AND NOT _component) + set(_component "(the libraries each package provides)") + elseif(NOT _component) + ## vcpkg/.txt + set(_component "${_stem}") + endif() + elseif(path MATCHES "^LICENSES/ThermoRawFileReader|^openms_thermo_bridge/") + set(_group 6) + if(path MATCHES "^LICENSES/") + set(_component "Thermo RawFileReader") + else() + set(_component "openms-thermo-bridge") + endif() + elseif(path MATCHES "^THIRDPARTY/([^/]+)/") + set(_component "${CMAKE_MATCH_1}") + set(_group 7) + elseif(path MATCHES "^LICENSES/PeptDeep/") + set(_group 8) + set(_component "PeptDeep (AlphaPeptDeep)") + else() + set(_group 9) + set(_component "${path}") + endif() + set(${group_var} "${_group}" PARENT_SCOPE) + set(${component_var} "${_component}" PARENT_SCOPE) +endfunction() + +## openms_write_third_party_notices( [FILE_LIST ] [SHARE_DIR ] +## [LICENSE LICENSE_OUTPUT ]) +## Writes the notices for the files named in (lines "|", as +## openms_install_third_party_notices() writes them) and for those installed in the +## share/OpenMS folder . With LICENSE, also writes LICENSE_OUTPUT: followed +## by the notices. +function(openms_write_third_party_notices output) + cmake_parse_arguments(PARSE_ARGV 1 arg "" "FILE_LIST;SHARE_DIR;LICENSE;LICENSE_OUTPUT" "") + set(_entries) + if(arg_FILE_LIST) + file(STRINGS "${arg_FILE_LIST}" _entries ENCODING UTF-8) + endif() + if(arg_SHARE_DIR) + file(GLOB_RECURSE _files LIST_DIRECTORIES false RELATIVE "${arg_SHARE_DIR}" + "${arg_SHARE_DIR}/LICENSES/*" + "${arg_SHARE_DIR}/openms_thermo_bridge/managed/THIRD-PARTY-NOTICES.txt") + ## OpenMS's own license is not third-party. + list(REMOVE_ITEM _files "LICENSES/OpenMS-BSD-3-Clause.txt") + file(GLOB _tools LIST_DIRECTORIES true RELATIVE "${arg_SHARE_DIR}/THIRDPARTY" + "${arg_SHARE_DIR}/THIRDPARTY/*") + foreach(_tool IN LISTS _tools) + openms_third_party_notice_files_of_tool(_tool_files "${arg_SHARE_DIR}/THIRDPARTY/${_tool}") + foreach(_file IN LISTS _tool_files) + list(APPEND _files "THIRDPARTY/${_tool}/${_file}") + endforeach() + endforeach() + foreach(_file IN LISTS _files) + list(APPEND _entries "${_file}|${arg_SHARE_DIR}/${_file}") + endforeach() + endif() + + ## Order: by group, then by path; "||". + set(_sorted) + foreach(_entry IN LISTS _entries) + string(REPLACE "|" ";" _entry "${_entry}") + list(GET _entry 0 _path) + list(GET _entry 1 _file) + if(NOT EXISTS "${_file}") + message(FATAL_ERROR "THIRD-PARTY-NOTICES.txt: ${_file} (installed as ${_path}) does not exist") + endif() + _openms_third_party_notice_component(_group _component "${_path}") + list(APPEND _sorted "${_group}|${_path}|${_file}") + endforeach() + list(REMOVE_DUPLICATES _sorted) + list(SORT _sorted) + + ## Numbers the distinct texts and collects, per component, the numbers of its texts. + set(_hashes) ## hash of each numbered text; its number is its index + 1 + set(_text_files) ## the file each numbered text is read from + set(_text_paths) ## and where it is installed + set(_components) ## "|", in order + foreach(_entry IN LISTS _sorted) + string(REPLACE "|" ";" _entry "${_entry}") + list(GET _entry 1 _path) + list(GET _entry 2 _file) + _openms_third_party_notice_component(_group _component "${_path}") + set(_key "${_group}|${_component}") + string(MD5 _refs "${_key}") + set(_refs "_refs_${_refs}") + if(NOT _key IN_LIST _components) + list(APPEND _components "${_key}") + set(${_refs} "") + endif() + _openms_third_party_notice_text(_text _binary "${_file}") + if(_binary) + string(APPEND ${_refs} " ${_path} (not a text file)") + continue() + endif() + ## Texts that differ only in white space (line breaks, indentation) are the same text. + string(REGEX REPLACE "[ \t\n]+" " " _hash "${_text}") + string(SHA256 _hash "${_hash}") + list(FIND _hashes "${_hash}" _index) + if(_index EQUAL -1) + list(APPEND _hashes "${_hash}") + list(APPEND _text_files "${_file}") + list(APPEND _text_paths "${_path}") + list(LENGTH _hashes _number) + else() + math(EXPR _number "${_index} + 1") + endif() + if(NOT "${${_refs}}" MATCHES " \\[${_number}\\]( |$)") + string(APPEND ${_refs} " [${_number}]") + endif() + endforeach() + + set(_titles + "Qt" + "Libraries from vcpkg" + "Libraries from Homebrew" + "Libraries of the build system" + "Third-party code compiled into OpenMS" + "Thermo RawFileReader" + "Tools in share/OpenMS/THIRDPARTY" + "Models in share/OpenMS/models" + "Other") + set(_rule "==========================================================================================") + string(CONCAT _header + "THIRD-PARTY SOFTWARE NOTICES\n" + "\n" + "This installation of OpenMS contains the third-party software listed below. Each component\n" + "is followed by the numbers of the license, copyright and notice texts that apply to it. The\n" + "texts come after the list, each only once: components whose texts are identical share a\n" + "number. Paths are relative to share/OpenMS, the folder in which the installation keeps the\n" + "same files as their projects distribute them: LICENSES, and the folders of the tools under\n" + "THIRDPARTY. In a pyOpenMS wheel, that folder is pyopenms/share/OpenMS. The license of\n" + "OpenMS itself is LICENSES/OpenMS-BSD-3-Clause.txt.\n") + set(_notices "${output}.tmp") + file(WRITE "${_notices}" "${_header}") + set(_current_group "") + foreach(_key IN LISTS _components) + string(REPLACE "|" ";" _parts "${_key}") + list(GET _parts 0 _group) + list(GET _parts 1 _component) + if(NOT _group STREQUAL _current_group) + math(EXPR _title_index "${_group} - 1") + list(GET _titles ${_title_index} _title) + file(APPEND "${_notices}" "\n${_title}\n") + set(_current_group "${_group}") + endif() + string(MD5 _refs "${_key}") + set(_refs "_refs_${_refs}") + string(LENGTH "${_component}" _length) + set(_padding " ") + if(_length LESS 44) + math(EXPR _pad "44 - ${_length}") + string(REPEAT " " ${_pad} _padding) + endif() + file(APPEND "${_notices}" " ${_component}${_padding}${${_refs}}\n") + endforeach() + + set(_number 0) + foreach(_file IN LISTS _text_files) + list(GET _text_paths ${_number} _path) + math(EXPR _number "${_number} + 1") + _openms_third_party_notice_text(_text _binary "${_file}") + file(APPEND "${_notices}" "\n\n${_rule}\n[${_number}] ${_path}\n${_rule}\n\n${_text}\n") + endforeach() + file(RENAME "${_notices}" "${output}") + + if(arg_LICENSE) + file(READ "${arg_LICENSE}" _license) + file(READ "${output}" _notices_text) + file(WRITE "${arg_LICENSE_OUTPUT}" "${_license}\n\n${_rule}\n\n${_notices_text}") + endif() + + list(LENGTH _components _component_count) + list(LENGTH _text_files _text_count) + message(STATUS "Wrote ${output}: ${_component_count} components, ${_text_count} texts") +endfunction() + +## Script mode, for the wheels: cmake -DSHARE_DIR=/share/OpenMS -P +if(CMAKE_SCRIPT_MODE_FILE STREQUAL CMAKE_CURRENT_LIST_FILE) + if(NOT SHARE_DIR OR NOT IS_DIRECTORY "${SHARE_DIR}") + message(FATAL_ERROR "Pass the installed share/OpenMS folder as -DSHARE_DIR=.") + endif() + openms_write_third_party_notices("${SHARE_DIR}/THIRD-PARTY-NOTICES.txt" SHARE_DIR "${SHARE_DIR}") +endif() diff --git a/cmake/topp_tool_macros.cmake b/cmake/topp_tool_macros.cmake new file mode 100644 index 000000000..95fe29ad9 --- /dev/null +++ b/cmake/topp_tool_macros.cmake @@ -0,0 +1,154 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Timo Sachsenberg $ +# $Authors: Timo Sachsenberg $ +# -------------------------------------------------------------------------- + +# Declaration of TOPP tools, and generation of the tool registry from those declarations. +# +# openms_topp_tool( ) is the single place a TOPP tool is declared. It says +# both that the tool exists (so the build produces it) and which category TOPPAS groups it +# under (so ToolHandler can list it). The registry share/OpenMS/TOOLS/OpenMS.tsv (one file per +# layer in a build against an installed library, see src/CMakeLists.txt) is written +# from these declarations by openms_write_tool_registry(), which is why there is no +# hand-maintained list to keep in step with the build: a tool that a build option does not +# build is not declared, so it is not registered either, and a tool cannot be built without +# being registered or registered without being built. + +#------------------------------------------------------------------------------ +# Forget the tools of an earlier configure of this build directory. +# +# The declarations accumulate in cache variables so that they survive the directory scopes +# they are made in (src/topp and, for the tools that need the GUI library, src/openms_gui). +# Cache variables also survive a reconfigure, so without this every configure would append +# the whole list again. +function(openms_reset_topp_tools) + set(TOPP_TOOLS "" CACHE INTERNAL "OpenMS' TOPP tools" FORCE) + set(TOPP_TOOL_CATEGORIES "" CACHE INTERNAL "TOPPAS category of the entry of TOPP_TOOLS at the same index" FORCE) +endfunction() + +#------------------------------------------------------------------------------ +# openms_topp_tool( ) +# +# @param Name the tool, built from .cpp or from the subdirectory / +# @param Category the TOPPAS category, e.g. "Quantitation". Mirror the set of categories in +# doc/doxygen/public/TOPP.doxygen. +function(openms_topp_tool name category) + if(ARGN) + message(FATAL_ERROR "openms_topp_tool(${name}): unexpected arguments '${ARGN}'. Usage: openms_topp_tool( )") + endif() + if("${name}" STREQUAL "") + message(FATAL_ERROR "openms_topp_tool(): the tool name may not be empty") + endif() + if("${category}" STREQUAL "") + message(FATAL_ERROR "openms_topp_tool(${name}): a category is required; it is what TOPPAS groups the tool under") + endif() + if(name IN_LIST TOPP_TOOLS) + message(FATAL_ERROR "openms_topp_tool(${name}): this tool is already declared. ToolHandler refuses to start any " + "tool when a name is registered twice, so the duplicate is rejected here instead.") + endif() + ## Some workflow systems read a slash in a category as a subcategory separator. + if(category MATCHES "/") + message(FATAL_ERROR "openms_topp_tool(${name}): the category '${category}' contains a '/', which some workflow " + "systems read as a subcategory separator. Use a plain category name.") + endif() + ## ';' would split the entry into two list elements and desynchronize it from TOPP_TOOLS. + if(category MATCHES ";") + message(FATAL_ERROR "openms_topp_tool(${name}): the category '${category}' contains a ';'.") + endif() + + set(TOPP_TOOLS ${TOPP_TOOLS} "${name}" + CACHE INTERNAL "OpenMS' TOPP tools" FORCE) + set(TOPP_TOOL_CATEGORIES ${TOPP_TOOL_CATEGORIES} "${category}" + CACHE INTERNAL "TOPPAS category of the entry of TOPP_TOOLS at the same index" FORCE) +endfunction() + +#------------------------------------------------------------------------------ +# openms_write_tool_registry( [TOOLS ...]) +# +# Write the registry of every tool declared so far. Call it once, after every +# add_subdirectory() that declares tools. +# +# TOOLS restricts the file to the given subset of the declared tools. A build against an +# installed OpenMS library (OPENMS_USE_INSTALLED_LIBRARY) writes one registry per layer it +# builds, so the TOPP tools and the GUI tools can be installed (and packaged) separately and +# ToolHandler still finds all of them in one TOOLS directory. +# +# Without any tool to list, no file is written and a file an earlier configure of this build +# directory left behind is removed: a build of the libraries alone registers nothing. +# +# The format is the tab-separated one the rest of share/OpenMS uses for tabular data, read +# back by ToolHandler through CsvFile: +# +# # comment +# \t[\t;...] +# +# The third column is the list of '-type' sub-modes a tool offers and is omitted by tools +# that have none, which is all of them today. +function(openms_write_tool_registry out_file) + cmake_parse_arguments(PARSE_ARGV 1 _registry "" "" "TOOLS") + if(_registry_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "openms_write_tool_registry(${out_file}): unexpected arguments '${_registry_UNPARSED_ARGUMENTS}'") + endif() + list(LENGTH TOPP_TOOLS _tool_count) + list(LENGTH TOPP_TOOL_CATEGORIES _category_count) + if(NOT _tool_count EQUAL _category_count) + message(FATAL_ERROR "The TOPP tool declarations are inconsistent: ${_tool_count} tools but ${_category_count} " + "categories. Both lists are only ever appended to by openms_topp_tool().") + endif() + + ## Ordered by tool name, so a reconfigure that declares the same tools produces a + ## byte-identical file. Sorting the names themselves rather than "namecategory" pairs: + ## any separator sorts somewhere among the letters and would order 'FooBar' before 'Foo'. + set(_sorted_names ${TOPP_TOOLS}) + if("TOOLS" IN_LIST ARGN) + foreach(_name IN LISTS _registry_TOOLS) + if(NOT _name IN_LIST TOPP_TOOLS) + message(FATAL_ERROR "openms_write_tool_registry(${out_file}): '${_name}' is not a declared tool") + endif() + endforeach() + set(_sorted_names ${_registry_TOOLS}) + endif() + list(LENGTH _sorted_names _tool_count) + if(_tool_count EQUAL 0) + file(REMOVE "${out_file}") + message(STATUS "TOPP tool registry: no tools, ${out_file} not written") + return() + endif() + list(SORT _sorted_names CASE INSENSITIVE) + + set(_content +"# GENERATED FILE, do not edit and do not commit. +# +# The TOPP tool registry: what ToolHandler lists, and the category TOPPAS groups each tool +# under. Written by openms_write_tool_registry() (cmake/topp_tool_macros.cmake) from the +# openms_topp_tool() declarations in src/topp/executables.cmake and, for the tools that need +# the GUI library, src/openms_gui/CMakeLists.txt. To add a tool, declare it there; it is +# built and registered by that one declaration. +# +# A tool describes itself (parameters, formats, documentation) through its own binary, via +# -write_ctd, so the registry carries nothing but the name and the category. Tools built +# outside this repository register themselves by installing their own *.tsv alongside this +# one; a name may be registered only once across all of them. +# +# \t +") + foreach(_name IN LISTS _sorted_names) + ## openms_topp_tool() rejects a duplicate name, so this finds the one declaration. + list(FIND TOPP_TOOLS "${_name}" _index) + list(GET TOPP_TOOL_CATEGORIES ${_index} _category) + string(APPEND _content "${_name}\t${_category}\n") + endforeach() + + ## Only rewrite on a real change, so a reconfigure does not restamp the file. + set(_previous "") + if(EXISTS "${out_file}") + file(READ "${out_file}" _previous) + endif() + if(NOT _previous STREQUAL _content) + file(WRITE "${out_file}" "${_content}") + endif() + message(STATUS "TOPP tool registry: ${_tool_count} tools -> ${out_file}") +endfunction() diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt new file mode 100644 index 000000000..82f2436bf --- /dev/null +++ b/doc/CMakeLists.txt @@ -0,0 +1,380 @@ +# Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin +# SPDX-License-Identifier: BSD-3-Clause +# +# -------------------------------------------------------------------------- +# $Maintainer: Stephan Aiche, Chris Bielow $ +# $Authors: Andreas Bertsch, Chris Bielow, Stephan Aiche $ +# -------------------------------------------------------------------------- + + +project("OpenMS_doc") + +#------------------------------------------------------------------------------ +# helper macro +#------------------------------------------------------------------------------ +macro(make_doxygen_path doxygen_style_list_var doc_path_list_var) + set(${doxygen_style_list_var} "") + foreach(_doc_path ${${doc_path_list_var}}) + set(${doxygen_style_list_var} "\"${_doc_path}\" ${${doxygen_style_list_var}}") + endforeach() +endmacro() + +if(ENABLE_DOCS) + message(STATUS "Documentation is built (-D ENABLE_DOCS=On).") + + #------------------------------------------------------------------------------ + # decide which doc target is part of all + #------------------------------------------------------------------------------ + if (HAS_XSERVER) + set(_DOC_ALL "ALL") + set(_DOC_MINIMAL_ALL "") + set(_DOC_MINIMAL_EXTRA_MESSAGE ) + else () + set(_DOC_ALL "") + set(_DOC_MINIMAL_ALL "ALL") + set(_DOC_MINIMAL_EXTRA_MESSAGE + COMMAND ${CMAKE_COMMAND} -E echo "We build only a minimal doc since OpenMS was configured without HAS_XSERVER=Off." + COMMAND ${CMAKE_COMMAND} -E echo "If you want the full doc, either execute cmake --build . --target doc manually" + COMMAND ${CMAKE_COMMAND} -E echo "or rerun cmake with -DHAS_XSERVER=On." + ) + endif () + + #------------------------------------------------------------------------------ + # doc programs + #------------------------------------------------------------------------------ + # TODO switch to target based linking and avoid re-searching Qt. + # At least reuse the COMPONENT variables + set(OpenMS_doc_executables) + include(doxygen/parameters/executables.cmake) + + set(OPENMS_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "doxygen/parameters") + + add_definitions(/DBOOST_ALL_NO_LIB) + + # build doc executables + foreach(i ${OpenMS_doc_executables}) + add_executable(${i} EXCLUDE_FROM_ALL doxygen/parameters/${i}.cpp) + + # let the doc progs decide how to handle a missing OpenMS_GUI library + if(WITH_GUI) + set_target_properties(${i} PROPERTIES COMPILE_DEFINITIONS "WITH_GUI=1") + target_link_libraries(${i} OpenMS OpenMS_CLI OpenMS_GUI) + else() + target_link_libraries(${i} OpenMS OpenMS_CLI) + endif() + endforeach(i) + + # collection target + add_custom_target(doc_progs) + add_dependencies(doc_progs ${OpenMS_doc_executables}) + if(TARGET TOPP) + add_dependencies(doc_progs TOPP) + endif() + + if(WITH_GUI) + add_dependencies(doc_progs GUI) + endif() + + #------------------------------------------------------------------------------ + # Initialize variables needed for a proper doxygen configuration + #------------------------------------------------------------------------------ + set(CF_OPENMS_BIN_PATH ${PROJECT_BINARY_DIR}) + set(CF_OPENMS_SRC_PATH ${OPENMS_HOST_DIRECTORY}) + + # make it a doxygen conform list + make_doxygen_path(CF_OPENMS_DOCUMENTATION_DIRECTORIES OPENMS_DOCUMENTATION_DIRECTORIES) + make_doxygen_path(CF_OPENMS_DOCUMENTATION_STRIP_INCLUDES OPENMS_DOCUMENTATION_DIRECTORIES) + make_doxygen_path(CF_STRIP_PATH OPENMS_DOCUMENTATION_DIRECTORIES) + + #------------------------------------------------------------------------------ + # the doc targets + #------------------------------------------------------------------------------ + # TeX formulas in the HTML documentation are rendered client-side via MathJax + # (USE_MATHJAX=YES in the Doxyfiles), so LaTeX, dvips and ghostscript are not needed. + + if (Doxygen_FOUND) + + # check doxygen for bug with generated latex files + set(DOXYGEN_MIN_REQUIRED "1.8.13") + + ## NOTE: keep the all-caps DOXYGEN_VERSION here. The mixed-case Doxygen_VERSION only exists in + ## CMake >= 4.2; on older CMake it would be empty, making + ## this version check always fire and dropping the version argument passed to Doxygen_Warning_test + ## below. DOXYGEN_VERSION is set across the whole supported range (3.9 .. 4.2+). + if (DOXYGEN_VERSION VERSION_LESS DOXYGEN_MIN_REQUIRED ) + message(STATUS "Warning: Doxygen ( vers. installed = ${DOXYGEN_VERSION} < ${DOXYGEN_MIN_REQUIRED}) does not correctly process \\include commands in developer's installation instructions. This will make them incomplete. Upgrade Doxygen to fix.") + endif() + + ## DOT (Graphviz) is an optional component and only used by the opt-in 'doc_dot' target. + ## The main documentation (doc, doc_class_only, doc_noclass, doc_minimal) never runs dot: + ## Doxyfile.in sets HAVE_DOT = NO literally, and class inheritance diagrams are drawn by + ## doxygen's built-in generator. When dot is present, its full path is still substituted into + ## DOT_PATH (inherited by Doxyfile_dot); otherwise DOT_PATH is left empty, which avoids + ## `warning: the dot tool could not be found ...` in doxygen-error.log. + if (TARGET Doxygen::dot) + get_target_property(CF_DOXYGEN_DOT_EXECUTABLE Doxygen::dot IMPORTED_LOCATION) + else() + set(CF_DOXYGEN_DOT_EXECUTABLE "") + endif() + + ## Conditional documentation, for doxygen's @if