瀏覽代碼

Merge topic 'vs-pdb-output'

2ccca05 Run PDBDirectoryAndName test on MSVC and Intel
efc83b3 Document that PDB_(NAME|OUTPUT_DIRECTORY) are ignored for VS 6
b294457 Verify that PDB_(NAME|OUTPUT_DIRECTORY) are honored in test
3f60dbf Add PDB_OUTPUT_DIRECTORY and PDB_NAME target properties (#10830)
Brad King 13 年之前
父節點
當前提交
7dce31f3d0

+ 9 - 0
Source/cmDocumentVariables.cxx

@@ -1210,6 +1210,15 @@ void cmDocumentVariables::DefineVariables(cmake* cm)
      false,
      false,
      "Variables that Control the Build");
      "Variables that Control the Build");
 
 
+  cm->DefineProperty
+    ("CMAKE_PDB_OUTPUT_DIRECTORY", cmProperty::VARIABLE,
+     "Where to put all the MS debug symbol files.",
+     "This variable is used to initialize the "
+     "PDB_OUTPUT_DIRECTORY property on all the targets. "
+     "See that target property for additional information.",
+     false,
+     "Variables that Control the Build");
+
   cm->DefineProperty
   cm->DefineProperty
     ("CMAKE_AUTOMOC", cmProperty::VARIABLE,
     ("CMAKE_AUTOMOC", cmProperty::VARIABLE,
      "Whether to handle moc automatically for Qt targets.",
      "Whether to handle moc automatically for Qt targets.",

+ 3 - 3
Source/cmLocalVisualStudio7Generator.cxx

@@ -842,7 +842,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
     // non-debug configurations because VS still creates .idb files.
     // non-debug configurations because VS still creates .idb files.
     fout <<  "\t\t\t\tProgramDataBaseFileName=\""
     fout <<  "\t\t\t\tProgramDataBaseFileName=\""
          << this->ConvertToXMLOutputPathSingle(
          << this->ConvertToXMLOutputPathSingle(
-              target.GetDirectory(configName).c_str())
+              target.GetPDBDirectory(configName).c_str())
          << "/"
          << "/"
          << target.GetPDBName(configName) << "\"\n";
          << target.GetPDBName(configName) << "\"\n";
     }
     }
@@ -1122,7 +1122,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
     fout << "\t\t\t\tAdditionalLibraryDirectories=\"";
     fout << "\t\t\t\tAdditionalLibraryDirectories=\"";
     this->OutputLibraryDirectories(fout, cli.GetDirectories());
     this->OutputLibraryDirectories(fout, cli.GetDirectories());
     fout << "\"\n";
     fout << "\"\n";
-    temp = target.GetDirectory(configName);
+    temp = target.GetPDBDirectory(configName);
     temp += "/";
     temp += "/";
     temp += targetNamePDB;
     temp += targetNamePDB;
     fout << "\t\t\t\tProgramDatabaseFile=\"" <<
     fout << "\t\t\t\tProgramDatabaseFile=\"" <<
@@ -1210,7 +1210,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
     this->OutputLibraryDirectories(fout, cli.GetDirectories());
     this->OutputLibraryDirectories(fout, cli.GetDirectories());
     fout << "\"\n";
     fout << "\"\n";
     std::string path = this->ConvertToXMLOutputPathSingle(
     std::string path = this->ConvertToXMLOutputPathSingle(
-      target.GetDirectory(configName).c_str());
+      target.GetPDBDirectory(configName).c_str());
     fout << "\t\t\t\tProgramDatabaseFile=\""
     fout << "\t\t\t\tProgramDatabaseFile=\""
          << path << "/" << targetNamePDB
          << path << "/" << targetNamePDB
          << "\"\n";
          << "\"\n";

+ 6 - 1
Source/cmMakefileExecutableTargetGenerator.cxx

@@ -131,9 +131,14 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
       outpathImp += "/";
       outpathImp += "/";
       }
       }
     }
     }
