cannot define custom toolchain because exe/lib flags are hardcoded for CMAKE_SYSTEM_NAME=Generic
Hello, I am writing a custom toolchain `i386-pc-win32-darwin-llvm.cmake` that I invoke with `cmake -D CMAKE_TOOLCHAIN_FILE=i386-pc-win32-darwin-llvm.cmake .` It is intended to: * cross-compile to Windows compatible binaries * using Clang (`clang++ -target i386-pc-win32` and `lld -flavor link`) - `brew install llvm` * running from MacOSX terminal Problem: * When I define these in my toolchain file, they all get overwritten when PROJECT() is called: `CMAKE_LIBRARY_PATH_FLAG`, `CMAKE_LINK_LIBRARY_FLAG`, `CMAKE_LINK_LIBRARY_SUFFIX`, `CMAKE_STATIC_LIBRARY_PREFIX`, `CMAKE_STATIC_LIBRARY_SUFFIX`, `CMAKE_EXECUTABLE_SUFFIX`, `CMAKE_C_OUTPUT_EXTENSION`, `CMAKE_CXX_OUTPUT_EXTENSION` --> they all get overwritten with default values by `cmake/Modules/CMakeGenericSystem.cmake` (looks like GCC style...) Example of working compilation (showing clang++/lld lines shown in toolchain below): Using `clang/clang++ and lld`: ``` =================== compile some 64bit C++ /usr/local/opt/llvm/bin/clang++ -target x86_64-pc-windows-msvc -isystem "/Volumes/[C] Windows 10/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include" -isystem "/Volumes/[C] Windows 10/Program Files (x86)/Windows Kits/10/Include/10.0.10150.0/ucrt" -fmsc-version=1900 -fms-extensions -fms-compatibility -fdelayed-template-parsing -std=c++11 -c main.cpp -o mainCPP-x64.o /usr/local/opt/llvm/bin/lld -flavor link /libpath:"/Volumes/[C] Windows 10/Program Files (x86)/Microsoft Visual Studio 14.0/VC/lib/amd64" /libpath:"/Volumes/[C] Windows 10/Program Files (x86)/Windows Kits/10/Lib/10.0.10150.0/ucrt/x64" /libpath:"/Volumes/[C] Windows 10/Program Files (x86)/Windows Kits/8.1/Lib/winv6.3/um/x64" libucrt.lib libcmt.lib /subsystem:console /out:mainCPP-x64.exe mainCPP-x64.o =================== compile some 64bit C /usr/local/opt/llvm/bin/clang -target x86_64-pc-windows-msvc -isystem "/Volumes/[C] Windows 10/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include" -isystem "/Volumes/[C] Windows 10/Program Files (x86)/Windows Kits/10/Include/10.0.10150.0/ucrt" -fmsc-version=1900 -fms-extensions -fms-compatibility -fdelayed-template-parsing -c main.c -o mainC-x64.o /usr/local/opt/llvm/bin/lld -flavor link /libpath:"/Volumes/[C] Windows 10/Program Files (x86)/Microsoft Visual Studio 14.0/VC/lib/amd64" /libpath:"/Volumes/[C] Windows 10/Program Files (x86)/Windows Kits/10/Lib/10.0.10150.0/ucrt/x64" /libpath:"/Volumes/[C] Windows 10/Program Files (x86)/Windows Kits/8.1/Lib/winv6.3/um/x64" libucrt.lib libcmt.lib /subsystem:console /out:mainC-x64.exe mainC-x64.o =================== compile some 32bit C++ /usr/local/opt/llvm/bin/clang++ -target i386-pc-win32 -isystem "/Volumes/[C] Windows 10/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include" -isystem "/Volumes/[C] Windows 10/Program Files (x86)/Windows Kits/10/Include/10.0.10150.0/ucrt" -fmsc-version=1900 -fms-extensions -fms-compatibility -fdelayed-template-parsing -std=c++11 -c main.cpp -o mainCPP-x86.o /usr/local/opt/llvm/bin/lld -flavor link /libpath:"/Volumes/[C] Windows 10/Program Files (x86)/Microsoft Visual Studio 14.0/VC/lib" /libpath:"/Volumes/[C] Windows 10/Program Files (x86)/Windows Kits/10/Lib/10.0.10150.0/ucrt/x86" /libpath:"/Volumes/[C] Windows 10/Program Files (x86)/Windows Kits/8.1/Lib/winv6.3/um/x86" libucrt.lib libcmt.lib /subsystem:console /out:mainCPP-x86.exe mainCPP-x86.o =================== compile some 32bit C /usr/local/opt/llvm/bin/clang -target i386-pc-win32 -isystem "/Volumes/[C] Windows 10/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include" -isystem "/Volumes/[C] Windows 10/Program Files (x86)/Windows Kits/10/Include/10.0.10150.0/ucrt" -fmsc-version=1900 -fms-extensions -fms-compatibility -fdelayed-template-parsing -c main.c -o mainC-x86.o /usr/local/opt/llvm/bin/lld -flavor link /libpath:"/Volumes/[C] Windows 10/Program Files (x86)/Microsoft Visual Studio 14.0/VC/lib" /libpath:"/Volumes/[C] Windows 10/Program Files (x86)/Windows Kits/10/Lib/10.0.10150.0/ucrt/x86" /libpath:"/Volumes/[C] Windows 10/Program Files (x86)/Windows Kits/8.1/Lib/winv6.3/um/x86" libucrt.lib libcmt.lib /subsystem:console /out:mainC-x86.exe mainC-x86.o ``` Example of compilation that works, using `clang-cl and lld-link` (for comparison): ``` =================== compile some 64bit C++ /usr/local/opt/llvm/bin/clang-cl -m64 /arch:AVX2 /imsvc "/Volumes/[C] Windows 10/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include" /imsvc "/Volumes/[C] Windows 10/Program Files (x86)/Windows Kits/10/Include/10.0.10150.0/ucrt" -fmsc-version=1900 -fms-extensions -fms-compatibility -fdelayed-template-parsing /c /Tpmain.cpp /omainCPP-x64.o /usr/local/opt/llvm/bin/lld-link /libpath:"/Volumes/[C] Windows 10/Program Files (x86)/Microsoft Visual Studio 14.0/VC/lib/amd64" /libpath:"/Volumes/[C] Windows 10/Program Files (x86)/Windows Kits/10/Lib/10.0.10150.0/ucrt/x64" /libpath:"/Volumes/[C] Windows 10/Program Files (x86)/Windows Kits/8.1/Lib/winv6.3/um/x64" libucrt.lib libcmt.lib /subsystem:console /out:mainCPP-x64.exe mainCPP-x64.o =================== compile some 64bit C /usr/local/opt/llvm/bin/clang-cl -m64 /arch:AVX2 /imsvc "/Volumes/[C] Windows 10/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include" /imsvc "/Volumes/[C] Windows 10/Program Files (x86)/Windows Kits/10/Include/10.0.10150.0/ucrt" -fmsc-version=1900 -fms-extensions -fms-compatibility -fdelayed-template-parsing /c /Tcmain.c /omainC-x64.o /usr/local/opt/llvm/bin/lld-link /libpath:"/Volumes/[C] Windows 10/Program Files (x86)/Microsoft Visual Studio 14.0/VC/lib/amd64" /libpath:"/Volumes/[C] Windows 10/Program Files (x86)/Windows Kits/10/Lib/10.0.10150.0/ucrt/x64" /libpath:"/Volumes/[C] Windows 10/Program Files (x86)/Windows Kits/8.1/Lib/winv6.3/um/x64" libucrt.lib libcmt.lib /subsystem:console /out:mainC-x64.exe mainC-x64.o =================== compile some 32bit C++ /usr/local/opt/llvm/bin/clang-cl -m32 /arch:SSE2 /imsvc "/Volumes/[C] Windows 10/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include" /imsvc "/Volumes/[C] Windows 10/Program Files (x86)/Windows Kits/10/Include/10.0.10150.0/ucrt" -fmsc-version=1900 -fms-extensions -fms-compatibility -fdelayed-template-parsing /c /Tpmain.cpp /omainCPP-x86.o /usr/local/opt/llvm/bin/lld-link /libpath:"/Volumes/[C] Windows 10/Program Files (x86)/Microsoft Visual Studio 14.0/VC/lib" /libpath:"/Volumes/[C] Windows 10/Program Files (x86)/Windows Kits/10/Lib/10.0.10150.0/ucrt/x86" /libpath:"/Volumes/[C] Windows 10/Program Files (x86)/Windows Kits/8.1/Lib/winv6.3/um/x86" libucrt.lib libcmt.lib /subsystem:console /out:mainCPP-x86.exe mainCPP-x86.o =================== compile some 32bit C /usr/local/opt/llvm/bin/clang-cl -m32 /arch:SSE2 /imsvc "/Volumes/[C] Windows 10/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include" /imsvc "/Volumes/[C] Windows 10/Program Files (x86)/Windows Kits/10/Include/10.0.10150.0/ucrt" -fmsc-version=1900 -fms-extensions -fms-compatibility -fdelayed-template-parsing /c /Tcmain.c /omainC-x86.o /usr/local/opt/llvm/bin/lld-link /libpath:"/Volumes/[C] Windows 10/Program Files (x86)/Microsoft Visual Studio 14.0/VC/lib" /libpath:"/Volumes/[C] Windows 10/Program Files (x86)/Windows Kits/10/Lib/10.0.10150.0/ucrt/x86" /libpath:"/Volumes/[C] Windows 10/Program Files (x86)/Windows Kits/8.1/Lib/winv6.3/um/x86" libucrt.lib libcmt.lib /subsystem:console /out:mainC-x86.exe mainC-x86.o ``` And here is the toolchain file `i386-pc-win32-darwin-llvm.cmake` I am working on: ``` message ("Loaded: ${CMAKE_TOOLCHAIN_FILE}") # I cannot use Windows here, it doesn't allow me to change `CMAKE_CXX_COMPILE_OBJECT` or `CMAKE_CXX_LINK_EXECUTABLE` (missing /Tc or /Tp flags for compile) # and REALLY, I want a blank slate, so we want Generic: SET(CMAKE_SYSTEM_NAME Generic CACHE STRING "Target system.") set( _MSC_VER 1900 ) # 1800=VC2013, 1900=VC2015, 1910=VC2017.. etc. if (NOT DEFINED ARCH) set( ARCH "x86" CACHE STRING "" FORCE ) endif() # MSVC Includes and Libs: # currently I am mounting MSVC from Parallels - TODO: allow configuring the path to MSVC. set( PROGRAMFILES "/Volumes/[C] Windows 10/Program Files (x86)" ) IF(NOT EXISTS "${PROGRAMFILES}") message(FATAL_ERROR "\n\nERROR: INCLUDE/LIB DIRECTORY DOESNT EXIST:\n ${PROGRAMFILES}\nLocation doesn't exist, please mount it, or install MSVC version ${_MSC_VER} v2015\n\n" ) endif() set( UniversalCRT_IncludePath "${PROGRAMFILES}/Windows Kits/10/Include/10.0.10150.0/ucrt" ) set( UniversalCRT_Lib "${PROGRAMFILES}/Windows Kits/10/Lib/10.0.10150.0/ucrt/${ARCH}" ) set( MSVC_INCLUDE "${PROGRAMFILES}/Microsoft Visual Studio 14.0/VC/include" ) if (ARCH STREQUAL "x64" ) set( MSVC_LIB "${PROGRAMFILES}/Microsoft Visual Studio 14.0/VC/lib/amd64" ) set( triple "x86_64-pc-windows-msvc" ) else() set( MSVC_LIB "${PROGRAMFILES}/Microsoft Visual Studio 14.0/VC/lib" ) set( triple "i386-pc-win32" ) endif() set( WINSDK_LIB "${PROGRAMFILES}/Windows Kits/8.1/Lib/winv6.3/um/${ARCH}" ) # compiler clang (same interface as gcc, with -target i386-pc-win32 outputs MSVC .obj files #set( SYSFLAGS "-target ${triple} -isystem \"${MSVC_INCLUDE}\" -isystem \"${UniversalCRT_IncludePath}\" -fmsc-version=${_MSC_VER} -fms-extensions -fms-compatibility -fdelayed-template-parsing" ) # compiler clang-cl (clang-cl has same interface as cl.exe... outputs MSVC .obj files) set( SYSFLAGS "/imsvc \"${MSVC_INCLUDE}\" /imsvc \"${UniversalCRT_IncludePath}\" -fmsc-version=${_MSC_VER} -fms-extensions -fms-compatibility -fdelayed-template-parsing" ) set( CMAKE_INCLUDE_SYSTEM_FLAG_C "${SYSFLAGS}" CACHE STRING "" FORCE) set( CMAKE_INCLUDE_SYSTEM_FLAG_CXX "${SYSFLAGS}" CACHE STRING "" FORCE) set( CMAKE_CXX_LINK_FLAGS "-flavor link /libpath:\"${MSVC_LIB}\" /libpath:\"${UniversalCRT_Lib}\" /libpath:\"${WINSDK_LIB}\"" CACHE STRING "" FORCE) # compiler clang # somehow choosing clang here switches around all the flags to gcc style. HOW? #set( CMAKE_C_COMPILER "/usr/local/opt/llvm/bin/clang" CACHE STRING "" FORCE) #set( CMAKE_CXX_COMPILER "/usr/local/opt/llvm/bin/clang++" CACHE STRING "" FORCE) #set( CMAKE_C_COMPILE_OBJECT "<CMAKE_C_COMPILER> ${CMAKE_INCLUDE_SYSTEM_FLAG_C} <DEFINES> <FLAGS> -o <OBJECT> -c <SOURCE>" CACHE STRING "" FORCE) #set( CMAKE_CXX_COMPILE_OBJECT "<CMAKE_CXX_COMPILER> ${CMAKE_INCLUDE_SYSTEM_FLAG_CXX} <DEFINES> <FLAGS> -o <OBJECT> -c <SOURCE>" CACHE STRING "" FORCE) # compiler clang-cl # somehow choosing clang-cl here switches around all the flags to cl.exe style. HOW? set( CMAKE_C_COMPILER "/usr/local/opt/llvm/bin/clang-cl" CACHE STRING "" FORCE) set( CMAKE_CXX_COMPILER "/usr/local/opt/llvm/bin/clang-cl" CACHE STRING "" FORCE) # CMAKE_SYSTEM_NAME=Windows will ignore CMAKE_??_COMPILE_OBJECT, WTF skips the /Tp and /Tc, so we get error about source path (/Users/blah/file.cxx results in /U flag error) set( CMAKE_C_COMPILE_OBJECT "<CMAKE_C_COMPILER> ${CMAKE_INCLUDE_SYSTEM_FLAG_C} <DEFINES> <FLAGS> /o<OBJECT> /c /Tc<SOURCE>" CACHE STRING "" FORCE) set( CMAKE_CXX_COMPILE_OBJECT "<CMAKE_CXX_COMPILER> ${CMAKE_INCLUDE_SYSTEM_FLAG_CXX} <DEFINES> <FLAGS> /o<OBJECT> /c /Tp<SOURCE>" CACHE STRING "" FORCE) # linker lld set( CMAKE_LINKER "/usr/local/opt/llvm/bin/lld" CACHE STRING "" FORCE) set( CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> /subsystem:console libcmt.lib <OBJECTS> /out:<TARGET> <LINK_LIBRARIES>; echo <LINK_LIBRARIES>" CACHE STRING "" FORCE) # https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html #set(CMAKE_CXX_LINK_EXECUTABLE "echo CXXFLAGS: ${CMAKE_CXX_FLAGS} LINK_FLAGS: <LINK_FLAGS> LINK_LIBRARIES: <LINK_LIBRARIES> OBJECTS: <OBJECTS>" CACHE STRING "" FORCE) set( CMAKE_CXX_LINK_EXECUTABLE "echo '';echo LINK_FLAGS: <LINK_FLAGS>;echo LINK_LIBRARIES: <LINK_LIBRARIES>;echo OBJECTS: <OBJECTS>; echo ''; <CMAKE_LINKER> <CMAKE_CXX_LINK_FLAGS> <FLAGS> <LINK_FLAGS> /subsystem:console libcmt.lib <OBJECTS> /out:<TARGET> <LINK_LIBRARIES>") # needed when using CMAKE_SYSTEM_NAME Windows, so weird... ar... in windows.. hmm. # set( CMAKE_AR "/usr/local/opt/llvm/bin/llvm-ar" CACHE INTERNAL STRING) set(CMAKE_LIBRARY_ARCHITECTURE x86 CACHE STRING "" FORCE) # you can set lib paths with , and libs with cmt (which will expand to libcmt.lib) # PROBLEM: makes no difference, every one gets overridden by cmake/Modules/CMakeGenericSystem.cmake during PROJECT() in the CMakeLists SET(CMAKE_LIBRARY_PATH_FLAG "/libpath:" CACHE STRING "" FORCE) SET(CMAKE_LINK_LIBRARY_FLAG "" CACHE STRING "" FORCE) SET(CMAKE_LINK_LIBRARY_SUFFIX ".lib" CACHE STRING "" FORCE) set(CMAKE_STATIC_LIBRARY_PREFIX "") SET(CMAKE_STATIC_LIBRARY_SUFFIX ".lib" CACHE STRING "" FORCE) set(CMAKE_EXECUTABLE_SUFFIX ".exe") set(CMAKE_C_OUTPUT_EXTENSION ".obj" CACHE STRING "C compiler object extension.") set(CMAKE_CXX_OUTPUT_EXTENSION ".obj" CACHE STRING "C++ compiler object extension.") # makes no difference, not sure _INIT is even a thing... SET(CMAKE_LIBRARY_PATH_FLAG_INIT "/libpath:" CACHE STRING "" FORCE) SET(CMAKE_LINK_LIBRARY_FLAG_INIT "" CACHE STRING "" FORCE) SET(CMAKE_LINK_LIBRARY_SUFFIX_INIT ".lib" CACHE STRING "" FORCE) set (CMAKE_STATIC_LIBRARY_PREFIX_INIT "") SET(CMAKE_STATIC_LIBRARY_SUFFIX_INIT ".lib" CACHE STRING "" FORCE) set(CMAKE_C_OUTPUT_EXTENSION_INIT ".obj" CACHE STRING "C compiler object extension.") set(CMAKE_CXX_OUTPUT_EXTENSION_INIT ".obj" CACHE STRING "C++ compiler object extension.") set (CMAKE_EXECUTABLE_SUFFIX_INIT ".exe") set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) ``` CMakeLists: ``` # compile for windows: # mkdir -p build && cd build # cmake -D CMAKE_TOOLCHAIN_FILE=../i386-pc-win32-darwin-llvm.cmake .. # make CMAKE_MINIMUM_REQUIRED(VERSION 3.10.0 FATAL_ERROR) SET(CMAKE_CXX_STANDARD 11) SET(CMAKE_CXX_STANDARD_REQUIRED ON) SET(CMAKE_CXX_EXTENSIONS OFF) PROJECT(example) INCLUDE_DIRECTORIES(.) ADD_EXECUTABLE(example ../main.cpp) set_property( TARGET example APPEND_STRING PROPERTY LINK_LIBRARIES "libcmt" ) # just testing that these come through set_property( TARGET example APPEND_STRING PROPERTY LINK_FLAGS "-Tsomeflag1" ) # this one doesn't seem to come through, WHY? set_property( TARGET example APPEND_STRING PROPERTY CXXFLAGS "-Tsomeflag2" ) ``` Run: ``` Loaded: ../i386-pc-win32-darwin-llvm.cmake Loaded: /Users/...path.../i386-pc-win32-darwin-llvm.cmake -- The C compiler identification is Clang 6.0.0 -- The CXX compiler identification is Clang 6.0.0 -- Check for working C compiler: /usr/local/opt/llvm/bin/clang-cl Loaded: -- Check for working C compiler: /usr/local/opt/llvm/bin/clang-cl -- works -- Detecting C compiler ABI info Loaded: -- Detecting C compiler ABI info - done -- Detecting C compile features Loaded: Loaded: Loaded: -- Detecting C compile features - done -- Check for working CXX compiler: /usr/local/opt/llvm/bin/clang-cl Loaded: -- Check for working CXX compiler: /usr/local/opt/llvm/bin/clang-cl -- works -- Detecting CXX compiler ABI info Loaded: -- Detecting CXX compiler ABI info - done -- Detecting CXX compile features Loaded: Loaded: Loaded: Loaded: -- Detecting CXX compile features - done -- Configuring done -- Generating done -- Build files have been written to: /Users/...path.../build-w Scanning dependencies of target example [ 50%] Building CXX object CMakeFiles/example.dir/Users/...path.../main.cpp.obj [100%] Linking CXX executable example LINK_FLAGS: -Tsomeflag1 LINK_LIBRARIES: -llibcmt OBJECTS: CMakeFiles/example.dir/Users/...path.../main.cpp.obj /usr/local/opt/llvm/bin/lld: warning: ignoring unknown argument: -Tsomeflag1 /usr/local/opt/llvm/bin/lld: warning: ignoring unknown argument: -llibcmt ``` Tracking it down, looks like `CMAKE_STATIC_LIBRARY_PREFIX` and friends are set correctly until `PROJECT()` is called, then they default to `gcc` defaults `-l` `-L` etc... See the `-llibcmt`? It should read `libcmt.lib` without any switch. I set this up, but it gets overridden to GCC defaults. Similarly, I've output, and none of the other flags, prefixes, exe suffix, are preserved either - same problem. Looks like maybe it's `CMakeGenericSystem.cmake` is setting these to defaults, and I'm not able to override them in my toolchain - which doesn't seem right to me that I can't. How do I define those for my toolchain? The documentation for Custom Toolchains / Cross Compiling, is a little light, and I've gotten into territory that is perhaps more advanced than your documentation. Could you advise?
issue