diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index bc2479894..77259a0f3 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -148,6 +148,17 @@ than 4.2.0. Name of file with soname (.so.3). ``$`` Directory of with soname (.so.3). +``$`` + Full path to the linker generated program database file (.pdb) + where ``tgt`` is the name of a target. + + See also the :prop_tgt:`PDB_NAME` and :prop_tgt:`PDB_OUTPUT_DIRECTORY` + target properties and their configuration specific variants + :prop_tgt:`PDB_NAME_` and :prop_tgt:`PDB_OUTPUT_DIRECTORY_`. +``$`` + Name of the linker generated program database file (.pdb). +``$`` + Directory of the linker generated program database file (.pdb). ``$`` Value of the property ``prop`` on the target ``tgt``. diff --git a/Modules/Platform/Windows-MSVC.cmake b/Modules/Platform/Windows-MSVC.cmake index 2cfe6fef9..e51c59285 100644 --- a/Modules/Platform/Windows-MSVC.cmake +++ b/Modules/Platform/Windows-MSVC.cmake @@ -258,4 +258,5 @@ macro(__windows_compiler_msvc lang) set(CMAKE_${lang}_FLAGS_RELEASE_INIT "/MD /O2 /Ob2 /D NDEBUG") set(CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT "/MD /Zi /O2 /Ob1 /D NDEBUG") set(CMAKE_${lang}_FLAGS_MINSIZEREL_INIT "/MD /O1 /Ob1 /D NDEBUG") + set(CMAKE_${lang}_LINKER_SUPPORTS_PDB ON) endmacro() diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index 7a53d65c9..35a9fcb52 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -1523,7 +1523,17 @@ static const struct InstallPrefixNode : public cmGeneratorExpressionNode } installPrefixNode; //---------------------------------------------------------------------------- -template +class ArtifactNameTag; +class ArtifactLinkerTag; +class ArtifactSonameTag; +class ArtifactPdbTag; + +class ArtifactPathTag; +class ArtifactDirTag; +class ArtifactNameTag; + +//---------------------------------------------------------------------------- +template struct TargetFilesystemArtifactResultCreator { static std::string Create(cmTarget* target, @@ -1533,7 +1543,7 @@ struct TargetFilesystemArtifactResultCreator //---------------------------------------------------------------------------- template<> -struct TargetFilesystemArtifactResultCreator +struct TargetFilesystemArtifactResultCreator { static std::string Create(cmTarget* target, cmGeneratorExpressionContext *context, @@ -1563,7 +1573,45 @@ struct TargetFilesystemArtifactResultCreator //---------------------------------------------------------------------------- template<> -struct TargetFilesystemArtifactResultCreator +struct TargetFilesystemArtifactResultCreator +{ + static std::string Create(cmTarget* target, + cmGeneratorExpressionContext *context, + const GeneratorExpressionContent *content) + { + std::string language = target->GetLinkerLanguage(context->Config); + + std::string pdbSupportVar = "CMAKE_" + language + "_LINKER_SUPPORTS_PDB"; + + if(!context->Makefile->IsOn(pdbSupportVar)) + { + ::reportError(context, content->GetOriginalExpression(), + "TARGET_PDB_FILE is not supported by the target linker."); + return std::string(); + } + + cmTarget::TargetType targetType = target->GetType(); + + if(targetType != cmTarget::SHARED_LIBRARY && + targetType != cmTarget::MODULE_LIBRARY && + targetType != cmTarget::EXECUTABLE) + { + ::reportError(context, content->GetOriginalExpression(), + "TARGET_PDB_FILE is allowed only for " + "targets with linker created artifacts."); + return std::string(); + } + + std::string result = target->GetPDBDirectory(context->Config); + result += "/"; + result += target->GetPDBName(context->Config); + return result; + } +}; + +//---------------------------------------------------------------------------- +template<> +struct TargetFilesystemArtifactResultCreator { static std::string Create(cmTarget* target, cmGeneratorExpressionContext *context, @@ -1584,7 +1632,7 @@ struct TargetFilesystemArtifactResultCreator //---------------------------------------------------------------------------- template<> -struct TargetFilesystemArtifactResultCreator +struct TargetFilesystemArtifactResultCreator { static std::string Create(cmTarget* target, cmGeneratorExpressionContext *context, @@ -1596,7 +1644,7 @@ struct TargetFilesystemArtifactResultCreator //---------------------------------------------------------------------------- -template +template struct TargetFilesystemArtifactResultGetter { static std::string Get(const std::string &result); @@ -1604,7 +1652,7 @@ struct TargetFilesystemArtifactResultGetter //---------------------------------------------------------------------------- template<> -struct TargetFilesystemArtifactResultGetter +struct TargetFilesystemArtifactResultGetter { static std::string Get(const std::string &result) { return cmSystemTools::GetFilenameName(result); } @@ -1612,7 +1660,7 @@ struct TargetFilesystemArtifactResultGetter //---------------------------------------------------------------------------- template<> -struct TargetFilesystemArtifactResultGetter +struct TargetFilesystemArtifactResultGetter { static std::string Get(const std::string &result) { return cmSystemTools::GetFilenamePath(result); } @@ -1620,14 +1668,14 @@ struct TargetFilesystemArtifactResultGetter //---------------------------------------------------------------------------- template<> -struct TargetFilesystemArtifactResultGetter +struct TargetFilesystemArtifactResultGetter { static std::string Get(const std::string &result) { return result; } }; //---------------------------------------------------------------------------- -template +template struct TargetFilesystemArtifact : public cmGeneratorExpressionNode { TargetFilesystemArtifact() {} @@ -1675,7 +1723,7 @@ struct TargetFilesystemArtifact : public cmGeneratorExpressionNode context->AllTargets.insert(target); std::string result = - TargetFilesystemArtifactResultCreator::Create( + TargetFilesystemArtifactResultCreator::Create( target, context, content); @@ -1684,29 +1732,35 @@ struct TargetFilesystemArtifact : public cmGeneratorExpressionNode return std::string(); } return - TargetFilesystemArtifactResultGetter::Get(result); + TargetFilesystemArtifactResultGetter::Get(result); } }; +//---------------------------------------------------------------------------- +template +struct TargetFilesystemArtifactNodeGroup +{ + TargetFilesystemArtifactNodeGroup() + { + } + + TargetFilesystemArtifact File; + TargetFilesystemArtifact FileName; + TargetFilesystemArtifact FileDir; +}; + //---------------------------------------------------------------------------- static const -TargetFilesystemArtifact targetFileNode; +TargetFilesystemArtifactNodeGroup targetNodeGroup; + static const -TargetFilesystemArtifact targetLinkerFileNode; +TargetFilesystemArtifactNodeGroup targetLinkerNodeGroup; + static const -TargetFilesystemArtifact targetSoNameFileNode; +TargetFilesystemArtifactNodeGroup targetSoNameNodeGroup; + static const -TargetFilesystemArtifact targetFileNameNode; -static const -TargetFilesystemArtifact targetLinkerFileNameNode; -static const -TargetFilesystemArtifact targetSoNameFileNameNode; -static const -TargetFilesystemArtifact targetFileDirNode; -static const -TargetFilesystemArtifact targetLinkerFileDirNode; -static const -TargetFilesystemArtifact targetSoNameFileDirNode; +TargetFilesystemArtifactNodeGroup targetPdbNodeGroup; //---------------------------------------------------------------------------- static const @@ -1732,15 +1786,18 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier) nodeMap["COMPILE_FEATURES"] = &compileFeaturesNode; nodeMap["CONFIGURATION"] = &configurationNode; nodeMap["CONFIG"] = &configurationTestNode; - nodeMap["TARGET_FILE"] = &targetFileNode; - nodeMap["TARGET_LINKER_FILE"] = &targetLinkerFileNode; - nodeMap["TARGET_SONAME_FILE"] = &targetSoNameFileNode; - nodeMap["TARGET_FILE_NAME"] = &targetFileNameNode; - nodeMap["TARGET_LINKER_FILE_NAME"] = &targetLinkerFileNameNode; - nodeMap["TARGET_SONAME_FILE_NAME"] = &targetSoNameFileNameNode; - nodeMap["TARGET_FILE_DIR"] = &targetFileDirNode; - nodeMap["TARGET_LINKER_FILE_DIR"] = &targetLinkerFileDirNode; - nodeMap["TARGET_SONAME_FILE_DIR"] = &targetSoNameFileDirNode; + nodeMap["TARGET_FILE"] = &targetNodeGroup.File; + nodeMap["TARGET_LINKER_FILE"] = &targetLinkerNodeGroup.File; + nodeMap["TARGET_SONAME_FILE"] = &targetSoNameNodeGroup.File; + nodeMap["TARGET_PDB_FILE"] = &targetPdbNodeGroup.File; + nodeMap["TARGET_FILE_NAME"] = &targetNodeGroup.FileName; + nodeMap["TARGET_LINKER_FILE_NAME"] = &targetLinkerNodeGroup.FileName; + nodeMap["TARGET_SONAME_FILE_NAME"] = &targetSoNameNodeGroup.FileName; + nodeMap["TARGET_PDB_FILE_NAME"] = &targetPdbNodeGroup.FileName; + nodeMap["TARGET_FILE_DIR"] = &targetNodeGroup.FileDir; + nodeMap["TARGET_LINKER_FILE_DIR"] = &targetLinkerNodeGroup.FileDir; + nodeMap["TARGET_SONAME_FILE_DIR"] = &targetSoNameNodeGroup.FileDir; + nodeMap["TARGET_PDB_FILE_DIR"] = &targetPdbNodeGroup.FileDir; nodeMap["STREQUAL"] = &strEqualNode; nodeMap["EQUAL"] = &equalNode; nodeMap["LOWER_CASE"] = &lowerCaseNode; diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index ff3b9a061..3cd9947c1 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -21,6 +21,12 @@ if(XCODE_VERSION AND "${XCODE_VERSION}" VERSION_LESS 2) set(File_Generate_ARGS -DXCODE_BELOW_2=1) endif() +# Test MSVC for older host CMake versions, and test +# WIN32/CMAKE_C_COMPILER_ID to fix check on Intel for Windows. +if(MSVC OR (WIN32 AND CMAKE_C_COMPILER_ID MATCHES "MSVC|Intel")) + set(GeneratorExpression_ARGS -DLINKER_SUPPORTS_PDB=1) +endif() + add_RunCMake_test(CMP0019) add_RunCMake_test(CMP0022) add_RunCMake_test(CMP0026) diff --git a/Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_FILE-result.txt b/Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_FILE-result.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_FILE-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_FILE-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_FILE-stderr.txt new file mode 100644 index 000000000..831edadcf --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_FILE-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at NonValidCompiler-TARGET_PDB_FILE.cmake:6 \(file\): + Error evaluating generator expression: + + \$ + + TARGET_PDB_FILE is not supported by the target linker. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_FILE.cmake b/Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_FILE.cmake new file mode 100644 index 000000000..84a2b2e8b --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/NonValidCompiler-TARGET_PDB_FILE.cmake @@ -0,0 +1,9 @@ + +enable_language(C) + +add_library(empty STATIC empty.c) + +file(GENERATE + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt" + CONTENT "[$]" +) diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_FILE-result.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_FILE-result.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_FILE-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_FILE-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_FILE-stderr.txt new file mode 100644 index 000000000..e5f21e2e3 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_FILE-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at NonValidTarget-TARGET_PDB_FILE.cmake:6 \(file\): + Error evaluating generator expression: + + \$ + + TARGET_PDB_FILE is allowed only for targets with linker created artifacts. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_FILE.cmake b/Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_FILE.cmake new file mode 100644 index 000000000..84a2b2e8b --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_PDB_FILE.cmake @@ -0,0 +1,9 @@ + +enable_language(C) + +add_library(empty STATIC empty.c) + +file(GENERATE + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt" + CONTENT "[$]" +) diff --git a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake index c8f3fdf81..6c32393fc 100644 --- a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake +++ b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake @@ -16,3 +16,10 @@ run_cmake(NonValidTarget-C_COMPILER_VERSION) run_cmake(NonValidTarget-CXX_COMPILER_VERSION) run_cmake(NonValidTarget-TARGET_PROPERTY) run_cmake(NonValidTarget-TARGET_POLICY) + +if(LINKER_SUPPORTS_PDB) + run_cmake(NonValidTarget-TARGET_PDB_FILE) + run_cmake(ValidTarget-TARGET_PDB_FILE) +else() + run_cmake(NonValidCompiler-TARGET_PDB_FILE) +endif() diff --git a/Tests/RunCMake/GeneratorExpression/ValidTarget-TARGET_PDB_FILE-check.cmake b/Tests/RunCMake/GeneratorExpression/ValidTarget-TARGET_PDB_FILE-check.cmake new file mode 100644 index 000000000..748d14f85 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/ValidTarget-TARGET_PDB_FILE-check.cmake @@ -0,0 +1,17 @@ +file(STRINGS ${RunCMake_TEST_BINARY_DIR}/test.txt TEST_TXT) + +list(GET TEST_TXT 0 PDB_PATH) +list(GET TEST_TXT 1 PDB_NAME) +list(GET TEST_TXT 2 PDB_DIR) + +if(NOT PDB_PATH MATCHES "empty\\.pdb") + message(FATAL_ERROR "unexpected PDB_PATH [${PDB_PATH}]") +endif() + +if(NOT PDB_NAME STREQUAL "empty.pdb") + message(FATAL_ERROR "unexpected PDB_NAME [${PDB_NAME}]") +endif() + +if(PDB_DIR MATCHES "empty\\.pdb") + message(FATAL_ERROR "unexpected PDB_DIR [${PDB_DIR}]") +endif() diff --git a/Tests/RunCMake/GeneratorExpression/ValidTarget-TARGET_PDB_FILE-stderr.txt b/Tests/RunCMake/GeneratorExpression/ValidTarget-TARGET_PDB_FILE-stderr.txt new file mode 100644 index 000000000..10f32932e --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/ValidTarget-TARGET_PDB_FILE-stderr.txt @@ -0,0 +1 @@ +^$ diff --git a/Tests/RunCMake/GeneratorExpression/ValidTarget-TARGET_PDB_FILE.cmake b/Tests/RunCMake/GeneratorExpression/ValidTarget-TARGET_PDB_FILE.cmake new file mode 100644 index 000000000..38e47f91f --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/ValidTarget-TARGET_PDB_FILE.cmake @@ -0,0 +1,19 @@ + +enable_language(C) + +add_library(empty SHARED empty.c) + +if(CMAKE_CONFIGURATION_TYPES) + list(GET CMAKE_CONFIGURATION_TYPES 0 FIRST_CONFIG) + set(GENERATE_CONDITION CONDITION $) +endif() + +file(GENERATE + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt" + CONTENT +[[$ +$ +$ +]] + ${GENERATE_CONDITION} +)