+
+  std::string pdbOutputPath = this->Target->GetPDBDirectory();
+  cmSystemTools::MakeDirectory(pdbOutputPath.c_str());
+  pdbOutputPath += "/";
+
   std::string targetFullPath = outpath + targetName;
   std::string targetFullPath = outpath + targetName;
   std::string targetFullPathReal = outpath + targetNameReal;
   std::string targetFullPathReal = outpath + targetNameReal;
-  std::string targetFullPathPDB = outpath + targetNamePDB;
+  std::string targetFullPathPDB =  pdbOutputPath + targetNamePDB;
   std::string targetFullPathImport = outpathImp + targetNameImport;
   std::string targetFullPathImport = outpathImp + targetNameImport;
   std::string targetOutPathPDB =
   std::string targetOutPathPDB =
     this->Convert(targetFullPathPDB.c_str(),
     this->Convert(targetFullPathPDB.c_str(),

+ 5 - 1
Source/cmMakefileLibraryTargetGenerator.cxx

@@ -328,8 +328,12 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
       }
       }
     }
     }
 
 
+  std::string pdbOutputPath = this->Target->GetPDBDirectory();
+  cmSystemTools::MakeDirectory(pdbOutputPath.c_str());
+  pdbOutputPath += "/";
+
   std::string targetFullPath = outpath + targetName;
   std::string targetFullPath = outpath + targetName;
-  std::string targetFullPathPDB = outpath + targetNamePDB;
+  std::string targetFullPathPDB = pdbOutputPath + targetNamePDB;
   std::string targetFullPathSO = outpath + targetNameSO;
   std::string targetFullPathSO = outpath + targetNameSO;
   std::string targetFullPathReal = outpath + targetNameReal;
   std::string targetFullPathReal = outpath + targetNameReal;
   std::string targetFullPathImport = outpathImp + targetNameImport;
   std::string targetFullPathImport = outpathImp + targetNameImport;

+ 1 - 1
Source/cmMakefileTargetGenerator.cxx

@@ -647,7 +647,7 @@ cmMakefileTargetGenerator
      this->Target->GetType() == cmTarget::SHARED_LIBRARY ||
      this->Target->GetType() == cmTarget::SHARED_LIBRARY ||
      this->Target->GetType() == cmTarget::MODULE_LIBRARY)
      this->Target->GetType() == cmTarget::MODULE_LIBRARY)
     {
     {
-    targetFullPathPDB = this->Target->GetDirectory(this->ConfigName);
+    targetFullPathPDB = this->Target->GetPDBDirectory(this->ConfigName);
     targetFullPathPDB += "/";
     targetFullPathPDB += "/";
     targetFullPathPDB += this->Target->GetPDBName(this->ConfigName);
     targetFullPathPDB += this->Target->GetPDBName(this->ConfigName);
     }
     }

+ 2 - 2
Source/cmNinjaTargetGenerator.cxx

@@ -329,10 +329,10 @@ bool cmNinjaTargetGenerator::SetMsvcTargetPdbVariable(cmNinjaVars& vars) const
        this->Target->GetType() == cmTarget::SHARED_LIBRARY ||
        this->Target->GetType() == cmTarget::SHARED_LIBRARY ||
        this->Target->GetType() == cmTarget::MODULE_LIBRARY)
        this->Target->GetType() == cmTarget::MODULE_LIBRARY)
       {
       {
-      pdbPath = this->Target->GetDirectory(this->GetConfigName());
+      pdbPath = this->Target->GetPDBDirectory(this->GetConfigName());
       pdbPath += "/";
       pdbPath += "/";
       pdbPath += this->Target->GetPDBName(this->GetConfigName());
       pdbPath += this->Target->GetPDBName(this->GetConfigName());
-    }
+      }
 
 
     vars["TARGET_PDB"] = this->GetLocalGenerator()->ConvertToOutputFormat(
     vars["TARGET_PDB"] = this->GetLocalGenerator()->ConvertToOutputFormat(
                           ConvertToNinjaPath(pdbPath.c_str()).c_str(),
                           ConvertToNinjaPath(pdbPath.c_str()).c_str(),

+ 136 - 3
Source/cmTarget.cxx

@@ -56,6 +56,7 @@ struct cmTarget::OutputInfo
 {
 {
   std::string OutDir;
   std::string OutDir;
   std::string ImpDir;
   std::string ImpDir;
+  std::string PdbDir;
 };
 };
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
@@ -739,6 +740,22 @@ void cmTarget::DefineProperties(cmake *cm)
      "This is a configuration-specific version of OUTPUT_NAME.  "
      "This is a configuration-specific version of OUTPUT_NAME.  "
      "Use OUTPUT_NAME_<CONFIG> instead.");
      "Use OUTPUT_NAME_<CONFIG> instead.");
 
 
