Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions VSWhere.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#----------------------------------------------------------------------------------------------------------------------
include_guard()

include("${CMAKE_CURRENT_LIST_DIR}/WSL.cmake")

#[[====================================================================================================================
toolchain_validate_vs_files
---------------------------
Expand Down Expand Up @@ -79,12 +81,21 @@ function(findVisualStudio)

cmake_parse_arguments(PARSE_ARGV 0 FIND_VS "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}")

set(VSWHERE_HINT_PATH "$ENV{ProgramFiles\(x86\)}/Microsoft Visual Studio/Installer")

# Accommodate WSL
if((CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") AND (EXISTS "/usr/bin/wslpath"))
toolchain_read_reg_string("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion" "ProgramFilesDir (x86)" PROGRAM_FILES_X86_PATH)
set(VSWHERE_HINT_PATH "${PROGRAM_FILES_X86_PATH}\\Microsoft Visual Studio\\Installer")
toolchain_to_wsl_path("${VSWHERE_HINT_PATH}" VSWHERE_HINT_PATH)
endif()

find_program(VSWHERE_PATH
NAMES vswhere vswhere.exe
HINTS "$ENV{ProgramFiles\(x86\)}/Microsoft Visual Studio/Installer"
HINTS ${VSWHERE_HINT_PATH}
)

if(VSWHERE_PATH STREQUAL "VSWHERE_PATH-NOTFOUND")
if(NOT VSWHERE_PATH)
message(FATAL_ERROR "'vswhere' isn't found.")
endif()

Expand Down
87 changes: 87 additions & 0 deletions WSL.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#----------------------------------------------------------------------------------------------------------------------
# MIT License
#
# Copyright (c) 2026 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()

#[[====================================================================================================================
toolchain_read_reg_string
-------------------------

Reads a string value from the Windows registry using reg.exe via WSL.

toolchain_read_reg_string(
<reg_key>
<reg_value>
<output_variable>
)

Note: Not supported for consumption outside of the toolchain files.
====================================================================================================================]]#
function(toolchain_read_reg_string REG_KEY REG_VALUE OUTPUT_VARIABLE)
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
message(FATAL_ERROR "toolchain_read_reg_string should not be used on Windows platforms.")
endif()

find_program(REG_EXE_PATH NAMES reg.exe)
if(NOT REG_EXE_PATH)
message(FATAL_ERROR "reg.exe not found - cannot read Windows registry from WSL.")
endif()

execute_process(
COMMAND ${REG_EXE_PATH} QUERY ${REG_KEY} /v ${REG_VALUE}
OUTPUT_VARIABLE REG_OUTPUT
OUTPUT_STRIP_TRAILING_WHITESPACE
)
string(REGEX REPLACE ".*REG_SZ[ \t]+(.*)$" "\\1" REG_OUTPUT "${REG_OUTPUT}")
message(VERBOSE "toolchain_read_reg_string: VALUE = ${REG_OUTPUT}")
set(${OUTPUT_VARIABLE} "${REG_OUTPUT}" PARENT_SCOPE)
endfunction()

#[[====================================================================================================================
toolchain_to_wsl_path
---------------------

Converts a Windows path to a WSL path.

toolchain_to_wsl_path(
<input_path>
<output_variable>
)

Note: Not supported for consumption outside of the toolchain files.
====================================================================================================================]]#
function(toolchain_to_wsl_path INPUT_PATH OUTPUT_VARIABLE)
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
message(FATAL_ERROR "toolchain_to_wsl_path should not be used on Windows platforms.")
endif()

if(NOT (EXISTS "/usr/bin/wslpath"))
message(FATAL_ERROR "wslpath not found - cannot convert Windows path to WSL path.")
endif()

