diff --git a/Help/prop_tgt/COMPILE_PDB_NAME.rst b/Help/prop_tgt/COMPILE_PDB_NAME.rst index b76afeb089..0649993fab 100644 --- a/Help/prop_tgt/COMPILE_PDB_NAME.rst +++ b/Help/prop_tgt/COMPILE_PDB_NAME.rst @@ -9,5 +9,10 @@ compiler while building source files. This property specifies the base name for the debug symbols file. If not set, the default is unspecified. +.. versionadded:: 4.1 + + Contents of ``COMPILE_PDB_NAME`` may use + :manual:`generator expressions `. + .. |PDB_XXX| replace:: :prop_tgt:`PDB_NAME` .. include:: COMPILE_PDB_NOTE.txt diff --git a/Help/prop_tgt/COMPILE_PDB_NAME_CONFIG.rst b/Help/prop_tgt/COMPILE_PDB_NAME_CONFIG.rst index 4c9825db24..4a78f853e7 100644 --- a/Help/prop_tgt/COMPILE_PDB_NAME_CONFIG.rst +++ b/Help/prop_tgt/COMPILE_PDB_NAME_CONFIG.rst @@ -8,5 +8,10 @@ generated by the compiler while building source files. This is the configuration-specific version of :prop_tgt:`COMPILE_PDB_NAME`. +.. versionadded:: 4.1 + + Contents of ``COMPILE_PDB_NAME_`` may use + :manual:`generator expressions `. + .. |PDB_XXX| replace:: :prop_tgt:`PDB_NAME_` .. include:: COMPILE_PDB_NOTE.txt diff --git a/Help/prop_tgt/PDB_NAME.rst b/Help/prop_tgt/PDB_NAME.rst index 3a65796690..e8cb4e68e5 100644 --- a/Help/prop_tgt/PDB_NAME.rst +++ b/Help/prop_tgt/PDB_NAME.rst @@ -8,5 +8,10 @@ This property specifies the base name for the debug symbols file. If not set, the :prop_tgt:`OUTPUT_NAME` target property value or logical target name is used by default. +.. versionadded:: 4.1 + + Contents of ``PDB_NAME`` may use + :manual:`generator expressions `. + .. |COMPILE_PDB_XXX| replace:: :prop_tgt:`COMPILE_PDB_NAME` .. include:: PDB_NOTE.txt diff --git a/Help/prop_tgt/PDB_NAME_CONFIG.rst b/Help/prop_tgt/PDB_NAME_CONFIG.rst index cb3121c2f3..7b1eddafd9 100644 --- a/Help/prop_tgt/PDB_NAME_CONFIG.rst +++ b/Help/prop_tgt/PDB_NAME_CONFIG.rst @@ -6,5 +6,10 @@ generated by the linker for an executable or shared library target. This is the configuration-specific version of :prop_tgt:`PDB_NAME`. +.. versionadded:: 4.1 + + Contents of ``PDB_NAME_`` may use + :manual:`generator expressions `. + .. |COMPILE_PDB_XXX| replace:: :prop_tgt:`COMPILE_PDB_NAME_` .. include:: PDB_NOTE.txt diff --git a/Help/release/dev/pdb-name-genex-support.rst b/Help/release/dev/pdb-name-genex-support.rst new file mode 100644 index 0000000000..de26b73962 --- /dev/null +++ b/Help/release/dev/pdb-name-genex-support.rst @@ -0,0 +1,5 @@ +pdb-name-genex-support +---------------------- + +* The :prop_tgt:`PDB_NAME` and :prop_tgt:`COMPILE_PDB_NAME` target properties + now support :manual:`generator expressions `. diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 43ab2d3a36..2a4f347d1d 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -1274,16 +1274,20 @@ std::string cmGeneratorTarget::GetCompilePDBName( std::string configProp = cmStrCat("COMPILE_PDB_NAME_", configUpper); cmValue config_name = this->GetProperty(configProp); if (cmNonempty(config_name)) { + std::string pdbName = cmGeneratorExpression::Evaluate( + *config_name, this->LocalGenerator, config, this); NameComponents const& components = GetFullNameInternalComponents( config, cmStateEnums::RuntimeBinaryArtifact); - return components.prefix + *config_name + ".pdb"; + return components.prefix + pdbName + ".pdb"; } cmValue name = this->GetProperty("COMPILE_PDB_NAME"); if (cmNonempty(name)) { + std::string pdbName = cmGeneratorExpression::Evaluate( + *name, this->LocalGenerator, config, this); NameComponents const& components = GetFullNameInternalComponents( config, cmStateEnums::RuntimeBinaryArtifact); - return components.prefix + *name + ".pdb"; + return components.prefix + pdbName + ".pdb"; } return ""; @@ -3771,27 +3775,50 @@ bool cmGeneratorTarget::LinkerEnforcesNoAllowShLibUndefined( std::string cmGeneratorTarget::GetPDBOutputName( std::string const& config) const { - std::string base = - this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact) + - this->GetFilePostfix(config); + // Lookup/compute/cache the pdb output name for this configuration. + auto i = this->PdbOutputNameMap.find(config); + if (i == this->PdbOutputNameMap.end()) { + // Add empty name in map to detect potential recursion. + PdbOutputNameMapType::value_type entry(config, ""); + i = this->PdbOutputNameMap.insert(entry).first; - std::vector props; - std::string configUpper = cmSystemTools::UpperCase(config); - if (!configUpper.empty()) { - // PDB_NAME_ - props.push_back("PDB_NAME_" + configUpper); - } - - // PDB_NAME - props.emplace_back("PDB_NAME"); - - for (std::string const& p : props) { - if (cmValue outName = this->GetProperty(p)) { - base = *outName; - break; + // Compute output name. + std::vector props; + std::string configUpper = cmSystemTools::UpperCase(config); + if (!configUpper.empty()) { + // PDB_NAME_ + props.push_back("PDB_NAME_" + configUpper); } + + // PDB_NAME + props.emplace_back("PDB_NAME"); + + std::string outName; + for (std::string const& p : props) { + if (cmValue outNameProp = this->GetProperty(p)) { + outName = *outNameProp; + break; + } + } + + // Now evaluate genex and update the previously-prepared map entry. + if (outName.empty()) { + i->second = + this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact) + + this->GetFilePostfix(config); + } else { + i->second = + cmGeneratorExpression::Evaluate(outName, this->LocalGenerator, config); + } + } else if (i->second.empty()) { + // An empty map entry indicates we have been called recursively + // from the above block. + this->LocalGenerator->GetCMakeInstance()->IssueMessage( + MessageType::FATAL_ERROR, + "Target '" + this->GetName() + "' PDB_NAME depends on itself.", + this->GetBacktrace()); } - return base; + return i->second; } std::string cmGeneratorTarget::GetPDBName(std::string const& config) const @@ -3799,22 +3826,9 @@ std::string cmGeneratorTarget::GetPDBName(std::string const& config) const NameComponents const& parts = this->GetFullNameInternalComponents( config, cmStateEnums::RuntimeBinaryArtifact); - std::vector props; - std::string configUpper = cmSystemTools::UpperCase(config); - if (!configUpper.empty()) { - // PDB_NAME_ - props.push_back("PDB_NAME_" + configUpper); - } + std::string base = this->GetPDBOutputName(config); - // PDB_NAME - props.emplace_back("PDB_NAME"); - - for (std::string const& p : props) { - if (cmValue outName = this->GetProperty(p)) { - return parts.prefix + *outName + ".pdb"; - } - } - return parts.prefix + parts.base + ".pdb"; + return parts.prefix + base + ".pdb"; } std::string cmGeneratorTarget::GetObjectDirectory( diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 083de54011..e17f500c65 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -1372,6 +1372,9 @@ private: using OutputInfoMapType = std::map; mutable OutputInfoMapType OutputInfoMap; + using PdbOutputNameMapType = std::map; + mutable PdbOutputNameMapType PdbOutputNameMap; + using ModuleDefinitionInfoMapType = std::map; mutable ModuleDefinitionInfoMapType ModuleDefinitionInfoMap; diff --git a/Tests/RunCMake/GenEx-TARGET_FILE/OUTPUT_NAME-recursion-stderr.txt b/Tests/RunCMake/GenEx-TARGET_FILE/OUTPUT_NAME-recursion-stderr.txt index 9af0573d56..d0451b3d72 100644 --- a/Tests/RunCMake/GenEx-TARGET_FILE/OUTPUT_NAME-recursion-stderr.txt +++ b/Tests/RunCMake/GenEx-TARGET_FILE/OUTPUT_NAME-recursion-stderr.txt @@ -2,8 +2,7 @@ CMake Error at OUTPUT_NAME-recursion.cmake:[0-9]+ \(add_executable\): Target 'empty1' OUTPUT_NAME depends on itself. Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) - - +.* CMake Error at OUTPUT_NAME-recursion.cmake:[0-9]+ \(add_executable\): Target 'empty2' OUTPUT_NAME depends on itself. Call Stack \(most recent call first\): diff --git a/Tests/RunCMake/GenEx-TARGET_FILE/PDB_NAME-recursion-result.txt b/Tests/RunCMake/GenEx-TARGET_FILE/PDB_NAME-recursion-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_FILE/PDB_NAME-recursion-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-TARGET_FILE/PDB_NAME-recursion-stderr.txt b/Tests/RunCMake/GenEx-TARGET_FILE/PDB_NAME-recursion-stderr.txt new file mode 100644 index 0000000000..5d288db081 --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_FILE/PDB_NAME-recursion-stderr.txt @@ -0,0 +1,9 @@ +CMake Error at PDB_NAME-recursion.cmake:[0-9]+ \(add_executable\): + Target 'empty1' PDB_NAME depends on itself. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) +.* +CMake Error at PDB_NAME-recursion.cmake:[0-9]+ \(add_executable\): + Target 'empty2' PDB_NAME depends on itself. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/GenEx-TARGET_FILE/PDB_NAME-recursion.cmake b/Tests/RunCMake/GenEx-TARGET_FILE/PDB_NAME-recursion.cmake new file mode 100644 index 0000000000..f9b164885f --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_FILE/PDB_NAME-recursion.cmake @@ -0,0 +1,6 @@ +enable_language(C) +add_executable(empty1 empty.c) +set_property(TARGET empty1 PROPERTY PDB_NAME $) + +add_executable(empty2 empty.c) +set_property(TARGET empty2 PROPERTY OUTPUT_NAME $) diff --git a/Tests/RunCMake/GenEx-TARGET_FILE/RunCMakeTest.cmake b/Tests/RunCMake/GenEx-TARGET_FILE/RunCMakeTest.cmake index 5abea25379..16bc89472e 100644 --- a/Tests/RunCMake/GenEx-TARGET_FILE/RunCMakeTest.cmake +++ b/Tests/RunCMake/GenEx-TARGET_FILE/RunCMakeTest.cmake @@ -32,6 +32,7 @@ run_cmake(ImportedTarget-TARGET_BUNDLE_CONTENT_DIR) run_cmake(ImportedTarget-TARGET_PDB_FILE) run_cmake(ImportedTarget-TARGET_PDB_FILE_BASE_NAME) if(LINKER_SUPPORTS_PDB) + run_cmake(PDB_NAME-recursion) run_cmake(NonValidTarget-TARGET_PDB_FILE) run_cmake(ValidTarget-TARGET_PDB_FILE) run_cmake(NonValidTarget-TARGET_PDB_FILE_BASE_NAME)