VS: Honor VS_TOOL_OVERRIDE for known source file types too

Visual Studio Generator: The `VS_TOOL_OVERRIDE` source file property
would previously only be respected for file types that CMake didn't know
how to build out of the box. This change allows the user to override how
any source file is built with a custom build tool, even ones with
standard/recognized extensions such as `.cxx`, `.idl`, etc.

Fixes: #26336
This commit is contained in:
Darragh Coy 2024-10-01 09:23:23 -07:00 committed by Brad King
parent d0ad8fd49c
commit 55831faf5b
6 changed files with 140 additions and 59 deletions

View File

@ -2544,66 +2544,73 @@ void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0)
}
const char* tool = nullptr;
switch (si.Kind) {
case cmGeneratorTarget::SourceKindAppManifest:
tool = "AppxManifest";
break;
case cmGeneratorTarget::SourceKindCertificate:
tool = "None";
break;
case cmGeneratorTarget::SourceKindCustomCommand:
// Handled elsewhere.
break;
case cmGeneratorTarget::SourceKindExternalObject:
tool = "Object";
break;
case cmGeneratorTarget::SourceKindExtra:
this->WriteExtraSource(e1, si.Source, toolSettings);
break;
case cmGeneratorTarget::SourceKindHeader:
this->WriteHeaderSource(e1, si.Source, toolSettings);
break;
case cmGeneratorTarget::SourceKindIDL:
tool = "Midl";
break;
case cmGeneratorTarget::SourceKindManifest:
// Handled elsewhere.
break;
case cmGeneratorTarget::SourceKindModuleDefinition:
tool = "None";
break;
case cmGeneratorTarget::SourceKindCxxModuleSource:
case cmGeneratorTarget::SourceKindUnityBatched:
case cmGeneratorTarget::SourceKindObjectSource: {
const std::string& lang = si.Source->GetLanguage();
if (lang == "C"_s || lang == "CXX"_s) {
tool = "ClCompile";
} else if (lang == "ASM_MARMASM"_s &&
this->GlobalGenerator->IsMarmasmEnabled()) {
tool = "MARMASM";
} else if (lang == "ASM_MASM"_s &&
this->GlobalGenerator->IsMasmEnabled()) {
tool = "MASM";
} else if (lang == "ASM_NASM"_s &&
this->GlobalGenerator->IsNasmEnabled()) {
tool = "NASM";
} else if (lang == "RC"_s) {
tool = "ResourceCompile";
} else if (lang == "CSharp"_s) {
tool = "Compile";
} else if (lang == "CUDA"_s &&
this->GlobalGenerator->IsCudaEnabled()) {
tool = "CudaCompile";
} else {
const cmValue toolOverride = si.Source->GetProperty("VS_TOOL_OVERRIDE");
if (cmNonempty(toolOverride)) {
// Custom tool specified: the file will be built in a user-defined way
this->WriteExtraSource(e1, si.Source, toolSettings);
} else {
switch (si.Kind) {
case cmGeneratorTarget::SourceKindAppManifest:
tool = "AppxManifest";
break;
case cmGeneratorTarget::SourceKindCertificate:
tool = "None";
}
} break;
case cmGeneratorTarget::SourceKindResx:
this->ResxObjs.push_back(si.Source);
break;
case cmGeneratorTarget::SourceKindXaml:
this->XamlObjs.push_back(si.Source);
break;
break;
case cmGeneratorTarget::SourceKindCustomCommand:
// Handled elsewhere.
break;
case cmGeneratorTarget::SourceKindExternalObject:
tool = "Object";
break;
case cmGeneratorTarget::SourceKindExtra:
this->WriteExtraSource(e1, si.Source, toolSettings);
break;
case cmGeneratorTarget::SourceKindHeader:
this->WriteHeaderSource(e1, si.Source, toolSettings);
break;
case cmGeneratorTarget::SourceKindIDL:
tool = "Midl";
break;
case cmGeneratorTarget::SourceKindManifest:
// Handled elsewhere.
break;
case cmGeneratorTarget::SourceKindModuleDefinition:
tool = "None";
break;
case cmGeneratorTarget::SourceKindCxxModuleSource:
case cmGeneratorTarget::SourceKindUnityBatched:
case cmGeneratorTarget::SourceKindObjectSource: {
const std::string& lang = si.Source->GetLanguage();
if (lang == "C"_s || lang == "CXX"_s) {
tool = "ClCompile";
} else if (lang == "ASM_MARMASM"_s &&
this->GlobalGenerator->IsMarmasmEnabled()) {
tool = "MARMASM";
} else if (lang == "ASM_MASM"_s &&
this->GlobalGenerator->IsMasmEnabled()) {
tool = "MASM";
} else if (lang == "ASM_NASM"_s &&
this->GlobalGenerator->IsNasmEnabled()) {
tool = "NASM";
} else if (lang == "RC"_s) {
tool = "ResourceCompile";
} else if (lang == "CSharp"_s) {
tool = "Compile";
} else if (lang == "CUDA"_s &&
this->GlobalGenerator->IsCudaEnabled()) {
tool = "CudaCompile";
} else {
tool = "None";
}
} break;
case cmGeneratorTarget::SourceKindResx:
this->ResxObjs.push_back(si.Source);
break;
case cmGeneratorTarget::SourceKindXaml:
this->XamlObjs.push_back(si.Source);
break;
}
}
std::string config;

View File

@ -50,6 +50,7 @@ run_cmake(VsSettings)
run_cmake(VsSourceSettingsTool)
run_cmake(VsPlatformToolset)
run_cmake(VsControlFlowGuardLinkSetting)
run_cmake(VsToolOverride)
run_cmake(VsWinRTByDefault)

View File

@ -0,0 +1,64 @@
# Figure out which build tool the test files in a project are using
macro(get_build_tools_from_project_file projectFile)
set(_s "[ \t\r\n]") # Whitespace character class
set(ItemGroupBeginRegex "<${_s}*ItemGroup${_s}*>")
set(ItemGroupEndRegex "</${_s}*ItemGroup${_s}*>")
set(GroupItemRegex ".*<${_s}*([A-Za-z0-9_]+)${_s}+Include${_s}*=${_s}*\"([^\"]*)\".*")
if(NOT EXISTS "${projectFile}")
set(RunCMake_TEST_FAILED "Project file ${projectFile} does not exist.")
return()
endif()
file(STRINGS "${projectFile}" lines)
foreach(line IN LISTS lines)
if(line MATCHES "${ItemGroupBeginRegex}")
set(InItemGroup TRUE)
elseif(line MATCHES "${ItemGroupEndRegex}")
set(InItemGroup FALSE)
elseif(line MATCHES "${GroupItemRegex}")
if(InItemGroup)
string(REGEX REPLACE "${GroupItemRegex}" "\\1" itemTool "${line}")
string(REGEX REPLACE "${GroupItemRegex}" "\\2" itemPath "${line}")
if(itemPath MATCHES ".*foo\\.cpp")
set(fooCppTool "${itemTool}")
elseif(itemPath MATCHES ".*foo\\.txt")
set(fooTxtTool "${itemTool}")
elseif(itemPath MATCHES ".*bar\\.cpp")
set(barCppTool "${itemTool}")
elseif(itemPath MATCHES ".*bar\\.txt")
set(barTxtTool "${itemTool}")
endif()
endif()
endif()
endforeach()
endmacro()
# Verify a build tool is as expected
macro(verify_build_tool fileName expectedBuildTool actualBuildTool)
if("${actualBuildTool}" STREQUAL "${expectedBuildTool}")
message(STATUS "File '${fileName}' in project file '${projectFile}' has expected build tool '${expectedBuildTool}'")
else()
set(RunCMake_TEST_FAILED "File '${fileName}' in project file '${projectFile}' has unexpected build tool '${actualBuildTool}'! Expected: '${expectedBuildTool}'" PARENT_SCOPE)
return()
endif()
endmacro()
# Test using VS_TOOL_OVERRIDE
block()
set(projectFile "${RunCMake_TEST_BINARY_DIR}/foo.vcxproj")
get_build_tools_from_project_file("${projectFile}")
verify_build_tool("foo.cpp" "CustomFooCppTool" "${fooCppTool}")
verify_build_tool("foo.txt" "CustomFooTxtTool" "${fooTxtTool}")
endblock()
# Test default behavior without using VS_TOOL_OVERRIDE
block()
set(projectFile "${RunCMake_TEST_BINARY_DIR}/bar.vcxproj")
get_build_tools_from_project_file("${projectFile}")
verify_build_tool("bar.cpp" "ClCompile" "${barCppTool}")
verify_build_tool("bar.txt" "None" "${barTxtTool}")
endblock()

View File

@ -0,0 +1,7 @@
enable_language(CXX)
set_property(SOURCE "foo.cpp" PROPERTY VS_TOOL_OVERRIDE CustomFooCppTool)
set_property(SOURCE "foo.txt" PROPERTY VS_TOOL_OVERRIDE CustomFooTxtTool)
add_library(foo foo.cpp foo.txt)
add_library(bar bar.cpp bar.txt)

View File

@ -0,0 +1 @@
Bar

View File

@ -0,0 +1 @@
Foo