+  cm->DefineProperty
+    ("PDB_NAME", cmProperty::TARGET,
+     "Output name for MS debug symbols .pdb file.",
+     "Set the base name for debug symbols file created for an "
+     "executable or library target.  "
+     "If not set, the logical target name is used by default.  "
+     "\n"
+     "This property is not implemented by the Visual Studio 6 generator.");
+
+  cm->DefineProperty
+    ("PDB_NAME_<CONFIG>", cmProperty::TARGET,
+     "Per-configuration name for MS debug symbols .pdb file.  ",
+     "This is the configuration-specific version of PDB_NAME.  "
+     "\n"
+     "This property is not implemented by the Visual Studio 6 generator.");
+
   cm->DefineProperty
   cm->DefineProperty
     ("PRE_INSTALL_SCRIPT", cmProperty::TARGET,
     ("PRE_INSTALL_SCRIPT", cmProperty::TARGET,
      "Deprecated install support.",
      "Deprecated install support.",
@@ -1188,6 +1205,27 @@ void cmTarget::DefineProperties(cmake *cm)
      "Per-configuration output directory for RUNTIME target files.",
      "Per-configuration output directory for RUNTIME target files.",
      CM_TARGET_OUTDIR_CONFIG_DOC(RUNTIME));
      CM_TARGET_OUTDIR_CONFIG_DOC(RUNTIME));
 
 
+  cm->DefineProperty
+    ("PDB_OUTPUT_DIRECTORY", cmProperty::TARGET,
+     "Output directory for MS debug symbols .pdb files.",
+     "This property specifies the directory into which the MS debug symbols "
+     "will be placed.  "
+     "This property is initialized by the value of the variable "
+     "CMAKE_PDB_OUTPUT_DIRECTORY if it is set when a target is created."
+     "\n"
+     "This property is not implemented by the Visual Studio 6 generator.");
+  cm->DefineProperty
+    ("PDB_OUTPUT_DIRECTORY_<CONFIG>", cmProperty::TARGET,
+     "Per-configuration output directory for MS debug symbols .pdb files.",
+     "This is a per-configuration version of PDB_OUTPUT_DIRECTORY, "
+     "but multi-configuration generators (VS, Xcode) do NOT append "
+     "a per-configuration subdirectory to the specified directory. "
+     "This property is initialized by the value of the variable "
+     "CMAKE_PDB_OUTPUT_DIRECTORY_<CONFIG> "
+     "if it is set when a target is created."
+     "\n"
+     "This property is not implemented by the Visual Studio 6 generator.");
+
   cm->DefineProperty
   cm->DefineProperty
     ("ARCHIVE_OUTPUT_NAME", cmProperty::TARGET,
     ("ARCHIVE_OUTPUT_NAME", cmProperty::TARGET,
      "Output name for ARCHIVE target files.",
      "Output name for ARCHIVE target files.",
@@ -1262,6 +1300,7 @@ void cmTarget::SetMakefile(cmMakefile* mf)
   this->SetPropertyDefault("ARCHIVE_OUTPUT_DIRECTORY", 0);
   this->SetPropertyDefault("ARCHIVE_OUTPUT_DIRECTORY", 0);
   this->SetPropertyDefault("LIBRARY_OUTPUT_DIRECTORY", 0);
   this->SetPropertyDefault("LIBRARY_OUTPUT_DIRECTORY", 0);
   this->SetPropertyDefault("RUNTIME_OUTPUT_DIRECTORY", 0);
   this->SetPropertyDefault("RUNTIME_OUTPUT_DIRECTORY", 0);
+  this->SetPropertyDefault("PDB_OUTPUT_DIRECTORY", 0);
   this->SetPropertyDefault("Fortran_FORMAT", 0);
   this->SetPropertyDefault("Fortran_FORMAT", 0);
   this->SetPropertyDefault("Fortran_MODULE_DIRECTORY", 0);
   this->SetPropertyDefault("Fortran_MODULE_DIRECTORY", 0);
   this->SetPropertyDefault("GNUtoMS", 0);
   this->SetPropertyDefault("GNUtoMS", 0);
@@ -1281,6 +1320,7 @@ void cmTarget::SetMakefile(cmMakefile* mf)
     "ARCHIVE_OUTPUT_DIRECTORY_",
     "ARCHIVE_OUTPUT_DIRECTORY_",
     "LIBRARY_OUTPUT_DIRECTORY_",
     "LIBRARY_OUTPUT_DIRECTORY_",
     "RUNTIME_OUTPUT_DIRECTORY_",
     "RUNTIME_OUTPUT_DIRECTORY_",
+    "PDB_OUTPUT_DIRECTORY_",
     0};
     0};
   for(std::vector<std::string>::iterator ci = configNames.begin();
   for(std::vector<std::string>::iterator ci = configNames.begin();
       ci != configNames.end(); ++ci)
       ci != configNames.end(); ++ci)
