From 33d108ae0e65aab7edd123a2e8fad9ee4d97b2f6 Mon Sep 17 00:00:00 2001 From: Tristan Labelle Date: Fri, 20 Sep 2024 22:06:59 -0400 Subject: [PATCH] Extract GenerateWinMD.cmake to avoid recursive CMake invocation (#307) --- CMakeLists.txt | 4 +- InteropTests/CMakeLists.txt | 47 +++++++++---------- InteropTests/WinRTComponent/CMakeLists.txt | 38 +++++---------- .../WinRTComponent/GenerateWinMD.cmake | 29 ++++++++++++ 4 files changed, 67 insertions(+), 51 deletions(-) create mode 100644 InteropTests/WinRTComponent/GenerateWinMD.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 75fd1e5..f9705d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ message(STATUS "Building Generator subproject...") execute_process( COMMAND ${CMAKE_COMMAND} --build "${CMAKE_CURRENT_BINARY_DIR}/Generator" COMMAND_ERROR_IS_FATAL ANY) -set(SWIFT_WINRT_EXE "${CMAKE_CURRENT_BINARY_DIR}/Generator/Sources/SwiftWinRT/SwiftWinRT.exe") +set(SWIFTWINRT_EXE "${CMAKE_CURRENT_BINARY_DIR}/Generator/Sources/SwiftWinRT/SwiftWinRT.exe") -# Now build InteropTests, which depends on SWIFT_WINRT_EXE +# Now build InteropTests, which depends on SWIFTWINRT_EXE add_subdirectory(InteropTests) \ No newline at end of file diff --git a/InteropTests/CMakeLists.txt b/InteropTests/CMakeLists.txt index 2f424f4..f140b68 100644 --- a/InteropTests/CMakeLists.txt +++ b/InteropTests/CMakeLists.txt @@ -4,44 +4,43 @@ if(NOT DEFINED CMAKE_PROJECT_NAME) project(InteropTests LANGUAGES C Swift) endif() -if (NOT DEFINED SWIFT_WINRT_EXE) - message(FATAL_ERROR "SWIFT_WINRT_EXE must be defined") +if (NOT DEFINED SWIFTWINRT_EXE) + message(FATAL_ERROR "SWIFTWINRT_EXE must be defined") endif() -cmake_path(ABSOLUTE_PATH SWIFT_WINRT_EXE NORMALIZE OUTPUT_VARIABLE SWIFT_WINRT_EXE) +cmake_path(ABSOLUTE_PATH SWIFTWINRT_EXE NORMALIZE OUTPUT_VARIABLE SWIFTWINRT_EXE) # Generating projection sources will depend on WinRTComponent.winmd, so build it now -message(STATUS "Configuring WinRTComponent subproject...") -execute_process( - COMMAND ${CMAKE_COMMAND} - -S "${CMAKE_CURRENT_SOURCE_DIR}/WinRTComponent" - -B "${CMAKE_CURRENT_BINARY_DIR}/WinRTComponent" - -G "${CMAKE_GENERATOR}" - -D "CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" - -D CMAKE_CXX_COMPILER=cl.exe - -D "CMAKE_CXX_FLAGS=/std:c++latest /W4 /EHsc" - COMMAND_ERROR_IS_FATAL ANY) - -message(STATUS "Building WinRTComponent subproject...") -execute_process( - COMMAND ${CMAKE_COMMAND} - --build "${CMAKE_CURRENT_BINARY_DIR}/WinRTComponent" - COMMAND_ERROR_IS_FATAL ANY) -set(WINRTCOMPONENT_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/WinRTComponent") +set(WINRTCOMPONENT_IDL "${CMAKE_CURRENT_SOURCE_DIR}/WinRTComponent/WinRTComponent.idl") +set(WINRTCOMPONENT_WINMD "${CMAKE_CURRENT_BINARY_DIR}/WinRTComponent.winmd") +include(WinRTComponent/GenerateWinMD.cmake) # Generate Swift projection message(STATUS "Generating Swift projection for WinRTComponent...") cmake_path(CONVERT "${CMAKE_CURRENT_SOURCE_DIR}/GenerateProjection.ps1" TO_NATIVE_PATH_LIST SCRIPT_PATH_NATIVE) -cmake_path(CONVERT "${SWIFT_WINRT_EXE}" TO_NATIVE_PATH_LIST SWIFT_WINRT_EXE_NATIVE) -cmake_path(CONVERT "${WINRTCOMPONENT_BINARY_DIR}/WinRTComponent.winmd" TO_NATIVE_PATH_LIST WINMD_NATIVE) +cmake_path(CONVERT "${SWIFTWINRT_EXE}" TO_NATIVE_PATH_LIST SWIFTWINRT_EXE_NATIVE) +cmake_path(CONVERT "${WINRTCOMPONENT_WINMD}" TO_NATIVE_PATH_LIST WINRTCOMPONENT_WINMD_NATIVE) cmake_path(CONVERT "${CMAKE_CURRENT_BINARY_DIR}/Generated/Sources" TO_NATIVE_PATH_LIST OUTPUT_DIR_NATIVE) set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${SCRIPT_PATH_ARG}") execute_process( COMMAND powershell.exe -File "${SCRIPT_PATH_NATIVE}" - -SwiftWinRT "${SWIFT_WINRT_EXE_NATIVE}" - -WinMD "${WINMD_NATIVE}" + -SwiftWinRT "${SWIFTWINRT_EXE_NATIVE}" + -WinMD "${WINRTCOMPONENT_WINMD_NATIVE}" -OutputDir "${OUTPUT_DIR_NATIVE}" COMMAND_ERROR_IS_FATAL ANY) +# Define WinRTComponent build (requires the cl.exe compiler) +include(ExternalProject) +message(STATUS "Building WinRTComponent...") +ExternalProject_Add(WinRTComponent + SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/WinRTComponent" + BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/WinRTComponent" + CMAKE_ARGS + -D "WINRTCOMPONENT_WINMD=${WINRTCOMPONENT_WINMD}" + -D "CMAKE_CXX_COMPILER=cl.exe" + -D "CMAKE_CXX_FLAGS=/std:c++latest /W4 /EHsc" + INSTALL_COMMAND "" + TEST_COMMAND "") + # Build the support module if not already the case (by root CMakeLists.txt) if(NOT TARGET WindowsRuntime) add_subdirectory(../Support "${CMAKE_CURRENT_BINARY_DIR}/Support") diff --git a/InteropTests/WinRTComponent/CMakeLists.txt b/InteropTests/WinRTComponent/CMakeLists.txt index 30fb8b1..1dc6326 100644 --- a/InteropTests/WinRTComponent/CMakeLists.txt +++ b/InteropTests/WinRTComponent/CMakeLists.txt @@ -2,37 +2,23 @@ cmake_minimum_required(VERSION 3.21.0) project(WinRTComponent LANGUAGES CXX) -# Generate the WinMDs from the idl files -message(STATUS "Generating WinRTComponent.winmd...") -set(MIDLRT.EXE_PATH_NATIVE "$ENV{WindowsSdkVerBinPath}$ENV{VSCMD_ARG_HOST_ARCH}\\midlrt.exe") -cmake_path(CONVERT "$ENV{WindowsSdkDir}References\\$ENV{WindowsSDKVersion}" TO_CMAKE_PATH_LIST WINSDK_REFERENCES_DIR NORMALIZE) -set(FOUNDATIONCONTRACT_DIR "${WINSDK_REFERENCES_DIR}/Windows.Foundation.FoundationContract/4.0.0.0") -cmake_path(CONVERT "${FOUNDATIONCONTRACT_DIR}" TO_NATIVE_PATH_LIST METADATA_DIR_NATIVE) -cmake_path(CONVERT "${FOUNDATIONCONTRACT_DIR}/Windows.Foundation.FoundationContract.winmd" TO_NATIVE_PATH_LIST FOUNDATIONCONTRACT_WINMD_NATIVE) -cmake_path(CONVERT "${WINSDK_REFERENCES_DIR}/Windows.Foundation.UniversalApiContract/15.0.0.0/Windows.Foundation.UniversalApiContract.winmd" TO_NATIVE_PATH_LIST UNIVERSALAPICONTRACT_WINMD_NATIVE) -cmake_path(CONVERT "${CMAKE_CURRENT_BINARY_DIR}/WinRTComponent.winmd" TO_NATIVE_PATH_LIST WINRTCOMPONENT_WINMD_PATH_NATIVE) -cmake_path(CONVERT "${CMAKE_CURRENT_BINARY_DIR}/WinRTComponent.h" TO_NATIVE_PATH_LIST WINRTCOMPONENT_H_PATH_NATIVE) -cmake_path(CONVERT "${CMAKE_CURRENT_SOURCE_DIR}/WinRTComponent.idl" TO_NATIVE_PATH_LIST IDL_PATH_NATIVE) -execute_process( - COMMAND "${MIDLRT.EXE_PATH_NATIVE}" - /W1 /nologo /nomidl - /metadata_dir "${METADATA_DIR_NATIVE}" - /reference "${FOUNDATIONCONTRACT_WINMD_NATIVE}" - /reference "${UNIVERSALAPICONTRACT_WINMD_NATIVE}" - /winmd "${WINRTCOMPONENT_WINMD_PATH_NATIVE}" - /header "${WINRTCOMPONENT_H_PATH_NATIVE}" - "${IDL_PATH_NATIVE}" - COMMAND_ERROR_IS_FATAL ANY) +# Generate the WinRTComponent.winmd file if not previously done +if(NOT DEFINED WINRTCOMPONENT_WINMD) + set(WINRTCOMPONENT_IDL "${CMAKE_CURRENT_SOURCE_DIR}/WinRTComponent.idl") + set(WINRTCOMPONENT_WINMD "${CMAKE_CURRENT_BINARY_DIR}/WinRTComponent.winmd") + include(GenerateWinMD.cmake) +endif() # Generate the C++/WinRT boilerplate message(STATUS "Generating C++/WinRT boilerplate for WinRTComponent...") -set(CPPWINRT.EXE_PATH_NATIVE "$ENV{WindowsSdkVerBinPath}$ENV{VSCMD_ARG_HOST_ARCH}\\cppwinrt.exe") +set(CPPWINRT_EXE_NATIVE "$ENV{WindowsSdkVerBinPath}$ENV{VSCMD_ARG_HOST_ARCH}\\cppwinrt.exe") +cmake_path(CONVERT "${WINRTCOMPONENT_WINMD}" TO_NATIVE_PATH_LIST WINRTCOMPONENT_WINMD_NATIVE) string(REPLACE "\\" "" WINSDK_VERSION "$ENV{WindowsSDKVersion}") set(CPPWINRT_GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/CppWinRT") cmake_path(CONVERT "${CPPWINRT_GENERATED_DIR}" TO_NATIVE_PATH_LIST CPPWINRT_GENERATED_DIR_NATIVE) execute_process( - COMMAND "${CPPWINRT.EXE_PATH_NATIVE}" - -input "${WINRTCOMPONENT_WINMD_PATH_NATIVE}" + COMMAND "${CPPWINRT_EXE_NATIVE}" + -input "${WINRTCOMPONENT_WINMD_NATIVE}" -reference "${WINSDK_VERSION}" -component "${CPPWINRT_GENERATED_DIR_NATIVE}" -overwrite -optimize -output "${CPPWINRT_GENERATED_DIR_NATIVE}" @@ -47,4 +33,6 @@ add_library(WinRTComponent SHARED target_include_directories(WinRTComponent PRIVATE "${CMAKE_CURRENT_SOURCES_DIR}" "${CPPWINRT_GENERATED_DIR}") -target_precompile_headers(WinRTComponent PRIVATE pch.h) \ No newline at end of file +target_precompile_headers(WinRTComponent PRIVATE pch.h) + +set(WINRTCOMPONENT_WINMD "${CMAKE_CURRENT_BINARY_DIR}/WinRTComponent.winmd" PARENT_SCOPE) \ No newline at end of file diff --git a/InteropTests/WinRTComponent/GenerateWinMD.cmake b/InteropTests/WinRTComponent/GenerateWinMD.cmake new file mode 100644 index 0000000..b71aebe --- /dev/null +++ b/InteropTests/WinRTComponent/GenerateWinMD.cmake @@ -0,0 +1,29 @@ +# Generates the WinRTComponent.winmd file from the WinRTComponent.idl file. +if(NOT DEFINED WINRTCOMPONENT_IDL) + message(FATAL_ERROR "WINRTCOMPONENT_IDL is not defined") +endif() + +if(NOT DEFINED WINRTCOMPONENT_WINMD) + message(FATAL_ERROR "WINRTCOMPONENT_WINMD_PATH is not defined") +endif() + +message(STATUS "Generating WinRTComponent.winmd...") +set(MIDLRT_EXE_NATIVE "$ENV{WindowsSdkVerBinPath}$ENV{VSCMD_ARG_HOST_ARCH}\\midlrt.exe") +cmake_path(CONVERT "$ENV{WindowsSdkDir}References\\$ENV{WindowsSDKVersion}" TO_CMAKE_PATH_LIST WINSDK_REFERENCES_DIR NORMALIZE) +set(FOUNDATIONCONTRACT_DIR "${WINSDK_REFERENCES_DIR}/Windows.Foundation.FoundationContract/4.0.0.0") +cmake_path(CONVERT "${FOUNDATIONCONTRACT_DIR}" TO_NATIVE_PATH_LIST METADATA_DIR_NATIVE) +cmake_path(CONVERT "${FOUNDATIONCONTRACT_DIR}/Windows.Foundation.FoundationContract.winmd" TO_NATIVE_PATH_LIST FOUNDATIONCONTRACT_WINMD_NATIVE) +cmake_path(CONVERT "${WINSDK_REFERENCES_DIR}/Windows.Foundation.UniversalApiContract/15.0.0.0/Windows.Foundation.UniversalApiContract.winmd" TO_NATIVE_PATH_LIST UNIVERSALAPICONTRACT_WINMD_NATIVE) +cmake_path(CONVERT "${WINRTCOMPONENT_WINMD}" TO_NATIVE_PATH_LIST WINRTCOMPONENT_WINMD_NATIVE) +string(REPLACE ".winmd" ".h" WINRTCOMPONENT_H_NATIVE "${WINRTCOMPONENT_WINMD_NATIVE}") +cmake_path(CONVERT "${WINRTCOMPONENT_IDL}" TO_NATIVE_PATH_LIST WINRTCOMPONENT_IDL_NATIVE) +execute_process( + COMMAND "${MIDLRT_EXE_NATIVE}" + /W1 /nologo /nomidl + /metadata_dir "${METADATA_DIR_NATIVE}" + /reference "${FOUNDATIONCONTRACT_WINMD_NATIVE}" + /reference "${UNIVERSALAPICONTRACT_WINMD_NATIVE}" + /winmd "${WINRTCOMPONENT_WINMD_NATIVE}" + /header "${WINRTCOMPONENT_H_NATIVE}" + "${WINRTCOMPONENT_IDL_NATIVE}" + COMMAND_ERROR_IS_FATAL ANY) \ No newline at end of file