From 4650c0a0973a668ff59061750e9ff967333e7808 Mon Sep 17 00:00:00 2001 From: Derek Morris Date: Wed, 22 Feb 2023 17:29:12 -0800 Subject: [PATCH 1/4] Get code building under c++20 The only thing that seems to break when building under c++20 is that the u8-string literals change to char8_ts. However, we're not using any character in these literals that would require the support, and the rest of the code isn't using the right functions to have robust unicode support anyway, so I swapped to just classic char-string-literals. I did a drive-by improvement to allow for some automatic determination of the right functions to use for these lists, if someone does want to change the types back to u8-literals (so, char under c++14 and char8_t under c++20), but there's issues further throughout the code that uses these values that building under c++20 reveals; I suspect that we're not universally using the right string comparison functions. --- CMakeLists.txt | 7 +- makelinux.sh | 9 ++- pipelines/templates/build-linux.yml | 2 + src/msix/common/AppxManifestObject.cpp | 100 +++++++++++++----------- src/msix/unpack/ApplicabilityCommon.cpp | 23 ++++-- 5 files changed, 84 insertions(+), 57 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a7dabd68..bd13b3934 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,8 +11,11 @@ message(STATUS "--------------------------------") message(STATUS "CMake version: ${CMAKE_VERSION}") -# specify that this binary is to be built with C++14 -set(CMAKE_CXX_STANDARD 14) + +if(NOT ${CMAKE_CXX_STANDARD}) + # if not otherwise set, specify that this binary is to be built with C++14 + set(CMAKE_CXX_STANDARD 14) +endif() set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) diff --git a/makelinux.sh b/makelinux.sh index 06c95d13b..f4b33630e 100755 --- a/makelinux.sh +++ b/makelinux.sh @@ -16,6 +16,7 @@ usage() echo $'\t' "--pack Include packaging features. Sets validation parser on." echo $'\t' "--skip-samples Skip building samples." echo $'\t' "--skip-tests Skip building tests." + echo $'\t' "--extra Extra flags to CMake." } printsetup() @@ -28,6 +29,8 @@ printsetup() echo "Build tests:" $tests } +extraArgs="" + while [ "$1" != "" ]; do case $1 in -b ) shift @@ -49,6 +52,9 @@ while [ "$1" != "" ]; do ;; --skip-tests ) tests=off ;; + --extra ) shift + extraArgs="$extraArgs $1" + ;; * ) usage exit 1 esac @@ -71,5 +77,6 @@ cmake -DCMAKE_BUILD_TYPE=$build \ -DMSIX_PACK=$pack \ -DMSIX_SAMPLES=$samples \ -DMSIX_TESTS=$tests \ - -DLINUX=on .. + -DLINUX=on .. \ + $extraArgs make diff --git a/pipelines/templates/build-linux.yml b/pipelines/templates/build-linux.yml index 9a35084ab..6127ef502 100644 --- a/pipelines/templates/build-linux.yml +++ b/pipelines/templates/build-linux.yml @@ -23,6 +23,8 @@ jobs: debug_pack: _arguments: -b Debug --pack _artifact: LINUXchk-pack + debug_pack_cxx20: + _arguments: -b Debug --pack --extra -DCMAKE_CXX_STANDARD=20 steps: - task: Bash@3 diff --git a/src/msix/common/AppxManifestObject.cpp b/src/msix/common/AppxManifestObject.cpp index c4957e5f8..cc2d0e4ad 100644 --- a/src/msix/common/AppxManifestObject.cpp +++ b/src/msix/common/AppxManifestObject.cpp @@ -11,69 +11,77 @@ #include "AppxPackageInfo.hpp" #include +#include +#include namespace MSIX { template struct Entry { - const char* tdf; + // Change the string constant type here to match that of the Entry constants + // in targetDeviceFamilyList and capabilitiesList - that is, u8"" if those + // strings regain the u8 prefix. + typedef std::remove_const::type>::type u8char; + const u8char* tdf; + const size_t len; const T value; - Entry(const char* t, const T p) : tdf(t), value(p) {} + template + Entry(const u8char (&t)[new_len], const T p) : tdf(t), len(new_len), value(p) {} - inline bool operator==(const char* otherTdf) const { - return 0 == strcmp(tdf, otherTdf); + inline bool operator==(const u8char *otherTdf) const { + return 0 == std::char_traits::compare(tdf, otherTdf, len); } }; // ALL THE TargetDeviceFamily ENTRIES MUST BE LOWER-CASE static const Entry targetDeviceFamilyList[] = { - Entry(u8"windows.universal", MSIX_PLATFORM_WINDOWS10), - Entry(u8"windows.mobile", MSIX_PLATFORM_WINDOWS10), - Entry(u8"windows.desktop", MSIX_PLATFORM_WINDOWS10), - Entry(u8"windows.xbox", MSIX_PLATFORM_WINDOWS10), - Entry(u8"windows.team", MSIX_PLATFORM_WINDOWS10), - Entry(u8"windows.holographic", MSIX_PLATFORM_WINDOWS10), - Entry(u8"windows.iot", MSIX_PLATFORM_WINDOWS10), - Entry(u8"windows.server", MSIX_PLATFORM_WINDOWS10), - Entry(u8"apple.ios.all", MSIX_PLATFORM_IOS), - Entry(u8"apple.ios.phone", MSIX_PLATFORM_IOS), - Entry(u8"apple.ios.tablet", MSIX_PLATFORM_IOS), - Entry(u8"apple.ios.tv", MSIX_PLATFORM_IOS), - Entry(u8"apple.ios.watch", MSIX_PLATFORM_IOS), - Entry(u8"apple.macos.all", MSIX_PLATFORM_MACOS), - Entry(u8"google.android.all", MSIX_PLATFORM_AOSP), - Entry(u8"google.android.phone", MSIX_PLATFORM_AOSP), - Entry(u8"google.android.tablet", MSIX_PLATFORM_AOSP), - Entry(u8"google.android.desktop", MSIX_PLATFORM_AOSP), - Entry(u8"google.android.tv", MSIX_PLATFORM_AOSP), - Entry(u8"google.android.watch", MSIX_PLATFORM_AOSP), - Entry(u8"msixcore.desktop", MSIX_PLATFORM_CORE), - Entry(u8"msixcore.server", MSIX_PLATFORM_CORE), - Entry(u8"linux.all", MSIX_PLATFORM_LINUX), - Entry(u8"web.edge.all", MSIX_PLATFORM_WEB), - Entry(u8"web.blink.all", MSIX_PLATFORM_WEB), - Entry(u8"web.chromium.all", MSIX_PLATFORM_WEB), - Entry(u8"web.webkit.all", MSIX_PLATFORM_WEB), - Entry(u8"web.safari.all", MSIX_PLATFORM_WEB), - Entry(u8"web.all", MSIX_PLATFORM_WEB), - Entry(u8"platform.all", static_cast(MSIX_PLATFORM_ALL)), + Entry("windows.universal", MSIX_PLATFORM_WINDOWS10), + Entry("windows.mobile", MSIX_PLATFORM_WINDOWS10), + Entry("windows.desktop", MSIX_PLATFORM_WINDOWS10), + Entry("windows.xbox", MSIX_PLATFORM_WINDOWS10), + Entry("windows.team", MSIX_PLATFORM_WINDOWS10), + Entry("windows.holographic", MSIX_PLATFORM_WINDOWS10), + Entry("windows.iot", MSIX_PLATFORM_WINDOWS10), + Entry("windows.server", MSIX_PLATFORM_WINDOWS10), + Entry("apple.ios.all", MSIX_PLATFORM_IOS), + Entry("apple.ios.phone", MSIX_PLATFORM_IOS), + Entry("apple.ios.tablet", MSIX_PLATFORM_IOS), + Entry("apple.ios.tv", MSIX_PLATFORM_IOS), + Entry("apple.ios.watch", MSIX_PLATFORM_IOS), + Entry("apple.macos.all", MSIX_PLATFORM_MACOS), + Entry("google.android.all", MSIX_PLATFORM_AOSP), + Entry("google.android.phone", MSIX_PLATFORM_AOSP), + Entry("google.android.tablet", MSIX_PLATFORM_AOSP), + Entry("google.android.desktop", MSIX_PLATFORM_AOSP), + Entry("google.android.tv", MSIX_PLATFORM_AOSP), + Entry("google.android.watch", MSIX_PLATFORM_AOSP), + Entry("msixcore.desktop", MSIX_PLATFORM_CORE), + Entry("msixcore.server", MSIX_PLATFORM_CORE), + Entry("linux.all", MSIX_PLATFORM_LINUX), + Entry("web.edge.all", MSIX_PLATFORM_WEB), + Entry("web.blink.all", MSIX_PLATFORM_WEB), + Entry("web.chromium.all", MSIX_PLATFORM_WEB), + Entry("web.webkit.all", MSIX_PLATFORM_WEB), + Entry("web.safari.all", MSIX_PLATFORM_WEB), + Entry("web.all", MSIX_PLATFORM_WEB), + Entry("platform.all", static_cast(MSIX_PLATFORM_ALL)), }; static const Entry capabilitiesList[] = { - Entry(u8"internetClient", APPX_CAPABILITY_INTERNET_CLIENT), - Entry(u8"internetClientServer", APPX_CAPABILITY_INTERNET_CLIENT_SERVER), - Entry(u8"privateNetworkClientServer", APPX_CAPABILITY_PRIVATE_NETWORK_CLIENT_SERVER), - Entry(u8"documentsLibrary", APPX_CAPABILITY_DOCUMENTS_LIBRARY), - Entry(u8"picturesLibrary", APPX_CAPABILITY_PICTURES_LIBRARY), - Entry(u8"videosLibrary", APPX_CAPABILITY_VIDEOS_LIBRARY), - Entry(u8"musicLibrary", APPX_CAPABILITY_MUSIC_LIBRARY), - Entry(u8"enterpriseAuthentication", APPX_CAPABILITY_ENTERPRISE_AUTHENTICATION), - Entry(u8"sharedUserCertificates", APPX_CAPABILITY_SHARED_USER_CERTIFICATES), - Entry(u8"removableStorage", APPX_CAPABILITY_REMOVABLE_STORAGE), - Entry(u8"appointments", APPX_CAPABILITY_APPOINTMENTS), - Entry(u8"contacts", APPX_CAPABILITY_CONTACTS), + Entry("internetClient", APPX_CAPABILITY_INTERNET_CLIENT), + Entry("internetClientServer", APPX_CAPABILITY_INTERNET_CLIENT_SERVER), + Entry("privateNetworkClientServer", APPX_CAPABILITY_PRIVATE_NETWORK_CLIENT_SERVER), + Entry("documentsLibrary", APPX_CAPABILITY_DOCUMENTS_LIBRARY), + Entry("picturesLibrary", APPX_CAPABILITY_PICTURES_LIBRARY), + Entry("videosLibrary", APPX_CAPABILITY_VIDEOS_LIBRARY), + Entry("musicLibrary", APPX_CAPABILITY_MUSIC_LIBRARY), + Entry("enterpriseAuthentication", APPX_CAPABILITY_ENTERPRISE_AUTHENTICATION), + Entry("sharedUserCertificates", APPX_CAPABILITY_SHARED_USER_CERTIFICATES), + Entry("removableStorage", APPX_CAPABILITY_REMOVABLE_STORAGE), + Entry("appointments", APPX_CAPABILITY_APPOINTMENTS), + Entry("contacts", APPX_CAPABILITY_CONTACTS), }; AppxManifestObject::AppxManifestObject(IMsixFactory* factory, const ComPtr& stream) : m_factory(factory), m_stream(stream) diff --git a/src/msix/unpack/ApplicabilityCommon.cpp b/src/msix/unpack/ApplicabilityCommon.cpp index e526372d0..53c561c93 100644 --- a/src/msix/unpack/ApplicabilityCommon.cpp +++ b/src/msix/unpack/ApplicabilityCommon.cpp @@ -6,6 +6,8 @@ #include #include +#include +#include #include #include "AppxBundleManifest.hpp" @@ -14,22 +16,27 @@ namespace MSIX { struct Bcp47Entry { - const char* icu; - const char* bcp47; + // Change the string constant type here to match that of the Bcp47Entry constants + // in bcp47List - that is, u8"" if those strings regain the u8 prefix. + typedef std::remove_const::type>::type u8char; + const u8char* icu; + const size_t len; + const u8char* bcp47; - Bcp47Entry(const char* i, const char* b) : icu(i), bcp47(b) {} + template + Bcp47Entry(const u8char (&i)[new_len], const u8char* b) : icu(i), len(new_len), bcp47(b) {} - inline bool operator==(const char* otherIcui) const { - return 0 == strcmp(icu, otherIcui); + inline bool operator==(const u8char* otherIcui) const { + return 0 == std::char_traits::compare(icu, otherIcui, len); } }; // We've seen cases were uloc_toLanguageTag returns zh-CN. Add here any inconsistencies. // Some AppxBundleManifests have zh-CN, zh-TW, zh-HK as languages. static const Bcp47Entry bcp47List[] = { - Bcp47Entry(u8"zh-cn", u8"zh-Hans-CN"), - Bcp47Entry(u8"zh-hk", u8"zh-Hant-HK"), - Bcp47Entry(u8"zh-tw", u8"zh-Hant-TW"), + Bcp47Entry("zh-cn", "zh-Hans-CN"), + Bcp47Entry("zh-hk", "zh-Hant-HK"), + Bcp47Entry("zh-tw", "zh-Hant-TW"), }; Bcp47Tag::Bcp47Tag(const std::string& fullTag, bool allowPseudoLocale) From 5a8c8963de0756ec123396bda1cc6b3f2aec7553 Mon Sep 17 00:00:00 2001 From: Derek Morris Date: Fri, 24 Feb 2023 11:11:25 -0800 Subject: [PATCH 2/4] switch from an '--extra' flag to a '--cxxstd' one --- makelinux.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/makelinux.sh b/makelinux.sh index f4b33630e..75fd2ddcf 100755 --- a/makelinux.sh +++ b/makelinux.sh @@ -16,7 +16,7 @@ usage() echo $'\t' "--pack Include packaging features. Sets validation parser on." echo $'\t' "--skip-samples Skip building samples." echo $'\t' "--skip-tests Skip building tests." - echo $'\t' "--extra Extra flags to CMake." + echo $'\t' "--cxxstd (14|17|20) c++ standard to use (default 14)." } printsetup() @@ -29,7 +29,7 @@ printsetup() echo "Build tests:" $tests } -extraArgs="" +cxxstd="14" while [ "$1" != "" ]; do case $1 in @@ -52,8 +52,8 @@ while [ "$1" != "" ]; do ;; --skip-tests ) tests=off ;; - --extra ) shift - extraArgs="$extraArgs $1" + --cxxstd ) shift + cxxstd=$1 ;; * ) usage exit 1 @@ -78,5 +78,5 @@ cmake -DCMAKE_BUILD_TYPE=$build \ -DMSIX_SAMPLES=$samples \ -DMSIX_TESTS=$tests \ -DLINUX=on .. \ - $extraArgs + -DCMAKE_CXX_STANDARD=$cxxstd make From aa79bdad8f7e4fe7bc469752bbeaa52d02da44c1 Mon Sep 17 00:00:00 2001 From: Derek Morris Date: Tue, 22 Oct 2024 22:10:25 -0700 Subject: [PATCH 3/4] Handle c++20 implicit wstring conversion removal --- src/msix/pack/BundleValidationHelper.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/msix/pack/BundleValidationHelper.cpp b/src/msix/pack/BundleValidationHelper.cpp index 3b148ecfb..be12371c6 100644 --- a/src/msix/pack/BundleValidationHelper.cpp +++ b/src/msix/pack/BundleValidationHelper.cpp @@ -214,7 +214,7 @@ namespace MSIX { std::string packageFullName = packageIdInternal->GetPackageFullName(); std::ostringstream errorBuilder; errorBuilder << "The package with file name " << fileName << " and package full name " << packageFullName << " is not valid in the bundle because its manifest declares a value for " - << ElementsToTest[i] << " which is not supported in bundles. The minimum supported value is " << MinimumAllowedOSVersion << "."; + << wstring_to_utf8(ElementsToTest[i]) << " which is not supported in bundles. The minimum supported value is " << MinimumAllowedOSVersion << "."; ThrowErrorAndLog(Error::AppxManifestSemanticError, errorBuilder.str().c_str()); } } @@ -246,4 +246,4 @@ namespace MSIX { } } } -} \ No newline at end of file +} From 79425491cbe41f80d006f7fe5a114c1963168a4a Mon Sep 17 00:00:00 2001 From: Derek Morris Date: Tue, 22 Oct 2024 22:11:05 -0700 Subject: [PATCH 4/4] get things building under c++14 and c++20 --- cmake/msix_resources.cmake | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/cmake/msix_resources.cmake b/cmake/msix_resources.cmake index ed0678f23..242b0393c 100644 --- a/cmake/msix_resources.cmake +++ b/cmake/msix_resources.cmake @@ -27,12 +27,17 @@ if ((XML_PARSER MATCHES msxml6) OR (XML_PARSER MATCHES xerces)) # Used by namespace manager if (XML_PARSER MATCHES msxml6) set(CHAR_TYPE "wchar_t") - set(STR_COMP "wcscmp") set(STR_PREFIX "L") else() # xerces - set(CHAR_TYPE "char") - set(STR_COMP "strcmp") - set(STR_PREFIX "u8") + # Previously, this was set to use u8 prefixes. However, with c++20 u8 means that + # we start getting char8_t and its ilk. While this does generally mean that it's + # not consistent what encoding we use here, wiring up everything to convert back + # and forth in a standard manner is exceedingly difficult. + # + # If you want to go down that rabbit hole, change STR_PREFIX to "u8"; CHAR_TYPE, + # as defined below, will then be 'char' on c++14/17, and 'char8_t' on c++20. + set(STR_PREFIX "") + set(CHAR_TYPE "std::remove_const::type>::type") endif() if(USE_VALIDATION_PARSER) @@ -317,7 +322,7 @@ if ((XML_PARSER MATCHES msxml6) OR (XML_PARSER MATCHES xerces)) list(GET ${TRIPLET} 0 NAMESPACE) list(GET ${TRIPLET} 1 ALIAS) list(GET ${TRIPLET} 2 FILE) - string(APPEND RESULT "SchemaEntry(" "${STR_PREFIX}" \" "${NAMESPACE}" \", "${STR_PREFIX}" \" "${ALIAS}" \" , u8\" "${FILE}" \" "),\n\t\t") + string(APPEND RESULT "SchemaEntry(" "${STR_PREFIX}" \" "${NAMESPACE}" \", "${STR_PREFIX}" \" "${ALIAS}" \" , \" "${FILE}" \" "),\n\t\t") endforeach() set(${OUTPUT} ${RESULT} PARENT_SCOPE) endfunction() @@ -335,11 +340,13 @@ if ((XML_PARSER MATCHES msxml6) OR (XML_PARSER MATCHES xerces)) const ${CHAR_TYPE}* uri; const ${CHAR_TYPE}* alias; const char* schema; + const size_t len; - SchemaEntry(const ${CHAR_TYPE}* u, const ${CHAR_TYPE}* a, const char* s) : uri(u), alias(a), schema(s) {} + template + SchemaEntry(const ${CHAR_TYPE} (&u)[new_len], const ${CHAR_TYPE}* a, const char* s) : uri(u), alias(a), schema(s), len(new_len) {} inline bool operator==(const ${CHAR_TYPE}* otherUri) const { - return 0 == ${STR_COMP}(uri, otherUri); + return 0 == std::char_traits<${CHAR_TYPE}>::compare(uri, otherUri, len); } };