@@ -2538,6 +2578,7 @@ cmTarget::OutputInfo const* cmTarget::GetOutputInfo(const char* config)
     OutputInfo info;
     OutputInfo info;
     this->ComputeOutputDir(config, false, info.OutDir);
     this->ComputeOutputDir(config, false, info.OutDir);
     this->ComputeOutputDir(config, true, info.ImpDir);
     this->ComputeOutputDir(config, true, info.ImpDir);
+    this->ComputePDBOutputDir(config, info.PdbDir);
     OutputInfoMapType::value_type entry(config_upper, info);
     OutputInfoMapType::value_type entry(config_upper, info);
     i = this->Internal->OutputInfoMap.insert(entry).first;
     i = this->Internal->OutputInfoMap.insert(entry).first;
     }
     }
@@ -2562,6 +2603,17 @@ std::string cmTarget::GetDirectory(const char* config, bool implib)
   return "";
   return "";
 }
 }
 
 
+//----------------------------------------------------------------------------
+std::string cmTarget::GetPDBDirectory(const char* config)
+{
+  if(OutputInfo const* info = this->GetOutputInfo(config))
+    {
+    // Return the directory in which the target will be built.
+    return info->PdbDir;
+    }
+  return "";
+}
+
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
 const char* cmTarget::GetLocation(const char* config)
 const char* cmTarget::GetLocation(const char* config)
 {
 {
@@ -3008,6 +3060,28 @@ std::string cmTarget::GetPDBName(const char* config)
   std::string base;
   std::string base;
   std::string suffix;
   std::string suffix;
   this->GetFullNameInternal(config, false, prefix, base, suffix);
   this->GetFullNameInternal(config, false, prefix, base, suffix);
+
+  std::vector<std::string> props;
+  std::string configUpper =
+    cmSystemTools::UpperCase(config? config : "");
+  if(!configUpper.empty())
+    {
+    // PDB_NAME_<CONFIG>
+    props.push_back("PDB_NAME_" + configUpper);
+    }
+
+  // PDB_NAME
+  props.push_back("PDB_NAME");
+
+  for(std::vector<std::string>::const_iterator i = props.begin();
+      i != props.end(); ++i)
+    {
+    if(const char* outName = this->GetProperty(i->c_str()))
+      {
+      base = outName;
+      break;
+      }
+    }
   return prefix+base+".pdb";
   return prefix+base+".pdb";
 }
 }
 
 
@@ -3392,7 +3466,7 @@ void cmTarget::GetLibraryNames(std::string& name,
     }
     }
 
 
   // The program database file name.
   // The program database file name.
