├── LICENSE ├── README.md ├── clang-cl-msvc.cmake ├── dumpbin ├── example ├── .gitignore ├── CMakeLists.txt ├── Makefile └── hello-world.cpp ├── llvm-mt-wrapper ├── llvm-rc-wrapper ├── msvc └── .gitkeep ├── powershell └── winsdk └── .gitkeep /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Roy van Dam 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cross toolchain configuration for using clang-cl on non-Windows hosts to target MSVC. 2 | 3 | Based on the CMake toolchain file of the LLVM project 4 | 5 | https://github.com/llvm-mirror/llvm/blob/master/cmake/platforms/WinMsvc.cmake 6 | 7 | ## Usage 8 | 9 | ``` 10 | cmake -G Ninja 11 | -DCMAKE_TOOLCHAIN_FILE=/path/to/clang-cl-msvc.cmake 12 | -DHOST_ARCH=[arm64|armv7|arm|i686|x86|x86_64|x64] 13 | -DMSVC_BASE=/path/to/msvc 14 | -DWINSDK_BASE=/path/to/winsdk 15 | -DWINSDK_VER=windows sdk version folder name 16 | -DLLVM_VER=7 17 | -DCLANG_VER=7 18 | ``` 19 | 20 | ##### HOST_ARCH: 21 | The architecture to build for. 22 | 23 | ##### MSVC_BASE: 24 | *Absolute path* to the folder containing MSVC headers and system libraries. 25 | The layout of the folder matches that which is intalled by MSVC 2017 on 26 | Windows, and should look like this: 27 | 28 | ``` 29 | ${MSVC_BASE} 30 | include 31 | vector 32 | stdint.h 33 | etc... 34 | lib 35 | x64 36 | libcmt.lib 37 | msvcrt.lib 38 | etc... 39 | x86 40 | libcmt.lib 41 | msvcrt.lib 42 | etc... 43 | ``` 44 | 45 | For versions of MSVC < 2017, or where you have a hermetic toolchain in a 46 | custom format, you must use symlinks or restructure it to look like the above. 47 | 48 | ##### WINSDK_BASE: 49 | Together with WINSDK_VER, determines the location of Windows SDK headers 50 | and libraries. 51 | 52 | ##### WINSDK_VER: 53 | Together with WINSDK_BASE, determines the locations of Windows SDK headers 54 | and libraries. 55 | 56 | WINSDK_BASE and WINSDK_VER work together to define a folder layout that matches 57 | that of the Windows SDK installation on a standard Windows machine. It should 58 | match the layout described below. 59 | 60 | Note that if you install Windows SDK to a windows machine and simply copy the 61 | files, it will already be in the correct layout. 62 | 63 | ``` 64 | ${WINSDK_BASE} 65 | Include 66 | ${WINSDK_VER} 67 | shared 68 | ucrt 69 | um 70 | windows.h 71 | etc... 72 | Lib 73 | ${WINSDK_VER} 74 | ucrt 75 | x64 76 | x86 77 | ucrt.lib 78 | etc... 79 | um 80 | x64 81 | x86 82 | kernel32.lib 83 | etc 84 | ``` 85 | 86 | IMPORTANT: In order for this to work, you will need a valid copy of the Windows 87 | SDK and C++ STL headers and libraries on your host. Additionally, since the 88 | Windows libraries and headers are not case-correct, this toolchain file sets 89 | up a VFS overlay for the SDK headers and case-correcting symlinks for the 90 | libraries when running on a case-sensitive filesystem. 91 | 92 | ##### LLVM_VER (optional): 93 | Version of the LLVM/LLD installation on the machine, it assumes version 7 in case it is 94 | not set. 95 | 96 | ##### CLANG_VER (optional): 97 | Version of the clang(-cl) installation on the machine, it assumes version 7 in case it is 98 | not set. 99 | 100 | ## Obtaining the llvm/clang toolchain 101 | 102 | The LLVM/Clang toolchain apt repositories can be found at: 103 | 104 | http://apt.llvm.org/ 105 | 106 | The following packages are required to be present on your system: 107 | 108 | - llvm-7 109 | - clang-7 110 | - clang-tools-7 111 | 112 | ## Obtaining the Windows SDK and MSVC files 113 | 114 | The Windows SDK can downloaded directly from Microsoft at: 115 | 116 | https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk 117 | 118 | The MSVC Base files can be obtained from any recent installation of Visual Studio assuming the VC++ components have been installed. 119 | The files can generally be found at the following location on your machine: 120 | 121 | C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC 122 | 123 | ## Examples 124 | 125 | ### Using a makefile for building a project on debian9 for win32 126 | 127 | ``` 128 | .PHONY: all clean clang-msvc-sdk 129 | 130 | MSVC_SDK_URL={Git URL to a copy of this repository which includes the MSVC SDK} 131 | 132 | HOSTS=win32-clang deb9 133 | BUILD_TYPES=debug release 134 | 135 | TARGETS=$(foreach h,$(HOSTS),$(addprefix $(h)-,$(BUILD_TYPES))) 136 | 137 | define build_type 138 | $(subst r,R,$(subst d,D,$(subst /,,$(lastword $(subst -, ,$(dir $1)))))) 139 | endef 140 | 141 | .SECONDEXPANSION: 142 | $(TARGETS): build/$$@/build.ninja 143 | @cmake --build build/$@ 144 | 145 | .clang-msvc-sdk: 146 | git clone $(MSVC_SDK_URL) .clang-msvc-sdk 147 | 148 | clang-msvc-sdk: .clang-msvc-sdk 149 | @cd .clang-msvc-sdk && git pull 150 | 151 | build/deb9-%/build.ninja: Makefile 152 | @mkdir -p $(dir $@) 153 | @cd $(dir $@) && cmake ../.. -G Ninja \ 154 | -DCMAKE_BUILD_TYPE=$(call build_type,$@) 155 | 156 | build/win32-clang-%/build.ninja: Makefile .clang-msvc-sdk 157 | @mkdir -p $(dir $@) 158 | @cd $(dir $@) && cmake ../.. -G Ninja \ 159 | -DCMAKE_BUILD_TYPE=$(call build_type,$@) \ 160 | -DCMAKE_TOOLCHAIN_FILE=$(abspath .clang-msvc-sdk)/clang-cl-msvc.cmake \ 161 | -DMSVC_BASE=$(abspath .clang-msvc-sdk)/msvc/14.14.26428 \ 162 | -DWINSDK_BASE=$(abspath .clang-msvc-sdk)/winsdk \ 163 | -DWINSDK_VER=10.0.17134.0 \ 164 | -DHOST_ARCH=x86 165 | ``` 166 | 167 | The above make file provides the following targets: 168 | 169 | ``` 170 | $ make 171 | all win32-clang-debug deb9-debug 172 | clang-msvc-sdk win32-clang-release deb9-release 173 | clean 174 | ``` 175 | -------------------------------------------------------------------------------- /clang-cl-msvc.cmake: -------------------------------------------------------------------------------- 1 | # When configuring CMake with a toolchain file against a top-level CMakeLists.txt, 2 | # it will actually run CMake many times, once for each small test program used to 3 | # determine what features a compiler supports. Unfortunately, none of these 4 | # invocations share a CMakeCache.txt with the top-level invocation, meaning they 5 | # won't see the value of any arguments the user passed via -D. Since these are 6 | # necessary to properly configure MSVC in both the top-level configuration as well as 7 | # all feature-test invocations, we set environment variables with the values so that 8 | # these environments get inherited by child invocations. 9 | function(init_user_prop prop) 10 | if(${prop}) 11 | set(ENV{_${prop}} "${${prop}}") 12 | else() 13 | set(${prop} "$ENV{_${prop}}" PARENT_SCOPE) 14 | endif() 15 | endfunction() 16 | 17 | macro(cmake_getconf VAR) 18 | if(NOT ${VAR}) 19 | set(${VAR} "$ENV{${VAR}}") 20 | if(${VAR}) 21 | set(${VAR} "${${VAR}}" CACHE STRING "${VAR}") 22 | message(STATUS "Found ${VAR}: ${${VAR}}") 23 | else() 24 | message(FATAL_ERROR "Cannot determine \"${VAR}\"") 25 | endif() 26 | endif() 27 | endmacro() 28 | 29 | function(generate_winsdk_vfs_overlay winsdk_include_dir output_path) 30 | set(include_dirs) 31 | file(GLOB_RECURSE entries LIST_DIRECTORIES true "${winsdk_include_dir}/*") 32 | foreach(entry ${entries}) 33 | if(IS_DIRECTORY "${entry}") 34 | list(APPEND include_dirs "${entry}") 35 | endif() 36 | endforeach() 37 | 38 | file(WRITE "${output_path}" "version: 0\n") 39 | file(APPEND "${output_path}" "case-sensitive: false\n") 40 | file(APPEND "${output_path}" "roots:\n") 41 | 42 | foreach(dir ${include_dirs}) 43 | file(GLOB headers RELATIVE "${dir}" "${dir}/*.h") 44 | if(NOT headers) 45 | continue() 46 | endif() 47 | 48 | file(APPEND "${output_path}" " - name: \"${dir}\"\n") 49 | file(APPEND "${output_path}" " type: directory\n") 50 | file(APPEND "${output_path}" " contents:\n") 51 | 52 | foreach(header ${headers}) 53 | file(APPEND "${output_path}" " - name: \"${header}\"\n") 54 | file(APPEND "${output_path}" " type: file\n") 55 | file(APPEND "${output_path}" " external-contents: \"${dir}/${header}\"\n") 56 | endforeach() 57 | endforeach() 58 | endfunction() 59 | 60 | function(generate_winsdk_lib_symlinks winsdk_um_lib_dir output_dir) 61 | execute_process(COMMAND "${CMAKE_COMMAND}" -E make_directory "${output_dir}") 62 | file(GLOB libraries RELATIVE "${winsdk_um_lib_dir}" "${winsdk_um_lib_dir}/*") 63 | foreach(library ${libraries}) 64 | string(TOLOWER "${library}" symlink_name) 65 | execute_process(COMMAND "${CMAKE_COMMAND}" 66 | -E create_symlink 67 | "${winsdk_um_lib_dir}/${library}" 68 | "${output_dir}/${symlink_name}") 69 | endforeach() 70 | endfunction() 71 | 72 | set(CMAKE_SYSTEM_NAME Windows) 73 | set(CMAKE_SYSTEM_VERSION 10.0) 74 | set(CMAKE_SYSTEM_PROCESSOR AMD64) 75 | 76 | cmake_getconf(HOST_ARCH) 77 | cmake_getconf(MSVC_BASE) 78 | cmake_getconf(WINSDK_BASE) 79 | cmake_getconf(WINSDK_VER) 80 | 81 | if(NOT HOST_ARCH) 82 | set(HOST_ARCH x86_64) 83 | endif() 84 | if(HOST_ARCH STREQUAL "aarch64" OR HOST_ARCH STREQUAL "arm64") 85 | set(TRIPLE_ARCH "aarch64") 86 | set(WINSDK_ARCH "arm64") 87 | set(DIASDK_ARCH "arm64") 88 | elseif(HOST_ARCH STREQUAL "armv7" OR HOST_ARCH STREQUAL "arm") 89 | set(TRIPLE_ARCH "armv7") 90 | set(WINSDK_ARCH "arm") 91 | set(DIASDK_ARCH "arm") 92 | elseif(HOST_ARCH STREQUAL "i686" OR HOST_ARCH STREQUAL "x86") 93 | set(TRIPLE_ARCH "i686") 94 | set(WINSDK_ARCH "x86") 95 | set(DIASDK_ARCH "") 96 | elseif(HOST_ARCH STREQUAL "x86_64" OR HOST_ARCH STREQUAL "x64") 97 | set(TRIPLE_ARCH "x86_64") 98 | set(WINSDK_ARCH "x64") 99 | set(DIASDK_ARCH "amd64") 100 | else() 101 | message(SEND_ERROR "Unknown host architecture ${HOST_ARCH}. Must be aarch64 (or arm64), armv7 (or arm), i686 (or x86), or x86_64 (or x64).") 102 | endif() 103 | 104 | set(MSVC_INCLUDE "${MSVC_BASE}/include") 105 | set(MSVC_LIB "${MSVC_BASE}/lib") 106 | set(ATLMFC_INCLUDE "${MSVC_BASE}/atlmfc/include") 107 | set(ATLMFC_LIB "${MSVC_BASE}/atlmfc/lib") 108 | set(DIASDK_INCLUDE "${MSVC_BASE}/diasdk/include") 109 | set(DIASDK_LIB "${MSVC_BASE}/lib") 110 | set(WINSDK_INCLUDE "${WINSDK_BASE}/Include/${WINSDK_VER}") 111 | set(WINSDK_LIB "${WINSDK_BASE}/Lib/${WINSDK_VER}") 112 | 113 | if(NOT EXISTS "${MSVC_BASE}" OR 114 | NOT EXISTS "${MSVC_INCLUDE}" OR 115 | NOT EXISTS "${MSVC_LIB}") 116 | message(SEND_ERROR 117 | "CMake variable MSVC_BASE must point to a folder containing MSVC " 118 | "system headers and libraries") 119 | endif() 120 | 121 | if(NOT EXISTS "${WINSDK_BASE}" OR 122 | NOT EXISTS "${WINSDK_INCLUDE}" OR 123 | NOT EXISTS "${WINSDK_LIB}") 124 | message(SEND_ERROR 125 | "CMake variable WINSDK_BASE and WINSDK_VER must resolve to a valid " 126 | "Windows SDK installation") 127 | endif() 128 | 129 | if(NOT EXISTS "${WINSDK_INCLUDE}/um/Windows.h") 130 | message(SEND_ERROR "Cannot find Windows.h") 131 | endif() 132 | if(NOT EXISTS "${WINSDK_INCLUDE}/um/WINDOWS.H") 133 | set(case_sensitive_filesystem TRUE) 134 | endif() 135 | 136 | # Attempt to find the clang-cl binary 137 | find_program(CLANG_CL_PATH NAMES clang-cl) 138 | if(${CLANG_CL_PATH} STREQUAL "CLANG_CL_PATH-NOTFOUND") 139 | message(SEND_ERROR "Unable to find clang-cl") 140 | endif() 141 | 142 | # Attempt to find the llvm-link binary 143 | find_program(LLD_LINK_PATH NAMES lld-link) 144 | if(${LLD_LINK_PATH} STREQUAL "LLD_LINK_PATH-NOTFOUND") 145 | message(SEND_ERROR "Unable to find lld-link") 146 | endif() 147 | 148 | # Attempt to find the lld-lib binary 149 | find_program(LLVM_LIB_PATH NAMES llvm-lib) 150 | if(${LLVM_LIB_PATH} STREQUAL "LLVM_LIB_PATH-NOTFOUND") 151 | message(SEND_ERROR "Unable to find llvm-lib") 152 | endif() 153 | 154 | # Attempt to find the llvm-nm binary 155 | find_program(LLVM_NM_PATH NAMES llvm-nm) 156 | if(${LLVM_NM_PATH} STREQUAL "LLVM_NM_PATH-NOTFOUND") 157 | message(SEND_ERROR "Unable to find llvm-nm") 158 | endif() 159 | 160 | # Attempt to find the llvm-mt binary 161 | #find_program(LLVM_MT_PATH NAMES llvm-mt) 162 | set(LLVM_MT_PATH "${CMAKE_CURRENT_LIST_DIR}/llvm-mt-wrapper") 163 | if(${LLVM_MT_PATH} STREQUAL "LLVM_MT_PATH-NOTFOUND") 164 | message(SEND_ERROR "Unable to find llvm-mt") 165 | endif() 166 | 167 | # Attempt to find the native clang binary 168 | find_program(CLANG_C_PATH NAMES clang) 169 | if(${CLANG_C_PATH} STREQUAL "CLANG_C_PATH-NOTFOUND") 170 | message(SEND_ERROR "Unable to find clang") 171 | endif() 172 | 173 | # Attempt to find the native clang++ binary 174 | find_program(CLANG_CXX_PATH NAMES clang++) 175 | if(${CLANG_CXX_PATH} STREQUAL "CLANG_CXX_PATH-NOTFOUND") 176 | message(SEND_ERROR "Unable to find clang++") 177 | endif() 178 | 179 | # Attempt to find the llvm-rc binary 180 | find_program(LLVM_RC_PATH NAMES llvm-rc) 181 | if(${LLVM_RC_PATH} STREQUAL "LLVM_RC_PATH-NOTFOUND") 182 | message(SEND_ERROR "Unable to find rc") 183 | endif() 184 | 185 | 186 | set(CMAKE_C_COMPILER "${CLANG_CL_PATH}" CACHE FILEPATH "") 187 | set(CMAKE_CXX_COMPILER "${CLANG_CL_PATH}" CACHE FILEPATH "") 188 | #set(CMAKE_RC_COMPILER "${LLVM_RC_PATH}" CACHE FILEPATH "") 189 | # Workaround until llvm-rc parses the .rc files like Microsoft's rc.exe 190 | set(CMAKE_RC_COMPILER "${CMAKE_CURRENT_LIST_DIR}/llvm-rc-wrapper" CACHE FILEPATH "") 191 | set(CMAKE_LINKER "${LLD_LINK_PATH}" CACHE FILEPATH "") 192 | set(CMAKE_LINKER_LLD "${LLD_LINK_PATH}" CACHE FILEPATH "") 193 | set(CMAKE_AR "${LLVM_LIB_PATH}" CACHE FILEPATH "") 194 | set(CMAKE_NM "${LLVM_NM_PATH}" CACHE FILEPATH "") 195 | set(CMAKE_MT "${LLVM_MT_PATH}" CACHE FILEPATH "") 196 | 197 | # Even though we're cross-compiling, we need some native tools (e.g. llvm-tblgen), and those 198 | # native tools have to be built before we can start doing the cross-build. LLVM supports 199 | # a CROSS_TOOLCHAIN_FLAGS_NATIVE argument which consists of a list of flags to pass to CMake 200 | # when configuring the NATIVE portion of the cross-build. By default we construct this so 201 | # that it points to the tools in the same location as the native clang-cl that we're using. 202 | list(APPEND _CTF_NATIVE_DEFAULT "-DCMAKE_ASM_COMPILER=${CLANG_C_PATH}") 203 | list(APPEND _CTF_NATIVE_DEFAULT "-DCMAKE_C_COMPILER=${CLANG_C_PATH}") 204 | list(APPEND _CTF_NATIVE_DEFAULT "-DCMAKE_CXX_COMPILER=${CLANG_CXX_PATH}") 205 | 206 | set(CROSS_TOOLCHAIN_FLAGS_NATIVE "${_CTF_NATIVE_DEFAULT}" CACHE STRING "") 207 | 208 | set(COMPILE_FLAGS 209 | -Xclang -fexceptions -Xclang -fcxx-exceptions -Xclang 210 | -D_CRT_SECURE_NO_WARNINGS 211 | --target=${TRIPLE_ARCH}-windows-msvc 212 | -fms-compatibility-version=19.11 213 | -Wno-unused-command-line-argument # Needed to accept projects pushing both -Werror and /MP 214 | -imsvc "${MSVC_INCLUDE}" 215 | -imsvc "${WINSDK_INCLUDE}/cppwinrt" 216 | -imsvc "${WINSDK_INCLUDE}/ucrt" 217 | -imsvc "${WINSDK_INCLUDE}/shared" 218 | -imsvc "${WINSDK_INCLUDE}/um" 219 | -imsvc "${WINSDK_INCLUDE}/winrt") 220 | 221 | if (EXISTS "${ATLMFC_INCLUDE}") 222 | list(APPEND COMPILE_FLAGS -imsvc "${ATLMFC_INCLUDE}") 223 | endif() 224 | 225 | if (EXISTS "${DIASDK_INCLUDE}") 226 | list(APPEND COMPILE_FLAGS -imsvc "${DIASDK_INCLUDE}") 227 | endif() 228 | 229 | if(case_sensitive_filesystem) 230 | # Ensure all sub-configures use the top-level VFS overlay instead of generating their own. 231 | init_user_prop(winsdk_vfs_overlay_path) 232 | if(NOT winsdk_vfs_overlay_path) 233 | set(winsdk_vfs_overlay_path "${CMAKE_BINARY_DIR}/winsdk_vfs_overlay.yaml") 234 | generate_winsdk_vfs_overlay("${WINSDK_BASE}/Include/${WINSDK_VER}" "${winsdk_vfs_overlay_path}") 235 | init_user_prop(winsdk_vfs_overlay_path) 236 | endif() 237 | list(APPEND COMPILE_FLAGS 238 | -Xclang -ivfsoverlay -Xclang "${winsdk_vfs_overlay_path}") 239 | 240 | set(CMAKE_CLANG_VFS_OVERLAY "${winsdk_vfs_overlay_path}") 241 | endif() 242 | 243 | string(REPLACE ";" " " COMPILE_FLAGS "${COMPILE_FLAGS}") 244 | 245 | # We need to preserve any flags that were passed in by the user. However, we 246 | # can't append to CMAKE_C_FLAGS and friends directly, because toolchain files 247 | # will be re-invoked on each reconfigure and therefore need to be idempotent. 248 | # The assignments to the _INITIAL cache variables don't use FORCE, so they'll 249 | # only be populated on the initial configure, and their values won't change 250 | # afterward. 251 | set(_CMAKE_RC_FLAGS_INITIAL -I "${MSVC_INCLUDE}" 252 | -I "${WINSDK_INCLUDE}/cppwinrt" 253 | -I "${WINSDK_INCLUDE}/ucrt" 254 | -I "${WINSDK_INCLUDE}/shared" 255 | -I "${WINSDK_INCLUDE}/um" 256 | -I "${WINSDK_INCLUDE}/winrt") 257 | 258 | if (EXISTS "${ATLMFC_INCLUDE}") 259 | list(APPEND _CMAKE_RC_FLAGS_INITIAL -I "${ATLMFC_INCLUDE}") 260 | endif() 261 | 262 | if (EXISTS "${DIASDK_INCLUDE}") 263 | list(APPEND _CMAKE_RC_FLAGS_INITIAL -I "${DIASDK_INCLUDE}") 264 | endif() 265 | 266 | string(REPLACE ";" " " _CMAKE_RC_FLAGS_INITIAL "${_CMAKE_RC_FLAGS_INITIAL}") 267 | set(CMAKE_RC_FLAGS "${_CMAKE_RC_FLAGS_INITIAL}" CACHE STRING "" FORCE) 268 | 269 | set(_CMAKE_C_FLAGS_INITIAL "${CMAKE_C_FLAGS}" CACHE STRING "") 270 | set(CMAKE_C_FLAGS "${_CMAKE_C_FLAGS_INITIAL} ${COMPILE_FLAGS}" CACHE STRING "" FORCE) 271 | 272 | set(_CMAKE_CXX_FLAGS_INITIAL "${CMAKE_CXX_FLAGS}" CACHE STRING "") 273 | set(CMAKE_CXX_FLAGS "${_CMAKE_CXX_FLAGS_INITIAL} ${COMPILE_FLAGS}" CACHE STRING "" FORCE) 274 | 275 | set(LINK_FLAGS 276 | # Prevent CMake from attempting to invoke mt.exe. It only recognizes the slashed form and not the dashed form. 277 | #/manifest:no 278 | 279 | -libpath:"${MSVC_LIB}/${WINSDK_ARCH}" 280 | -libpath:"${WINSDK_LIB}/ucrt/${WINSDK_ARCH}" 281 | -libpath:"${WINSDK_LIB}/um/${WINSDK_ARCH}") 282 | 283 | if (EXISTS "${ATLMFC_LIB}") 284 | list(APPEND LINK_FLAGS -libpath:"${ATLMFC_LIB}/${WINSDK_ARCH}") 285 | endif() 286 | 287 | if (EXISTS "${DIASDK_LIB}") 288 | list(APPEND LINK_FLAGS -libpath:"${DIASDK_LIB}/${DIASDK_ARCH}") 289 | endif() 290 | 291 | if(case_sensitive_filesystem) 292 | # Ensure all sub-configures use the top-level symlinks dir instead of generating their own. 293 | init_user_prop(winsdk_lib_symlinks_dir) 294 | if(NOT winsdk_lib_symlinks_dir) 295 | set(winsdk_lib_symlinks_dir "${CMAKE_BINARY_DIR}/winsdk_lib_symlinks") 296 | generate_winsdk_lib_symlinks("${WINSDK_BASE}/Lib/${WINSDK_VER}/um/${WINSDK_ARCH}" "${winsdk_lib_symlinks_dir}") 297 | init_user_prop(winsdk_lib_symlinks_dir) 298 | endif() 299 | list(APPEND LINK_FLAGS 300 | -libpath:"${winsdk_lib_symlinks_dir}") 301 | endif() 302 | 303 | string(REPLACE ";" " " LINK_FLAGS "${LINK_FLAGS}") 304 | 305 | # See explanation for compiler flags above for the _INITIAL variables. 306 | set(_CMAKE_EXE_LINKER_FLAGS_INITIAL "${CMAKE_EXE_LINKER_FLAGS}" CACHE STRING "") 307 | set(CMAKE_EXE_LINKER_FLAGS "${_CMAKE_EXE_LINKER_FLAGS_INITIAL} ${LINK_FLAGS}" CACHE STRING "" FORCE) 308 | 309 | set(_CMAKE_MODULE_LINKER_FLAGS_INITIAL "${CMAKE_MODULE_LINKER_FLAGS}" CACHE STRING "") 310 | set(CMAKE_MODULE_LINKER_FLAGS "${_CMAKE_MODULE_LINKER_FLAGS_INITIAL} ${LINK_FLAGS}" CACHE STRING "" FORCE) 311 | 312 | set(_CMAKE_SHARED_LINKER_FLAGS_INITIAL "${CMAKE_SHARED_LINKER_FLAGS}" CACHE STRING "") 313 | set(CMAKE_SHARED_LINKER_FLAGS "${_CMAKE_SHARED_LINKER_FLAGS_INITIAL} ${LINK_FLAGS}" CACHE STRING "" FORCE) 314 | 315 | # CMake populates these with a bunch of unnecessary libraries, which requires 316 | # extra case-correcting symlinks and what not. Instead, let projects explicitly 317 | # control which libraries they require. 318 | # NOTE: Re-enable this, CMake adds libraries lowercase, WINDOWS_PHONE OR WINDOWS_STORE add libraries with uppercase characters. 319 | #set(CMAKE_C_STANDARD_LIBRARIES "" CACHE STRING "" FORCE) 320 | #set(CMAKE_CXX_STANDARD_LIBRARIES "" CACHE STRING "" FORCE) 321 | 322 | if(NOT $ENV{VCPKG_TOOLCHAIN} STREQUAL "") 323 | message(STATUS "Included VCPKG: $ENV{VCPKG_TOOLCHAIN}") 324 | include($ENV{VCPKG_TOOLCHAIN}) 325 | endif() 326 | -------------------------------------------------------------------------------- /dumpbin: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | echo "${0}: ${@}" 4 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(example VERSION 1.0.0 LANGUAGES C CXX) 4 | 5 | set(CMAKE_COLOR_MAKEFILE ON) 6 | set(CMAKE_VERBOSE_MAKEFILE OFF) 7 | 8 | add_executable(hello-world hello-world.cpp) 9 | -------------------------------------------------------------------------------- /example/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | 3 | all: hello-world.exe 4 | 5 | hello-world.exe: hello-world.cpp build/build.ninja 6 | cmake --build build 7 | 8 | build/build.ninja: 9 | mkdir -p build 10 | cd build && cmake .. -G Ninja \ 11 | -DCMAKE_TOOLCHAIN_FILE=$(abspath ../clang-cl-msvc.cmake) \ 12 | -DMSVC_BASE=$(abspath ../msvc/14.14.26428) \ 13 | -DWINSDK_BASE=$(abspath ../winsdk) \ 14 | -DWINSDK_VER=10.0.17134.0 15 | 16 | clean: 17 | rm -rf build 18 | -------------------------------------------------------------------------------- /example/hello-world.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char* argv[]) { 4 | printf("Hello, World!\n"); 5 | 6 | return 0; 7 | } -------------------------------------------------------------------------------- /llvm-mt-wrapper: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | #dummy_manifest=" 4 | # 6 | # 7 | # 8 | # 9 | # 10 | # 11 | # 12 | # 13 | #" 14 | 15 | echo "${0}: ${@}" 16 | 17 | output="$(llvm-mt "${@}" 2>&1)" 18 | res=$? 19 | 20 | if [ "$res" -ne 0 ]; then 21 | if echo "$output" | grep -q "no libxml2"; then 22 | echo "llvm-mt not compiled with libxml2, skipping manifest." 23 | exit 0 24 | fi 25 | echo "$output" 26 | fi 27 | 28 | exit "$res" 29 | -------------------------------------------------------------------------------- /llvm-rc-wrapper: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | shopt -s nocasematch 4 | 5 | llvm_rc_args=() 6 | while [ $# -gt 1 ]; do 7 | param=$1 8 | shift 9 | case "$param" in 10 | -c*|/c*) 11 | if [ "${#param}" -eq 2 ]; then 12 | llvm_rc_args+=("/C" "$1") 13 | shift 14 | else 15 | llvm_rc_args+=("/C" "${param:2}") 16 | fi 17 | ;; 18 | -d*|/d*) 19 | if [ "${#param}" -eq 2 ]; then 20 | llvm_rc_args+=("/D" "$1") 21 | shift 22 | else 23 | llvm_rc_args+=("/D" "${param:2}") 24 | fi 25 | ;; 26 | -fo*|/fo*) 27 | if [ "${#param}" -eq 3 ]; then 28 | llvm_rc_args+=("/FO" "$1") 29 | shift 30 | else 31 | llvm_rc_args+=("/FO" "${param:3}") 32 | fi 33 | ;; 34 | -i*|/i*) 35 | if [ "${#param}" -eq 2 ]; then 36 | llvm_rc_args+=("/I" "$1") 37 | shift 38 | else 39 | llvm_rc_args+=("/I" "${param:2}") 40 | fi 41 | ;; 42 | -ln*|/ln*) 43 | if [ "${#param}" -eq 3 ]; then 44 | llvm_rc_args+=("/LN" "$1") 45 | shift 46 | else 47 | llvm_rc_args+=("/LN" "${param:3}") 48 | fi 49 | ;; 50 | -l*|/l*) 51 | if [ "${#param}" -eq 2 ]; then 52 | llvm_rc_args+=("/l" "$1") 53 | shift 54 | else 55 | llvm_rc_args+=("/l" "${param:2}") 56 | fi 57 | ;; 58 | -u*|/u*) 59 | if [ "${#param}" -eq 2 ]; then 60 | llvm_rc_args+=("/U" "$1") 61 | shift 62 | else 63 | llvm_rc_args+=("/U" "${param:2}") 64 | fi 65 | ;; 66 | *) llvm_rc_args+=("$param");; 67 | esac 68 | done 69 | 70 | rc_file=$1 71 | # Fix: llvm-rc: Error in VERSIONINFO statement (ID 1): 72 | # Non-ASCII 8-bit codepoint (169) can't occur in a non-Unicode string> 73 | # Non-ASCII 8-bit codepoint (251) can't occur in a non-Unicode string> 74 | sed -i "s/\\\\169/(C)/g;s/\xa9/(C)/g;s/\\\\xa9/(C)/g;s/\\\\251/(C)/g;s/\xfb/(C)/g;s/\\\\xfb/(C)/g" "$rc_file" 75 | 76 | llvm_rc_args+=("$rc_file") 77 | echo llvm-rc "${llvm_rc_args[@]}" 78 | llvm-rc "${llvm_rc_args[@]}" 79 | -------------------------------------------------------------------------------- /msvc/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nemirtingas/clang-msvc-sdk/bfe794979245034c0e13a56eddbde6b86291e658/msvc/.gitkeep -------------------------------------------------------------------------------- /powershell: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | echo "${0}: ${@}" 4 | -------------------------------------------------------------------------------- /winsdk/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nemirtingas/clang-msvc-sdk/bfe794979245034c0e13a56eddbde6b86291e658/winsdk/.gitkeep --------------------------------------------------------------------------------