[RFC][CMake] Linker flags need -Wl equivalent for Intel C++ (icx) on Windows

Background

In CMake 3.25 (specifically IntelLLVM: Enable IPO for Linux and Windows (!7533) · Merge requests · CMake / CMake · GitLab) the way CMake drives compilation for the Intel C++ Compiler (IntelLLVM) has changed on Windows.

Prior to CMake 3.25 user provided link options (CMAKE_(EXE|SHARED)_LINKER_FLAGS, target_link_options, LINK_FLAGS property etc.) were passed directly to the linker, in the same way as is done for MSVC and clang-cl.
After 3.25 the link options are passed to the compiler driver similar to compilers on *nix platforms or the gcc compatible clang++ driver on Windows.

This change was done because some features (notably SYCL or OpenMP offloading) require to pass options to the driver itself during
linking.

This is a breaking change for the CMake project authors: options meant for the linker now need to be prefixed to ask the driver to pass them along.

Prior to this change in CMake icx was basically interchangeable with clang-cl/MSVC. We (Intel) are
still exploring how to restore/mitigate this compatibility for CMake project authors that depend on it (1).

Proposal

LLVM is impacted by this, so current main fails to build with the Intel C++ compiler using recent
versions of CMake. We would like to update the LLVM CMake scripts to pass the linker prefix on Windows. This needs to be done for all linker options, because all of them are intended for the linker (only offloading options like -fsycl need to be seen by the driver, and LLVM does not use these).

Examples of the required changes:

  1. Options passed to target_link_options or set via the (INTERFACE)_LINK_OPTIONS property:
-      set(export_file_linker_flag "/DEF:\"${export_file_linker_flag}\"")
+      set(export_file_linker_flag "LINKER:/DEF:${export_file_linker_flag}")

Options get prefixed by LINKER:, CMake translates that to the correct syntax for passing it through the driver. This will work for clang-cl and MSVC, where LINKER: is replaced by an empty string, since CMake does not use the driver for linking.

  1. CMAKE_(EXE|SHARED|MODULE)_LINK_FLAGS
-  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:10000000")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${CMAKE_CXX_LINKER_WRAPPER_FLAG}/STACK:10000000")

These do not support the LINKER: prefix currently, though it is proposed: Extend support of "LINKER:" prefix to all link options (#26171) · Issues · CMake / CMake · GitLab. CMAKE_CXX_LINKER_WRAPPER_FLAG is used directly instead.

  1. LINK_FLAGS(_<CONFIG>) properties

This is superseeded by the LINK_OPTIONS property and generator expressions since CMake 3.13. LINK_FLAGS does not support the LINKER: prefix, so replace with LINK_OPTIONS.

  1. target_link_libraries(foo PUBLIC|PRIVATE|INTERFACE -<option>)

(CMake parses items passed here as options if they start with a dash (-), but not with -l.)

The LINKER: prefix is not supported here either, although it is also proposed: feat: Support LINKER: prefix in target_link_libraries (#26318) · Issues · CMake / CMake · GitLab.

Unfortunately we can’t use ${CMAKE_EXE_LINKER_FLAGS} because it is set to /Qoption,link for ICX. ICX also accepts it as -Qoption,link, so we end up with having to pass that, but for IntelLLVM only.

Preventing future breakage

Overall the number of required changes is small, but we understand not everyone will be aware of this difference between icx and clang-cl/msvc. Therefore we are also proposing to add a buildbot to build LLVM with ICX. The responsibility here can be similar to Bazel builds; in the case of ICX only problems Intel will fix them.

1 Like