execute_process(COMMAND /usr/bin/wslpath -u ${INPUT_PATH}
OUTPUT_VARIABLE WSL_PATH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
set(${OUTPUT_VARIABLE} "${WSL_PATH}" PARENT_SCOPE)
endfunction()
41 changes: 29 additions & 12 deletions Windows.Clang.toolchain.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,6 @@ cmake_minimum_required(VERSION 3.20)

include_guard()

# If `CMAKE_HOST_SYSTEM_NAME` is not 'Windows', there's nothing to do.
if(NOT (CMAKE_HOST_SYSTEM_NAME STREQUAL Windows))
return()
endif()

option(TOOLCHAIN_UPDATE_PROGRAM_PATH "Whether the toolchain should update CMAKE_PROGRAM_PATH." ON)
option(TOOLCHAIN_ADD_VS_NINJA_PATH "Whether the toolchain should add the path to the VS Ninja to the CMAKE_SYSTEM_PROGRAM_PATH." ON)

Expand Down Expand Up @@ -147,6 +142,11 @@ if(NOT VS_INSTALLATION_PATH)
installationPath VS_INSTALLATION_PATH
)
endif()

if((CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") AND (EXISTS "/usr/bin/wslpath"))
# Path properties returned by VSWhere are Windows-style paths. Convert to WSL-style paths on WSL.
toolchain_to_wsl_path("${VS_INSTALLATION_PATH}" VS_INSTALLATION_PATH)
endif()
endif()

message(VERBOSE "VS_INSTALLATION_VERSION = ${VS_INSTALLATION_VERSION}")
Expand Down Expand Up @@ -177,13 +177,23 @@ set(VS_TOOLSET_PATH "${VS_INSTALLATION_PATH}/VC/Tools/MSVC/${CMAKE_VS_PLATFORM_T

# Map CMAKE_SYSTEM_PROCESSOR values to CMAKE_VS_PLATFORM_TOOLSET_ARCHITECTURE that identifies the tools that should
# be used to produce code for the CMAKE_SYSTEM_PROCESSOR.
if(CMAKE_SYSTEM_PROCESSOR STREQUAL AMD64)
set(CMAKE_VS_PLATFORM_TOOLSET_ARCHITECTURE x64)
elseif((CMAKE_SYSTEM_PROCESSOR STREQUAL ARM)
OR (CMAKE_SYSTEM_PROCESSOR STREQUAL ARM64)
OR (CMAKE_SYSTEM_PROCESSOR STREQUAL X86))
set(CMAKE_VS_PLATFORM_TOOLSET_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR})
else()
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
if(CMAKE_SYSTEM_PROCESSOR STREQUAL AMD64)
set(CMAKE_VS_PLATFORM_TOOLSET_ARCHITECTURE x64)
elseif((CMAKE_SYSTEM_PROCESSOR STREQUAL ARM)
OR (CMAKE_SYSTEM_PROCESSOR STREQUAL ARM64)
OR (CMAKE_SYSTEM_PROCESSOR STREQUAL X86))
set(CMAKE_VS_PLATFORM_TOOLSET_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR})
endif()
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
if(CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64)
set(CMAKE_VS_PLATFORM_TOOLSET_ARCHITECTURE ARM64)
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64)
set(CMAKE_VS_PLATFORM_TOOLSET_ARCHITECTURE x64)
endif()
endif()

if(NOT CMAKE_VS_PLATFORM_TOOLSET_ARCHITECTURE)
message(FATAL_ERROR "Unable identify compiler architecture for CMAKE_SYSTEM_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR}")
endif()

Expand Down Expand Up @@ -234,6 +244,13 @@ foreach(LANG C CXX)
endif()
endforeach()

