diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8336eee12..b75b06cfd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -273,6 +273,53 @@ jobs: _build/${{ matrix.arch }}/${{ matrix.config }}/*.lib _build/${{ matrix.arch }}/${{ matrix.config }}/*.pdb + test-llvm-mingw-cppwinrt: + name: 'llvm-mingw: Build and test' + strategy: + matrix: + arch: [i686, x86_64] + runs-on: windows-latest + steps: + - uses: actions/checkout@v3 + + - name: Install llvm-mingw toolchain + run: | + $llvm_mingw_version = "20220906" + Invoke-WebRequest "https://github.com/mstorsjo/llvm-mingw/releases/download/${llvm_mingw_version}/llvm-mingw-${llvm_mingw_version}-ucrt-${{ matrix.arch }}.zip" -OutFile llvm-mingw.zip + 7z x llvm-mingw.zip + rm llvm-mingw.zip + if (!(Test-Path "$pwd\llvm-mingw-${llvm_mingw_version}-ucrt-${{ matrix.arch }}\bin\clang++.exe")) { return 1 } + Add-Content $env:GITHUB_PATH "$pwd\llvm-mingw-${llvm_mingw_version}-ucrt-${{ matrix.arch }}\bin" + + - name: Build cppwinrt + run: | + mkdir build + cd build + cmake ../ -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Debug + cmake --build . --target cppwinrt + + - name: Upload cppwinrt.exe + uses: actions/upload-artifact@v3 + with: + name: llvm-mingw-build-${{ matrix.arch }}-bin + path: build/cppwinrt.exe + + - name: Build tests + run: | + cd build + cmake --build . --target test-vanilla test_win7 + + - name: Upload test binaries + uses: actions/upload-artifact@v3 + with: + name: llvm-mingw-tests-${{ matrix.arch }}-bin + path: build/test/*.exe + + - name: Run tests + run: | + cd build + ctest --verbose + build-msvc-natvis: name: 'Build natvis' strategy: diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..0a60ba31e --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,167 @@ +# This CMake build file is intended for use with the llvm-mingw toolchain: +# https://github.com/mstorsjo/llvm-mingw +# +# It most probably doesn't work with MSVC. + +cmake_minimum_required(VERSION 3.12) + +project(cppwinrt LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +set(CPPWINRT_BUILD_VERSION "2.3.4.5" CACHE STRING "The version string used for cppwinrt.") +add_compile_definitions(CPPWINRT_VERSION_STRING="${CPPWINRT_BUILD_VERSION}") + +# WinMD uses CreateFile2 which requires Windows 8. +add_compile_definitions(_WIN32_WINNT=0x0602) + + +# === prebuild: Generator tool for strings.cpp, strings.h, version.rc === + +set(PREBUILD_SRCS + prebuild/main.cpp + prebuild/pch.h +) +add_executable(prebuild ${PREBUILD_SRCS}) +target_include_directories(prebuild PRIVATE cppwinrt/) + + +# === Step to create autogenerated files === + +file(GLOB PREBUILD_STRINGS_FILES + LIST_DIRECTORIES false + CONFIGURE_DEPENDS + strings/*.h +) +add_custom_command( + OUTPUT + ${PROJECT_BINARY_DIR}/strings.cpp + ${PROJECT_BINARY_DIR}/version.rc + COMMAND "${PROJECT_BINARY_DIR}/prebuild.exe" ARGS "${PROJECT_SOURCE_DIR}/strings" "${PROJECT_BINARY_DIR}" + DEPENDS + prebuild + ${PREBUILD_STRINGS_FILES} + VERBATIM +) + + +# === cppwinrt === + +set(CPPWINRT_SRCS + cppwinrt/main.cpp + "${PROJECT_BINARY_DIR}/strings.cpp" +) + +set(CPPWINRT_HEADERS + cppwinrt/pch.h + cppwinrt/cmd_reader.h + cppwinrt/code_writers.h + cppwinrt/component_writers.h + cppwinrt/file_writers.h + cppwinrt/helpers.h + cppwinrt/pch.h + cppwinrt/settings.h + cppwinrt/task_group.h + cppwinrt/text_writer.h + cppwinrt/type_writers.h +) + +add_custom_command( + OUTPUT + "${PROJECT_BINARY_DIR}/app.manifest" + COMMAND ${CMAKE_COMMAND} -E copy "${PROJECT_SOURCE_DIR}/cppwinrt/app.manifest" "${PROJECT_BINARY_DIR}/app.manifest" + DEPENDS "${PROJECT_SOURCE_DIR}/cppwinrt/app.manifest" + VERBATIM +) +# Do the configure_file dance so that app.manifest.rc don't get modified every +# single time the project is reconfigured and trigger a rebuild. +file(WRITE "${PROJECT_BINARY_DIR}/app.manifest.rc.in" "1 24 \"app.manifest\"\n") +configure_file( + "${PROJECT_BINARY_DIR}/app.manifest.rc.in" + "${PROJECT_BINARY_DIR}/app.manifest.rc" + COPYONLY +) + +set(CPPWINRT_RESOURCES + "${PROJECT_BINARY_DIR}/app.manifest" + "${PROJECT_BINARY_DIR}/app.manifest.rc" + "${PROJECT_BINARY_DIR}/version.rc" +) + +add_executable(cppwinrt ${CPPWINRT_SRCS} ${CPPWINRT_RESOURCES} ${CPPWINRT_HEADERS}) +target_include_directories(cppwinrt PRIVATE ${PROJECT_BINARY_DIR}) +target_link_libraries(cppwinrt shlwapi) + + +# HACK: Handle the xmllite import lib. +# mingw-w64 before commit 5ac1a2c is missing the import lib for xmllite. This +# checks whether the current build environment provides libxmllite.a, and +# generates the import lib if needed. + +set(XMLLITE_LIBRARY xmllite) +if(MINGW) + function(TestLinkXmlLite OUTPUT_VARNAME) + include(CheckCXXSourceCompiles) + set(CMAKE_REQUIRED_LIBRARIES xmllite) + check_cxx_source_compiles(" +#include +int main() { + CreateXmlReader(__uuidof(IXmlReader), nullptr, nullptr); +} + " ${OUTPUT_VARNAME}) + endfunction() + + function(TestIsI386 OUTPUT_VARNAME) + include(CheckCXXSourceCompiles) + check_cxx_source_compiles(" +#if !defined(__i386__) && !defined(_M_IX86) +# error Not i386 +#endif +int main() {} + " ${OUTPUT_VARNAME}) + endfunction() + + TestLinkXmlLite(HAS_LIBXMLLITE) + if(NOT HAS_LIBXMLLITE) + TestIsI386(TARGET_IS_I386) + if(TARGET_IS_I386) + set(XMLLITE_DEF_FILE xmllite_i386) + else() + set(XMLLITE_DEF_FILE xmllite) + endif() + add_custom_command( + OUTPUT + "${PROJECT_BINARY_DIR}/libxmllite.a" + COMMAND dlltool -k -d "${PROJECT_SOURCE_DIR}/mingw-support/${XMLLITE_DEF_FILE}.def" -l "${PROJECT_BINARY_DIR}/libxmllite.a" + DEPENDS "${PROJECT_SOURCE_DIR}/mingw-support/${XMLLITE_DEF_FILE}.def" + VERBATIM + ) + add_custom_target(gen-libxmllite + DEPENDS "${PROJECT_BINARY_DIR}/libxmllite.a" + ) + set(XMLLITE_LIBRARY "${PROJECT_BINARY_DIR}/libxmllite.a") + add_dependencies(cppwinrt gen-libxmllite) + endif() +endif() +target_link_libraries(cppwinrt "${XMLLITE_LIBRARY}") + + +# === winmd: External header-only library for reading winmd files === + +include(ExternalProject) +ExternalProject_Add(winmd + URL https://github.com/microsoft/winmd/releases/download/1.0.210629.2/Microsoft.Windows.WinMD.1.0.210629.2.nupkg + URL_HASH SHA256=4c5f29d948f5b3d724d229664c8f8e4823250d3c9f23ad8067b732fc7076d8c7 + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" +) +add_dependencies(cppwinrt winmd) +ExternalProject_Get_Property(winmd SOURCE_DIR) +set(winmd_SOURCE_DIR "${SOURCE_DIR}") +target_include_directories(cppwinrt PRIVATE "${winmd_SOURCE_DIR}") + + +include(CTest) +add_subdirectory(test) diff --git a/mingw-support/xmllite.def b/mingw-support/xmllite.def new file mode 100644 index 000000000..c96291d16 --- /dev/null +++ b/mingw-support/xmllite.def @@ -0,0 +1,8 @@ +LIBRARY "XmlLite.dll" +EXPORTS +CreateXmlReader +CreateXmlReaderInputWithEncodingCodePage +CreateXmlReaderInputWithEncodingName +CreateXmlWriter +CreateXmlWriterOutputWithEncodingCodePage +CreateXmlWriterOutputWithEncodingName diff --git a/mingw-support/xmllite_i386.def b/mingw-support/xmllite_i386.def new file mode 100644 index 000000000..79921fce7 --- /dev/null +++ b/mingw-support/xmllite_i386.def @@ -0,0 +1,8 @@ +LIBRARY "XmlLite.dll" +EXPORTS +CreateXmlReader@12 +CreateXmlReaderInputWithEncodingCodePage@24 +CreateXmlReaderInputWithEncodingName@24 +CreateXmlWriter@12 +CreateXmlWriterOutputWithEncodingCodePage@16 +CreateXmlWriterOutputWithEncodingName@16 diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 000000000..4cf322da9 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,40 @@ +# The tests use newer C++ features. +set(CMAKE_CXX_STANDARD 20) + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + +include_directories("${CMAKE_CURRENT_SOURCE_DIR}") +include_directories("${PROJECT_SOURCE_DIR}/cppwinrt") +include_directories("${CMAKE_CURRENT_BINARY_DIR}/cppwinrt") + +function(TestIsX64 OUTPUT_VARNAME) + include(CheckCXXSourceCompiles) + check_cxx_source_compiles(" +#if !defined(__x86_64__) && !defined(_M_X64) +# error Not x86_64 +#endif +int main() {} + " ${OUTPUT_VARNAME}) +endfunction() +TestIsX64(TARGET_IS_X64) +if(TARGET_IS_X64) + add_compile_options(-mcx16) +endif() + + +add_custom_command( + OUTPUT + "${CMAKE_CURRENT_BINARY_DIR}/cppwinrt/winrt/base.h" + COMMAND "${PROJECT_BINARY_DIR}/cppwinrt" -input local -output "${CMAKE_CURRENT_BINARY_DIR}/cppwinrt" -verbose + DEPENDS + cppwinrt + VERBATIM +) +add_custom_target(build-cppwinrt-projection + DEPENDS + "${CMAKE_CURRENT_BINARY_DIR}/cppwinrt/winrt/base.h" +) + + +add_subdirectory(test) +add_subdirectory(test_win7) diff --git a/test/mingw_com_support.h b/test/mingw_com_support.h new file mode 100644 index 000000000..80e56455b --- /dev/null +++ b/test/mingw_com_support.h @@ -0,0 +1,13 @@ +#if defined(__clang__) +#define HAS_DECLSPEC_UUID __has_declspec_attribute(uuid) +#elif defined(_MSC_VER) +#define HAS_DECLSPEC_UUID 1 +#else +#define HAS_DECLSPEC_UUID 0 +#endif + +#if HAS_DECLSPEC_UUID +#define DECLSPEC_UUID(x) __declspec(uuid(x)) +#else +#define DECLSPEC_UUID(x) +#endif diff --git a/test/test/CMakeLists.txt b/test/test/CMakeLists.txt new file mode 100644 index 000000000..f5921a0bc --- /dev/null +++ b/test/test/CMakeLists.txt @@ -0,0 +1,71 @@ +file(GLOB TEST_SRCS + LIST_DIRECTORIES false + CONFIGURE_DEPENDS + *.cpp +) +list(FILTER TEST_SRCS EXCLUDE REGEX "/(main|pch)\\.cpp") + + +# We can't build test_component[*] for mingw-w64 because it doesn't have an +# alternative to midl that can produce winmd files. Also, even if we do manage +# to reuse the MSVC-compiled binaries, mingw-w64 is still missing +# windowsnumerics.impl.h which is needed to provide the types +# winrt::Windows::Foundation::Numerics::float2 and friends that the components +# use. +list(APPEND BROKEN_TESTS + agility + delegates + enum + event_deferral + in_params + in_params_abi + no_make_detection + noexcept + optional + out_params + out_params_abi + parent_includes + rational + return_params + return_params_abi + struct_delegate + structs + uniform_in_params + velocity +) + +list(APPEND BROKEN_TESTS + # depends on pplawait.h + when +) + +# Exclude broken tests +foreach(TEST_SRCS_EXCLUDE_ITEM IN LISTS BROKEN_TESTS) + list(FILTER TEST_SRCS EXCLUDE REGEX "/${TEST_SRCS_EXCLUDE_ITEM}\\.cpp") +endforeach() + +add_executable(test-vanilla main.cpp ${TEST_SRCS}) +set_target_properties(test-vanilla PROPERTIES OUTPUT_NAME "test") +target_link_libraries(test-vanilla runtimeobject) + +target_precompile_headers(test-vanilla PRIVATE pch.h) +set_source_files_properties( + main.cpp + coro_foundation.cpp + coro_system.cpp + coro_threadpool.cpp + coro_uicore.cpp + custom_activation.cpp + generic_type_names.cpp + guid_include.cpp + inspectable_interop.cpp + module_lock_dll.cpp + PROPERTIES SKIP_PRECOMPILE_HEADERS true +) + +add_dependencies(test-vanilla build-cppwinrt-projection) + +add_test( + NAME test + COMMAND "$" +) diff --git a/test/test/async_auto_cancel.cpp b/test/test/async_auto_cancel.cpp index ef5ce2aa3..bffcb6e44 100644 --- a/test/test/async_auto_cancel.cpp +++ b/test/test/async_auto_cancel.cpp @@ -83,7 +83,7 @@ namespace } } -#if defined(__clang__) +#if defined(__clang__) && defined(_MSC_VER) // FIXME: Test is known to segfault when built with Clang. TEST_CASE("async_auto_cancel", "[.clang-crash]") #else diff --git a/test/test/async_cancel_callback.cpp b/test/test/async_cancel_callback.cpp index 98a08ff99..c99e1dad4 100644 --- a/test/test/async_cancel_callback.cpp +++ b/test/test/async_cancel_callback.cpp @@ -93,7 +93,7 @@ namespace } } -#if defined(__clang__) +#if defined(__clang__) && defined(_MSC_VER) // FIXME: Test is known to segfault when built with Clang. TEST_CASE("async_cancel_callback", "[.clang-crash]") #else diff --git a/test/test/async_check_cancel.cpp b/test/test/async_check_cancel.cpp index fb661d8c8..7547609f6 100644 --- a/test/test/async_check_cancel.cpp +++ b/test/test/async_check_cancel.cpp @@ -104,7 +104,7 @@ namespace } } -#if defined(__clang__) +#if defined(__clang__) && defined(_MSC_VER) // FIXME: Test is known to segfault when built with Clang. TEST_CASE("async_check_cancel", "[.clang-crash]") #else diff --git a/test/test/async_propagate_cancel.cpp b/test/test/async_propagate_cancel.cpp index 2739897ff..a3e5af749 100644 --- a/test/test/async_propagate_cancel.cpp +++ b/test/test/async_propagate_cancel.cpp @@ -128,7 +128,7 @@ namespace } } -#if defined(__clang__) +#if defined(__clang__) && defined(_MSC_VER) // FIXME: Test is known to segfault when built with Clang. TEST_CASE("async_propagate_cancel", "[.clang-crash]") #else diff --git a/test/test/async_throw.cpp b/test/test/async_throw.cpp index bca1e9b26..779351439 100644 --- a/test/test/async_throw.cpp +++ b/test/test/async_throw.cpp @@ -77,7 +77,7 @@ namespace } } -#if defined(__clang__) +#if defined(__clang__) && defined(_MSC_VER) // FIXME: Test is known to segfault when built with Clang. TEST_CASE("async_throw", "[.clang-crash]") #else diff --git a/test/test/async_wait_for.cpp b/test/test/async_wait_for.cpp index d25664495..d7613083c 100644 --- a/test/test/async_wait_for.cpp +++ b/test/test/async_wait_for.cpp @@ -96,7 +96,7 @@ namespace } } -#if defined(__clang__) +#if defined(__clang__) && defined(_MSC_VER) // FIXME: Test is known to segfault when built with Clang. TEST_CASE("async_wait_for", "[.clang-crash]") #else diff --git a/test/test/await_adapter.cpp b/test/test/await_adapter.cpp index 15a179e49..809567695 100644 --- a/test/test/await_adapter.cpp +++ b/test/test/await_adapter.cpp @@ -93,7 +93,7 @@ namespace } } -#if defined(__clang__) && (defined(_M_IX86) || defined(__i386__)) +#if defined(__clang__) && defined(_MSC_VER) && (defined(_M_IX86) || defined(__i386__)) // FIXME: Test is known to segfault on x86 when built with Clang. TEST_CASE("await_adapter", "[.clang-crash]") #else diff --git a/test/test/box_array.cpp b/test/test/box_array.cpp index 1c5b4a966..04377b334 100644 --- a/test/test/box_array.cpp +++ b/test/test/box_array.cpp @@ -8,17 +8,17 @@ namespace T defaultValue{}; winrt::com_array ary{ otherValue, defaultValue }; auto box = winrt::box_value(ary); - winrt::com_array unbox = box.try_as>().value(); + winrt::com_array unbox = box.template try_as>().value(); REQUIRE(unbox.size() == 2); REQUIRE(unbox.at(0) == otherValue); REQUIRE(unbox.at(1) == defaultValue); - unbox = box.as>(); + unbox = box.template as>(); REQUIRE(unbox.size() == 2); REQUIRE(unbox.at(0) == otherValue); REQUIRE(unbox.at(1) == defaultValue); if constexpr (!std::is_same_v) { - unbox = box.as>>().Value(); + unbox = box.template as>>().Value(); REQUIRE(unbox.size() == 2); REQUIRE(unbox.at(0) == otherValue); REQUIRE(unbox.at(1) == defaultValue); @@ -53,4 +53,4 @@ TEST_CASE("box_array") Verify({ 1,1 }); Verify({ 1,1 }); Verify({ 1,1,1,1 }); -} \ No newline at end of file +} diff --git a/test/test/capture.cpp b/test/test/capture.cpp index 8c75681b4..9019d1e34 100644 --- a/test/test/capture.cpp +++ b/test/test/capture.cpp @@ -3,12 +3,16 @@ using namespace winrt; using namespace Windows::Foundation; -struct __declspec(uuid("5fb96f8d-409c-42a9-99a7-8a95c1459dbd")) ICapture : ::IUnknown +struct DECLSPEC_UUID("5fb96f8d-409c-42a9-99a7-8a95c1459dbd") ICapture : ::IUnknown { virtual int32_t __stdcall GetValue() noexcept = 0; virtual int32_t __stdcall CreateMemberCapture(int32_t value, GUID const& iid, void** object) noexcept = 0; }; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(ICapture, 0x5fb96f8d, 0x409c, 0x42a9, 0x99, 0xa7, 0x8a, 0x95, 0xc1, 0x45, 0x9d, 0xbd) +#endif + struct Capture : implements { int32_t const m_value{}; diff --git a/test/test/disconnected.cpp b/test/test/disconnected.cpp index ac97f8477..13fcad601 100644 --- a/test/test/disconnected.cpp +++ b/test/test/disconnected.cpp @@ -171,6 +171,12 @@ struct non_agile_abandoned_action : implements m_disconnect; }; +// Not yet buildable on mingw-w64. +// Missing CLSID_ContextSwitcher, IID_ICallbackWithNoReentrancyToApplicationSTA +// and __uuidof(IContextCallback). Also, the lambda needs to have __stdcall +// specified on it but there is a Clang crash bug blocking this: +// https://github.com/llvm/llvm-project/issues/58366 +#if !defined(__MINGW32__) namespace { template @@ -285,3 +291,4 @@ TEST_CASE("disconnected,double") test.get(); } +#endif diff --git a/test/test/generic_type_names.cpp b/test/test/generic_type_names.cpp index 580d69ac3..5a2d648a2 100644 --- a/test/test/generic_type_names.cpp +++ b/test/test/generic_type_names.cpp @@ -120,6 +120,7 @@ TEST_CASE("generic_type_names") IReference); REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", IReference); +#if __has_include() REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", IReference); REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", @@ -134,6 +135,7 @@ TEST_CASE("generic_type_names") IReference); REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", IReference); +#endif // Enums, structs, IInspectable, classes, and delegates diff --git a/test/test/generic_types.h b/test/test/generic_types.h index d96b3bbfe..5ddba76d9 100644 --- a/test/test/generic_types.h +++ b/test/test/generic_types.h @@ -3,7 +3,9 @@ using namespace winrt; using namespace Windows::Foundation; using namespace Windows::Foundation::Collections; +#if __has_include() using namespace Windows::Foundation::Numerics; +#endif using namespace std::literals; #define REQUIRE_EQUAL_GUID(left, ...) STATIC_REQUIRE(equal(guid(left), guid_of<__VA_ARGS__>())); @@ -92,6 +94,7 @@ namespace REQUIRE_EQUAL_GUID("84F14C22-A00A-5272-8D3D-82112E66DF00", IReference); REQUIRE_EQUAL_GUID("80423F11-054F-5EAC-AFD3-63B6CE15E77B", IReference); REQUIRE_EQUAL_GUID("61723086-8e53-5276-9f36-2a4bb93e2b75", IReference); +#if __has_include() REQUIRE_EQUAL_GUID("48F6A69E-8465-57AE-9400-9764087F65AD", IReference); REQUIRE_EQUAL_GUID("1EE770FF-C954-59CA-A754-6199A9BE282C", IReference); REQUIRE_EQUAL_GUID("A5E843C9-ED20-5339-8F8D-9FE404CF3654", IReference); @@ -99,6 +102,7 @@ namespace REQUIRE_EQUAL_GUID("DACBFFDC-68EF-5FD0-B657-782D0AC9807E", IReference); REQUIRE_EQUAL_GUID("B27004BB-C014-5DCE-9A21-799C5A3C1461", IReference); REQUIRE_EQUAL_GUID("46D542A1-52F7-58E7-ACFC-9A6D364DA022", IReference); +#endif // Enums, structs, IInspectable, classes, and delegates diff --git a/test/test/initialize.cpp b/test/test/initialize.cpp index dbd95c3fe..e5532fe2d 100644 --- a/test/test/initialize.cpp +++ b/test/test/initialize.cpp @@ -5,11 +5,11 @@ using namespace Windows::Foundation; namespace { - class some_exception : public std::exception + class some_exception : public std::runtime_error { public: some_exception() noexcept - : exception("some_exception", 1) + : runtime_error("some_exception") { } }; diff --git a/test/test/inspectable_interop.cpp b/test/test/inspectable_interop.cpp index d693a6062..bfe46d041 100644 --- a/test/test/inspectable_interop.cpp +++ b/test/test/inspectable_interop.cpp @@ -1,3 +1,4 @@ +#include "mingw_com_support.h" #include #include "winrt/Windows.Foundation.h" #include "catch.hpp" @@ -6,11 +7,18 @@ using namespace winrt; namespace { - struct __declspec(uuid("ed0dd761-c31e-4803-8cf9-22a2cb20ec47")) IBadInterop : ::IInspectable + struct DECLSPEC_UUID("ed0dd761-c31e-4803-8cf9-22a2cb20ec47") IBadInterop : ::IInspectable { virtual int32_t __stdcall JustSayNo() noexcept = 0; }; +} + +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IBadInterop, 0xed0dd761, 0xc31e, 0x4803, 0x8c, 0xf9, 0x22, 0xa2, 0xcb, 0x20, 0xec, 0x47) +#endif +namespace +{ struct Sample : implements { Windows::Foundation::IInspectable ActivateInstance() diff --git a/test/test/interop.cpp b/test/test/interop.cpp index 9ca4c94ea..ec5476d15 100644 --- a/test/test/interop.cpp +++ b/test/test/interop.cpp @@ -1,18 +1,24 @@ #include "pch.h" #include -struct __declspec(uuid("5040a5f4-796a-42ff-9f06-be89137a518f")) IBase : IUnknown +struct DECLSPEC_UUID("5040a5f4-796a-42ff-9f06-be89137a518f") IBase : IUnknown { }; -struct __declspec(uuid("529fed32-514f-4150-b1ba-15b47df700b7")) IDerived : IBase +struct DECLSPEC_UUID("529fed32-514f-4150-b1ba-15b47df700b7") IDerived : IBase { }; -struct __declspec(uuid("b81fb2a2-eab4-488a-96a7-434873c2c20b")) IMoreDerived : IDerived +struct DECLSPEC_UUID("b81fb2a2-eab4-488a-96a7-434873c2c20b") IMoreDerived : IDerived { }; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IBase, 0x5040a5f4, 0x796a, 0x42ff, 0x9f, 0x06, 0xbe, 0x89, 0x13, 0x7a, 0x51, 0x8f) +__CRT_UUID_DECL(IDerived, 0x529fed32, 0x514f, 0x4150, 0xb1, 0xba, 0x15, 0xb4, 0x7d, 0xf7, 0x00, 0xb7) +__CRT_UUID_DECL(IMoreDerived, 0xb81fb2a2, 0xeab4, 0x488a, 0x96, 0xa7, 0x43, 0x48, 0x73, 0xc2, 0xc2, 0x0b) +#endif + namespace winrt { template<> bool is_guid_of(guid const& id) noexcept diff --git a/test/test/main.cpp b/test/test/main.cpp index cb2203171..10150c369 100644 --- a/test/test/main.cpp +++ b/test/test/main.cpp @@ -1,5 +1,9 @@ #include #define CATCH_CONFIG_RUNNER + +// Force reportFatal to be available on mingw-w64 +#define CATCH_CONFIG_WINDOWS_SEH + #include "catch.hpp" #include "winrt/base.h" diff --git a/test/test/notify_awaiter.cpp b/test/test/notify_awaiter.cpp index de2c5f1ab..0305e5a23 100644 --- a/test/test/notify_awaiter.cpp +++ b/test/test/notify_awaiter.cpp @@ -144,6 +144,14 @@ namespace } } +// GNUC does not support MSVC extension lambda call convention conversion +// https://devblogs.microsoft.com/oldnewthing/20150220-00/?p=44623 +#if defined(__GNUC__) +#define LAMBDA_STDCALL __attribute__((stdcall)) +#else +#define LAMBDA_STDCALL +#endif + TEST_CASE("notify_awaiter") { // Everything works fine when nobody is watching. @@ -156,12 +164,12 @@ TEST_CASE("notify_awaiter") // Hook up some watchers. - winrt_suspend_handler = [](void const* token) noexcept + winrt_suspend_handler = [](void const* token) LAMBDA_STDCALL noexcept { watcher.push_back({ token, notification::suspend }); }; - winrt_resume_handler = [](void const* token) noexcept + winrt_resume_handler = [](void const* token) LAMBDA_STDCALL noexcept { auto last = watcher.back(); REQUIRE(last.first == token); diff --git a/test/test/numerics.cpp b/test/test/numerics.cpp index cfc73c0dd..23b2dfb34 100644 --- a/test/test/numerics.cpp +++ b/test/test/numerics.cpp @@ -5,9 +5,11 @@ using namespace Windows::Foundation::Numerics; TEST_CASE("numerics") { +#if __has_include() // Basic smoke test exercising SIMD intrinsics used by numerics. auto one = float4::one(); REQUIRE(one * one == one); +#endif } diff --git a/test/test/pch.h b/test/test/pch.h index 65588aec3..24d65c225 100644 --- a/test/test/pch.h +++ b/test/test/pch.h @@ -2,6 +2,8 @@ #pragma warning(4: 4458) // ensure we compile clean with this warning enabled +#include "mingw_com_support.h" + #define WINRT_LEAN_AND_MEAN #include #include "winrt/Windows.Foundation.Collections.h" diff --git a/test/test/variadic_delegate.cpp b/test/test/variadic_delegate.cpp index a4d0c4a80..6ffbe5ef4 100644 --- a/test/test/variadic_delegate.cpp +++ b/test/test/variadic_delegate.cpp @@ -150,7 +150,7 @@ TEST_CASE("variadic_delegate") // Exception { - delegate<> d = [] { throw std::exception("what"); }; + delegate<> d = [] { throw std::runtime_error("what"); }; REQUIRE_THROWS_AS(d(), std::exception); } diff --git a/test/test_win7/CMakeLists.txt b/test/test_win7/CMakeLists.txt new file mode 100644 index 000000000..7ada247c4 --- /dev/null +++ b/test/test_win7/CMakeLists.txt @@ -0,0 +1,58 @@ +file(GLOB TEST_SRCS + LIST_DIRECTORIES false + CONFIGURE_DEPENDS + *.cpp +) +list(FILTER TEST_SRCS EXCLUDE REGEX "/(main|pch)\\.cpp") + + +# We can't build test_component[*] for mingw-w64 because it doesn't have an +# alternative to midl that can produce winmd files. Also, even if we do manage +# to reuse the MSVC-compiled binaries, mingw-w64 is still missing +# windowsnumerics.impl.h which is needed to provide the types +# winrt::Windows::Foundation::Numerics::float2 and friends that the components +# use. +list(APPEND BROKEN_TESTS + agility + delegates + enum + in_params + no_make_detection + noexcept + out_params + parent_includes + return_params + structs + uniform_in_params + velocity +) + +list(APPEND BROKEN_TESTS + # depends on pplawait.h + when +) + +# Exclude broken tests +foreach(TEST_SRCS_EXCLUDE_ITEM IN LISTS BROKEN_TESTS) + list(FILTER TEST_SRCS EXCLUDE REGEX "/${TEST_SRCS_EXCLUDE_ITEM}\\.cpp") +endforeach() + +add_executable(test_win7 main.cpp ${TEST_SRCS}) + +target_precompile_headers(test_win7 PRIVATE pch.h) +set_source_files_properties( + main.cpp + coro_foundation.cpp + coro_threadpool.cpp + generic_type_names.cpp + inspectable_interop.cpp + module_lock_dll.cpp + PROPERTIES SKIP_PRECOMPILE_HEADERS true +) + +add_dependencies(test_win7 build-cppwinrt-projection) + +add_test( + NAME test_win7 + COMMAND "$" +) diff --git a/test/test_win7/capture.cpp b/test/test_win7/capture.cpp index 8c75681b4..9019d1e34 100644 --- a/test/test_win7/capture.cpp +++ b/test/test_win7/capture.cpp @@ -3,12 +3,16 @@ using namespace winrt; using namespace Windows::Foundation; -struct __declspec(uuid("5fb96f8d-409c-42a9-99a7-8a95c1459dbd")) ICapture : ::IUnknown +struct DECLSPEC_UUID("5fb96f8d-409c-42a9-99a7-8a95c1459dbd") ICapture : ::IUnknown { virtual int32_t __stdcall GetValue() noexcept = 0; virtual int32_t __stdcall CreateMemberCapture(int32_t value, GUID const& iid, void** object) noexcept = 0; }; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(ICapture, 0x5fb96f8d, 0x409c, 0x42a9, 0x99, 0xa7, 0x8a, 0x95, 0xc1, 0x45, 0x9d, 0xbd) +#endif + struct Capture : implements { int32_t const m_value{}; diff --git a/test/test_win7/generic_type_names.cpp b/test/test_win7/generic_type_names.cpp index 580d69ac3..a91266a83 100644 --- a/test/test_win7/generic_type_names.cpp +++ b/test/test_win7/generic_type_names.cpp @@ -114,6 +114,7 @@ TEST_CASE("generic_type_names") IReference); REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", IReference); +#if __has_include() REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", IReference); REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", @@ -134,6 +135,7 @@ TEST_CASE("generic_type_names") IReference); REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", IReference); +#endif // Enums, structs, IInspectable, classes, and delegates diff --git a/test/test_win7/generic_types.h b/test/test_win7/generic_types.h index d96b3bbfe..5ddba76d9 100644 --- a/test/test_win7/generic_types.h +++ b/test/test_win7/generic_types.h @@ -3,7 +3,9 @@ using namespace winrt; using namespace Windows::Foundation; using namespace Windows::Foundation::Collections; +#if __has_include() using namespace Windows::Foundation::Numerics; +#endif using namespace std::literals; #define REQUIRE_EQUAL_GUID(left, ...) STATIC_REQUIRE(equal(guid(left), guid_of<__VA_ARGS__>())); @@ -92,6 +94,7 @@ namespace REQUIRE_EQUAL_GUID("84F14C22-A00A-5272-8D3D-82112E66DF00", IReference); REQUIRE_EQUAL_GUID("80423F11-054F-5EAC-AFD3-63B6CE15E77B", IReference); REQUIRE_EQUAL_GUID("61723086-8e53-5276-9f36-2a4bb93e2b75", IReference); +#if __has_include() REQUIRE_EQUAL_GUID("48F6A69E-8465-57AE-9400-9764087F65AD", IReference); REQUIRE_EQUAL_GUID("1EE770FF-C954-59CA-A754-6199A9BE282C", IReference); REQUIRE_EQUAL_GUID("A5E843C9-ED20-5339-8F8D-9FE404CF3654", IReference); @@ -99,6 +102,7 @@ namespace REQUIRE_EQUAL_GUID("DACBFFDC-68EF-5FD0-B657-782D0AC9807E", IReference); REQUIRE_EQUAL_GUID("B27004BB-C014-5DCE-9A21-799C5A3C1461", IReference); REQUIRE_EQUAL_GUID("46D542A1-52F7-58E7-ACFC-9A6D364DA022", IReference); +#endif // Enums, structs, IInspectable, classes, and delegates diff --git a/test/test_win7/inspectable_interop.cpp b/test/test_win7/inspectable_interop.cpp index d693a6062..95ee35522 100644 --- a/test/test_win7/inspectable_interop.cpp +++ b/test/test_win7/inspectable_interop.cpp @@ -6,11 +6,18 @@ using namespace winrt; namespace { - struct __declspec(uuid("ed0dd761-c31e-4803-8cf9-22a2cb20ec47")) IBadInterop : ::IInspectable + struct DECLSPEC_UUID("ed0dd761-c31e-4803-8cf9-22a2cb20ec47") IBadInterop : ::IInspectable { virtual int32_t __stdcall JustSayNo() noexcept = 0; }; +} + +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IBadInterop, 0xed0dd761, 0xc31e, 0x4803, 0x8c, 0xf9, 0x22, 0xa2, 0xcb, 0x20, 0xec, 0x47) +#endif +namespace +{ struct Sample : implements { Windows::Foundation::IInspectable ActivateInstance() diff --git a/test/test_win7/interop.cpp b/test/test_win7/interop.cpp index 9ca4c94ea..ec5476d15 100644 --- a/test/test_win7/interop.cpp +++ b/test/test_win7/interop.cpp @@ -1,18 +1,24 @@ #include "pch.h" #include -struct __declspec(uuid("5040a5f4-796a-42ff-9f06-be89137a518f")) IBase : IUnknown +struct DECLSPEC_UUID("5040a5f4-796a-42ff-9f06-be89137a518f") IBase : IUnknown { }; -struct __declspec(uuid("529fed32-514f-4150-b1ba-15b47df700b7")) IDerived : IBase +struct DECLSPEC_UUID("529fed32-514f-4150-b1ba-15b47df700b7") IDerived : IBase { }; -struct __declspec(uuid("b81fb2a2-eab4-488a-96a7-434873c2c20b")) IMoreDerived : IDerived +struct DECLSPEC_UUID("b81fb2a2-eab4-488a-96a7-434873c2c20b") IMoreDerived : IDerived { }; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IBase, 0x5040a5f4, 0x796a, 0x42ff, 0x9f, 0x06, 0xbe, 0x89, 0x13, 0x7a, 0x51, 0x8f) +__CRT_UUID_DECL(IDerived, 0x529fed32, 0x514f, 0x4150, 0xb1, 0xba, 0x15, 0xb4, 0x7d, 0xf7, 0x00, 0xb7) +__CRT_UUID_DECL(IMoreDerived, 0xb81fb2a2, 0xeab4, 0x488a, 0x96, 0xa7, 0x43, 0x48, 0x73, 0xc2, 0xc2, 0x0b) +#endif + namespace winrt { template<> bool is_guid_of(guid const& id) noexcept diff --git a/test/test_win7/main.cpp b/test/test_win7/main.cpp index cb2203171..10150c369 100644 --- a/test/test_win7/main.cpp +++ b/test/test_win7/main.cpp @@ -1,5 +1,9 @@ #include #define CATCH_CONFIG_RUNNER + +// Force reportFatal to be available on mingw-w64 +#define CATCH_CONFIG_WINDOWS_SEH + #include "catch.hpp" #include "winrt/base.h" diff --git a/test/test_win7/numerics.cpp b/test/test_win7/numerics.cpp index cfc73c0dd..23b2dfb34 100644 --- a/test/test_win7/numerics.cpp +++ b/test/test_win7/numerics.cpp @@ -5,9 +5,11 @@ using namespace Windows::Foundation::Numerics; TEST_CASE("numerics") { +#if __has_include() // Basic smoke test exercising SIMD intrinsics used by numerics. auto one = float4::one(); REQUIRE(one * one == one); +#endif } diff --git a/test/test_win7/pch.h b/test/test_win7/pch.h index 1989286de..92e8caa96 100644 --- a/test/test_win7/pch.h +++ b/test/test_win7/pch.h @@ -1,5 +1,7 @@ #pragma once +#include "mingw_com_support.h" + #define WINRT_LEAN_AND_MEAN #include #include "winrt/Windows.Foundation.Collections.h"