CMake中MSVC变量仅在project调用后赋值的问题及项目命名需求
MSVC isn't set before project() in your first CMake run, and how to fix it Let's break down what's happening here, then walk through reliable ways to set your project name based on the compiler.
The Root Cause
CMake's compiler-specific variables like MSVC don't get initialized until the project() function executes. Here's why your test behaves differently between first-run and cached runs:
- First run (no cache): When you start fresh, CMake hasn't detected your compiler yet. The
project()function is what triggers the full compiler detection workflow—so variables likeMSVCare unset or non-existent until after this call. That's why your initialif(MSVC)check does nothing. - Cached run: After the first run, CMake stores detected compiler details in its cache. On subsequent runs, it loads this cached data at startup, making
MSVCavailable immediately, even beforeproject()is called.
Your test output confirms this: on the first run, MSVC only becomes valid after project() runs, while cached runs have the variable ready from the start.
Fixes to Set Project Name by Compiler
You need to trigger compiler detection before checking for MSVC, or identify the compiler upfront using alternative methods. Here are two solid approaches:
Approach 1: Trigger Compiler Detection First
Use a minimal placeholder project or enable_language() to initialize compiler variables, then set your desired project name:
# Trigger compiler detection with a temporary placeholder project project(Placeholder LANGUAGES CXX) # Now MSVC is available to check if(MSVC) set(FINAL_PROJECT_NAME "Block3Windows") else() set(FINAL_PROJECT_NAME "Block3Linux") endif() # Set your actual project with the tailored name project(${FINAL_PROJECT_NAME} LANGUAGES CXX ...)
Alternatively, use enable_language() if you just want to detect the compiler without setting a placeholder project name:
enable_language(CXX) if(MSVC) set(FINAL_PROJECT_NAME "Block3Windows") else() set(FINAL_PROJECT_NAME "Block3Linux") endif() project(${FINAL_PROJECT_NAME} ...)
Approach 2: Check the Compiler Executable Directly
If you want to skip an extra project() call, you can check the compiler executable path upfront. This works if CMake has already picked up the compiler (via environment variables, command-line flags, or default system search):
# Check if the C++ compiler is MSVC's cl.exe if(CMAKE_CXX_COMPILER MATCHES "cl.exe$") set(FINAL_PROJECT_NAME "Block3Windows") else() set(FINAL_PROJECT_NAME "Block3Linux") endif() project(${FINAL_PROJECT_NAME} ...)
Note: This relies on CMAKE_CXX_COMPILER being set before project(). For automatic compiler detection (no manual flags), Approach 1 is more reliable.
Quick Best Practice
While CMake allows multiple project() calls, it’s better to minimize them to avoid unexpected behavior with project settings. Approach 1 uses a minimal placeholder to gather compiler info, then sets your real project—this is safe and clean.
内容的提问来源于stack exchange,提问作者Alon Adler