# If not compiling on Windows, set the clang compiler target to Windows.
if(NOT (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows"))
foreach(LANG C CXX)
set(CMAKE_${LANG}_COMPILER_TARGET "${CMAKE_SYSTEM_PROCESSOR}-windows-msvc")
endforeach()
endif()

if(VS_USE_SPECTRE_MITIGATION_ATLMFC_RUNTIME)
# Ensure that the necessary folder and files are present before adding the 'link_directories'
toolchain_validate_vs_files(
Expand Down
39 changes: 29 additions & 10 deletions Windows.Kits.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
#
include_guard()

include("${CMAKE_CURRENT_LIST_DIR}/WSL.cmake")

if(NOT CMAKE_SYSTEM_VERSION)
set(CMAKE_SYSTEM_VERSION ${CMAKE_HOST_SYSTEM_VERSION})
endif()
Expand All @@ -59,12 +61,19 @@ if(NOT CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE)
endif()

if(NOT CMAKE_WINDOWS_KITS_10_DIR)
get_filename_component(CMAKE_WINDOWS_KITS_10_DIR "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\v10.0;InstallationFolder]" ABSOLUTE CACHE)
if ("${CMAKE_WINDOWS_KITS_10_DIR}" STREQUAL "/registry")
unset(CMAKE_WINDOWS_KITS_10_DIR)
if((CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") AND (EXISTS "/usr/bin/wslpath"))
toolchain_read_reg_string("HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\Microsoft SDKs\\Windows\\v10.0" "InstallationFolder" CMAKE_WINDOWS_KITS_10_DIR)
message(VERBOSE "Windows.Kits: CMAKE_WINDOWS_KITS_10_DIR (WSL) = ${CMAKE_WINDOWS_KITS_10_DIR}")
toolchain_to_wsl_path("${CMAKE_WINDOWS_KITS_10_DIR}" CMAKE_WINDOWS_KITS_10_DIR)
else()
get_filename_component(CMAKE_WINDOWS_KITS_10_DIR "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\v10.0;InstallationFolder]" ABSOLUTE CACHE)
if ("${CMAKE_WINDOWS_KITS_10_DIR}" STREQUAL "/registry")
unset(CMAKE_WINDOWS_KITS_10_DIR)
endif()
endif()
endif()

message(VERBOSE "Windows.Kits: CMAKE_WINDOWS_KITS_10_DIR = ${CMAKE_WINDOWS_KITS_10_DIR}")
if(NOT CMAKE_WINDOWS_KITS_10_DIR)
message(FATAL_ERROR "Unable to find an installed Windows SDK, and one wasn't specified.")
endif()
Expand Down Expand Up @@ -127,13 +136,23 @@ set(MIDL_COMPILER "${WINDOWS_KITS_BIN_PATH}/${CMAKE_VS_PLATFORM_TOOLSET_HOST_ARC
set(MDMERGE_TOOL "${WINDOWS_KITS_BIN_PATH}/${CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE}/mdmerge.exe")

# Windows SDK
if(CMAKE_SYSTEM_PROCESSOR STREQUAL AMD64)
set(WINDOWS_KITS_TARGET_ARCHITECTURE x64)
elseif((CMAKE_SYSTEM_PROCESSOR STREQUAL ARM)
OR (CMAKE_SYSTEM_PROCESSOR STREQUAL ARM64)
OR (CMAKE_SYSTEM_PROCESSOR STREQUAL X86))
set(WINDOWS_KITS_TARGET_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR})
else()
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
if(CMAKE_SYSTEM_PROCESSOR STREQUAL AMD64)
set(WINDOWS_KITS_TARGET_ARCHITECTURE x64)
elseif((CMAKE_SYSTEM_PROCESSOR STREQUAL ARM)
OR (CMAKE_SYSTEM_PROCESSOR STREQUAL ARM64)
OR (CMAKE_SYSTEM_PROCESSOR STREQUAL X86))
set(WINDOWS_KITS_TARGET_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR})
endif()
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
if(CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64)
set(WINDOWS_KITS_TARGET_ARCHITECTURE ARM64)
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64)
set(WINDOWS_KITS_TARGET_ARCHITECTURE x64)
endif()
endif()

if(NOT WINDOWS_KITS_TARGET_ARCHITECTURE)
message(FATAL_ERROR "Unable identify Windows Kits architecture for CMAKE_SYSTEM_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR}")
endif()

Expand Down
49 changes: 49 additions & 0 deletions example/CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
{
"name": "windows",
"inherits": ["default"],
"condition": { "lhs": "${hostSystemName}", "type": "equals", "rhs": "Windows" },
"hidden": true
},
{
Expand Down Expand Up @@ -167,6 +168,46 @@
"CMAKE_GENERATOR_PLATFORM": "ARM64,version=10.0.26100.0",
"CMAKE_SYSTEM_PROCESSOR": "ARM64"
}
},
{
"name": "linux-windows",
"inherits": ["default"],
"description": "Cross-compiling to Windows from Linux",
"condition": { "lhs": "${hostSystemName}", "type": "equals", "rhs": "Linux" },
"hidden": true,
"cacheVariables": {
"CMAKE_SYSTEM_NAME": "Windows"
}
},
{
"name": "linux-windows-ninja-clang",
"inherits": ["linux-windows"],
"generator": "Ninja Multi-Config",
"hidden": true,
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "../Windows.Clang.toolchain.cmake",
"CMAKE_C_COMPILER": "clang-20",
"CMAKE_CXX_COMPILER": "clang++-20",
"CMAKE_LINKER_TYPE": "lld",
"CMAKE_MT": "llvm-mt-20",
"CMAKE_RC_COMPILER": "llvm-rc-20",
"CMAKE_C_USING_LINKER_lld": "-fuse-ld=lld",
"CMAKE_CXX_USING_LINKER_lld": "-fuse-ld=lld"
}
},
{
"name": "linux-windows-ninja-clang-arm64",
"inherits": ["linux-windows-ninja-clang"],
"cacheVariables": {
"CMAKE_SYSTEM_PROCESSOR": "aarch64"
}
},
{
"name": "linux-windows-ninja-clang-x64",
"inherits": ["linux-windows-ninja-clang"],
"cacheVariables": {
"CMAKE_SYSTEM_PROCESSOR": "x86_64"
}
}
],
"buildPresets": [
Expand Down Expand Up @@ -213,6 +254,14 @@
{
"name": "windows-vs2022-arm64",
"configurePreset": "windows-vs2022-arm64"
},
{
"name": "linux-windows-ninja-clang-arm64",
"configurePreset": "linux-windows-ninja-clang-arm64"
},
{
"name": "linux-windows-ninja-clang-x64",
"configurePreset": "linux-windows-ninja-clang-x64"
}
]
}
3 changes: 2 additions & 1 deletion example/CommandLineAsm/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ if((CMAKE_SYSTEM_PROCESSOR STREQUAL AMD64) OR (CMAKE_SYSTEM_PROCESSOR STREQUAL X
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL ARM64)
enable_language(ASM_MARMASM)
else()
message(FATAL_ERROR "Unknown CMAKE_SYSTEM_PROCESSOR for ASM language.")
message(STATUS "Unknown CMAKE_SYSTEM_PROCESSOR for ASM language.")
return()
endif()

add_executable(CommandLineAsm
Expand Down
11 changes: 1 addition & 10 deletions example/WindowsApplication/WindowsApplication.rc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------------------------------------------
//
//---------------------------------------------------------------------------------------------------------------------
#include "resource.h"
#include "Resource.h"

#define APSTUDIO_READONLY_SYMBOLS
#ifndef APSTUDIO_INVOKED
Expand Down Expand Up @@ -38,15 +38,6 @@ BEGIN
END
END

//---------------------------------------------------------------------------------------------------------------------
// Accelerator
//---------------------------------------------------------------------------------------------------------------------
IDC_WINDOWSAPPLICATION ACCELERATORS
BEGIN
"?", IDM_ABOUT, ASCII, ALT
"/", IDM_ABOUT, ASCII, ALT
END

//---------------------------------------------------------------------------------------------------------------------
// Dialog
//---------------------------------------------------------------------------------------------------------------------
Expand Down