Skip to content

Commit

Permalink
Extract GenerateWinMD.cmake to avoid recursive CMake invocation (#307)
Browse files Browse the repository at this point in the history
  • Loading branch information
tristanlabelle committed Sep 21, 2024
1 parent ae379aa commit 33d108a
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 51 deletions.
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
47 changes: 23 additions & 24 deletions InteropTests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
38 changes: 13 additions & 25 deletions InteropTests/WinRTComponent/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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}"
Expand All @@ -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)
target_precompile_headers(WinRTComponent PRIVATE pch.h)

set(WINRTCOMPONENT_WINMD "${CMAKE_CURRENT_BINARY_DIR}/WinRTComponent.winmd" PARENT_SCOPE)
29 changes: 29 additions & 0 deletions InteropTests/WinRTComponent/GenerateWinMD.cmake
Original file line number Diff line number Diff line change
@@ -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)

0 comments on commit 33d108a

Please sign in to comment.