-  pdbName = prefix+base+".pdb";
+  pdbName = this->GetPDBName(config);
 }
 }
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
@@ -3471,7 +3545,7 @@ void cmTarget::GetExecutableNames(std::string& name,
   impName = this->GetFullNameInternal(config, true);
   impName = this->GetFullNameInternal(config, true);
 
 
   // The program database file name.
   // The program database file name.
-  pdbName = prefix+base+".pdb";
+  pdbName = this->GetPDBName(config);
 }
 }
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
@@ -3550,7 +3624,7 @@ void cmTarget::GenerateTargetManifest(const char* config)
     }
     }
   if(!pdbName.empty())
   if(!pdbName.empty())
     {
     {
-    f = dir;
+    f = this->GetPDBDirectory(config);
     f += "/";
     f += "/";
     f += pdbName;
     f += pdbName;
     gg->AddToManifest(config? config:"", f);
     gg->AddToManifest(config? config:"", f);
@@ -3859,6 +3933,65 @@ bool cmTarget::ComputeOutputDir(const char* config,
   return usesDefaultOutputDir;
   return usesDefaultOutputDir;
 }
 }
 
 
+//----------------------------------------------------------------------------
+void cmTarget::ComputePDBOutputDir(const char* config, std::string& out)
+{
+  // Look for a target property defining the target output directory
+  // based on the target type.
+  std::string targetTypeName = "PDB";
+  const char* propertyName = 0;
+  std::string propertyNameStr = targetTypeName;
+  if(!propertyNameStr.empty())
+    {
+    propertyNameStr += "_OUTPUT_DIRECTORY";
+    propertyName = propertyNameStr.c_str();
+    }
+
+  // Check for a per-configuration output directory target property.
+  std::string configUpper = cmSystemTools::UpperCase(config? config : "");
+  const char* configProp = 0;
+  std::string configPropStr = targetTypeName;
+  if(!configPropStr.empty())
+    {
+    configPropStr += "_OUTPUT_DIRECTORY_";
+    configPropStr += configUpper;
+    configProp = configPropStr.c_str();
+    }
+
+  // Select an output directory.
+  if(const char* config_outdir = this->GetProperty(configProp))
+    {
+    // Use the user-specified per-configuration output directory.
+    out = config_outdir;
+
+    // Skip per-configuration subdirectory.
+    config = 0;
+    }
+  else if(const char* outdir = this->GetProperty(propertyName))
+    {
+    // Use the user-specified output directory.
+    out = outdir;
+    }
+  if(out.empty())
+    {
+    // Default to the current output directory.
+    out = ".";
+    }
+
+  // Convert the output path to a full path in case it is
+  // specified as a relative path.  Treat a relative path as
+  // relative to the current output directory for this makefile.
+  out = (cmSystemTools::CollapseFullPath
+         (out.c_str(), this->Makefile->GetStartOutputDirectory()));
+
+  // The generator may add the configuration's subdirectory.
+  if(config && *config)
+    {
+    this->Makefile->GetLocalGenerator()->GetGlobalGenerator()->
+      AppendDirectoryForConfig("/", config, "", out);
+    }
+}
+
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
 bool cmTarget::UsesDefaultOutputDir(const char* config, bool implib)
 bool cmTarget::UsesDefaultOutputDir(const char* config, bool implib)
 {
 {

+ 7 - 0
Source/cmTarget.h

@@ -291,6 +291,12 @@ public:
       output directory is given.  */
       output directory is given.  */
   std::string GetDirectory(const char* config = 0, bool implib = false);
   std::string GetDirectory(const char* config = 0, bool implib = false);
 
 
+  /** Get the directory in which this targets .pdb files will be placed.
+      If the configuration name is given then the generator will add its
+      subdirectory for that configuration.  Otherwise just the canonical
+      pdb output directory is given.  */
+  std::string GetPDBDirectory(const char* config = 0);
+
   /** Get the location of the target in the build tree for the given
   /** Get the location of the target in the build tree for the given
       configuration.  This location is suitable for use as the LOCATION
       configuration.  This location is suitable for use as the LOCATION
       target property.  */
       target property.  */
@@ -571,6 +577,7 @@ private:
   struct OutputInfo;
   struct OutputInfo;
   OutputInfo const* GetOutputInfo(const char* config);
   OutputInfo const* GetOutputInfo(const char* config);
   bool ComputeOutputDir(const char* config, bool implib, std::string& out);
   bool ComputeOutputDir(const char* config, bool implib, std::string& out);
+  void ComputePDBOutputDir(const char* config, std::string& out);
 
 
   // Cache import information from properties for each configuration.
   // Cache import information from properties for each configuration.
   struct ImportInfo;
   struct ImportInfo;

+ 3 - 5
Source/cmVisualStudio10TargetGenerator.cxx

@@ -1279,9 +1279,8 @@ void cmVisualStudio10TargetGenerator::WriteClOptions(
   this->WriteString("<ObjectFileName>$(IntDir)</ObjectFileName>\n", 3);
   this->WriteString("<ObjectFileName>$(IntDir)</ObjectFileName>\n", 3);
   if(this->Target->GetType() != cmTarget::OBJECT_LIBRARY)
   if(this->Target->GetType() != cmTarget::OBJECT_LIBRARY)
     {
     {
-    // TODO: PDB for object library?
     this->WriteString("<ProgramDataBaseFileName>", 3);
     this->WriteString("<ProgramDataBaseFileName>", 3);
-    *this->BuildFileStream << this->Target->GetDirectory(configName.c_str())
+    *this->BuildFileStream << this->Target->GetPDBDirectory(configName.c_str())
                            << "/"
                            << "/"
                            << this->Target->GetPDBName(configName.c_str())
                            << this->Target->GetPDBName(configName.c_str())
                            << "</ProgramDataBaseFileName>\n";
                            << "</ProgramDataBaseFileName>\n";
@@ -1506,9 +1505,8 @@ void cmVisualStudio10TargetGenerator::WriteLinkOptions(std::string const&
                                   config.c_str());
                                   config.c_str());
     }
     }
 
 
-  std::string dir = this->Target->GetDirectory(config.c_str());
-  dir += "/";
-  std::string pdb = dir;
+  std::string pdb = this->Target->GetPDBDirectory(config.c_str());
+  pdb += "/";
   pdb += targetNamePDB;
   pdb += targetNamePDB;
   std::string imLib = this->Target->GetDirectory(config.c_str(), true);
   std::string imLib = this->Target->GetDirectory(config.c_str(), true);
   imLib += "/";
   imLib += "/";

+ 1 - 0
Tests/CMakeLists.txt

@@ -1254,6 +1254,7 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/
 
 
   if(CMAKE_TEST_MSVC)
   if(CMAKE_TEST_MSVC)
     ADD_TEST_MACRO(ForceInclude foo)
     ADD_TEST_MACRO(ForceInclude foo)
+    ADD_TEST_MACRO(PDBDirectoryAndName myexe)
     ADD_TEST_MACRO(PrecompiledHeader foo)
     ADD_TEST_MACRO(PrecompiledHeader foo)
   endif()
   endif()
   if(CMAKE_TEST_MSVC OR
   if(CMAKE_TEST_MSVC OR

+ 79 - 0
Tests/PDBDirectoryAndName/CMakeLists.txt

@@ -0,0 +1,79 @@
+cmake_minimum_required(VERSION 2.8)
+project(PDBDirectoryAndName C)
+
+# Make sure the proper compiler is in use.
+if(NOT MSVC AND NOT "${CMAKE_C_COMPILER_ID}" MATCHES "^(Intel)$")
+  message(FATAL_ERROR "The PDBDirectoryAndName test works only with MSVC or Intel")
+endif()
+
+set(my_targets "")
+
+add_library(mylibA SHARED mylibA.c)
+set_target_properties(mylibA PROPERTIES
+    PDB_NAME "mylibA_Special"
+    PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/mylibA_PDB"
+)
+list(APPEND my_targets mylibA)
+
+add_library(mylibB STATIC mylibB.c)
+set_target_properties(mylibB PROPERTIES
+    PDB_NAME "mylibB_Special"
+    PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/mylibB_PDB"
+)
+list(APPEND my_targets mylibB)
+
+add_library(mylibC SHARED mylibC.c)
+set_target_properties(mylibC PROPERTIES
+    PDB_NAME "mylibC_Special"
+)
+list(APPEND my_targets mylibC)
+
+add_library(mylibD STATIC mylibD.c)
+set_target_properties(mylibD PROPERTIES
+    PDB_NAME "mylibD_Special"
+)
+list(APPEND my_targets mylibD)
+
+add_executable(myexe myexe.c)
+set_target_properties(myexe PROPERTIES
+    PDB_NAME "myexe_Special"
+    PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/myexe_PDB"
+)
+list(APPEND my_targets myexe)
+
+target_link_libraries(myexe mylibA mylibB mylibC mylibD)
+
+add_executable(myexe2 myexe2.c)
+set_target_properties(myexe2 PROPERTIES
+    PDB_NAME "myexe2_Special"
+)
+list(APPEND my_targets myexe2)
+
+target_link_libraries(myexe2 mylibA mylibD)
+
+#-----------------------------------------------------------------------------
+# Check that PDB files actually appear where expected.
+
+# The PDB_NAME and PDB_OUTPUT_DIRECTORY options do not work in VS 6.
+if("${CMAKE_GENERATOR}" MATCHES "Visual Studio 6")
+  return()
+endif()
+# PDB output not fully implemented for Intel
+if("${CMAKE_C_COMPILER_ID}" MATCHES "^(Intel)$")
+  return()
+endif()
+
+set(pdbs "")
+foreach(t ${my_targets})
+  get_property(pdb_name TARGET ${t} PROPERTY PDB_NAME)
+  get_property(pdb_dir TARGET ${t} PROPERTY PDB_OUTPUT_DIRECTORY)
+  if(NOT pdb_dir)
+    set(pdb_dir ${CMAKE_CURRENT_BINARY_DIR})
+  endif()
+  list(APPEND pdbs ${pdb_dir}/${CMAKE_CFG_INTDIR}/${pdb_name}.pdb)
+endforeach()
+add_custom_target(check_pdbs ALL VERBATIM
+  COMMAND ${CMAKE_COMMAND} -Dconfig=$<CONFIGURATION> "-Dpdbs=${pdbs}"
+                           -P ${CMAKE_CURRENT_SOURCE_DIR}/check_pdbs.cmake
+  )
+add_dependencies(check_pdbs ${my_targets})

+ 10 - 0
Tests/PDBDirectoryAndName/check_pdbs.cmake

@@ -0,0 +1,10 @@
+if(NOT "${config}" MATCHES "[Dd][Ee][Bb]")
+  return()
+endif()
+foreach(pdb ${pdbs})
+  if(EXISTS "${pdb}")
+    message(STATUS "PDB Exists: ${pdb}")
+  else()
+    message(SEND_ERROR "PDB MISSING: ${pdb}")
+  endif()
+endforeach()

+ 5 - 0
Tests/PDBDirectoryAndName/myexe.c

@@ -0,0 +1,5 @@
+extern int mylibA();
+extern int mylibB();
+extern int mylibC();
+extern int mylibD();
+int main() { return mylibA() + mylibB() + mylibC() + mylibD(); }

+ 3 - 0
Tests/PDBDirectoryAndName/myexe2.c

@@ -0,0 +1,3 @@
+extern int mylibA();
+extern int mylibD();
+int main() { return mylibA() + mylibD(); }

+ 1 - 0
Tests/PDBDirectoryAndName/mylibA.c

@@ -0,0 +1 @@
+__declspec(dllexport) int mylibA() { return 1; }

+ 1 - 0
Tests/PDBDirectoryAndName/mylibB.c

@@ -0,0 +1 @@
+int mylibB() { return -1; }

+ 1 - 0
Tests/PDBDirectoryAndName/mylibC.c

@@ -0,0 +1 @@
+__declspec(dllexport) int mylibC() { return 1; }

+ 1 - 0
Tests/PDBDirectoryAndName/mylibD.c

@@ -0,0 +1 @@
+int mylibD() { return -1; }