diff options
Diffstat (limited to 'Source')
48 files changed, 1992 insertions, 1131 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 175a034..966e0f6 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -562,7 +562,11 @@ if(WIN32) set(CPACK_SRCS ${CPACK_SRCS} CPack/WiX/cmCPackWIXGenerator.cxx CPack/WiX/cmWIXSourceWriter.cxx + CPack/WiX/cmWIXDirectoriesSourceWriter.cxx + CPack/WiX/cmWIXFeaturesSourceWriter.cxx + CPack/WiX/cmWIXFilesSourceWriter.cxx CPack/WiX/cmWIXRichTextFormatWriter.cxx + CPack/WiX/cmWIXPatch.cxx CPack/WiX/cmWIXPatchParser.cxx ) endif() diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 693144a..ccc5183 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 0) -set(CMake_VERSION_PATCH 20140223) +set(CMake_VERSION_PATCH 20140228) #set(CMake_VERSION_RC 1) diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx index 43119d6..8e671cc 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx +++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx @@ -1,6 +1,6 @@ /*============================================================================ CMake - Cross Platform Makefile Generator - Copyright 2000-2013 Kitware, Inc., Insight Software Consortium + Copyright 2000-2014 Kitware, Inc., Insight Software Consortium Distributed under the OSI-approved BSD License (the "License"); see accompanying file Copyright.txt for details. @@ -19,6 +19,9 @@ #include <CPack/cmCPackComponentGroup.h> #include "cmWIXSourceWriter.h" +#include "cmWIXDirectoriesSourceWriter.h" +#include "cmWIXFeaturesSourceWriter.h" +#include "cmWIXFilesSourceWriter.h" #include "cmWIXRichTextFormatWriter.h" #include <cmsys/SystemTools.hxx> @@ -28,11 +31,9 @@ #include <rpc.h> // for GUID generation -#include <sys/types.h> -#include <sys/stat.h> - cmCPackWIXGenerator::cmCPackWIXGenerator(): - HasDesktopShortcuts(false) + HasDesktopShortcuts(false), + Patch(Logger) { } @@ -44,15 +45,9 @@ int cmCPackWIXGenerator::InitializeInternal() return this->Superclass::InitializeInternal(); } -bool cmCPackWIXGenerator::RunWiXCommand(const std::string& command) +bool cmCPackWIXGenerator::RunWiXCommand(std::string const& command) { - std::string cpackTopLevel; - if(!RequireOption("CPACK_TOPLEVEL_DIRECTORY", cpackTopLevel)) - { - return false; - } - - std::string logFileName = cpackTopLevel + "/wix.log"; + std::string logFileName = this->CPackTopLevel + "/wix.log"; cmCPackLogger(cmCPackLog::LOG_DEBUG, "Running WiX command: " << command << std::endl); @@ -81,7 +76,7 @@ bool cmCPackWIXGenerator::RunWiXCommand(const std::string& command) } bool cmCPackWIXGenerator::RunCandleCommand( - const std::string& sourceFile, const std::string& objectFile) + std::string const& sourceFile, std::string const& objectFile) { std::string executable; if(!RequireOption("CPACK_WIX_CANDLE_EXECUTABLE", executable)) @@ -108,7 +103,7 @@ bool cmCPackWIXGenerator::RunCandleCommand( return RunWiXCommand(command.str()); } -bool cmCPackWIXGenerator::RunLightCommand(const std::string& objectFiles) +bool cmCPackWIXGenerator::RunLightCommand(std::string const& objectFiles) { std::string executable; if(!RequireOption("CPACK_WIX_LIGHT_EXECUTABLE", executable)) @@ -121,8 +116,8 @@ bool cmCPackWIXGenerator::RunLightCommand(const std::string& objectFiles) command << " -nologo"; command << " -out " << QuotePath(packageFileNames.at(0)); - for(extension_set_t::const_iterator i = LightExtensions.begin(); - i != LightExtensions.end(); ++i) + for(extension_set_t::const_iterator i = this->LightExtensions.begin(); + i != this->LightExtensions.end(); ++i) { command << " -ext " << QuotePath(*i); } @@ -182,15 +177,14 @@ bool cmCPackWIXGenerator::InitializeWiXConfiguration() "you might want to set this explicitly." << std::endl); } - std::string cpackTopLevel; - if(!RequireOption("CPACK_TOPLEVEL_DIRECTORY", cpackTopLevel)) + if(!RequireOption("CPACK_TOPLEVEL_DIRECTORY", this->CPackTopLevel)) { return false; } if(GetOption("CPACK_WIX_LICENSE_RTF") == 0) { - std::string licenseFilename = cpackTopLevel + "/License.rtf"; + std::string licenseFilename = this->CPackTopLevel + "/License.rtf"; SetOption("CPACK_WIX_LICENSE_RTF", licenseFilename.c_str()); if(!CreateLicenseFile()) @@ -213,7 +207,7 @@ bool cmCPackWIXGenerator::InitializeWiXConfiguration() { std::string defaultRef = "WixUI_InstallDir"; - if(Components.size()) + if(this->Components.size()) { defaultRef = "WixUI_FeatureTree"; } @@ -221,17 +215,17 @@ bool cmCPackWIXGenerator::InitializeWiXConfiguration() SetOption("CPACK_WIX_UI_REF", defaultRef.c_str()); } - CollectExtensions("CPACK_WIX_EXTENSIONS", CandleExtensions); - CollectExtensions("CPACK_WIX_CANDLE_EXTENSIONS", CandleExtensions); + CollectExtensions("CPACK_WIX_EXTENSIONS", this->CandleExtensions); + CollectExtensions("CPACK_WIX_CANDLE_EXTENSIONS", this->CandleExtensions); - LightExtensions.insert("WixUIExtension"); - CollectExtensions("CPACK_WIX_EXTENSIONS", LightExtensions); - CollectExtensions("CPACK_WIX_LIGHT_EXTENSIONS", LightExtensions); + this->LightExtensions.insert("WixUIExtension"); + CollectExtensions("CPACK_WIX_EXTENSIONS", this->LightExtensions); + CollectExtensions("CPACK_WIX_LIGHT_EXTENSIONS", this->LightExtensions); const char* patchFilePath = GetOption("CPACK_WIX_PATCH_FILE"); if(patchFilePath) { - LoadPatchFragments(patchFilePath); + this->Patch.LoadFragments(patchFilePath); } return true; @@ -244,10 +238,7 @@ bool cmCPackWIXGenerator::PackageFilesImpl() return false; } - if(!CreateWiXVariablesIncludeFile()) - { - return false; - } + CreateWiXVariablesIncludeFile(); if(!CreateWiXSourceFiles()) { @@ -257,9 +248,9 @@ bool cmCPackWIXGenerator::PackageFilesImpl() AppendUserSuppliedExtraSources(); std::stringstream objectFiles; - for(size_t i = 0; i < WixSources.size(); ++i) + for(size_t i = 0; i < this->WixSources.size(); ++i) { - const std::string& sourceFilename = WixSources[i]; + std::string const& sourceFilename = this->WixSources[i]; std::string objectFilename = cmSystemTools::GetFilenameWithoutExtension(sourceFilename) + ".wixobj"; @@ -282,7 +273,7 @@ void cmCPackWIXGenerator::AppendUserSuppliedExtraSources() const char *cpackWixExtraSources = GetOption("CPACK_WIX_EXTRA_SOURCES"); if(!cpackWixExtraSources) return; - cmSystemTools::ExpandListArgument(cpackWixExtraSources, WixSources); + cmSystemTools::ExpandListArgument(cpackWixExtraSources, this->WixSources); } void cmCPackWIXGenerator::AppendUserSuppliedExtraObjects(std::ostream& stream) @@ -297,22 +288,18 @@ void cmCPackWIXGenerator::AppendUserSuppliedExtraObjects(std::ostream& stream) for(size_t i = 0; i < expandedExtraObjects.size(); ++i) { - stream << " " << QuotePath(expandedExtraObjects[i]); + stream << " " << QuotePath(expandedExtraObjects[i]); } } -bool cmCPackWIXGenerator::CreateWiXVariablesIncludeFile() +void cmCPackWIXGenerator::CreateWiXVariablesIncludeFile() { - std::string cpackTopLevel; - if(!RequireOption("CPACK_TOPLEVEL_DIRECTORY", cpackTopLevel)) - { - return false; - } - std::string includeFilename = - cpackTopLevel + "/cpack_variables.wxi"; + this->CPackTopLevel + "/cpack_variables.wxi"; + + cmWIXSourceWriter includeFile( + this->Logger, includeFilename, true); - cmWIXSourceWriter includeFile(Logger, includeFilename, true); CopyDefinition(includeFile, "CPACK_WIX_PRODUCT_GUID"); CopyDefinition(includeFile, "CPACK_WIX_UPGRADE_GUID"); CopyDefinition(includeFile, "CPACK_PACKAGE_VENDOR"); @@ -326,12 +313,10 @@ bool cmCPackWIXGenerator::CreateWiXVariablesIncludeFile() GetOption("CPACK_PACKAGE_NAME")); CopyDefinition(includeFile, "CPACK_WIX_PROGRAM_MENU_FOLDER"); CopyDefinition(includeFile, "CPACK_WIX_UI_REF"); - - return true; } void cmCPackWIXGenerator::CopyDefinition( - cmWIXSourceWriter &source, const std::string &name) + cmWIXSourceWriter &source, std::string const& name) { const char* value = GetOption(name.c_str()); if(value) @@ -341,7 +326,7 @@ void cmCPackWIXGenerator::CopyDefinition( } void cmCPackWIXGenerator::AddDefinition(cmWIXSourceWriter& source, - const std::string& name, const std::string& value) + std::string const& name, std::string const& value) { std::stringstream tmp; tmp << name << "=\"" << value << '"'; @@ -352,81 +337,47 @@ void cmCPackWIXGenerator::AddDefinition(cmWIXSourceWriter& source, bool cmCPackWIXGenerator::CreateWiXSourceFiles() { - std::string cpackTopLevel; - if(!RequireOption("CPACK_TOPLEVEL_DIRECTORY", cpackTopLevel)) - { - return false; - } - std::string directoryDefinitionsFilename = - cpackTopLevel + "/directories.wxs"; + this->CPackTopLevel + "/directories.wxs"; - WixSources.push_back(directoryDefinitionsFilename); + this->WixSources.push_back(directoryDefinitionsFilename); - cmWIXSourceWriter directoryDefinitions(Logger, directoryDefinitionsFilename); + cmWIXDirectoriesSourceWriter directoryDefinitions( + this->Logger, directoryDefinitionsFilename); directoryDefinitions.BeginElement("Fragment"); - directoryDefinitions.BeginElement("Directory"); - directoryDefinitions.AddAttribute("Id", "TARGETDIR"); - directoryDefinitions.AddAttribute("Name", "SourceDir"); - - directoryDefinitions.BeginElement("Directory"); - if(GetArchitecture() == "x86") - { - directoryDefinitions.AddAttribute("Id", "ProgramFilesFolder"); - } - else - { - directoryDefinitions.AddAttribute("Id", "ProgramFiles64Folder"); - } - - std::vector<std::string> install_root; - - std::string tmp; - if(!RequireOption("CPACK_PACKAGE_INSTALL_DIRECTORY", tmp)) + std::string installRoot; + if(!RequireOption("CPACK_PACKAGE_INSTALL_DIRECTORY", installRoot)) { return false; } - cmSystemTools::SplitPath(tmp.c_str(), install_root); - - if(!install_root.empty() && install_root.back().empty()) - { - install_root.pop_back(); - } - - for(size_t i = 1; i < install_root.size(); ++i) - { - directoryDefinitions.BeginElement("Directory"); - - if(i == install_root.size() - 1) - { - directoryDefinitions.AddAttribute("Id", "INSTALL_ROOT"); - } - else - { - std::stringstream ss; - ss << "INSTALL_PREFIX_" << i; - directoryDefinitions.AddAttribute("Id", ss.str()); - } + directoryDefinitions.BeginElement("Directory"); + directoryDefinitions.AddAttribute("Id", "TARGETDIR"); + directoryDefinitions.AddAttribute("Name", "SourceDir"); - directoryDefinitions.AddAttribute("Name", install_root[i]); - } + size_t installRootSize = + directoryDefinitions.BeginInstallationPrefixDirectory( + GetProgramFilesFolderId(), installRoot); std::string fileDefinitionsFilename = - cpackTopLevel + "/files.wxs"; + this->CPackTopLevel + "/files.wxs"; - WixSources.push_back(fileDefinitionsFilename); + this->WixSources.push_back(fileDefinitionsFilename); + + cmWIXFilesSourceWriter fileDefinitions( + this->Logger, fileDefinitionsFilename); - cmWIXSourceWriter fileDefinitions(Logger, fileDefinitionsFilename); fileDefinitions.BeginElement("Fragment"); std::string featureDefinitionsFilename = - cpackTopLevel +"/features.wxs"; + this->CPackTopLevel +"/features.wxs"; + + this->WixSources.push_back(featureDefinitionsFilename); - WixSources.push_back(featureDefinitionsFilename); + cmWIXFeaturesSourceWriter featureDefinitions( + this->Logger, featureDefinitionsFilename); - cmWIXSourceWriter featureDefinitions(Logger, featureDefinitionsFilename); featureDefinitions.BeginElement("Fragment"); featureDefinitions.BeginElement("Feature"); @@ -439,13 +390,15 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles() { return false; } - featureDefinitions.AddAttribute("Title", cpackPackageName); + featureDefinitions.AddAttribute("Title", cpackPackageName); featureDefinitions.AddAttribute("Level", "1"); - if(!CreateCMakePackageRegistryEntry(featureDefinitions)) + const char* package = GetOption("CPACK_WIX_CMAKE_PACKAGE_REGISTRY"); + if(package) { - return false; + featureDefinitions.CreateCMakePackageRegistryEntry( + package, GetOption("CPACK_WIX_UPGRADE_GUID")); } if(!CreateFeatureHierarchy(featureDefinitions)) @@ -471,7 +424,7 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles() else { for(std::map<std::string, cmCPackComponent>::const_iterator - i = Components.begin(); i != Components.end(); ++i) + i = this->Components.begin(); i != this->Components.end(); ++i) { cmCPackComponent const& component = i->second; @@ -513,31 +466,51 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles() featureDefinitions.EndElement("Fragment"); fileDefinitions.EndElement("Fragment"); - for(size_t i = 1; i < install_root.size(); ++i) - { - directoryDefinitions.EndElement("Directory"); - } - - directoryDefinitions.EndElement("Directory"); + directoryDefinitions.EndInstallationPrefixDirectory( + installRootSize); if(hasShortcuts) { - CreateStartMenuFolder(directoryDefinitions); + directoryDefinitions.EmitStartMenuFolder( + GetOption("CPACK_WIX_PROGRAM_MENU_FOLDER")); } if(this->HasDesktopShortcuts) { - CreateDesktopFolder(directoryDefinitions); + directoryDefinitions.EmitDesktopFolder(); } directoryDefinitions.EndElement("Directory"); directoryDefinitions.EndElement("Fragment"); + if(!GenerateMainSourceFileFromTemplate()) + { + return false; + } + + return this->Patch.CheckForUnappliedFragments(); +} + +std::string cmCPackWIXGenerator::GetProgramFilesFolderId() const +{ + if(GetArchitecture() == "x86") + { + return "ProgramFilesFolder"; + } + else + { + return "ProgramFiles64Folder"; + } +} + +bool cmCPackWIXGenerator::GenerateMainSourceFileFromTemplate() +{ std::string wixTemplate = FindTemplate("WIX.template.in"); if(GetOption("CPACK_WIX_TEMPLATE") != 0) { wixTemplate = GetOption("CPACK_WIX_TEMPLATE"); } + if(wixTemplate.empty()) { cmCPackLogger(cmCPackLog::LOG_ERROR, @@ -545,7 +518,7 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles() return false; } - std::string mainSourceFilePath = cpackTopLevel + "/main.wxs"; + std::string mainSourceFilePath = this->CPackTopLevel + "/main.wxs"; if(!ConfigureFile(wixTemplate.c_str(), mainSourceFilePath .c_str())) { @@ -556,68 +529,13 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles() return false; } - WixSources.push_back(mainSourceFilePath); - - std::string fragmentList; - for(cmWIXPatchParser::fragment_map_t::const_iterator - i = Fragments.begin(); i != Fragments.end(); ++i) - { - if(!fragmentList.empty()) - { - fragmentList += ", "; - } - - fragmentList += "'"; - fragmentList += i->first; - fragmentList += "'"; - } - - if(fragmentList.size()) - { - cmCPackLogger(cmCPackLog::LOG_ERROR, - "Some XML patch fragments did not have matching IDs: " << - fragmentList << std::endl); - return false; - } - - return true; -} - -bool cmCPackWIXGenerator::CreateCMakePackageRegistryEntry( - cmWIXSourceWriter& featureDefinitions) -{ - const char* package = GetOption("CPACK_WIX_CMAKE_PACKAGE_REGISTRY"); - if(!package) - { - return true; - } - - featureDefinitions.BeginElement("Component"); - featureDefinitions.AddAttribute("Id", "CM_PACKAGE_REGISTRY"); - featureDefinitions.AddAttribute("Directory", "TARGETDIR"); - featureDefinitions.AddAttribute("Guid", "*"); - - std::string registryKey = - std::string("Software\\Kitware\\CMake\\Packages\\") + package; - - std::string upgradeGuid = GetOption("CPACK_WIX_UPGRADE_GUID"); - - featureDefinitions.BeginElement("RegistryValue"); - featureDefinitions.AddAttribute("Root", "HKLM"); - featureDefinitions.AddAttribute("Key", registryKey); - featureDefinitions.AddAttribute("Name", upgradeGuid); - featureDefinitions.AddAttribute("Type", "string"); - featureDefinitions.AddAttribute("Value", "[INSTALL_ROOT]"); - featureDefinitions.AddAttribute("KeyPath", "yes"); - featureDefinitions.EndElement("RegistryValue"); - - featureDefinitions.EndElement("Component"); + this->WixSources.push_back(mainSourceFilePath); return true; } bool cmCPackWIXGenerator::CreateFeatureHierarchy( - cmWIXSourceWriter& featureDefinitions) + cmWIXFeaturesSourceWriter& featureDefinitions) { for(std::map<std::string, cmCPackComponentGroup>::const_iterator i = ComponentGroups.begin(); i != ComponentGroups.end(); ++i) @@ -625,105 +543,30 @@ bool cmCPackWIXGenerator::CreateFeatureHierarchy( cmCPackComponentGroup const& group = i->second; if(group.ParentGroup == 0) { - if(!EmitFeatureForComponentGroup(featureDefinitions, group)) - { - return false; - } + featureDefinitions.EmitFeatureForComponentGroup(group); } } for(std::map<std::string, cmCPackComponent>::const_iterator - i = Components.begin(); i != Components.end(); ++i) + i = this->Components.begin(); i != this->Components.end(); ++i) { cmCPackComponent const& component = i->second; if(!component.Group) { - if(!EmitFeatureForComponent(featureDefinitions, component)) - { - return false; - } + featureDefinitions.EmitFeatureForComponent(component); } } return true; } -bool cmCPackWIXGenerator::EmitFeatureForComponentGroup( - cmWIXSourceWriter& featureDefinitions, - cmCPackComponentGroup const& group) -{ - featureDefinitions.BeginElement("Feature"); - featureDefinitions.AddAttribute("Id", "CM_G_" + group.Name); - - if(group.IsExpandedByDefault) - { - featureDefinitions.AddAttribute("Display", "expand"); - } - - featureDefinitions.AddAttributeUnlessEmpty( - "Title", group.DisplayName); - - featureDefinitions.AddAttributeUnlessEmpty( - "Description", group.Description); - - for(std::vector<cmCPackComponentGroup*>::const_iterator - i = group.Subgroups.begin(); i != group.Subgroups.end(); ++i) - { - if(!EmitFeatureForComponentGroup(featureDefinitions, **i)) - { - return false; - } - } - - for(std::vector<cmCPackComponent*>::const_iterator - i = group.Components.begin(); i != group.Components.end(); ++i) - { - if(!EmitFeatureForComponent(featureDefinitions, **i)) - { - return false; - } - } - - featureDefinitions.EndElement("Feature"); - - return true; -} - -bool cmCPackWIXGenerator::EmitFeatureForComponent( - cmWIXSourceWriter& featureDefinitions, - cmCPackComponent const& component) -{ - featureDefinitions.BeginElement("Feature"); - featureDefinitions.AddAttribute("Id", "CM_C_" + component.Name); - - featureDefinitions.AddAttributeUnlessEmpty( - "Title", component.DisplayName); - - featureDefinitions.AddAttributeUnlessEmpty( - "Description", component.Description); - - if(component.IsRequired) - { - featureDefinitions.AddAttribute("Absent", "disallow"); - } - - if(component.IsHidden) - { - featureDefinitions.AddAttribute("Display", "hidden"); - } - - featureDefinitions.EndElement("Feature"); - - return true; -} - bool cmCPackWIXGenerator::AddComponentsToFeature( std::string const& rootPath, std::string const& featureId, - cmWIXSourceWriter& directoryDefinitions, - cmWIXSourceWriter& fileDefinitions, - cmWIXSourceWriter& featureDefinitions, + cmWIXDirectoriesSourceWriter& directoryDefinitions, + cmWIXFilesSourceWriter& fileDefinitions, + cmWIXFeaturesSourceWriter& featureDefinitions, shortcut_map_t& shortcutMap) { featureDefinitions.BeginElement("FeatureRef"); @@ -768,8 +611,8 @@ bool cmCPackWIXGenerator::CreateStartMenuShortcuts( std::string const& cpackComponentName, std::string const& featureId, shortcut_map_t& shortcutMap, - cmWIXSourceWriter& fileDefinitions, - cmWIXSourceWriter& featureDefinitions) + cmWIXFilesSourceWriter& fileDefinitions, + cmWIXFeaturesSourceWriter& featureDefinitions) { bool thisHasDesktopShortcuts = false; @@ -799,6 +642,7 @@ bool cmCPackWIXGenerator::CreateStartMenuShortcuts( fileDefinitions.BeginElement("DirectoryRef"); fileDefinitions.AddAttribute("Id", "PROGRAM_MENU_FOLDER"); + fileDefinitions.BeginElement("Component"); fileDefinitions.AddAttribute("Id", componentId); fileDefinitions.AddAttribute("Guid", "*"); @@ -809,63 +653,34 @@ bool cmCPackWIXGenerator::CreateStartMenuShortcuts( std::string const& id = i->first; cmWIXShortcut const& shortcut = i->second; - std::string shortcutId = std::string("CM_S") + id; - std::string fileId = std::string("CM_F") + id; - - fileDefinitions.BeginElement("Shortcut"); - fileDefinitions.AddAttribute("Id", shortcutId); - fileDefinitions.AddAttribute("Name", shortcut.textLabel); - std::string target = "[#" + fileId + "]"; - fileDefinitions.AddAttribute("Target", target); - fileDefinitions.AddAttribute("WorkingDirectory", - shortcut.workingDirectoryId); - fileDefinitions.EndElement("Shortcut"); + fileDefinitions.EmitShortcut(id, shortcut, false); - if (shortcut.desktop) + if(shortcut.desktop) { - thisHasDesktopShortcuts = true; + thisHasDesktopShortcuts = true; } } if(cpackComponentName.empty()) { - CreateUninstallShortcut(cpackPackageName, fileDefinitions); + fileDefinitions.EmitUninstallShortcut(cpackPackageName); } - fileDefinitions.BeginElement("RemoveFolder"); - fileDefinitions.AddAttribute("Id", + fileDefinitions.EmitRemoveFolder( "CM_REMOVE_PROGRAM_MENU_FOLDER" + idSuffix); - fileDefinitions.AddAttribute("On", "uninstall"); - fileDefinitions.EndElement("RemoveFolder"); std::string registryKey = std::string("Software\\") + cpackVendor + "\\" + cpackPackageName; - fileDefinitions.BeginElement("RegistryValue"); - fileDefinitions.AddAttribute("Root", "HKCU"); - fileDefinitions.AddAttribute("Key", registryKey); - - std::string valueName; - if(!cpackComponentName.empty()) - { - valueName = cpackComponentName + "_"; - } - valueName += "installed"; - - fileDefinitions.AddAttribute("Name", valueName); - fileDefinitions.AddAttribute("Type", "integer"); - fileDefinitions.AddAttribute("Value", "1"); - fileDefinitions.AddAttribute("KeyPath", "yes"); - fileDefinitions.EndElement("RegistryValue"); + fileDefinitions.EmitStartMenuShortcutRegistryValue( + registryKey, cpackComponentName); fileDefinitions.EndElement("Component"); fileDefinitions.EndElement("DirectoryRef"); - featureDefinitions.BeginElement("ComponentRef"); - featureDefinitions.AddAttribute("Id", componentId); - featureDefinitions.EndElement("ComponentRef"); + featureDefinitions.EmitComponentRef(componentId); - if (thisHasDesktopShortcuts) + if(thisHasDesktopShortcuts) { this->HasDesktopShortcuts = true; componentId = "CM_DESKTOP_SHORTCUT" + idSuffix; @@ -876,7 +691,7 @@ bool cmCPackWIXGenerator::CreateStartMenuShortcuts( fileDefinitions.AddAttribute("Id", componentId); fileDefinitions.AddAttribute("Guid", "*"); - for (shortcut_map_t::const_iterator + for(shortcut_map_t::const_iterator i = shortcutMap.begin(); i != shortcutMap.end(); ++i) { std::string const& id = i->first; @@ -885,34 +700,16 @@ bool cmCPackWIXGenerator::CreateStartMenuShortcuts( if (!shortcut.desktop) continue; - std::string shortcutId = std::string("CM_DS") + id; - std::string fileId = std::string("CM_F") + id; - - fileDefinitions.BeginElement("Shortcut"); - fileDefinitions.AddAttribute("Id", shortcutId); - fileDefinitions.AddAttribute("Name", shortcut.textLabel); - std::string target = "[#" + fileId + "]"; - fileDefinitions.AddAttribute("Target", target); - fileDefinitions.AddAttribute("WorkingDirectory", - shortcut.workingDirectoryId); - fileDefinitions.EndElement("Shortcut"); + fileDefinitions.EmitShortcut(id, shortcut, true); } - fileDefinitions.BeginElement("RegistryValue"); - fileDefinitions.AddAttribute("Root", "HKCU"); - fileDefinitions.AddAttribute("Key", registryKey); - fileDefinitions.AddAttribute("Name", valueName + "_desktop"); - fileDefinitions.AddAttribute("Type", "integer"); - fileDefinitions.AddAttribute("Value", "1"); - fileDefinitions.AddAttribute("KeyPath", "yes"); - fileDefinitions.EndElement("RegistryValue"); + fileDefinitions.EmitDesktopShortcutRegistryValue( + registryKey, cpackComponentName); fileDefinitions.EndElement("Component"); fileDefinitions.EndElement("DirectoryRef"); - featureDefinitions.BeginElement("ComponentRef"); - featureDefinitions.AddAttribute("Id", componentId); - featureDefinitions.EndElement("ComponentRef"); + featureDefinitions.EmitComponentRef(componentId); } featureDefinitions.EndElement("FeatureRef"); @@ -920,19 +717,6 @@ bool cmCPackWIXGenerator::CreateStartMenuShortcuts( return true; } -void cmCPackWIXGenerator::CreateUninstallShortcut( - std::string const& packageName, - cmWIXSourceWriter& fileDefinitions) -{ - fileDefinitions.BeginElement("Shortcut"); - fileDefinitions.AddAttribute("Id", "UNINSTALL"); - fileDefinitions.AddAttribute("Name", "Uninstall " + packageName); - fileDefinitions.AddAttribute("Description", "Uninstalls " + packageName); - fileDefinitions.AddAttribute("Target", "[SystemFolder]msiexec.exe"); - fileDefinitions.AddAttribute("Arguments", "/x [ProductCode]"); - fileDefinitions.EndElement("Shortcut"); -} - bool cmCPackWIXGenerator::CreateLicenseFile() { std::string licenseSourceFilename; @@ -981,11 +765,11 @@ bool cmCPackWIXGenerator::CreateLicenseFile() } void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons( - const std::string& topdir, - const std::string& directoryId, - cmWIXSourceWriter& directoryDefinitions, - cmWIXSourceWriter& fileDefinitions, - cmWIXSourceWriter& featureDefinitions, + std::string const& topdir, + std::string const& directoryId, + cmWIXDirectoriesSourceWriter& directoryDefinitions, + cmWIXFilesSourceWriter& fileDefinitions, + cmWIXFeaturesSourceWriter& featureDefinitions, const std::vector<std::string>& packageExecutables, const std::vector<std::string>& desktopExecutables, shortcut_map_t& shortcutMap) @@ -1026,44 +810,15 @@ void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons( desktopExecutables, shortcutMap); - ApplyPatchFragment(subDirectoryId, directoryDefinitions); + this->Patch.ApplyFragment(subDirectoryId, directoryDefinitions); directoryDefinitions.EndElement("Directory"); } else { - std::string componentId = std::string("CM_C") + id; - std::string fileId = std::string("CM_F") + id; - - fileDefinitions.BeginElement("DirectoryRef"); - fileDefinitions.AddAttribute("Id", directoryId); - - fileDefinitions.BeginElement("Component"); - fileDefinitions.AddAttribute("Id", componentId); - fileDefinitions.AddAttribute("Guid", "*"); + std::string componentId = fileDefinitions.EmitComponentFile( + directoryId, id, fullPath, this->Patch); - fileDefinitions.BeginElement("File"); - fileDefinitions.AddAttribute("Id", fileId); - fileDefinitions.AddAttribute("Source", fullPath); - fileDefinitions.AddAttribute("KeyPath", "yes"); - - mode_t fileMode = 0; - cmSystemTools::GetPermissions(fullPath.c_str(), fileMode); - - if(!(fileMode & S_IWRITE)) - { - fileDefinitions.AddAttribute("ReadOnly", "yes"); - } - - ApplyPatchFragment(fileId, fileDefinitions); - fileDefinitions.EndElement("File"); - - ApplyPatchFragment(componentId, fileDefinitions); - fileDefinitions.EndElement("Component"); - fileDefinitions.EndElement("DirectoryRef"); - - featureDefinitions.BeginElement("ComponentRef"); - featureDefinitions.AddAttribute("Id", componentId); - featureDefinitions.EndElement("ComponentRef"); + featureDefinitions.EmitComponentRef(componentId); for(size_t j = 0; j < packageExecutables.size(); ++j) { @@ -1092,7 +847,7 @@ void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons( } bool cmCPackWIXGenerator::RequireOption( - const std::string& name, std::string &value) const + std::string const& name, std::string &value) const { const char* tmp = GetOption(name.c_str()); if(tmp) @@ -1140,13 +895,13 @@ std::string cmCPackWIXGenerator::GenerateGUID() return cmSystemTools::UpperCase(result); } -std::string cmCPackWIXGenerator::QuotePath(const std::string& path) +std::string cmCPackWIXGenerator::QuotePath(std::string const& path) { return std::string("\"") + path + '"'; } std::string cmCPackWIXGenerator::GetRightmostExtension( - const std::string& filename) + std::string const& filename) { std::string extension; @@ -1159,7 +914,7 @@ std::string cmCPackWIXGenerator::GetRightmostExtension( return cmSystemTools::LowerCase(extension); } -std::string cmCPackWIXGenerator::PathToId(const std::string& path) +std::string cmCPackWIXGenerator::PathToId(std::string const& path) { id_map_t::const_iterator i = PathToIdMap.find(path); if(i != PathToIdMap.end()) return i->second; @@ -1168,7 +923,7 @@ std::string cmCPackWIXGenerator::PathToId(const std::string& path) return id; } -std::string cmCPackWIXGenerator::CreateNewIdForPath(const std::string& path) +std::string cmCPackWIXGenerator::CreateNewIdForPath(std::string const& path) { std::vector<std::string> components; cmSystemTools::SplitPath(path.c_str(), components, false); @@ -1222,7 +977,7 @@ std::string cmCPackWIXGenerator::CreateNewIdForPath(const std::string& path) } std::string cmCPackWIXGenerator::CreateHashedId( - const std::string& path, const std::string& normalizedFilename) + std::string const& path, std::string const& normalizedFilename) { cmsys::auto_ptr<cmCryptoHash> sha1 = cmCryptoHash::New("SHA1"); std::string hash = sha1->HashString(path.c_str()); @@ -1245,7 +1000,7 @@ std::string cmCPackWIXGenerator::CreateHashedId( } std::string cmCPackWIXGenerator::NormalizeComponentForId( - const std::string& component, size_t& replacementCount) + std::string const& component, size_t& replacementCount) { std::string result; result.resize(component.size()); @@ -1276,7 +1031,7 @@ bool cmCPackWIXGenerator::IsLegalIdCharacter(char c) } void cmCPackWIXGenerator::CollectExtensions( - const std::string& variableName, extension_set_t& extensions) + std::string const& variableName, extension_set_t& extensions) { const char *variableContent = GetOption(variableName.c_str()); if(!variableContent) return; @@ -1292,7 +1047,7 @@ void cmCPackWIXGenerator::CollectExtensions( } void cmCPackWIXGenerator::AddCustomFlags( - const std::string& variableName, std::ostream& stream) + std::string const& variableName, std::ostream& stream) { const char *variableContent = GetOption(variableName.c_str()); if(!variableContent) return; @@ -1306,69 +1061,3 @@ void cmCPackWIXGenerator::AddCustomFlags( stream << " " << QuotePath(*i); } } - -void cmCPackWIXGenerator::CreateStartMenuFolder( - cmWIXSourceWriter& directoryDefinitions) -{ - directoryDefinitions.BeginElement("Directory"); - directoryDefinitions.AddAttribute("Id", "ProgramMenuFolder"); - - directoryDefinitions.BeginElement("Directory"); - directoryDefinitions.AddAttribute("Id", "PROGRAM_MENU_FOLDER"); - const char *startMenuFolder = GetOption("CPACK_WIX_PROGRAM_MENU_FOLDER"); - directoryDefinitions.AddAttribute("Name", startMenuFolder); - directoryDefinitions.EndElement("Directory"); - - directoryDefinitions.EndElement("Directory"); -} - -void cmCPackWIXGenerator::CreateDesktopFolder( - cmWIXSourceWriter& directoryDefinitions) -{ - directoryDefinitions.BeginElement("Directory"); - directoryDefinitions.AddAttribute("Id", "DesktopFolder"); - directoryDefinitions.AddAttribute("Name", "Desktop"); - directoryDefinitions.EndElement("Directory"); -} - -void cmCPackWIXGenerator::LoadPatchFragments(const std::string& patchFilePath) -{ - cmWIXPatchParser parser(Fragments, Logger); - parser.ParseFile(patchFilePath.c_str()); -} - -void cmCPackWIXGenerator::ApplyPatchFragment( - const std::string& id, cmWIXSourceWriter& writer) -{ - cmWIXPatchParser::fragment_map_t::iterator i = Fragments.find(id); - if(i == Fragments.end()) return; - - const cmWIXPatchElement& fragment = i->second; - for(cmWIXPatchElement::child_list_t::const_iterator - j = fragment.children.begin(); j != fragment.children.end(); ++j) - { - ApplyPatchElement(**j, writer); - } - - Fragments.erase(i); -} - -void cmCPackWIXGenerator::ApplyPatchElement( - const cmWIXPatchElement& element, cmWIXSourceWriter& writer) -{ - writer.BeginElement(element.name); - - for(cmWIXPatchElement::attributes_t::const_iterator - i = element.attributes.begin(); i != element.attributes.end(); ++i) - { - writer.AddAttribute(i->first, i->second); - } - - for(cmWIXPatchElement::child_list_t::const_iterator - i = element.children.begin(); i != element.children.end(); ++i) - { - ApplyPatchElement(**i, writer); - } - - writer.EndElement(element.name); -} diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.h b/Source/CPack/WiX/cmCPackWIXGenerator.h index 1de4810..ee66c05 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.h +++ b/Source/CPack/WiX/cmCPackWIXGenerator.h @@ -13,25 +13,18 @@ #ifndef cmCPackWIXGenerator_h #define cmCPackWIXGenerator_h -#include "cmWIXPatchParser.h" +#include "cmWIXPatch.h" +#include "cmWIXShortcut.h" #include <CPack/cmCPackGenerator.h> #include <string> #include <map> -struct cmWIXShortcut -{ - cmWIXShortcut() - :desktop(false) - {} - - std::string textLabel; - std::string workingDirectoryId; - bool desktop; -}; - class cmWIXSourceWriter; +class cmWIXDirectoriesSourceWriter; +class cmWIXFilesSourceWriter; +class cmWIXFeaturesSourceWriter; /** \class cmCPackWIXGenerator * \brief A generator for WIX files @@ -78,48 +71,37 @@ private: bool PackageFilesImpl(); - bool CreateWiXVariablesIncludeFile(); + void CreateWiXVariablesIncludeFile(); void CopyDefinition( - cmWIXSourceWriter &source, const std::string &name); + cmWIXSourceWriter &source, std::string const& name); void AddDefinition(cmWIXSourceWriter& source, - const std::string& name, const std::string& value); + std::string const& name, std::string const& value); bool CreateWiXSourceFiles(); - bool CreateCMakePackageRegistryEntry( - cmWIXSourceWriter& featureDefinitions); + std::string GetProgramFilesFolderId() const; - bool CreateFeatureHierarchy( - cmWIXSourceWriter& featureDefinitions); - - bool EmitFeatureForComponentGroup( - cmWIXSourceWriter& featureDefinitions, - cmCPackComponentGroup const& group); + bool GenerateMainSourceFileFromTemplate(); - bool EmitFeatureForComponent( - cmWIXSourceWriter& featureDefinitions, - cmCPackComponent const& component); + bool CreateFeatureHierarchy( + cmWIXFeaturesSourceWriter& featureDefinitions); bool AddComponentsToFeature( std::string const& rootPath, std::string const& featureId, - cmWIXSourceWriter& directoryDefinitions, - cmWIXSourceWriter& fileDefinitions, - cmWIXSourceWriter& featureDefinitions, + cmWIXDirectoriesSourceWriter& directoryDefinitions, + cmWIXFilesSourceWriter& fileDefinitions, + cmWIXFeaturesSourceWriter& featureDefinitions, shortcut_map_t& shortcutMap); bool CreateStartMenuShortcuts( std::string const& cpackComponentName, std::string const& featureId, shortcut_map_t& shortcutMap, - cmWIXSourceWriter& fileDefinitions, - cmWIXSourceWriter& featureDefinitions); - - void CreateUninstallShortcut( - std::string const& packageName, - cmWIXSourceWriter& fileDefinitions); + cmWIXFilesSourceWriter& fileDefinitions, + cmWIXFeaturesSourceWriter& featureDefinitions); void AppendUserSuppliedExtraSources(); @@ -127,60 +109,49 @@ private: bool CreateLicenseFile(); - bool RunWiXCommand(const std::string& command); + bool RunWiXCommand(std::string const& command); bool RunCandleCommand( - const std::string& sourceFile, const std::string& objectFile); + std::string const& sourceFile, std::string const& objectFile); - bool RunLightCommand(const std::string& objectFiles); + bool RunLightCommand(std::string const& objectFiles); - void AddDirectoryAndFileDefinitons(const std::string& topdir, - const std::string& directoryId, - cmWIXSourceWriter& directoryDefinitions, - cmWIXSourceWriter& fileDefinitions, - cmWIXSourceWriter& featureDefinitions, + void AddDirectoryAndFileDefinitons(std::string const& topdir, + std::string const& directoryId, + cmWIXDirectoriesSourceWriter& directoryDefinitions, + cmWIXFilesSourceWriter& fileDefinitions, + cmWIXFeaturesSourceWriter& featureDefinitions, const std::vector<std::string>& pkgExecutables, const std::vector<std::string>& desktopExecutables, shortcut_map_t& shortcutMap); - bool RequireOption(const std::string& name, std::string& value) const; + bool RequireOption(std::string const& name, std::string& value) const; std::string GetArchitecture() const; static std::string GenerateGUID(); - static std::string QuotePath(const std::string& path); + static std::string QuotePath(std::string const& path); - static std::string GetRightmostExtension(const std::string& filename); + static std::string GetRightmostExtension(std::string const& filename); - std::string PathToId(const std::string& path); + std::string PathToId(std::string const& path); - std::string CreateNewIdForPath(const std::string& path); + std::string CreateNewIdForPath(std::string const& path); static std::string CreateHashedId( - const std::string& path, const std::string& normalizedFilename); + std::string const& path, std::string const& normalizedFilename); std::string NormalizeComponentForId( - const std::string& component, size_t& replacementCount); + std::string const& component, size_t& replacementCount); static bool IsLegalIdCharacter(char c); void CollectExtensions( - const std::string& variableName, extension_set_t& extensions); + std::string const& variableName, extension_set_t& extensions); void AddCustomFlags( - const std::string& variableName, std::ostream& stream); - - void CreateStartMenuFolder(cmWIXSourceWriter& directoryDefinitions); - - void CreateDesktopFolder(cmWIXSourceWriter& directoryDefinitions); - - void LoadPatchFragments(const std::string& patchFilePath); - - void ApplyPatchFragment(const std::string& id, cmWIXSourceWriter& writer); - - void ApplyPatchElement(const cmWIXPatchElement& element, - cmWIXSourceWriter& writer); + std::string const& variableName, std::ostream& stream); std::vector<std::string> WixSources; id_map_t PathToIdMap; @@ -189,9 +160,11 @@ private: extension_set_t CandleExtensions; extension_set_t LightExtensions; - cmWIXPatchParser::fragment_map_t Fragments; - bool HasDesktopShortcuts; + + std::string CPackTopLevel; + + cmWIXPatch Patch; }; #endif diff --git a/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx b/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx new file mode 100644 index 0000000..a93f89b --- /dev/null +++ b/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx @@ -0,0 +1,87 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2014 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmWIXDirectoriesSourceWriter.h" + +cmWIXDirectoriesSourceWriter::cmWIXDirectoriesSourceWriter(cmCPackLog* logger, + std::string const& filename): + cmWIXSourceWriter(logger, filename) +{ + +} + +void cmWIXDirectoriesSourceWriter::EmitStartMenuFolder( + std::string const& startMenuFolder) +{ + BeginElement("Directory"); + AddAttribute("Id", "ProgramMenuFolder"); + + BeginElement("Directory"); + AddAttribute("Id", "PROGRAM_MENU_FOLDER"); + AddAttribute("Name", startMenuFolder); + EndElement("Directory"); + + EndElement("Directory"); +} + +void cmWIXDirectoriesSourceWriter::EmitDesktopFolder() +{ + BeginElement("Directory"); + AddAttribute("Id", "DesktopFolder"); + AddAttribute("Name", "Desktop"); + EndElement("Directory"); +} + +size_t cmWIXDirectoriesSourceWriter::BeginInstallationPrefixDirectory( + std::string const& programFilesFolderId, + std::string const& installRootString) +{ + BeginElement("Directory"); + AddAttribute("Id", programFilesFolderId); + + std::vector<std::string> installRoot; + + cmSystemTools::SplitPath(installRootString.c_str(), installRoot); + + if(!installRoot.empty() && installRoot.back().empty()) + { + installRoot.pop_back(); + } + + for(size_t i = 1; i < installRoot.size(); ++i) + { + BeginElement("Directory"); + + if(i == installRoot.size() - 1) + { + AddAttribute("Id", "INSTALL_ROOT"); + } + else + { + std::stringstream tmp; + tmp << "INSTALL_PREFIX_" << i; + AddAttribute("Id", tmp.str()); + } + + AddAttribute("Name", installRoot[i]); + } + + return installRoot.size(); +} + +void cmWIXDirectoriesSourceWriter::EndInstallationPrefixDirectory(size_t size) +{ + for(size_t i = 0; i < size; ++i) + { + EndElement("Directory"); + } +} diff --git a/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.h b/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.h new file mode 100644 index 0000000..f51fdb4 --- /dev/null +++ b/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.h @@ -0,0 +1,42 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2014 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmWIXDirectoriesSourceWriter_h +#define cmWIXDirectoriesSourceWriter_h + +#include "cmWIXSourceWriter.h" + +#include <CPack/cmCPackGenerator.h> + +#include <string> + +/** \class cmWIXDirectoriesSourceWriter + * \brief Helper class to generate directories.wxs + */ +class cmWIXDirectoriesSourceWriter : public cmWIXSourceWriter +{ +public: + cmWIXDirectoriesSourceWriter(cmCPackLog* logger, + std::string const& filename); + + void EmitStartMenuFolder(std::string const& startMenuFolder); + + void EmitDesktopFolder(); + + size_t BeginInstallationPrefixDirectory( + std::string const& programFilesFolderId, + std::string const& installRootString); + + void EndInstallationPrefixDirectory(size_t size); +}; + +#endif diff --git a/Source/CPack/WiX/cmWIXFeaturesSourceWriter.cxx b/Source/CPack/WiX/cmWIXFeaturesSourceWriter.cxx new file mode 100644 index 0000000..0bcfc38 --- /dev/null +++ b/Source/CPack/WiX/cmWIXFeaturesSourceWriter.cxx @@ -0,0 +1,102 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2014 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmWIXFeaturesSourceWriter.h" + +cmWIXFeaturesSourceWriter::cmWIXFeaturesSourceWriter(cmCPackLog* logger, + std::string const& filename): + cmWIXSourceWriter(logger, filename) +{ + +} + +void cmWIXFeaturesSourceWriter::CreateCMakePackageRegistryEntry( + std::string const& package, + std::string const& upgradeGuid) +{ + BeginElement("Component"); + AddAttribute("Id", "CM_PACKAGE_REGISTRY"); + AddAttribute("Directory", "TARGETDIR"); + AddAttribute("Guid", "*"); + + std::string registryKey = + std::string("Software\\Kitware\\CMake\\Packages\\") + package; + + BeginElement("RegistryValue"); + AddAttribute("Root", "HKLM"); + AddAttribute("Key", registryKey); + AddAttribute("Name", upgradeGuid); + AddAttribute("Type", "string"); + AddAttribute("Value", "[INSTALL_ROOT]"); + AddAttribute("KeyPath", "yes"); + EndElement("RegistryValue"); + + EndElement("Component"); +} + +void cmWIXFeaturesSourceWriter::EmitFeatureForComponentGroup( + cmCPackComponentGroup const& group) +{ + BeginElement("Feature"); + AddAttribute("Id", "CM_G_" + group.Name); + + if(group.IsExpandedByDefault) + { + AddAttribute("Display", "expand"); + } + + AddAttributeUnlessEmpty("Title", group.DisplayName); + AddAttributeUnlessEmpty("Description", group.Description); + + for(std::vector<cmCPackComponentGroup*>::const_iterator + i = group.Subgroups.begin(); i != group.Subgroups.end(); ++i) + { + EmitFeatureForComponentGroup(**i); + } + + for(std::vector<cmCPackComponent*>::const_iterator + i = group.Components.begin(); i != group.Components.end(); ++i) + { + EmitFeatureForComponent(**i); + } + + EndElement("Feature"); +} + +void cmWIXFeaturesSourceWriter::EmitFeatureForComponent( + cmCPackComponent const& component) +{ + BeginElement("Feature"); + AddAttribute("Id", "CM_C_" + component.Name); + + AddAttributeUnlessEmpty("Title", component.DisplayName); + AddAttributeUnlessEmpty("Description", component.Description); + + if(component.IsRequired) + { + AddAttribute("Absent", "disallow"); + } + + if(component.IsHidden) + { + AddAttribute("Display", "hidden"); + } + + EndElement("Feature"); +} + +void cmWIXFeaturesSourceWriter::EmitComponentRef(std::string const& id) +{ + BeginElement("ComponentRef"); + AddAttribute("Id", id); + EndElement("ComponentRef"); +} diff --git a/Source/CPack/WiX/cmWIXFeaturesSourceWriter.h b/Source/CPack/WiX/cmWIXFeaturesSourceWriter.h new file mode 100644 index 0000000..7670417 --- /dev/null +++ b/Source/CPack/WiX/cmWIXFeaturesSourceWriter.h @@ -0,0 +1,39 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2014 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmWIXFeaturesSourceWriter_h +#define cmWIXFeaturesSourceWriter_h + +#include "cmWIXSourceWriter.h" +#include <CPack/cmCPackGenerator.h> + +/** \class cmWIXFeaturesSourceWriter + * \brief Helper class to generate features.wxs + */ +class cmWIXFeaturesSourceWriter : public cmWIXSourceWriter +{ +public: + cmWIXFeaturesSourceWriter(cmCPackLog* logger, + std::string const& filename); + + void CreateCMakePackageRegistryEntry( + std::string const& package, + std::string const& upgradeGuid); + + void EmitFeatureForComponentGroup(const cmCPackComponentGroup& group); + + void EmitFeatureForComponent(const cmCPackComponent& component); + + void EmitComponentRef(std::string const& id); +}; + +#endif diff --git a/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx b/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx new file mode 100644 index 0000000..0835f3a --- /dev/null +++ b/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx @@ -0,0 +1,149 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2014 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmWIXFilesSourceWriter.h" + +#include <sys/types.h> +#include <sys/stat.h> + +cmWIXFilesSourceWriter::cmWIXFilesSourceWriter(cmCPackLog* logger, + std::string const& filename): + cmWIXSourceWriter(logger, filename) +{ + +} + +void cmWIXFilesSourceWriter::EmitShortcut( + std::string const& id, + cmWIXShortcut const& shortcut, + bool desktop) +{ + std::string shortcutId; + + if(desktop) + { + shortcutId = "CM_DS"; + } + else + { + shortcutId = "CM_S"; + } + + shortcutId += id; + + std::string fileId = std::string("CM_F") + id; + + BeginElement("Shortcut"); + AddAttribute("Id", shortcutId); + AddAttribute("Name", shortcut.textLabel); + std::string target = "[#" + fileId + "]"; + AddAttribute("Target", target); + AddAttribute("WorkingDirectory", shortcut.workingDirectoryId); + EndElement("Shortcut"); +} + +void cmWIXFilesSourceWriter::EmitRemoveFolder(std::string const& id) +{ + BeginElement("RemoveFolder"); + AddAttribute("Id", id); + AddAttribute("On", "uninstall"); + EndElement("RemoveFolder"); +} + +void cmWIXFilesSourceWriter::EmitStartMenuShortcutRegistryValue( + std::string const& registryKey, + std::string const& cpackComponentName) +{ + EmitInstallRegistryValue(registryKey, cpackComponentName, std::string()); +} + +void cmWIXFilesSourceWriter::EmitDesktopShortcutRegistryValue( + std::string const& registryKey, + std::string const& cpackComponentName) +{ + EmitInstallRegistryValue(registryKey, cpackComponentName, "_desktop"); +} + +void cmWIXFilesSourceWriter::EmitInstallRegistryValue( + std::string const& registryKey, + std::string const& cpackComponentName, + std::string const& suffix) +{ + std::string valueName; + if(!cpackComponentName.empty()) + { + valueName = cpackComponentName + "_"; + } + + valueName += "installed"; + valueName += suffix; + + BeginElement("RegistryValue"); + AddAttribute("Root", "HKCU"); + AddAttribute("Key", registryKey); + AddAttribute("Name", valueName); + AddAttribute("Type", "integer"); + AddAttribute("Value", "1"); + AddAttribute("KeyPath", "yes"); + EndElement("RegistryValue"); +} + +void cmWIXFilesSourceWriter::EmitUninstallShortcut( + std::string const& packageName) +{ + BeginElement("Shortcut"); + AddAttribute("Id", "UNINSTALL"); + AddAttribute("Name", "Uninstall " + packageName); + AddAttribute("Description", "Uninstalls " + packageName); + AddAttribute("Target", "[SystemFolder]msiexec.exe"); + AddAttribute("Arguments", "/x [ProductCode]"); + EndElement("Shortcut"); +} + +std::string cmWIXFilesSourceWriter::EmitComponentFile( + std::string const& directoryId, + std::string const& id, + std::string const& filePath, + cmWIXPatch &patch) +{ + std::string componentId = std::string("CM_C") + id; + std::string fileId = std::string("CM_F") + id; + + BeginElement("DirectoryRef"); + AddAttribute("Id", directoryId); + + BeginElement("Component"); + AddAttribute("Id", componentId); + AddAttribute("Guid", "*"); + + BeginElement("File"); + AddAttribute("Id", fileId); + AddAttribute("Source", filePath); + AddAttribute("KeyPath", "yes"); + + mode_t fileMode = 0; + cmSystemTools::GetPermissions(filePath.c_str(), fileMode); + + if(!(fileMode & S_IWRITE)) + { + AddAttribute("ReadOnly", "yes"); + } + + patch.ApplyFragment(fileId, *this); + EndElement("File"); + + patch.ApplyFragment(componentId, *this); + EndElement("Component"); + EndElement("DirectoryRef"); + + return componentId; +} diff --git a/Source/CPack/WiX/cmWIXFilesSourceWriter.h b/Source/CPack/WiX/cmWIXFilesSourceWriter.h new file mode 100644 index 0000000..d22d270 --- /dev/null +++ b/Source/CPack/WiX/cmWIXFilesSourceWriter.h @@ -0,0 +1,62 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2014 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmWIXFilesSourceWriter_h +#define cmWIXFilesSourceWriter_h + +#include "cmWIXSourceWriter.h" +#include "cmWIXShortcut.h" +#include "cmWIXPatch.h" + +#include <CPack/cmCPackGenerator.h> + +/** \class cmWIXFilesSourceWriter + * \brief Helper class to generate files.wxs + */ +class cmWIXFilesSourceWriter : public cmWIXSourceWriter +{ +public: + cmWIXFilesSourceWriter(cmCPackLog* logger, + std::string const& filename); + + void EmitShortcut( + std::string const& id, + cmWIXShortcut const& shortcut, + bool desktop); + + void EmitRemoveFolder(std::string const& id); + + void EmitStartMenuShortcutRegistryValue( + std::string const& registryKey, + std::string const& cpackComponentName); + + void EmitDesktopShortcutRegistryValue( + std::string const& registryKey, + std::string const& cpackComponentName); + + void EmitUninstallShortcut(std::string const& packageName); + + std::string EmitComponentFile( + std::string const& directoryId, + std::string const& id, + std::string const& filePath, + cmWIXPatch &patch); + +private: + void EmitInstallRegistryValue( + std::string const& registryKey, + std::string const& cpackComponentName, + std::string const& suffix); +}; + + +#endif diff --git a/Source/CPack/WiX/cmWIXPatch.cxx b/Source/CPack/WiX/cmWIXPatch.cxx new file mode 100644 index 0000000..b5202e0 --- /dev/null +++ b/Source/CPack/WiX/cmWIXPatch.cxx @@ -0,0 +1,91 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2014 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmWIXPatch.h" + +#include <CPack/cmCPackGenerator.h> + +cmWIXPatch::cmWIXPatch(cmCPackLog* logger): + Logger(logger) +{ + +} + +void cmWIXPatch::LoadFragments(std::string const& patchFilePath) +{ + cmWIXPatchParser parser(Fragments, Logger); + parser.ParseFile(patchFilePath.c_str()); +} + +void cmWIXPatch::ApplyFragment( + std::string const& id, cmWIXSourceWriter& writer) +{ + cmWIXPatchParser::fragment_map_t::iterator i = Fragments.find(id); + if(i == Fragments.end()) return; + + const cmWIXPatchElement& fragment = i->second; + for(cmWIXPatchElement::child_list_t::const_iterator + j = fragment.children.begin(); j != fragment.children.end(); ++j) + { + ApplyElement(**j, writer); + } + + Fragments.erase(i); +} + +void cmWIXPatch::ApplyElement( + const cmWIXPatchElement& element, cmWIXSourceWriter& writer) +{ + writer.BeginElement(element.name); + + for(cmWIXPatchElement::attributes_t::const_iterator + i = element.attributes.begin(); i != element.attributes.end(); ++i) + { + writer.AddAttribute(i->first, i->second); + } + + for(cmWIXPatchElement::child_list_t::const_iterator + i = element.children.begin(); i != element.children.end(); ++i) + { + ApplyElement(**i, writer); + } + + writer.EndElement(element.name); +} + + +bool cmWIXPatch::CheckForUnappliedFragments() +{ + std::string fragmentList; + for(cmWIXPatchParser::fragment_map_t::const_iterator + i = Fragments.begin(); i != Fragments.end(); ++i) + { + if(!fragmentList.empty()) + { + fragmentList += ", "; + } + + fragmentList += "'"; + fragmentList += i->first; + fragmentList += "'"; + } + + if(fragmentList.size()) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Some XML patch fragments did not have matching IDs: " << + fragmentList << std::endl); + return false; + } + + return true; +} diff --git a/Source/CPack/WiX/cmWIXPatch.h b/Source/CPack/WiX/cmWIXPatch.h new file mode 100644 index 0000000..7b7b2f1 --- /dev/null +++ b/Source/CPack/WiX/cmWIXPatch.h @@ -0,0 +1,45 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2014 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmWIXPatch_h +#define cmWIXPatch_h + +#include "cmWIXSourceWriter.h" +#include "cmWIXPatchParser.h" + +#include <string> + +/** \class cmWIXPatch + * \brief Class that maintains and applies patch fragments + */ +class cmWIXPatch +{ +public: + cmWIXPatch(cmCPackLog* logger); + + void LoadFragments(std::string const& patchFilePath); + + void ApplyFragment(std::string const& id, cmWIXSourceWriter& writer); + + bool CheckForUnappliedFragments(); + +private: + void ApplyElement(const cmWIXPatchElement& element, + cmWIXSourceWriter& writer); + + cmCPackLog* Logger; + + cmWIXPatchParser::fragment_map_t Fragments; +}; + + +#endif diff --git a/Source/CPack/WiX/cmWIXPatchParser.cxx b/Source/CPack/WiX/cmWIXPatchParser.cxx index 7ceaf1f..10af1f6 100644 --- a/Source/CPack/WiX/cmWIXPatchParser.cxx +++ b/Source/CPack/WiX/cmWIXPatchParser.cxx @@ -132,7 +132,7 @@ void cmWIXPatchParser::ReportError(int line, int column, const char* msg) Valid = false; } -void cmWIXPatchParser::ReportValidationError(const std::string& message) +void cmWIXPatchParser::ReportValidationError(std::string const& message) { ReportError(XML_GetCurrentLineNumber(Parser), XML_GetCurrentColumnNumber(Parser), diff --git a/Source/CPack/WiX/cmWIXPatchParser.h b/Source/CPack/WiX/cmWIXPatchParser.h index 91b3b66..da3adf5 100644 --- a/Source/CPack/WiX/cmWIXPatchParser.h +++ b/Source/CPack/WiX/cmWIXPatchParser.h @@ -50,7 +50,7 @@ private: virtual void EndElement(const char *name); virtual void ReportError(int line, int column, const char* msg); - void ReportValidationError(const std::string& message); + void ReportValidationError(std::string const& message); bool IsValid() const; diff --git a/Source/CPack/WiX/cmWIXRichTextFormatWriter.cxx b/Source/CPack/WiX/cmWIXRichTextFormatWriter.cxx index ddc1d71..f27caa9 100644 --- a/Source/CPack/WiX/cmWIXRichTextFormatWriter.cxx +++ b/Source/CPack/WiX/cmWIXRichTextFormatWriter.cxx @@ -15,7 +15,7 @@ #include <cmVersion.h> cmWIXRichTextFormatWriter::cmWIXRichTextFormatWriter( - const std::string& filename): + std::string const& filename): File(filename.c_str(), std::ios::binary) { StartGroup(); @@ -33,7 +33,7 @@ cmWIXRichTextFormatWriter::~cmWIXRichTextFormatWriter() File.put(0); } -void cmWIXRichTextFormatWriter::AddText(const std::string& text) +void cmWIXRichTextFormatWriter::AddText(std::string const& text) { typedef unsigned char rtf_byte_t; @@ -167,12 +167,12 @@ void cmWIXRichTextFormatWriter::WriteDocumentPrefix() ControlWord("fs20"); } -void cmWIXRichTextFormatWriter::ControlWord(const std::string& keyword) +void cmWIXRichTextFormatWriter::ControlWord(std::string const& keyword) { File << "\\" << keyword; } -void cmWIXRichTextFormatWriter::NewControlWord(const std::string& keyword) +void cmWIXRichTextFormatWriter::NewControlWord(std::string const& keyword) { File << "\\*\\" << keyword; } diff --git a/Source/CPack/WiX/cmWIXRichTextFormatWriter.h b/Source/CPack/WiX/cmWIXRichTextFormatWriter.h index 2b665d4..f6327fb 100644 --- a/Source/CPack/WiX/cmWIXRichTextFormatWriter.h +++ b/Source/CPack/WiX/cmWIXRichTextFormatWriter.h @@ -22,10 +22,10 @@ class cmWIXRichTextFormatWriter { public: - cmWIXRichTextFormatWriter(const std::string& filename); + cmWIXRichTextFormatWriter(std::string const& filename); ~cmWIXRichTextFormatWriter(); - void AddText(const std::string& text); + void AddText(std::string const& text); private: void WriteHeader(); @@ -35,8 +35,8 @@ private: void WriteDocumentPrefix(); - void ControlWord(const std::string& keyword); - void NewControlWord(const std::string& keyword); + void ControlWord(std::string const& keyword); + void NewControlWord(std::string const& keyword); void StartGroup(); void EndGroup(); diff --git a/Source/CPack/WiX/cmWIXShortcut.h b/Source/CPack/WiX/cmWIXShortcut.h new file mode 100644 index 0000000..93095e0 --- /dev/null +++ b/Source/CPack/WiX/cmWIXShortcut.h @@ -0,0 +1,29 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2014 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmWIXFilesShortcut_h +#define cmWIXFilesShortcut_h + +#include <string> + +struct cmWIXShortcut +{ + cmWIXShortcut() + :desktop(false) + {} + + std::string textLabel; + std::string workingDirectoryId; + bool desktop; +}; + +#endif diff --git a/Source/CPack/WiX/cmWIXSourceWriter.cxx b/Source/CPack/WiX/cmWIXSourceWriter.cxx index e83c226..aad19da 100644 --- a/Source/CPack/WiX/cmWIXSourceWriter.cxx +++ b/Source/CPack/WiX/cmWIXSourceWriter.cxx @@ -17,7 +17,7 @@ #include <windows.h> cmWIXSourceWriter::cmWIXSourceWriter(cmCPackLog* logger, - const std::string& filename, + std::string const& filename, bool isIncludeFile): Logger(logger), File(filename.c_str()), @@ -51,7 +51,7 @@ cmWIXSourceWriter::~cmWIXSourceWriter() EndElement(Elements.back()); } -void cmWIXSourceWriter::BeginElement(const std::string& name) +void cmWIXSourceWriter::BeginElement(std::string const& name) { if(State == BEGIN) { @@ -101,7 +101,7 @@ void cmWIXSourceWriter::EndElement(std::string const& name) } void cmWIXSourceWriter::AddProcessingInstruction( - const std::string& target, const std::string& content) + std::string const& target, std::string const& content) { if(State == BEGIN) { @@ -116,7 +116,7 @@ void cmWIXSourceWriter::AddProcessingInstruction( } void cmWIXSourceWriter::AddAttribute( - const std::string& key, const std::string& value) + std::string const& key, std::string const& value) { std::string utf8 = WindowsCodepageToUtf8(value); @@ -124,7 +124,7 @@ void cmWIXSourceWriter::AddAttribute( } void cmWIXSourceWriter::AddAttributeUnlessEmpty( - const std::string& key, const std::string& value) + std::string const& key, std::string const& value) { if(value.size()) { @@ -132,7 +132,7 @@ void cmWIXSourceWriter::AddAttributeUnlessEmpty( } } -std::string cmWIXSourceWriter::WindowsCodepageToUtf8(const std::string& value) +std::string cmWIXSourceWriter::WindowsCodepageToUtf8(std::string const& value) { if(value.empty()) { @@ -184,7 +184,7 @@ void cmWIXSourceWriter::Indent(size_t count) } std::string cmWIXSourceWriter::EscapeAttributeValue( - const std::string& value) + std::string const& value) { std::string result; result.reserve(value.size()); diff --git a/Source/CPack/WiX/cmWIXSourceWriter.h b/Source/CPack/WiX/cmWIXSourceWriter.h index 894ad78..65b7240 100644 --- a/Source/CPack/WiX/cmWIXSourceWriter.h +++ b/Source/CPack/WiX/cmWIXSourceWriter.h @@ -26,24 +26,24 @@ class cmWIXSourceWriter { public: cmWIXSourceWriter(cmCPackLog* logger, - const std::string& filename, bool isIncludeFile = false); + std::string const& filename, bool isIncludeFile = false); ~cmWIXSourceWriter(); - void BeginElement(const std::string& name); + void BeginElement(std::string const& name); - void EndElement(const std::string& name); + void EndElement(std::string const& name); void AddProcessingInstruction( - const std::string& target, const std::string& content); + std::string const& target, std::string const& content); void AddAttribute( - const std::string& key, const std::string& value); + std::string const& key, std::string const& value); void AddAttributeUnlessEmpty( - const std::string& key, const std::string& value); + std::string const& key, std::string const& value); - static std::string WindowsCodepageToUtf8(const std::string& value); + static std::string WindowsCodepageToUtf8(std::string const& value); private: enum State @@ -56,7 +56,7 @@ private: void Indent(size_t count); - static std::string EscapeAttributeValue(const std::string& value); + static std::string EscapeAttributeValue(std::string const& value); cmCPackLog* Logger; diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx index 3c65c55..0503d94 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -871,6 +871,12 @@ int cmCTestCoverageHandler::HandleGCovCoverage( { std::string gcovCommand = this->CTest->GetCTestConfiguration("CoverageCommand"); + if (gcovCommand.empty()) + { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Could not find gcov." << std::endl); + return 0; + } std::string gcovExtraFlags = this->CTest->GetCTestConfiguration("CoverageExtraFlags"); diff --git a/Source/CTest/cmCTestLaunch.cxx b/Source/CTest/cmCTestLaunch.cxx index 7d9c034..cd3bd57 100644 --- a/Source/CTest/cmCTestLaunch.cxx +++ b/Source/CTest/cmCTestLaunch.cxx @@ -587,8 +587,7 @@ void cmCTestLaunch::DumpFileToXML(std::ostream& fxml, while(cmSystemTools::GetLineFromStream(fin, line)) { - if(OptionFilterPrefix.size() && cmSystemTools::StringStartsWith( - line.c_str(), OptionFilterPrefix.c_str())) + if(MatchesFilterPrefix(line)) { continue; } @@ -676,6 +675,11 @@ bool cmCTestLaunch::ScrapeLog(std::string const& fname) std::string line; while(cmSystemTools::GetLineFromStream(fin, line)) { + if(MatchesFilterPrefix(line)) + { + continue; + } + if(this->Match(line.c_str(), this->RegexWarning) && !this->Match(line.c_str(), this->RegexWarningSuppress)) { @@ -701,6 +705,17 @@ bool cmCTestLaunch::Match(std::string const& line, } //---------------------------------------------------------------------------- +bool cmCTestLaunch::MatchesFilterPrefix(std::string const& line) const +{ + if(this->OptionFilterPrefix.size() && cmSystemTools::StringStartsWith( + line.c_str(), this->OptionFilterPrefix.c_str())) + { + return true; + } + return false; +} + +//---------------------------------------------------------------------------- int cmCTestLaunch::Main(int argc, const char* const argv[]) { if(argc == 2) diff --git a/Source/CTest/cmCTestLaunch.h b/Source/CTest/cmCTestLaunch.h index a86a9df..f680d19 100644 --- a/Source/CTest/cmCTestLaunch.h +++ b/Source/CTest/cmCTestLaunch.h @@ -88,6 +88,7 @@ private: bool ScrapeLog(std::string const& fname); bool Match(std::string const& line, std::vector<cmsys::RegularExpression>& regexps); + bool MatchesFilterPrefix(std::string const& line) const; // Methods to generate the xml fragment. void WriteXML(); diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx index 2e66d78..cd30546 100644 --- a/Source/cmGeneratorExpression.cxx +++ b/Source/cmGeneratorExpression.cxx @@ -157,17 +157,24 @@ cmCompiledGeneratorExpression::~cmCompiledGeneratorExpression() std::string cmGeneratorExpression::StripEmptyListElements( const std::string &input) { + if (input.find(';') == input.npos) + { + return input; + } std::string result; + result.reserve(input.size()); const char *c = input.c_str(); + const char *last = c; bool skipSemiColons = true; for ( ; *c; ++c) { - if(c[0] == ';') + if(*c == ';') { if(skipSemiColons) { - continue; + result.append(last, c - last); + last = c + 1; } skipSemiColons = true; } @@ -175,8 +182,8 @@ std::string cmGeneratorExpression::StripEmptyListElements( { skipSemiColons = false; } - result += *c; } + result.append(last); if (!result.empty() && *(result.end() - 1) == ';') { diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index 7036992..bdefcfb 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -800,7 +800,7 @@ static const char* targetPropertyTransitiveWhitelist[] = { #undef TRANSITIVE_PROPERTY_NAME -std::string getLinkedTargetsContent(const std::vector<std::string> &libraries, +std::string getLinkedTargetsContent(const std::vector<cmTarget*> &targets, cmTarget const* target, cmTarget const* headTarget, cmGeneratorExpressionContext *context, @@ -811,23 +811,21 @@ std::string getLinkedTargetsContent(const std::vector<std::string> &libraries, std::string sep; std::string depString; - for (std::vector<std::string>::const_iterator - it = libraries.begin(); - it != libraries.end(); ++it) + for (std::vector<cmTarget*>::const_iterator + it = targets.begin(); + it != targets.end(); ++it) { - if (*it == target->GetName()) + if (*it == target) { // Broken code can have a target in its own link interface. // Don't follow such link interface entries so as not to create a // self-referencing loop. continue; } - if (context->Makefile->FindTargetToUse(*it)) - { - depString += - sep + "$<TARGET_PROPERTY:" + *it + "," + interfacePropertyName + ">"; - sep = ";"; - } + depString += + sep + "$<TARGET_PROPERTY:" + + (*it)->GetName() + "," + interfacePropertyName + ">"; + sep = ";"; } cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(depString); std::string linkedTargetsContent = cge->Evaluate(context->Makefile, @@ -843,6 +841,27 @@ std::string getLinkedTargetsContent(const std::vector<std::string> &libraries, return linkedTargetsContent; } +std::string getLinkedTargetsContent(const std::vector<std::string> &libraries, + cmTarget const* target, + cmTarget const* headTarget, + cmGeneratorExpressionContext *context, + cmGeneratorExpressionDAGChecker *dagChecker, + const std::string &interfacePropertyName) +{ + std::vector<cmTarget*> tgts; + for (std::vector<std::string>::const_iterator + it = libraries.begin(); + it != libraries.end(); ++it) + { + if (cmTarget *tgt = context->Makefile->FindTargetToUse(*it)) + { + tgts.push_back(tgt); + } + } + return getLinkedTargetsContent(tgts, target, headTarget, context, + dagChecker, interfacePropertyName); +} + //---------------------------------------------------------------------------- static const struct TargetPropertyNode : public cmGeneratorExpressionNode { @@ -1065,13 +1084,13 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode cmStrCmp(propertyName)) != transEnd) { - std::vector<std::string> libs; - target->GetTransitivePropertyLinkLibraries(context->Config, - headTarget, libs); - if (!libs.empty()) + std::vector<cmTarget*> tgts; + target->GetTransitivePropertyTargets(context->Config, + headTarget, tgts); + if (!tgts.empty()) { linkedTargetsContent = - getLinkedTargetsContent(libs, target, + getLinkedTargetsContent(tgts, target, headTarget, context, &dagChecker, interfacePropertyName); @@ -1080,9 +1099,9 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode else if (std::find_if(transBegin, transEnd, cmStrCmp(interfacePropertyName)) != transEnd) { - const cmTarget::LinkImplementation *impl = target->GetLinkImplementation( - context->Config, - headTarget); + const cmTarget::LinkImplementation *impl + = target->GetLinkImplementationLibraries(context->Config, + headTarget); if(impl) { linkedTargetsContent = diff --git a/Source/cmGeneratorExpressionLexer.cxx b/Source/cmGeneratorExpressionLexer.cxx index cd71ec0..117a24e 100644 --- a/Source/cmGeneratorExpressionLexer.cxx +++ b/Source/cmGeneratorExpressionLexer.cxx @@ -42,42 +42,42 @@ cmGeneratorExpressionLexer::Tokenize(const char *input) const char *upto = c; for ( ; *c; ++c) - { - if(c[0] == '$' && c[1] == '<') { - InsertText(upto, c, result); - upto = c; - result.push_back(cmGeneratorExpressionToken( - cmGeneratorExpressionToken::BeginExpression, upto, 2)); - upto = c + 2; - ++c; - SawBeginExpression = true; - } - else if(c[0] == '>') - { - InsertText(upto, c, result); - upto = c; - result.push_back(cmGeneratorExpressionToken( - cmGeneratorExpressionToken::EndExpression, upto, 1)); - upto = c + 1; - SawGeneratorExpression = SawBeginExpression; - } - else if(c[0] == ':') - { - InsertText(upto, c, result); - upto = c; - result.push_back(cmGeneratorExpressionToken( - cmGeneratorExpressionToken::ColonSeparator, upto, 1)); - upto = c + 1; - } - else if(c[0] == ',') - { - InsertText(upto, c, result); - upto = c; - result.push_back(cmGeneratorExpressionToken( - cmGeneratorExpressionToken::CommaSeparator, upto, 1)); - upto = c + 1; - } + switch(*c) + { + case '$': + if(c[1] == '<') + { + InsertText(upto, c, result); + result.push_back(cmGeneratorExpressionToken( + cmGeneratorExpressionToken::BeginExpression, c, 2)); + upto = c + 2; + ++c; + SawBeginExpression = true; + } + break; + case '>': + InsertText(upto, c, result); + result.push_back(cmGeneratorExpressionToken( + cmGeneratorExpressionToken::EndExpression, c, 1)); + upto = c + 1; + SawGeneratorExpression = SawBeginExpression; + break; + case ':': + InsertText(upto, c, result); + result.push_back(cmGeneratorExpressionToken( + cmGeneratorExpressionToken::ColonSeparator, c, 1)); + upto = c + 1; + break; + case ',': + InsertText(upto, c, result); + result.push_back(cmGeneratorExpressionToken( + cmGeneratorExpressionToken::CommaSeparator, c, 1)); + upto = c + 1; + break; + default: + break; + } } InsertText(upto, c, result); diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 175bb0e..a7b2fb6 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -25,7 +25,196 @@ #include "assert.h" //---------------------------------------------------------------------------- -cmGeneratorTarget::cmGeneratorTarget(cmTarget* t): Target(t) +void reportBadObjLib(std::vector<cmSourceFile*> const& badObjLib, + cmTarget *target, cmake *cm) +{ + if(!badObjLib.empty()) + { + cmOStringStream e; + e << "OBJECT library \"" << target->GetName() << "\" contains:\n"; + for(std::vector<cmSourceFile*>::const_iterator i = badObjLib.begin(); + i != badObjLib.end(); ++i) + { + e << " " << (*i)->GetLocation().GetName() << "\n"; + } + e << "but may contain only headers and sources that compile."; + cm->IssueMessage(cmake::FATAL_ERROR, e.str(), + target->GetBacktrace()); + } +} + +struct ObjectSourcesTag {}; +struct CustomCommandsTag {}; +struct ExtraSourcesTag {}; +struct HeaderSourcesTag {}; +struct ExternalObjectsTag {}; +struct IDLSourcesTag {}; +struct ResxTag {}; +struct ModuleDefinitionFileTag {}; + +#if !defined(_MSC_VER) || _MSC_VER >= 1310 +template<typename Tag, typename OtherTag> +struct IsSameTag +{ + enum { + Result = false + }; +}; + +template<typename Tag> +struct IsSameTag<Tag, Tag> +{ + enum { + Result = true + }; +}; +#else +struct IsSameTagBase +{ + typedef char (&no_type)[1]; + typedef char (&yes_type)[2]; + template<typename T> struct Check; + template<typename T> static yes_type check(Check<T>*, Check<T>*); + static no_type check(...); +}; +template<typename Tag1, typename Tag2> +struct IsSameTag: public IsSameTagBase +{ + enum { + Result = (sizeof(check(static_cast< Check<Tag1>* >(0), + static_cast< Check<Tag2>* >(0))) == + sizeof(yes_type)) + }; +}; +#endif + +template<bool> +struct DoAccept +{ + template <typename T> static void Do(T&, cmSourceFile*) {} +}; + +template<> +struct DoAccept<true> +{ + static void Do(std::vector<cmSourceFile*>& files, cmSourceFile* f) + { + files.push_back(f); + } + static void Do(cmGeneratorTarget::ResxData& data, cmSourceFile* f) + { + // Build and save the name of the corresponding .h file + // This relationship will be used later when building the project files. + // Both names would have been auto generated from Visual Studio + // where the user supplied the file name and Visual Studio + // appended the suffix. + std::string resx = f->GetFullPath(); + std::string hFileName = resx.substr(0, resx.find_last_of(".")) + ".h"; + data.ExpectedResxHeaders.insert(hFileName); + data.ResxSources.push_back(f); + } + static void Do(std::string& data, cmSourceFile* f) + { + data = f->GetFullPath(); + } +}; + +//---------------------------------------------------------------------------- +template<typename Tag, typename DataType = std::vector<cmSourceFile*> > +struct TagVisitor +{ + DataType& Data; + std::vector<cmSourceFile*> BadObjLibFiles; + cmTarget *Target; + cmGlobalGenerator *GlobalGenerator; + cmsys::RegularExpression Header; + bool IsObjLib; + + TagVisitor(cmTarget *target, DataType& data) + : Data(data), Target(target), + GlobalGenerator(target->GetMakefile() + ->GetLocalGenerator()->GetGlobalGenerator()), + Header(CM_HEADER_REGEX), + IsObjLib(target->GetType() == cmTarget::OBJECT_LIBRARY) + { + } + + ~TagVisitor() + { + reportBadObjLib(this->BadObjLibFiles, this->Target, + this->GlobalGenerator->GetCMakeInstance()); + } + + void Accept(cmSourceFile *sf) + { + std::string ext = cmSystemTools::LowerCase(sf->GetExtension()); + if(sf->GetCustomCommand()) + { + DoAccept<IsSameTag<Tag, CustomCommandsTag>::Result>::Do(this->Data, sf); + } + else if(this->Target->GetType() == cmTarget::UTILITY) + { + DoAccept<IsSameTag<Tag, ExtraSourcesTag>::Result>::Do(this->Data, sf); + } + else if(sf->GetPropertyAsBool("HEADER_FILE_ONLY")) + { + DoAccept<IsSameTag<Tag, HeaderSourcesTag>::Result>::Do(this->Data, sf); + } + else if(sf->GetPropertyAsBool("EXTERNAL_OBJECT")) + { + DoAccept<IsSameTag<Tag, ExternalObjectsTag>::Result>::Do(this->Data, sf); + if(this->IsObjLib) + { + this->BadObjLibFiles.push_back(sf); + } + } + else if(sf->GetLanguage()) + { + DoAccept<IsSameTag<Tag, ObjectSourcesTag>::Result>::Do(this->Data, sf); + } + else if(ext == "def") + { + DoAccept<IsSameTag<Tag, ModuleDefinitionFileTag>::Result>::Do(this->Data, + sf); + if(this->IsObjLib) + { + this->BadObjLibFiles.push_back(sf); + } + } + else if(ext == "idl") + { + DoAccept<IsSameTag<Tag, IDLSourcesTag>::Result>::Do(this->Data, sf); + if(this->IsObjLib) + { + this->BadObjLibFiles.push_back(sf); + } + } + else if(ext == "resx") + { + DoAccept<IsSameTag<Tag, ResxTag>::Result>::Do(this->Data, sf); + } + else if(this->Header.find(sf->GetFullPath().c_str())) + { + DoAccept<IsSameTag<Tag, HeaderSourcesTag>::Result>::Do(this->Data, sf); + } + else if(this->GlobalGenerator->IgnoreFile(sf->GetExtension().c_str())) + { + DoAccept<IsSameTag<Tag, ExtraSourcesTag>::Result>::Do(this->Data, sf); + } + else + { + DoAccept<IsSameTag<Tag, ExtraSourcesTag>::Result>::Do(this->Data, sf); + if(this->IsObjLib && ext != "txt") + { + this->BadObjLibFiles.push_back(sf); + } + } + } +}; + +//---------------------------------------------------------------------------- +cmGeneratorTarget::cmGeneratorTarget(cmTarget* t): Target(t), + SourceFileFlagsConstructed(false) { this->Makefile = this->Target->GetMakefile(); this->LocalGenerator = this->Makefile->GetLocalGenerator(); @@ -62,19 +251,12 @@ cmGeneratorTarget::GetSourceDepends(cmSourceFile* sf) const return 0; } -static void handleSystemIncludesDep(cmMakefile *mf, const std::string &name, +static void handleSystemIncludesDep(cmMakefile *mf, cmTarget* depTgt, const char *config, cmTarget *headTarget, cmGeneratorExpressionDAGChecker *dagChecker, std::vector<std::string>& result, bool excludeImported) { - cmTarget* depTgt = mf->FindTargetToUse(name); - - if (!depTgt) - { - return; - } - cmListFileBacktrace lfbt; if (const char* dirs = @@ -102,11 +284,34 @@ static void handleSystemIncludesDep(cmMakefile *mf, const std::string &name, } } +#define IMPLEMENT_VISIT_IMPL(DATA, DATATYPE) \ + { \ + std::vector<cmSourceFile*> sourceFiles; \ + this->Target->GetSourceFiles(sourceFiles); \ + TagVisitor<DATA ## Tag DATATYPE> visitor(this->Target, data); \ + for(std::vector<cmSourceFile*>::const_iterator si = sourceFiles.begin(); \ + si != sourceFiles.end(); ++si) \ + { \ + visitor.Accept(*si); \ + } \ + } \ + + +#define IMPLEMENT_VISIT(DATA) \ + IMPLEMENT_VISIT_IMPL(DATA, EMPTY) \ + +#define EMPTY +#define COMMA , + //---------------------------------------------------------------------------- void -cmGeneratorTarget::GetObjectSources(std::vector<cmSourceFile*> &objs) const +cmGeneratorTarget::GetObjectSources(std::vector<cmSourceFile*> &data) const { - objs = this->ObjectSources; + IMPLEMENT_VISIT(ObjectSources); + if (this->Target->GetType() == cmTarget::OBJECT_LIBRARY) + { + this->ObjectSources = data; + } } //---------------------------------------------------------------------------- @@ -135,49 +340,53 @@ bool cmGeneratorTarget::HasExplicitObjectName(cmSourceFile const* file) const } //---------------------------------------------------------------------------- -void cmGeneratorTarget::GetResxSources(std::vector<cmSourceFile*>& srcs) const +void cmGeneratorTarget::GetIDLSources(std::vector<cmSourceFile*>& data) const { - srcs = this->ResxSources; + IMPLEMENT_VISIT(IDLSources); } //---------------------------------------------------------------------------- -void cmGeneratorTarget::GetIDLSources(std::vector<cmSourceFile*>& srcs) const +void +cmGeneratorTarget::GetHeaderSources(std::vector<cmSourceFile*>& data) const { - srcs = this->IDLSources; + IMPLEMENT_VISIT(HeaderSources); } //---------------------------------------------------------------------------- -void -cmGeneratorTarget::GetHeaderSources(std::vector<cmSourceFile*>& srcs) const +void cmGeneratorTarget::GetExtraSources(std::vector<cmSourceFile*>& data) const { - srcs = this->HeaderSources; + IMPLEMENT_VISIT(ExtraSources); } //---------------------------------------------------------------------------- -void cmGeneratorTarget::GetExtraSources(std::vector<cmSourceFile*>& srcs) const +void +cmGeneratorTarget::GetCustomCommands(std::vector<cmSourceFile*>& data) const { - srcs = this->ExtraSources; + IMPLEMENT_VISIT(CustomCommands); } //---------------------------------------------------------------------------- void -cmGeneratorTarget::GetCustomCommands(std::vector<cmSourceFile*>& srcs) const +cmGeneratorTarget::GetExternalObjects(std::vector<cmSourceFile*>& data) const { - srcs = this->CustomCommands; + IMPLEMENT_VISIT(ExternalObjects); } //---------------------------------------------------------------------------- void cmGeneratorTarget::GetExpectedResxHeaders(std::set<std::string>& srcs) const { - srcs = this->ExpectedResxHeaders; + ResxData data; + IMPLEMENT_VISIT_IMPL(Resx, COMMA cmGeneratorTarget::ResxData) + srcs = data.ExpectedResxHeaders; } //---------------------------------------------------------------------------- -void -cmGeneratorTarget::GetExternalObjects(std::vector<cmSourceFile*>& srcs) const +void cmGeneratorTarget::GetResxSources(std::vector<cmSourceFile*>& srcs) const { - srcs = this->ExternalObjects; + ResxData data; + IMPLEMENT_VISIT_IMPL(Resx, COMMA cmGeneratorTarget::ResxData) + srcs = data.ResxSources; } //---------------------------------------------------------------------------- @@ -224,26 +433,25 @@ bool cmGeneratorTarget::IsSystemIncludeDirectory(const char *dir, &dagChecker), result); } - std::set<cmStdString> uniqueDeps; + std::set<cmTarget*> uniqueDeps; for(std::vector<std::string>::const_iterator li = impl->Libraries.begin(); li != impl->Libraries.end(); ++li) { - if (uniqueDeps.insert(*li).second) + cmTarget* tgt = this->Makefile->FindTargetToUse(*li); + if (!tgt) { - cmTarget* tgt = this->Makefile->FindTargetToUse(*li); - - if (!tgt) - { - continue; - } + continue; + } - handleSystemIncludesDep(this->Makefile, *li, config, this->Target, + if (uniqueDeps.insert(tgt).second) + { + handleSystemIncludesDep(this->Makefile, tgt, config, this->Target, &dagChecker, result, excludeImported); - std::vector<std::string> deps; - tgt->GetTransitivePropertyLinkLibraries(config, this->Target, deps); + std::vector<cmTarget*> deps; + tgt->GetTransitivePropertyTargets(config, this->Target, deps); - for(std::vector<std::string>::const_iterator di = deps.begin(); + for(std::vector<cmTarget*>::const_iterator di = deps.begin(); di != deps.end(); ++di) { if (uniqueDeps.insert(*di).second) @@ -290,102 +498,6 @@ void cmGeneratorTarget::GetSourceFiles(std::vector<cmSourceFile*> &files) const } //---------------------------------------------------------------------------- -void cmGeneratorTarget::ClassifySources() -{ - cmsys::RegularExpression header(CM_HEADER_REGEX); - - cmTarget::TargetType targetType = this->Target->GetType(); - bool isObjLib = targetType == cmTarget::OBJECT_LIBRARY; - - std::vector<cmSourceFile*> badObjLib; - std::vector<cmSourceFile*> sources; - this->Target->GetSourceFiles(sources); - for(std::vector<cmSourceFile*>::const_iterator si = sources.begin(); - si != sources.end(); ++si) - { - cmSourceFile* sf = *si; - std::string ext = cmSystemTools::LowerCase(sf->GetExtension()); - if(sf->GetCustomCommand()) - { - this->CustomCommands.push_back(sf); - } - else if(targetType == cmTarget::UTILITY) - { - this->ExtraSources.push_back(sf); - } - else if(sf->GetPropertyAsBool("HEADER_FILE_ONLY")) - { - this->HeaderSources.push_back(sf); - } - else if(sf->GetPropertyAsBool("EXTERNAL_OBJECT")) - { - this->ExternalObjects.push_back(sf); - if(isObjLib) { badObjLib.push_back(sf); } - } - else if(sf->GetLanguage()) - { - this->ObjectSources.push_back(sf); - } - else if(ext == "def") - { - this->ModuleDefinitionFile = sf->GetFullPath(); - if(isObjLib) { badObjLib.push_back(sf); } - } - else if(ext == "idl") - { - this->IDLSources.push_back(sf); - if(isObjLib) { badObjLib.push_back(sf); } - } - else if(ext == "resx") - { - // Build and save the name of the corresponding .h file - // This relationship will be used later when building the project files. - // Both names would have been auto generated from Visual Studio - // where the user supplied the file name and Visual Studio - // appended the suffix. - std::string resx = sf->GetFullPath(); - std::string hFileName = resx.substr(0, resx.find_last_of(".")) + ".h"; - this->ExpectedResxHeaders.insert(hFileName); - this->ResxSources.push_back(sf); - } - else if(header.find(sf->GetFullPath().c_str())) - { - this->HeaderSources.push_back(sf); - } - else if(this->GlobalGenerator->IgnoreFile(sf->GetExtension().c_str())) - { - // We only get here if a source file is not an external object - // and has an extension that is listed as an ignored file type. - // No message or diagnosis should be given. - this->ExtraSources.push_back(sf); - } - else - { - this->ExtraSources.push_back(sf); - if(isObjLib && ext != "txt") - { - badObjLib.push_back(sf); - } - } - } - - if(!badObjLib.empty()) - { - cmOStringStream e; - e << "OBJECT library \"" << this->Target->GetName() << "\" contains:\n"; - for(std::vector<cmSourceFile*>::iterator i = badObjLib.begin(); - i != badObjLib.end(); ++i) - { - e << " " << (*i)->GetLocation().GetName() << "\n"; - } - e << "but may contain only headers and sources that compile."; - this->GlobalGenerator->GetCMakeInstance() - ->IssueMessage(cmake::FATAL_ERROR, e.str(), - this->Target->GetBacktrace()); - } -} - -//---------------------------------------------------------------------------- void cmGeneratorTarget::LookupObjectLibraries() { std::vector<std::string> const& objLibs = @@ -438,6 +550,14 @@ void cmGeneratorTarget::LookupObjectLibraries() } //---------------------------------------------------------------------------- +std::string cmGeneratorTarget::GetModuleDefinitionFile() const +{ + std::string data; + IMPLEMENT_VISIT_IMPL(ModuleDefinitionFile, COMMA std::string) + return data; +} + +//---------------------------------------------------------------------------- void cmGeneratorTarget::UseObjectLibraries(std::vector<std::string>& objs) const { @@ -876,3 +996,97 @@ bool cmStrictTargetComparison::operator()(cmTarget const* t1, } return nameResult < 0; } + +//---------------------------------------------------------------------------- +struct cmGeneratorTarget::SourceFileFlags +cmGeneratorTarget::GetTargetSourceFileFlags(const cmSourceFile* sf) const +{ + struct SourceFileFlags flags; + this->ConstructSourceFileFlags(); + std::map<cmSourceFile const*, SourceFileFlags>::iterator si = + this->SourceFlagsMap.find(sf); + if(si != this->SourceFlagsMap.end()) + { + flags = si->second; + } + else + { + // Handle the MACOSX_PACKAGE_LOCATION property on source files that + // were not listed in one of the other lists. + if(const char* location = sf->GetProperty("MACOSX_PACKAGE_LOCATION")) + { + flags.MacFolder = location; + if(strcmp(location, "Resources") == 0) + { + flags.Type = cmGeneratorTarget::SourceFileTypeResource; + } + else + { + flags.Type = cmGeneratorTarget::SourceFileTypeMacContent; + } + } + } + return flags; +} + +//---------------------------------------------------------------------------- +void cmGeneratorTarget::ConstructSourceFileFlags() const +{ + if(this->SourceFileFlagsConstructed) + { + return; + } + this->SourceFileFlagsConstructed = true; + + // Process public headers to mark the source files. + if(const char* files = this->Target->GetProperty("PUBLIC_HEADER")) + { + std::vector<std::string> relFiles; + cmSystemTools::ExpandListArgument(files, relFiles); + for(std::vector<std::string>::iterator it = relFiles.begin(); + it != relFiles.end(); ++it) + { + if(cmSourceFile* sf = this->Makefile->GetSource(it->c_str())) + { + SourceFileFlags& flags = this->SourceFlagsMap[sf]; + flags.MacFolder = "Headers"; + flags.Type = cmGeneratorTarget::SourceFileTypePublicHeader; + } + } + } + + // Process private headers after public headers so that they take + // precedence if a file is listed in both. + if(const char* files = this->Target->GetProperty("PRIVATE_HEADER")) + { + std::vector<std::string> relFiles; + cmSystemTools::ExpandListArgument(files, relFiles); + for(std::vector<std::string>::iterator it = relFiles.begin(); + it != relFiles.end(); ++it) + { + if(cmSourceFile* sf = this->Makefile->GetSource(it->c_str())) + { + SourceFileFlags& flags = this->SourceFlagsMap[sf]; + flags.MacFolder = "PrivateHeaders"; + flags.Type = cmGeneratorTarget::SourceFileTypePrivateHeader; + } + } + } + + // Mark sources listed as resources. + if(const char* files = this->Target->GetProperty("RESOURCE")) + { + std::vector<std::string> relFiles; + cmSystemTools::ExpandListArgument(files, relFiles); + for(std::vector<std::string>::iterator it = relFiles.begin(); + it != relFiles.end(); ++it) + { + if(cmSourceFile* sf = this->Makefile->GetSource(it->c_str())) + { + SourceFileFlags& flags = this->SourceFlagsMap[sf]; + flags.MacFolder = "Resources"; + flags.Type = cmGeneratorTarget::SourceFileTypeResource; + } + } + } +} diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index a4caba1..1e6ce64 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -52,7 +52,7 @@ public: cmLocalGenerator* LocalGenerator; cmGlobalGenerator const* GlobalGenerator; - std::string ModuleDefinitionFile; + std::string GetModuleDefinitionFile() const; /** Full path with trailing slash to the top-level directory holding object files for this target. Includes the build @@ -82,31 +82,56 @@ public: */ void TraceDependencies(); - void ClassifySources(); void LookupObjectLibraries(); /** Get sources that must be built before the given source. */ std::vector<cmSourceFile*> const* GetSourceDepends(cmSourceFile* sf) const; + /** + * Flags for a given source file as used in this target. Typically assigned + * via SET_TARGET_PROPERTIES when the property is a list of source files. + */ + enum SourceFileType + { + SourceFileTypeNormal, + SourceFileTypePrivateHeader, // is in "PRIVATE_HEADER" target property + SourceFileTypePublicHeader, // is in "PUBLIC_HEADER" target property + SourceFileTypeResource, // is in "RESOURCE" target property *or* + // has MACOSX_PACKAGE_LOCATION=="Resources" + SourceFileTypeMacContent // has MACOSX_PACKAGE_LOCATION!="Resources" + }; + struct SourceFileFlags + { + SourceFileFlags(): Type(SourceFileTypeNormal), MacFolder(0) {} + SourceFileFlags(SourceFileFlags const& r): + Type(r.Type), MacFolder(r.MacFolder) {} + SourceFileType Type; + const char* MacFolder; // location inside Mac content folders + }; + + struct SourceFileFlags + GetTargetSourceFileFlags(const cmSourceFile* sf) const; + + struct ResxData { + mutable std::set<std::string> ExpectedResxHeaders; + mutable std::vector<cmSourceFile*> ResxSources; + }; private: friend class cmTargetTraceDependencies; struct SourceEntry { std::vector<cmSourceFile*> Depends; }; typedef std::map<cmSourceFile*, SourceEntry> SourceEntriesType; SourceEntriesType SourceEntries; - std::vector<cmSourceFile*> CustomCommands; - std::vector<cmSourceFile*> ExtraSources; - std::vector<cmSourceFile*> HeaderSources; - std::vector<cmSourceFile*> ExternalObjects; - std::vector<cmSourceFile*> IDLSources; - std::vector<cmSourceFile*> ResxSources; std::map<cmSourceFile const*, std::string> Objects; std::set<cmSourceFile const*> ExplicitObjectName; - std::set<std::string> ExpectedResxHeaders; - std::vector<cmSourceFile*> ObjectSources; + mutable std::vector<cmSourceFile*> ObjectSources; std::vector<cmTarget*> ObjectLibraries; mutable std::map<std::string, std::vector<std::string> > SystemIncludesCache; + void ConstructSourceFileFlags() const; + mutable bool SourceFileFlagsConstructed; + mutable std::map<cmSourceFile const*, SourceFileFlags> SourceFlagsMap; + cmGeneratorTarget(cmGeneratorTarget const&); void operator=(cmGeneratorTarget const&); }; diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 4f3328d..f76c6d1 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -1148,12 +1148,6 @@ void cmGlobalGenerator::Generate() return; } - // Check that all targets are valid. - if(!this->CheckTargets()) - { - return; - } - this->FinalizeTargetCompileInfo(); #ifdef CMAKE_BUILD_WITH_CMAKE @@ -1306,35 +1300,6 @@ bool cmGlobalGenerator::ComputeTargetDepends() } //---------------------------------------------------------------------------- -bool cmGlobalGenerator::CheckTargets() -{ - // Make sure all targets can find their source files. - for(unsigned int i=0; i < this->LocalGenerators.size(); ++i) - { - cmTargets& targets = - this->LocalGenerators[i]->GetMakefile()->GetTargets(); - for(cmTargets::iterator ti = targets.begin(); - ti != targets.end(); ++ti) - { - cmTarget& target = ti->second; - if(target.GetType() == cmTarget::EXECUTABLE || - target.GetType() == cmTarget::STATIC_LIBRARY || - target.GetType() == cmTarget::SHARED_LIBRARY || - target.GetType() == cmTarget::MODULE_LIBRARY || - target.GetType() == cmTarget::OBJECT_LIBRARY || - target.GetType() == cmTarget::UTILITY) - { - if(!target.FindSourceFiles()) - { - return false; - } - } - } - } - return true; -} - -//---------------------------------------------------------------------------- void cmGlobalGenerator::CreateQtAutoGeneratorsTargets(AutogensType &autogens) { #ifdef CMAKE_BUILD_WITH_CMAKE @@ -1474,7 +1439,6 @@ void cmGlobalGenerator::ComputeGeneratorTargetObjects() continue; } cmGeneratorTarget* gt = ti->second; - gt->ClassifySources(); gt->LookupObjectLibraries(); this->ComputeTargetObjects(gt); } diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 753eebf..b66f01e 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -340,7 +340,6 @@ protected: virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const; - bool CheckTargets(); typedef std::vector<std::pair<cmQtAutoGenerators, cmTarget const*> > AutogensType; void CreateQtAutoGeneratorsTargets(AutogensType& autogens); diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 484b28f..004f7ac 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -713,22 +713,23 @@ cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg, // Is this a resource file in this target? Add it to the resources group... // - cmTarget::SourceFileFlags tsFlags = cmtarget.GetTargetSourceFileFlags(sf); - bool isResource = (tsFlags.Type == cmTarget::SourceFileTypeResource); + cmGeneratorTarget::SourceFileFlags tsFlags = + this->GetGeneratorTarget(&cmtarget)->GetTargetSourceFileFlags(sf); + bool isResource = tsFlags.Type == cmGeneratorTarget::SourceFileTypeResource; // Is this a "private" or "public" framework header file? // Set the ATTRIBUTES attribute appropriately... // if(cmtarget.IsFrameworkOnApple()) { - if(tsFlags.Type == cmTarget::SourceFileTypePrivateHeader) + if(tsFlags.Type == cmGeneratorTarget::SourceFileTypePrivateHeader) { cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST); attrs->AddObject(this->CreateString("Private")); settings->AddAttribute("ATTRIBUTES", attrs); isResource = true; } - else if(tsFlags.Type == cmTarget::SourceFileTypePublicHeader) + else if(tsFlags.Type == cmGeneratorTarget::SourceFileTypePublicHeader) { cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST); attrs->AddObject(this->CreateString("Public")); @@ -973,6 +974,7 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen, for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++) { cmTarget& cmtarget = l->second; + cmGeneratorTarget* gtgt = this->GetGeneratorTarget(&cmtarget); // make sure ALL_BUILD, INSTALL, etc are only done once if(this->SpecialTargetEmitted(l->first.c_str())) @@ -1011,8 +1013,8 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen, cmXCodeObject* filetype = fr->GetObject()->GetObject("explicitFileType"); - cmTarget::SourceFileFlags tsFlags = - cmtarget.GetTargetSourceFileFlags(*i); + cmGeneratorTarget::SourceFileFlags tsFlags = + gtgt->GetTargetSourceFileFlags(*i); if(filetype && strcmp(filetype->GetString(), "compiled.mach-o.objfile") == 0) @@ -1020,12 +1022,12 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen, externalObjFiles.push_back(xsf); } else if(this->IsHeaderFile(*i) || - (tsFlags.Type == cmTarget::SourceFileTypePrivateHeader) || - (tsFlags.Type == cmTarget::SourceFileTypePublicHeader)) + (tsFlags.Type == cmGeneratorTarget::SourceFileTypePrivateHeader) || + (tsFlags.Type == cmGeneratorTarget::SourceFileTypePublicHeader)) { headerFiles.push_back(xsf); } - else if(tsFlags.Type == cmTarget::SourceFileTypeResource) + else if(tsFlags.Type == cmGeneratorTarget::SourceFileTypeResource) { resourceFiles.push_back(xsf); } @@ -1048,7 +1050,7 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen, // the externalObjFiles above, except each one is not a cmSourceFile // within the target.) std::vector<std::string> objs; - this->GetGeneratorTarget(&cmtarget)->UseObjectLibraries(objs); + gtgt->UseObjectLibraries(objs); for(std::vector<std::string>::const_iterator oi = objs.begin(); oi != objs.end(); ++oi) { @@ -1138,9 +1140,9 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen, for(std::vector<cmSourceFile*>::const_iterator i = classes.begin(); i != classes.end(); ++i) { - cmTarget::SourceFileFlags tsFlags = - cmtarget.GetTargetSourceFileFlags(*i); - if(tsFlags.Type == cmTarget::SourceFileTypeMacContent) + cmGeneratorTarget::SourceFileFlags tsFlags = + gtgt->GetTargetSourceFileFlags(*i); + if(tsFlags.Type == cmGeneratorTarget::SourceFileTypeMacContent) { bundleFiles[tsFlags.MacFolder].push_back(*i); } diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 6f2dd65..0878aae 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -32,10 +32,12 @@ static cmInstallTargetGenerator* CreateInstallTargetGenerator(cmTarget& target, } static cmInstallFilesGenerator* CreateInstallFilesGenerator( + cmMakefile* mf, const std::vector<std::string>& absFiles, const cmInstallCommandArguments& args, bool programs) { - return new cmInstallFilesGenerator(absFiles, args.GetDestination().c_str(), + return new cmInstallFilesGenerator(mf, + absFiles, args.GetDestination().c_str(), programs, args.GetPermissions().c_str(), args.GetConfigurations(), args.GetComponent().c_str(), args.GetRename().c_str(), args.GetOptional()); @@ -668,7 +670,8 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) if (!privateHeaderArgs.GetDestination().empty()) { privateHeaderGenerator = - CreateInstallFilesGenerator(absFiles, privateHeaderArgs, false); + CreateInstallFilesGenerator(this->Makefile, absFiles, + privateHeaderArgs, false); } else { @@ -694,7 +697,8 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) if (!publicHeaderArgs.GetDestination().empty()) { publicHeaderGenerator = - CreateInstallFilesGenerator(absFiles, publicHeaderArgs, false); + CreateInstallFilesGenerator(this->Makefile, absFiles, + publicHeaderArgs, false); } else { @@ -719,8 +723,8 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) // Create the files install generator. if (!resourceArgs.GetDestination().empty()) { - resourceGenerator = CreateInstallFilesGenerator(absFiles, - resourceArgs, false); + resourceGenerator = CreateInstallFilesGenerator( + this->Makefile, absFiles, resourceArgs, false); } else { @@ -888,7 +892,7 @@ bool cmInstallCommand::HandleFilesMode(std::vector<std::string> const& args) // Create the files install generator. this->Makefile->AddInstallGenerator( - CreateInstallFilesGenerator(absFiles, ica, programs)); + CreateInstallFilesGenerator(this->Makefile, absFiles, ica, programs)); //Tell the global generator about any installation component names specified. this->Makefile->GetLocalGenerator()->GetGlobalGenerator() @@ -1351,7 +1355,8 @@ bool cmInstallCommand::MakeFilesFullPath(const char* modeName, ++fileIt) { std::string file = (*fileIt); - if(!cmSystemTools::FileIsFullPath(file.c_str())) + std::string::size_type gpos = cmGeneratorExpression::Find(file); + if(gpos != 0 && !cmSystemTools::FileIsFullPath(file.c_str())) { file = this->Makefile->GetCurrentDirectory(); file += "/"; @@ -1359,7 +1364,7 @@ bool cmInstallCommand::MakeFilesFullPath(const char* modeName, } // Make sure the file is not a directory. - if(cmSystemTools::FileIsDirectory(file.c_str())) + if(gpos == file.npos && cmSystemTools::FileIsDirectory(file.c_str())) { cmOStringStream e; e << modeName << " given directory \"" << (*fileIt) << "\" to install."; diff --git a/Source/cmInstallFilesCommand.cxx b/Source/cmInstallFilesCommand.cxx index cc62c4b..488d486 100644 --- a/Source/cmInstallFilesCommand.cxx +++ b/Source/cmInstallFilesCommand.cxx @@ -133,7 +133,7 @@ void cmInstallFilesCommand::CreateInstallGenerator() const "CMAKE_INSTALL_DEFAULT_COMPONENT_NAME"); std::vector<std::string> no_configurations; this->Makefile->AddInstallGenerator( - new cmInstallFilesGenerator(this->Files, + new cmInstallFilesGenerator(this->Makefile, this->Files, destination.c_str(), false, no_permissions, no_configurations, no_component.c_str(), no_rename)); @@ -148,7 +148,8 @@ void cmInstallFilesCommand::CreateInstallGenerator() const */ std::string cmInstallFilesCommand::FindInstallSource(const char* name) const { - if(cmSystemTools::FileIsFullPath(name)) + if(cmSystemTools::FileIsFullPath(name) || + cmGeneratorExpression::Find(name) == 0) { // This is a full path. return name; diff --git a/Source/cmInstallFilesGenerator.cxx b/Source/cmInstallFilesGenerator.cxx index ec02bc7..ec15044 100644 --- a/Source/cmInstallFilesGenerator.cxx +++ b/Source/cmInstallFilesGenerator.cxx @@ -11,9 +11,13 @@ ============================================================================*/ #include "cmInstallFilesGenerator.h" +#include "cmGeneratorExpression.h" +#include "cmSystemTools.h" + //---------------------------------------------------------------------------- cmInstallFilesGenerator -::cmInstallFilesGenerator(std::vector<std::string> const& files, +::cmInstallFilesGenerator(cmMakefile* mf, + std::vector<std::string> const& files, const char* dest, bool programs, const char* file_permissions, std::vector<std::string> const& configurations, @@ -21,10 +25,20 @@ cmInstallFilesGenerator const char* rename, bool optional): cmInstallGenerator(dest, configurations, component), + Makefile(mf), Files(files), Programs(programs), FilePermissions(file_permissions), Rename(rename), Optional(optional) { + // We need per-config actions if any files have generator expressions. + for(std::vector<std::string>::const_iterator i = files.begin(); + !this->ActionsPerConfig && i != files.end(); ++i) + { + if(cmGeneratorExpression::Find(*i) != std::string::npos) + { + this->ActionsPerConfig = true; + } + } } //---------------------------------------------------------------------------- @@ -34,8 +48,9 @@ cmInstallFilesGenerator } //---------------------------------------------------------------------------- -void cmInstallFilesGenerator::GenerateScriptActions(std::ostream& os, - Indent const& indent) +void cmInstallFilesGenerator::AddFilesInstallRule( + std::ostream& os, Indent const& indent, + std::vector<std::string> const& files) { // Write code to install the files. const char* no_dir_permissions = 0; @@ -43,8 +58,40 @@ void cmInstallFilesGenerator::GenerateScriptActions(std::ostream& os, (this->Programs ? cmInstallType_PROGRAMS : cmInstallType_FILES), - this->Files, + files, this->Optional, this->FilePermissions.c_str(), no_dir_permissions, this->Rename.c_str(), 0, indent); } + +//---------------------------------------------------------------------------- +void cmInstallFilesGenerator::GenerateScriptActions(std::ostream& os, + Indent const& indent) +{ + if(this->ActionsPerConfig) + { + this->cmInstallGenerator::GenerateScriptActions(os, indent); + } + else + { + this->AddFilesInstallRule(os, indent, this->Files); + } +} + +//---------------------------------------------------------------------------- +void cmInstallFilesGenerator::GenerateScriptForConfig(std::ostream& os, + const char* config, + Indent const& indent) +{ + std::vector<std::string> files; + cmListFileBacktrace lfbt; + cmGeneratorExpression ge(lfbt); + for(std::vector<std::string>::const_iterator i = this->Files.begin(); + i != this->Files.end(); ++i) + { + cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*i); + cmSystemTools::ExpandListArgument(cge->Evaluate(this->Makefile, config), + files); + } + this->AddFilesInstallRule(os, indent, files); +} diff --git a/Source/cmInstallFilesGenerator.h b/Source/cmInstallFilesGenerator.h index 871335c..9dea296 100644 --- a/Source/cmInstallFilesGenerator.h +++ b/Source/cmInstallFilesGenerator.h @@ -14,13 +14,16 @@ #include "cmInstallGenerator.h" +class cmMakefile; + /** \class cmInstallFilesGenerator * \brief Generate file installation rules. */ class cmInstallFilesGenerator: public cmInstallGenerator { public: - cmInstallFilesGenerator(std::vector<std::string> const& files, + cmInstallFilesGenerator(cmMakefile* mf, + std::vector<std::string> const& files, const char* dest, bool programs, const char* file_permissions, std::vector<std::string> const& configurations, @@ -31,6 +34,13 @@ public: protected: virtual void GenerateScriptActions(std::ostream& os, Indent const& indent); + virtual void GenerateScriptForConfig(std::ostream& os, + const char* config, + Indent const& indent); + void AddFilesInstallRule(std::ostream& os, Indent const& indent, + std::vector<std::string> const& files); + + cmMakefile* Makefile; std::vector<std::string> Files; bool Programs; std::string FilePermissions; diff --git a/Source/cmInstallProgramsCommand.cxx b/Source/cmInstallProgramsCommand.cxx index 3a0a322..54d903a 100644 --- a/Source/cmInstallProgramsCommand.cxx +++ b/Source/cmInstallProgramsCommand.cxx @@ -94,7 +94,7 @@ void cmInstallProgramsCommand::FinalPass() "CMAKE_INSTALL_DEFAULT_COMPONENT_NAME"); std::vector<std::string> no_configurations; this->Makefile->AddInstallGenerator( - new cmInstallFilesGenerator(this->Files, + new cmInstallFilesGenerator(this->Makefile, this->Files, destination.c_str(), true, no_permissions, no_configurations, no_component.c_str(), no_rename)); @@ -109,7 +109,8 @@ void cmInstallProgramsCommand::FinalPass() std::string cmInstallProgramsCommand ::FindInstallSource(const char* name) const { - if(cmSystemTools::FileIsFullPath(name)) + if(cmSystemTools::FileIsFullPath(name) || + cmGeneratorExpression::Find(name) == 0) { // This is a full path. return name; diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index aca195c..4266dd0 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -901,6 +901,13 @@ cmLocalGenerator::ExpandRuleVariable(std::string const& variable, return replaceValues.TargetPDB; } } + if(replaceValues.TargetCompilePDB) + { + if(variable == "TARGET_COMPILE_PDB") + { + return replaceValues.TargetCompilePDB; + } + } if(replaceValues.DependencyFile ) { if(variable == "DEP_FILE") diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 9764813..0f7fd25 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -245,6 +245,7 @@ public: } cmTarget* CMTarget; const char* TargetPDB; + const char* TargetCompilePDB; const char* TargetVersionMajor; const char* TargetVersionMinor; const char* Language; diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 212b06b..ce24d8d 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -660,7 +660,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout, switch(target.GetType()) { case cmTarget::OBJECT_LIBRARY: - targetBuilds = false; // TODO: PDB for object library? + targetBuilds = false; // no manifest tool for object library case cmTarget::STATIC_LIBRARY: projectType = "typeStaticLibrary"; configType = "4"; @@ -846,6 +846,17 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout, targetOptions.OutputFlagMap(fout, "\t\t\t\t"); targetOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t", "\n", "CXX"); fout << "\t\t\t\tObjectFile=\"$(IntDir)\\\"\n"; + if(target.GetType() <= cmTarget::OBJECT_LIBRARY) + { + // Specify the compiler program database file if configured. + std::string pdb = target.GetCompilePDBPath(configName); + if(!pdb.empty()) + { + fout << "\t\t\t\tProgramDataBaseFileName=\"" + << this->ConvertToXMLOutputPathSingle(pdb.c_str()) + << "\"\n"; + } + } fout << "/>\n"; // end of <Tool Name=VCCLCompilerTool tool = "VCCustomBuildTool"; if(this->FortranProject) diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 69b8092..03fdda2 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -129,7 +129,11 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) } } - std::string pdbOutputPath = this->Target->GetPDBDirectory(); + std::string compilePdbOutputPath = + this->Target->GetCompilePDBDirectory(this->ConfigName); + cmSystemTools::MakeDirectory(compilePdbOutputPath.c_str()); + + std::string pdbOutputPath = this->Target->GetPDBDirectory(this->ConfigName); cmSystemTools::MakeDirectory(pdbOutputPath.c_str()); pdbOutputPath += "/"; diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index d6a0cd4..807aca8 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -321,7 +321,11 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules } } - std::string pdbOutputPath = this->Target->GetPDBDirectory(); + std::string compilePdbOutputPath = + this->Target->GetCompilePDBDirectory(this->ConfigName); + cmSystemTools::MakeDirectory(compilePdbOutputPath.c_str()); + + std::string pdbOutputPath = this->Target->GetPDBDirectory(this->ConfigName); cmSystemTools::MakeDirectory(pdbOutputPath.c_str()); pdbOutputPath += "/"; diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index c3ca85d..e8a9fd1 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -624,9 +624,11 @@ cmMakefileTargetGenerator std::string targetOutPathReal; std::string targetOutPathPDB; + std::string targetOutPathCompilePDB; { std::string targetFullPathReal; std::string targetFullPathPDB; + std::string targetFullPathCompilePDB; if(this->Target->GetType() == cmTarget::EXECUTABLE || this->Target->GetType() == cmTarget::STATIC_LIBRARY || this->Target->GetType() == cmTarget::SHARED_LIBRARY || @@ -638,12 +640,26 @@ cmMakefileTargetGenerator targetFullPathPDB += "/"; targetFullPathPDB += this->Target->GetPDBName(this->ConfigName); } + if(this->Target->GetType() <= cmTarget::OBJECT_LIBRARY) + { + targetFullPathCompilePDB = + this->Target->GetCompilePDBPath(this->ConfigName); + if(targetFullPathCompilePDB.empty()) + { + targetFullPathCompilePDB = this->Target->GetSupportDirectory() + "/"; + } + } + targetOutPathReal = this->Convert(targetFullPathReal.c_str(), cmLocalGenerator::START_OUTPUT, cmLocalGenerator::SHELL); targetOutPathPDB = this->Convert(targetFullPathPDB.c_str(),cmLocalGenerator::NONE, cmLocalGenerator::SHELL); + targetOutPathCompilePDB = + this->Convert(targetFullPathCompilePDB.c_str(), + cmLocalGenerator::START_OUTPUT, + cmLocalGenerator::SHELL); } cmLocalGenerator::RuleVariables vars; vars.RuleLauncher = "RULE_LAUNCH_COMPILE"; @@ -651,6 +667,7 @@ cmMakefileTargetGenerator vars.Language = lang; vars.Target = targetOutPathReal.c_str(); vars.TargetPDB = targetOutPathPDB.c_str(); + vars.TargetCompilePDB = targetOutPathCompilePDB.c_str(); vars.Source = sourceFile.c_str(); std::string shellObj = this->Convert(obj.c_str(), @@ -1650,9 +1667,10 @@ void cmMakefileTargetGenerator this->AppendTargetDepends(depends); // Add a dependency on the link definitions file, if any. - if(!this->GeneratorTarget->ModuleDefinitionFile.empty()) + std::string def = this->GeneratorTarget->GetModuleDefinitionFile(); + if(!def.empty()) { - depends.push_back(this->GeneratorTarget->ModuleDefinitionFile); + depends.push_back(def); } // Add user-specified dependencies. @@ -2019,7 +2037,8 @@ void cmMakefileTargetGenerator::AddFortranFlags(std::string& flags) //---------------------------------------------------------------------------- void cmMakefileTargetGenerator::AddModuleDefinitionFlag(std::string& flags) { - if(this->GeneratorTarget->ModuleDefinitionFile.empty()) + std::string def = this->GeneratorTarget->GetModuleDefinitionFile(); + if(def.empty()) { return; } @@ -2035,8 +2054,7 @@ void cmMakefileTargetGenerator::AddModuleDefinitionFlag(std::string& flags) // Append the flag and value. Use ConvertToLinkReference to help // vs6's "cl -link" pass it to the linker. std::string flag = defFileFlag; - flag += (this->LocalGenerator->ConvertToLinkReference( - this->GeneratorTarget->ModuleDefinitionFile.c_str())); + flag += (this->LocalGenerator->ConvertToLinkReference(def.c_str())); this->LocalGenerator->AppendFlags(flags, flag.c_str()); } diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 900af8d..00b0441 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -320,6 +320,7 @@ bool cmNinjaTargetGenerator::SetMsvcTargetPdbVariable(cmNinjaVars& vars) const mf->GetDefinition("MSVC_CXX_ARCHITECTURE_ID")) { std::string pdbPath; + std::string compilePdbPath; if(this->Target->GetType() == cmTarget::EXECUTABLE || this->Target->GetType() == cmTarget::STATIC_LIBRARY || this->Target->GetType() == cmTarget::SHARED_LIBRARY || @@ -329,11 +330,25 @@ bool cmNinjaTargetGenerator::SetMsvcTargetPdbVariable(cmNinjaVars& vars) const pdbPath += "/"; pdbPath += this->Target->GetPDBName(this->GetConfigName()); } + if(this->Target->GetType() <= cmTarget::OBJECT_LIBRARY) + { + compilePdbPath = this->Target->GetCompilePDBPath(this->GetConfigName()); + if(compilePdbPath.empty()) + { + compilePdbPath = this->Target->GetSupportDirectory() + "/"; + } + } vars["TARGET_PDB"] = this->GetLocalGenerator()->ConvertToOutputFormat( ConvertToNinjaPath(pdbPath.c_str()).c_str(), cmLocalGenerator::SHELL); + vars["TARGET_COMPILE_PDB"] = + this->GetLocalGenerator()->ConvertToOutputFormat( + ConvertToNinjaPath(compilePdbPath.c_str()).c_str(), + cmLocalGenerator::SHELL); + EnsureParentDirectoryExists(pdbPath); + EnsureParentDirectoryExists(compilePdbPath); return true; } return false; @@ -362,6 +377,7 @@ cmNinjaTargetGenerator vars.Object = "$out"; vars.Defines = "$DEFINES"; vars.TargetPDB = "$TARGET_PDB"; + vars.TargetCompilePDB = "$TARGET_COMPILE_PDB"; vars.ObjectDir = "$OBJECT_DIR"; cmMakefile* mf = this->GetMakefile(); @@ -498,10 +514,10 @@ cmNinjaTargetGenerator { this->WriteObjectBuildStatement(*si); } - if(!this->GeneratorTarget->ModuleDefinitionFile.empty()) + std::string def = this->GeneratorTarget->GetModuleDefinitionFile(); + if(!def.empty()) { - this->ModuleDefinitionFile = this->ConvertToNinjaPath( - this->GeneratorTarget->ModuleDefinitionFile.c_str()); + this->ModuleDefinitionFile = this->ConvertToNinjaPath(def.c_str()); } { diff --git a/Source/cmOSXBundleGenerator.cxx b/Source/cmOSXBundleGenerator.cxx index 9a340dc..78b59b3 100644 --- a/Source/cmOSXBundleGenerator.cxx +++ b/Source/cmOSXBundleGenerator.cxx @@ -20,7 +20,7 @@ cmOSXBundleGenerator:: cmOSXBundleGenerator(cmGeneratorTarget* target, const char* configName) - : Target(target->Target) + : GT(target) , Makefile(target->Target->GetMakefile()) , LocalGenerator(Makefile->GetLocalGenerator()) , ConfigName(configName) @@ -34,7 +34,7 @@ cmOSXBundleGenerator(cmGeneratorTarget* target, //---------------------------------------------------------------------------- bool cmOSXBundleGenerator::MustSkip() { - return !this->Target->HaveWellDefinedOutputFiles(); + return !this->GT->Target->HaveWellDefinedOutputFiles(); } //---------------------------------------------------------------------------- @@ -47,7 +47,7 @@ void cmOSXBundleGenerator::CreateAppBundle(const std::string& targetName, // Compute bundle directory names. std::string out = outpath; out += "/"; - out += this->Target->GetAppBundleDirectory(this->ConfigName, false); + out += this->GT->Target->GetAppBundleDirectory(this->ConfigName, false); cmSystemTools::MakeDirectory(out.c_str()); this->Makefile->AddCMakeOutputFile(out); @@ -57,9 +57,9 @@ void cmOSXBundleGenerator::CreateAppBundle(const std::string& targetName, // to be set. std::string plist = outpath; plist += "/"; - plist += this->Target->GetAppBundleDirectory(this->ConfigName, true); + plist += this->GT->Target->GetAppBundleDirectory(this->ConfigName, true); plist += "/Info.plist"; - this->LocalGenerator->GenerateAppleInfoPList(this->Target, + this->LocalGenerator->GenerateAppleInfoPList(this->GT->Target, targetName.c_str(), plist.c_str()); this->Makefile->AddCMakeOutputFile(plist); @@ -77,20 +77,20 @@ void cmOSXBundleGenerator::CreateFramework( // Compute the location of the top-level foo.framework directory. std::string contentdir = outpath + "/" + - this->Target->GetFrameworkDirectory(this->ConfigName, true); + this->GT->Target->GetFrameworkDirectory(this->ConfigName, true); contentdir += "/"; std::string newoutpath = outpath + "/" + - this->Target->GetFrameworkDirectory(this->ConfigName, false); + this->GT->Target->GetFrameworkDirectory(this->ConfigName, false); - std::string frameworkVersion = this->Target->GetFrameworkVersion(); + std::string frameworkVersion = this->GT->Target->GetFrameworkVersion(); // Configure the Info.plist file into the Resources directory. this->MacContentFolders->insert("Resources"); std::string plist = newoutpath; plist += "/Resources/Info.plist"; std::string name = cmSystemTools::GetFilenameName(targetName); - this->LocalGenerator->GenerateFrameworkInfoPList(this->Target, + this->LocalGenerator->GenerateFrameworkInfoPList(this->GT->Target, name.c_str(), plist.c_str()); @@ -172,16 +172,16 @@ void cmOSXBundleGenerator::CreateCFBundle(const std::string& targetName, // Compute bundle directory names. std::string out = root; out += "/"; - out += this->Target->GetCFBundleDirectory(this->ConfigName, false); + out += this->GT->Target->GetCFBundleDirectory(this->ConfigName, false); cmSystemTools::MakeDirectory(out.c_str()); this->Makefile->AddCMakeOutputFile(out); // Configure the Info.plist file. Note that it needs the executable name // to be set. std::string plist = - this->Target->GetCFBundleDirectory(this->ConfigName, true); + this->GT->Target->GetCFBundleDirectory(this->ConfigName, true); plist += "/Info.plist"; - this->LocalGenerator->GenerateAppleInfoPList(this->Target, + this->LocalGenerator->GenerateAppleInfoPList(this->GT->Target, targetName.c_str(), plist.c_str()); this->Makefile->AddCMakeOutputFile(plist); @@ -199,9 +199,9 @@ GenerateMacOSXContentStatements(std::vector<cmSourceFile*> const& sources, for(std::vector<cmSourceFile*>::const_iterator si = sources.begin(); si != sources.end(); ++si) { - cmTarget::SourceFileFlags tsFlags = - this->Target->GetTargetSourceFileFlags(*si); - if(tsFlags.Type != cmTarget::SourceFileTypeNormal) + cmGeneratorTarget::SourceFileFlags tsFlags = + this->GT->GetTargetSourceFileFlags(*si); + if(tsFlags.Type != cmGeneratorTarget::SourceFileTypeNormal) { (*generator)(**si, tsFlags.MacFolder); } @@ -215,7 +215,7 @@ cmOSXBundleGenerator::InitMacOSXContentDirectory(const char* pkgloc) // Construct the full path to the content subdirectory. std::string macdir = - this->Target->GetMacContentDirectory(this->ConfigName, + this->GT->Target->GetMacContentDirectory(this->ConfigName, /*implib*/ false); macdir += "/"; macdir += pkgloc; diff --git a/Source/cmOSXBundleGenerator.h b/Source/cmOSXBundleGenerator.h index 29b7611..2f36394 100644 --- a/Source/cmOSXBundleGenerator.h +++ b/Source/cmOSXBundleGenerator.h @@ -59,7 +59,7 @@ private: bool MustSkip(); private: - cmTarget* Target; + cmGeneratorTarget* GT; cmMakefile* Makefile; cmLocalGenerator* LocalGenerator; const char* ConfigName; diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index ff05975..7cc63bb 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -1044,7 +1044,7 @@ void cmSystemTools::ExpandListArgument(const std::string& arg, bool emptyArgs) { // If argument is empty, it is an empty list. - if(arg.length() == 0 && !emptyArgs) + if(!emptyArgs && arg.empty()) { return; } @@ -1054,10 +1054,11 @@ void cmSystemTools::ExpandListArgument(const std::string& arg, newargs.push_back(arg); return; } - std::vector<char> newArgVec; + std::string newArg; + const char *last = arg.c_str(); // Break the string at non-escaped semicolons not nested in []. int squareNesting = 0; - for(const char* c = arg.c_str(); *c; ++c) + for(const char* c = last; *c; ++c) { switch(*c) { @@ -1065,34 +1066,21 @@ void cmSystemTools::ExpandListArgument(const std::string& arg, { // We only want to allow escaping of semicolons. Other // escapes should not be processed here. - ++c; - if(*c == ';') - { - newArgVec.push_back(*c); - } - else + const char* next = c + 1; + if(*next == ';') { - newArgVec.push_back('\\'); - if(*c) - { - newArgVec.push_back(*c); - } - else - { - // Terminate the loop properly. - --c; - } + newArg.append(last, c - last); + // Skip over the escape character + last = c = next; } } break; case '[': { ++squareNesting; - newArgVec.push_back(*c); } break; case ']': { --squareNesting; - newArgVec.push_back(*c); } break; case ';': { @@ -1100,31 +1088,28 @@ void cmSystemTools::ExpandListArgument(const std::string& arg, // brackets. if(squareNesting == 0) { - if ( newArgVec.size() || emptyArgs ) + newArg.append(last, c - last); + // Skip over the semicolon + last = c + 1; + if ( !newArg.empty() || emptyArgs ) { // Add the last argument if the string is not empty. - newArgVec.push_back(0); - newargs.push_back(&*newArgVec.begin()); - newArgVec.clear(); + newargs.push_back(newArg); + newArg = ""; } } - else - { - newArgVec.push_back(*c); - } } break; default: { // Just append this character. - newArgVec.push_back(*c); } break; } } - if ( newArgVec.size() || emptyArgs ) + newArg.append(last); + if ( !newArg.empty() || emptyArgs ) { // Add the last argument if the string is not empty. - newArgVec.push_back(0); - newargs.push_back(&*newArgVec.begin()); + newargs.push_back(newArg); } } diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index db34bd8..1c2b27a 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -71,6 +71,12 @@ struct cmTarget::ImportInfo cmTarget::LinkInterface LinkInterface; }; +//---------------------------------------------------------------------------- +struct cmTarget::CompileInfo +{ + std::string CompilePdbDir; +}; + struct TargetConfigPair : public std::pair<cmTarget const* , std::string> { TargetConfigPair(cmTarget const* tgt, const std::string &config) : std::pair<cmTarget const* , std::string>(tgt, config) {} @@ -83,17 +89,12 @@ public: cmTargetInternals() { this->PolicyWarnedCMP0022 = false; - this->SourceFileFlagsConstructed = false; } cmTargetInternals(cmTargetInternals const&) { this->PolicyWarnedCMP0022 = false; - this->SourceFileFlagsConstructed = false; } ~cmTargetInternals(); - typedef cmTarget::SourceFileFlags SourceFileFlags; - mutable std::map<cmSourceFile const*, SourceFileFlags> SourceFlagsMap; - mutable bool SourceFileFlagsConstructed; // The backtrace when the target was created. cmListFileBacktrace Backtrace; @@ -101,9 +102,17 @@ public: // Cache link interface computation from each configuration. struct OptionalLinkInterface: public cmTarget::LinkInterface { - OptionalLinkInterface(): Exists(false) {} + OptionalLinkInterface(): + Exists(false), Complete(false), ExplicitLibraries(0) {} bool Exists; + bool Complete; + const char* ExplicitLibraries; }; + void ComputeLinkInterface(cmTarget const* thisTarget, + const char* config, OptionalLinkInterface& iface, + cmTarget const* head, + const char *explicitLibraries) const; + typedef std::map<TargetConfigPair, OptionalLinkInterface> LinkInterfaceMapType; LinkInterfaceMapType LinkInterfaceMap; @@ -116,6 +125,9 @@ public: ImportInfoMapType; ImportInfoMapType ImportInfoMap; + typedef std::map<std::string, cmTarget::CompileInfo> CompileInfoMapType; + CompileInfoMapType CompileInfoMap; + // Cache link implementation computation from each configuration. typedef std::map<TargetConfigPair, cmTarget::LinkImplementation> LinkImplMapType; @@ -267,6 +279,7 @@ void cmTarget::SetMakefile(cmMakefile* mf) this->SetPropertyDefault("LIBRARY_OUTPUT_DIRECTORY", 0); this->SetPropertyDefault("RUNTIME_OUTPUT_DIRECTORY", 0); this->SetPropertyDefault("PDB_OUTPUT_DIRECTORY", 0); + this->SetPropertyDefault("COMPILE_PDB_OUTPUT_DIRECTORY", 0); this->SetPropertyDefault("Fortran_FORMAT", 0); this->SetPropertyDefault("Fortran_MODULE_DIRECTORY", 0); this->SetPropertyDefault("GNUtoMS", 0); @@ -295,6 +308,7 @@ void cmTarget::SetMakefile(cmMakefile* mf) "LIBRARY_OUTPUT_DIRECTORY_", "RUNTIME_OUTPUT_DIRECTORY_", "PDB_OUTPUT_DIRECTORY_", + "COMPILE_PDB_OUTPUT_DIRECTORY_", "MAP_IMPORTED_CONFIG_", 0}; for(std::vector<std::string>::iterator ci = configNames.begin(); @@ -527,10 +541,11 @@ bool cmTarget::IsBundleOnApple() const } //---------------------------------------------------------------------------- -bool cmTarget::FindSourceFiles() +void cmTarget::GetSourceFiles(std::vector<cmSourceFile*> &files) const { + assert(this->GetType() != INTERFACE_LIBRARY); for(std::vector<cmSourceFile*>::const_iterator - si = this->SourceFiles.begin(); + si = this->SourceFiles.begin(); si != this->SourceFiles.end(); ++si) { std::string e; @@ -542,16 +557,9 @@ bool cmTarget::FindSourceFiles() cm->IssueMessage(cmake::FATAL_ERROR, e, this->GetBacktrace()); } - return false; + return; } } - return true; -} - -//---------------------------------------------------------------------------- -void cmTarget::GetSourceFiles(std::vector<cmSourceFile*> &files) const -{ - assert(this->GetType() != INTERFACE_LIBRARY); files = this->SourceFiles; } @@ -648,109 +656,6 @@ void cmTarget::ProcessSourceExpression(std::string const& expr) } //---------------------------------------------------------------------------- -struct cmTarget::SourceFileFlags -cmTarget::GetTargetSourceFileFlags(const cmSourceFile* sf) const -{ - struct SourceFileFlags flags; - this->ConstructSourceFileFlags(); - std::map<cmSourceFile const*, SourceFileFlags>::iterator si = - this->Internal->SourceFlagsMap.find(sf); - if(si != this->Internal->SourceFlagsMap.end()) - { - flags = si->second; - } - return flags; -} - -//---------------------------------------------------------------------------- -void cmTarget::ConstructSourceFileFlags() const -{ - if(this->Internal->SourceFileFlagsConstructed) - { - return; - } - this->Internal->SourceFileFlagsConstructed = true; - - // Process public headers to mark the source files. - if(const char* files = this->GetProperty("PUBLIC_HEADER")) - { - std::vector<std::string> relFiles; - cmSystemTools::ExpandListArgument(files, relFiles); - for(std::vector<std::string>::iterator it = relFiles.begin(); - it != relFiles.end(); ++it) - { - if(cmSourceFile* sf = this->Makefile->GetSource(it->c_str())) - { - SourceFileFlags& flags = this->Internal->SourceFlagsMap[sf]; - flags.MacFolder = "Headers"; - flags.Type = cmTarget::SourceFileTypePublicHeader; - } - } - } - - // Process private headers after public headers so that they take - // precedence if a file is listed in both. - if(const char* files = this->GetProperty("PRIVATE_HEADER")) - { - std::vector<std::string> relFiles; - cmSystemTools::ExpandListArgument(files, relFiles); - for(std::vector<std::string>::iterator it = relFiles.begin(); - it != relFiles.end(); ++it) - { - if(cmSourceFile* sf = this->Makefile->GetSource(it->c_str())) - { - SourceFileFlags& flags = this->Internal->SourceFlagsMap[sf]; - flags.MacFolder = "PrivateHeaders"; - flags.Type = cmTarget::SourceFileTypePrivateHeader; - } - } - } - - // Mark sources listed as resources. - if(const char* files = this->GetProperty("RESOURCE")) - { - std::vector<std::string> relFiles; - cmSystemTools::ExpandListArgument(files, relFiles); - for(std::vector<std::string>::iterator it = relFiles.begin(); - it != relFiles.end(); ++it) - { - if(cmSourceFile* sf = this->Makefile->GetSource(it->c_str())) - { - SourceFileFlags& flags = this->Internal->SourceFlagsMap[sf]; - flags.MacFolder = "Resources"; - flags.Type = cmTarget::SourceFileTypeResource; - } - } - } - - // Handle the MACOSX_PACKAGE_LOCATION property on source files that - // were not listed in one of the other lists. - std::vector<cmSourceFile*> sources; - this->GetSourceFiles(sources); - for(std::vector<cmSourceFile*>::const_iterator si = sources.begin(); - si != sources.end(); ++si) - { - cmSourceFile* sf = *si; - if(const char* location = sf->GetProperty("MACOSX_PACKAGE_LOCATION")) - { - SourceFileFlags& flags = this->Internal->SourceFlagsMap[sf]; - if(flags.Type == cmTarget::SourceFileTypeNormal) - { - flags.MacFolder = location; - if(strcmp(location, "Resources") == 0) - { - flags.Type = cmTarget::SourceFileTypeResource; - } - else - { - flags.Type = cmTarget::SourceFileTypeMacContent; - } - } - } - } -} - -//---------------------------------------------------------------------------- void cmTarget::MergeLinkLibraries( cmMakefile& mf, const char *selfname, const LinkLibraryVectorType& libs ) @@ -2467,7 +2372,7 @@ cmTarget::OutputInfo const* cmTarget::GetOutputInfo(const char* config) const OutputInfo info; this->ComputeOutputDir(config, false, info.OutDir); this->ComputeOutputDir(config, true, info.ImpDir); - if(!this->ComputePDBOutputDir(config, info.PdbDir)) + if(!this->ComputePDBOutputDir("PDB", config, info.PdbDir)) { info.PdbDir = info.OutDir; } @@ -2478,6 +2383,45 @@ cmTarget::OutputInfo const* cmTarget::GetOutputInfo(const char* config) const } //---------------------------------------------------------------------------- +cmTarget::CompileInfo const* cmTarget::GetCompileInfo(const char* config) const +{ + // There is no compile information for imported targets. + if(this->IsImported()) + { + return 0; + } + + if(this->GetType() > cmTarget::OBJECT_LIBRARY) + { + std::string msg = "cmTarget::GetCompileInfo called for "; + msg += this->GetName(); + msg += " which has type "; + msg += cmTarget::GetTargetTypeName(this->GetType()); + this->GetMakefile()->IssueMessage(cmake::INTERNAL_ERROR, msg); + abort(); + return 0; + } + + // Lookup/compute/cache the compile information for this configuration. + std::string config_upper; + if(config && *config) + { + config_upper = cmSystemTools::UpperCase(config); + } + typedef cmTargetInternals::CompileInfoMapType CompileInfoMapType; + CompileInfoMapType::const_iterator i = + this->Internal->CompileInfoMap.find(config_upper); + if(i == this->Internal->CompileInfoMap.end()) + { + CompileInfo info; + this->ComputePDBOutputDir("COMPILE_PDB", config, info.CompilePdbDir); + CompileInfoMapType::value_type entry(config_upper, info); + i = this->Internal->CompileInfoMap.insert(entry).first; + } + return &i->second; +} + +//---------------------------------------------------------------------------- std::string cmTarget::GetDirectory(const char* config, bool implib) const { if (this->IsImported()) @@ -2507,6 +2451,16 @@ std::string cmTarget::GetPDBDirectory(const char* config) const } //---------------------------------------------------------------------------- +std::string cmTarget::GetCompilePDBDirectory(const char* config) const +{ + if(CompileInfo const* info = this->GetCompileInfo(config)) + { + return info->CompilePdbDir; + } + return ""; +} + +//---------------------------------------------------------------------------- const char* cmTarget::GetLocation(const char* config) const { if (this->IsImported()) @@ -3167,6 +3121,49 @@ std::string cmTarget::GetPDBName(const char* config) const } //---------------------------------------------------------------------------- +std::string cmTarget::GetCompilePDBName(const char* config) const +{ + std::string prefix; + std::string base; + std::string suffix; + this->GetFullNameInternal(config, false, prefix, base, suffix); + + // Check for a per-configuration output directory target property. + std::string configUpper = cmSystemTools::UpperCase(config? config : ""); + std::string configProp = "COMPILE_PDB_NAME_"; + configProp += configUpper; + const char* config_name = this->GetProperty(configProp.c_str()); + if(config_name && *config_name) + { + return prefix + config_name + ".pdb"; + } + + const char* name = this->GetProperty("COMPILE_PDB_NAME"); + if(name && *name) + { + return prefix + name + ".pdb"; + } + + return ""; +} + +//---------------------------------------------------------------------------- +std::string cmTarget::GetCompilePDBPath(const char* config) const +{ + std::string dir = this->GetCompilePDBDirectory(config); + std::string name = this->GetCompilePDBName(config); + if(dir.empty() && !name.empty()) + { + dir = this->GetPDBDirectory(config); + } + if(!dir.empty()) + { + dir += "/"; + } + return dir + name; +} + +//---------------------------------------------------------------------------- bool cmTarget::HasSOName(const char* config) const { // soname is supported only for shared libraries and modules, @@ -4111,13 +4108,13 @@ bool cmTarget::ComputeOutputDir(const char* config, } //---------------------------------------------------------------------------- -bool cmTarget::ComputePDBOutputDir(const char* config, std::string& out) const +bool cmTarget::ComputePDBOutputDir(const char* kind, const char* config, + std::string& out) const { // 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; + std::string propertyNameStr = kind; if(!propertyNameStr.empty()) { propertyNameStr += "_OUTPUT_DIRECTORY"; @@ -4127,7 +4124,7 @@ bool cmTarget::ComputePDBOutputDir(const char* config, std::string& out) const // Check for a per-configuration output directory target property. std::string configUpper = cmSystemTools::UpperCase(config? config : ""); const char* configProp = 0; - std::string configPropStr = targetTypeName; + std::string configPropStr = kind; if(!configPropStr.empty()) { configPropStr += "_OUTPUT_DIRECTORY_"; @@ -4530,12 +4527,13 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget const* tgt, assert((impliedByUse ^ explicitlySet) || (!impliedByUse && !explicitlySet)); - cmComputeLinkInformation *info = tgt->GetLinkInformation(config); - if(!info) + std::vector<cmTarget*> deps; + tgt->GetTransitiveTargetClosure(config, tgt, deps); + + if(deps.empty()) { return propContent; } - const cmComputeLinkInformation::ItemVector &deps = info->GetItems(); bool propInitialized = explicitlySet; std::string report = " * Target \""; @@ -4555,7 +4553,7 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget const* tgt, report += "\" property not set.\n"; } - for(cmComputeLinkInformation::ItemVector::const_iterator li = + for(std::vector<cmTarget*>::const_iterator li = deps.begin(); li != deps.end(); ++li) { @@ -4565,23 +4563,20 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget const* tgt, // target itself has a POSITION_INDEPENDENT_CODE which disagrees // with a dependency. - if (!li->Target) - { - continue; - } + cmTarget const* theTarget = *li; - const bool ifaceIsSet = li->Target->GetProperties() + const bool ifaceIsSet = theTarget->GetProperties() .find("INTERFACE_" + p) - != li->Target->GetProperties().end(); + != theTarget->GetProperties().end(); PropertyType ifacePropContent = - getTypedProperty<PropertyType>(li->Target, + getTypedProperty<PropertyType>(theTarget, ("INTERFACE_" + p).c_str(), 0); std::string reportEntry; if (ifaceIsSet) { reportEntry += " * Target \""; - reportEntry += li->Target->GetName(); + reportEntry += theTarget->GetName(); reportEntry += "\" property value \""; reportEntry += valueAsString<PropertyType>(ifacePropContent); reportEntry += "\" "; @@ -4602,7 +4597,7 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget const* tgt, e << "Property " << p << " on target \"" << tgt->GetName() << "\" does\nnot match the " "INTERFACE_" << p << " property requirement\nof " - "dependency \"" << li->Target->GetName() << "\".\n"; + "dependency \"" << theTarget->GetName() << "\".\n"; cmSystemTools::Error(e.str().c_str()); break; } @@ -4636,7 +4631,7 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget const* tgt, << tgt->GetName() << "\" is\nimplied to be " << defaultValue << " because it was used to determine the link libraries\n" "already. The INTERFACE_" << p << " property on\ndependency \"" - << li->Target->GetName() << "\" is in conflict.\n"; + << theTarget->GetName() << "\" is in conflict.\n"; cmSystemTools::Error(e.str().c_str()); break; } @@ -4667,7 +4662,7 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget const* tgt, { cmOStringStream e; e << "The INTERFACE_" << p << " property of \"" - << li->Target->GetName() << "\" does\nnot agree with the value " + << theTarget->GetName() << "\" does\nnot agree with the value " "of " << p << " already determined\nfor \"" << tgt->GetName() << "\".\n"; cmSystemTools::Error(e.str().c_str()); @@ -4748,23 +4743,19 @@ bool isLinkDependentProperty(cmTarget const* tgt, const std::string &p, const char *interfaceProperty, const char *config) { - cmComputeLinkInformation *info = tgt->GetLinkInformation(config); - if(!info) + std::vector<cmTarget*> deps; + tgt->GetTransitiveTargetClosure(config, tgt, deps); + + if(deps.empty()) { return false; } - const cmComputeLinkInformation::ItemVector &deps = info->GetItems(); - - for(cmComputeLinkInformation::ItemVector::const_iterator li = + for(std::vector<cmTarget*>::const_iterator li = deps.begin(); li != deps.end(); ++li) { - if (!li->Target) - { - continue; - } - const char *prop = li->Target->GetProperty(interfaceProperty); + const char *prop = (*li)->GetProperty(interfaceProperty); if (!prop) { continue; @@ -5316,24 +5307,124 @@ cmTarget::LinkInterface const* cmTarget::GetLinkInterface(const char* config, { // Compute the link interface for this configuration. cmTargetInternals::OptionalLinkInterface iface; - iface.Exists = this->ComputeLinkInterface(config, iface, head); + iface.ExplicitLibraries = + this->ComputeLinkInterfaceLibraries(config, iface, head, iface.Exists); + if (iface.Exists) + { + this->Internal->ComputeLinkInterface(this, config, iface, + head, iface.ExplicitLibraries); + } // Store the information for this configuration. cmTargetInternals::LinkInterfaceMapType::value_type entry(key, iface); i = this->Internal->LinkInterfaceMap.insert(entry).first; } + else if(!i->second.Complete && i->second.Exists) + { + this->Internal->ComputeLinkInterface(this, config, i->second, head, + i->second.ExplicitLibraries); + } - return i->second.Exists? &i->second : 0; + return i->second.Exists ? &i->second : 0; } //---------------------------------------------------------------------------- -void cmTarget::GetTransitivePropertyLinkLibraries( - const char* config, +cmTarget::LinkInterface const* +cmTarget::GetLinkInterfaceLibraries(const char* config, + cmTarget const* head) const +{ + // Imported targets have their own link interface. + if(this->IsImported()) + { + if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, head)) + { + return &info->LinkInterface; + } + return 0; + } + + // Link interfaces are not supported for executables that do not + // export symbols. + if(this->GetType() == cmTarget::EXECUTABLE && + !this->IsExecutableWithExports()) + { + return 0; + } + + // Lookup any existing link interface for this configuration. + TargetConfigPair key(head, cmSystemTools::UpperCase(config? config : "")); + + cmTargetInternals::LinkInterfaceMapType::iterator + i = this->Internal->LinkInterfaceMap.find(key); + if(i == this->Internal->LinkInterfaceMap.end()) + { + // Compute the link interface for this configuration. + cmTargetInternals::OptionalLinkInterface iface; + iface.ExplicitLibraries = this->ComputeLinkInterfaceLibraries(config, + iface, + head, + iface.Exists); + + // Store the information for this configuration. + cmTargetInternals::LinkInterfaceMapType::value_type entry(key, iface); + i = this->Internal->LinkInterfaceMap.insert(entry).first; + } + + return i->second.Exists ? &i->second : 0; +} + +//---------------------------------------------------------------------------- +void processILibs(const char* config, + cmTarget const* headTarget, + std::string const& name, + std::vector<cmTarget*>& tgts, std::set<cmTarget*>& emitted) +{ + if (cmTarget* tgt = headTarget->GetMakefile() + ->FindTargetToUse(name.c_str())) + { + if (emitted.insert(tgt).second) + { + tgts.push_back(tgt); + std::vector<std::string> ilibs; + cmTarget::LinkInterface const* iface = + tgt->GetLinkInterfaceLibraries(config, headTarget); + if (iface) + { + for(std::vector<std::string>::const_iterator + it = iface->Libraries.begin(); + it != iface->Libraries.end(); ++it) + { + processILibs(config, headTarget, *it, tgts, emitted); + } + } + } + } +} + +//---------------------------------------------------------------------------- +void cmTarget::GetTransitiveTargetClosure(const char* config, cmTarget const* headTarget, - std::vector<std::string> &libs) const + std::vector<cmTarget*> &tgts) const { - cmTarget::LinkInterface const* iface = this->GetLinkInterface(config, - headTarget); + std::set<cmTarget*> emitted; + + cmTarget::LinkImplementation const* impl + = this->GetLinkImplementationLibraries(config, headTarget); + + for(std::vector<std::string>::const_iterator it = impl->Libraries.begin(); + it != impl->Libraries.end(); ++it) + { + processILibs(config, headTarget, *it, tgts, emitted); + } +} + +//---------------------------------------------------------------------------- +void cmTarget::GetTransitivePropertyTargets(const char* config, + cmTarget const* headTarget, + std::vector<cmTarget*> &tgts) const +{ + cmTarget::LinkInterface const* iface + = this->GetLinkInterfaceLibraries(config, headTarget); if (!iface) { return; @@ -5342,7 +5433,15 @@ void cmTarget::GetTransitivePropertyLinkLibraries( || this->GetPolicyStatusCMP0022() == cmPolicies::WARN || this->GetPolicyStatusCMP0022() == cmPolicies::OLD) { - libs = iface->Libraries; + for(std::vector<std::string>::const_iterator it = iface->Libraries.begin(); + it != iface->Libraries.end(); ++it) + { + if (cmTarget* tgt = headTarget->GetMakefile() + ->FindTargetToUse(it->c_str())) + { + tgts.push_back(tgt); + } + } return; } @@ -5360,17 +5459,30 @@ void cmTarget::GetTransitivePropertyLinkLibraries( cmGeneratorExpressionDAGChecker dagChecker(lfbt, this->GetName(), linkIfaceProp, 0, 0); dagChecker.SetTransitivePropertiesOnly(); + std::vector<std::string> libs; cmSystemTools::ExpandListArgument(ge.Parse(interfaceLibs)->Evaluate( this->Makefile, config, false, headTarget, this, &dagChecker), libs); + + for(std::vector<std::string>::const_iterator it = libs.begin(); + it != libs.end(); ++it) + { + if (cmTarget* tgt = headTarget->GetMakefile() + ->FindTargetToUse(it->c_str())) + { + tgts.push_back(tgt); + } + } } //---------------------------------------------------------------------------- -bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface, - cmTarget const* headTarget) const +const char* cmTarget::ComputeLinkInterfaceLibraries(const char* config, + LinkInterface& iface, + cmTarget const* headTarget, + bool &exists) const { // Construct the property name suffix for this configuration. std::string suffix = "_"; @@ -5446,8 +5558,10 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface, (this->GetType() == cmTarget::EXECUTABLE || (this->GetType() == cmTarget::MODULE_LIBRARY))) { - return false; + exists = false; + return 0; } + exists = true; if(explicitLibraries) { @@ -5462,52 +5576,6 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface, false, headTarget, this, &dagChecker), iface.Libraries); - - if(this->GetType() == cmTarget::SHARED_LIBRARY - || this->GetType() == cmTarget::STATIC_LIBRARY - || this->GetType() == cmTarget::INTERFACE_LIBRARY) - { - // Shared libraries may have runtime implementation dependencies - // on other shared libraries that are not in the interface. - std::set<cmStdString> emitted; - for(std::vector<std::string>::const_iterator - li = iface.Libraries.begin(); li != iface.Libraries.end(); ++li) - { - emitted.insert(*li); - } - if (this->GetType() != cmTarget::INTERFACE_LIBRARY) - { - LinkImplementation const* impl = this->GetLinkImplementation(config, - headTarget); - for(std::vector<std::string>::const_iterator - li = impl->Libraries.begin(); li != impl->Libraries.end(); ++li) - { - if(emitted.insert(*li).second) - { - if(cmTarget* tgt = this->Makefile->FindTargetToUse(*li)) - { - // This is a runtime dependency on another shared library. - if(tgt->GetType() == cmTarget::SHARED_LIBRARY) - { - iface.SharedDeps.push_back(*li); - } - } - else - { - // TODO: Recognize shared library file names. Perhaps this - // should be moved to cmComputeLinkInformation, but that creates - // a chicken-and-egg problem since this list is needed for its - // construction. - } - } - } - if(this->LinkLanguagePropagatesToDependents()) - { - // Targets using this archive need its language runtime libraries. - iface.Languages = impl->Languages; - } - } - } } else if (this->PolicyStatusCMP0022 == cmPolicies::WARN || this->PolicyStatusCMP0022 == cmPolicies::OLD) @@ -5517,17 +5585,9 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface, // to the link implementation. { // The link implementation is the default link interface. - LinkImplementation const* impl = this->GetLinkImplementation(config, - headTarget); - iface.ImplementationIsInterface = true; + LinkImplementation const* impl = + this->GetLinkImplementationLibraries(config, headTarget); iface.Libraries = impl->Libraries; - iface.WrongConfigLibraries = impl->WrongConfigLibraries; - if(this->LinkLanguagePropagatesToDependents()) - { - // Targets using this archive need its language runtime libraries. - iface.Languages = impl->Languages; - } - if(this->PolicyStatusCMP0022 == cmPolicies::WARN && !this->Internal->PolicyWarnedCMP0022) { @@ -5592,25 +5652,107 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface, } } } + return explicitLibraries; +} - if(this->GetType() == cmTarget::STATIC_LIBRARY) +//---------------------------------------------------------------------------- +void cmTargetInternals::ComputeLinkInterface(cmTarget const* thisTarget, + const char* config, + OptionalLinkInterface& iface, + cmTarget const* headTarget, + const char* explicitLibraries) const +{ + if(explicitLibraries) { + if(thisTarget->GetType() == cmTarget::SHARED_LIBRARY + || thisTarget->GetType() == cmTarget::STATIC_LIBRARY + || thisTarget->GetType() == cmTarget::INTERFACE_LIBRARY) + { + // Shared libraries may have runtime implementation dependencies + // on other shared libraries that are not in the interface. + std::set<cmStdString> emitted; + for(std::vector<std::string>::const_iterator + li = iface.Libraries.begin(); li != iface.Libraries.end(); ++li) + { + emitted.insert(*li); + } + if (thisTarget->GetType() != cmTarget::INTERFACE_LIBRARY) + { + cmTarget::LinkImplementation const* impl = + thisTarget->GetLinkImplementation(config, headTarget); + for(std::vector<std::string>::const_iterator + li = impl->Libraries.begin(); li != impl->Libraries.end(); ++li) + { + if(emitted.insert(*li).second) + { + if(cmTarget* tgt = thisTarget->Makefile->FindTargetToUse(*li)) + { + // This is a runtime dependency on another shared library. + if(tgt->GetType() == cmTarget::SHARED_LIBRARY) + { + iface.SharedDeps.push_back(*li); + } + } + else + { + // TODO: Recognize shared library file names. Perhaps this + // should be moved to cmComputeLinkInformation, but that creates + // a chicken-and-egg problem since this list is needed for its + // construction. + } + } + } + if(thisTarget->LinkLanguagePropagatesToDependents()) + { + // Targets using this archive need its language runtime libraries. + iface.Languages = impl->Languages; + } + } + } + } + else if (thisTarget->PolicyStatusCMP0022 == cmPolicies::WARN + || thisTarget->PolicyStatusCMP0022 == cmPolicies::OLD) + { + // The link implementation is the default link interface. + cmTarget::LinkImplementation const* + impl = thisTarget->GetLinkImplementation(config, headTarget); + iface.ImplementationIsInterface = true; + iface.WrongConfigLibraries = impl->WrongConfigLibraries; + if(thisTarget->LinkLanguagePropagatesToDependents()) + { + // Targets using this archive need its language runtime libraries. + iface.Languages = impl->Languages; + } + } + + if(thisTarget->GetType() == cmTarget::STATIC_LIBRARY) + { + // Construct the property name suffix for this configuration. + std::string suffix = "_"; + if(config && *config) + { + suffix += cmSystemTools::UpperCase(config); + } + else + { + suffix += "NOCONFIG"; + } + // How many repetitions are needed if this library has cyclic // dependencies? std::string propName = "LINK_INTERFACE_MULTIPLICITY"; propName += suffix; - if(const char* config_reps = this->GetProperty(propName.c_str())) + if(const char* config_reps = thisTarget->GetProperty(propName.c_str())) { sscanf(config_reps, "%u", &iface.Multiplicity); } else if(const char* reps = - this->GetProperty("LINK_INTERFACE_MULTIPLICITY")) + thisTarget->GetProperty("LINK_INTERFACE_MULTIPLICITY")) { sscanf(reps, "%u", &iface.Multiplicity); } } - - return true; + iface.Complete = true; } //---------------------------------------------------------------------------- @@ -5633,6 +5775,41 @@ cmTarget::GetLinkImplementation(const char* config, cmTarget const* head) const // Compute the link implementation for this configuration. LinkImplementation impl; this->ComputeLinkImplementation(config, impl, head); + this->ComputeLinkImplementationLanguages(impl); + + // Store the information for this configuration. + cmTargetInternals::LinkImplMapType::value_type entry(key, impl); + i = this->Internal->LinkImplMap.insert(entry).first; + } + else if (i->second.Languages.empty()) + { + this->ComputeLinkImplementationLanguages(i->second); + } + + return &i->second; +} + +//---------------------------------------------------------------------------- +cmTarget::LinkImplementation const* +cmTarget::GetLinkImplementationLibraries(const char* config, + cmTarget const* head) const +{ + // There is no link implementation for imported targets. + if(this->IsImported()) + { + return 0; + } + + // Lookup any existing link implementation for this configuration. + TargetConfigPair key(head, cmSystemTools::UpperCase(config? config : "")); + + cmTargetInternals::LinkImplMapType::iterator + i = this->Internal->LinkImplMap.find(key); + if(i == this->Internal->LinkImplMap.end()) + { + // Compute the link implementation for this configuration. + LinkImplementation impl; + this->ComputeLinkImplementation(config, impl, head); // Store the information for this configuration. cmTargetInternals::LinkImplMapType::value_type entry(key, impl); @@ -5715,7 +5892,12 @@ void cmTarget::ComputeLinkImplementation(const char* config, impl.WrongConfigLibraries.push_back(item); } } +} +//---------------------------------------------------------------------------- +void +cmTarget::ComputeLinkImplementationLanguages(LinkImplementation& impl) const +{ // This target needs runtime libraries for its source languages. std::set<cmStdString> languages; // Get languages used in our source files. diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 271824b..471ea94 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -140,34 +140,6 @@ public: } /** - * Flags for a given source file as used in this target. Typically assigned - * via SET_TARGET_PROPERTIES when the property is a list of source files. - */ - enum SourceFileType - { - SourceFileTypeNormal, - SourceFileTypePrivateHeader, // is in "PRIVATE_HEADER" target property - SourceFileTypePublicHeader, // is in "PUBLIC_HEADER" target property - SourceFileTypeResource, // is in "RESOURCE" target property *or* - // has MACOSX_PACKAGE_LOCATION=="Resources" - SourceFileTypeMacContent // has MACOSX_PACKAGE_LOCATION!="Resources" - }; - struct SourceFileFlags - { - SourceFileFlags(): Type(SourceFileTypeNormal), MacFolder(0) {} - SourceFileFlags(SourceFileFlags const& r): - Type(r.Type), MacFolder(r.MacFolder) {} - SourceFileType Type; - const char* MacFolder; // location inside Mac content folders - }; - - /** - * Get the flags for a given source file as used in this target - */ - struct SourceFileFlags - GetTargetSourceFileFlags(const cmSourceFile* sf) const; - - /** * Add sources to the target. */ void AddSources(std::vector<std::string> const& srcs); @@ -292,9 +264,14 @@ public: if the target cannot be linked. */ LinkInterface const* GetLinkInterface(const char* config, cmTarget const* headTarget) const; - void GetTransitivePropertyLinkLibraries(const char* config, + LinkInterface const* GetLinkInterfaceLibraries(const char* config, + cmTarget const* headTarget) const; + void GetTransitivePropertyTargets(const char* config, + cmTarget const* headTarget, + std::vector<cmTarget*> &libs) const; + void GetTransitiveTargetClosure(const char* config, cmTarget const* headTarget, - std::vector<std::string> &libs) const; + std::vector<cmTarget*> &libs) const; /** The link implementation specifies the direct library dependencies needed by the object files of the target. */ @@ -313,6 +290,9 @@ public: LinkImplementation const* GetLinkImplementation(const char* config, cmTarget const* head) const; + LinkImplementation const* GetLinkImplementationLibraries(const char* config, + cmTarget const* head) const; + /** Link information from the transitive closure of the link implementation and the interfaces of its dependencies. */ struct LinkClosure @@ -340,7 +320,13 @@ public: 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) const; + std::string GetPDBDirectory(const char* config) const; + + /** Get the directory in which to place the target compiler .pdb file. + If the configuration name is given then the generator will add its + subdirectory for that configuration. Otherwise just the canonical + compiler pdb output directory is given. */ + std::string GetCompilePDBDirectory(const char* config = 0) const; /** Get the location of the target in the build tree for the given configuration. This location is suitable for use as the LOCATION @@ -358,11 +344,6 @@ public: void GetTargetVersion(bool soversion, int& major, int& minor, int& patch) const; - /** - * Make sure the full path to all source files is known. - */ - bool FindSourceFiles(); - ///! Return the preferred linker language for this target const char* GetLinkerLanguage(const char* config = 0, cmTarget const* head = 0) const; @@ -375,7 +356,13 @@ public: const char* config=0, bool implib = false) const; /** Get the name of the pdb file for the target. */ - std::string GetPDBName(const char* config=0) const; + std::string GetPDBName(const char* config) const; + + /** Get the name of the compiler pdb file for the target. */ + std::string GetCompilePDBName(const char* config=0) const; + + /** Get the path for the MSVC /Fd option for this target. */ + std::string GetCompilePDBPath(const char* config=0) const; /** Whether this library has soname enabled and platform supports it. */ bool HasSOName(const char* config) const; @@ -710,7 +697,8 @@ private: OutputInfo const* GetOutputInfo(const char* config) const; bool ComputeOutputDir(const char* config, bool implib, std::string& out) const; - bool ComputePDBOutputDir(const char* config, std::string& out) const; + bool ComputePDBOutputDir(const char* kind, const char* config, + std::string& out) const; // Cache import information from properties for each configuration. struct ImportInfo; @@ -719,16 +707,23 @@ private: void ComputeImportInfo(std::string const& desired_config, ImportInfo& info, cmTarget const* head) const; + // Cache target compile paths for each configuration. + struct CompileInfo; + CompileInfo const* GetCompileInfo(const char* config) const; + mutable cmTargetLinkInformationMap LinkInformation; void CheckPropertyCompatibility(cmComputeLinkInformation *info, const char* config) const; - bool ComputeLinkInterface(const char* config, LinkInterface& iface, - cmTarget const* head) const; + const char* ComputeLinkInterfaceLibraries(const char* config, + LinkInterface& iface, + cmTarget const* head, + bool &exists) const; void ComputeLinkImplementation(const char* config, LinkImplementation& impl, cmTarget const* head) const; + void ComputeLinkImplementationLanguages(LinkImplementation& impl) const; void ComputeLinkClosure(const char* config, LinkClosure& lc, cmTarget const* head) const; @@ -756,7 +751,6 @@ private: friend class cmTargetTraceDependencies; cmTargetInternalPointer Internal; - void ConstructSourceFileFlags() const; void ComputeVersionedName(std::string& vName, std::string const& prefix, std::string const& base, diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index ed7e243..2d21a3d 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -1427,6 +1427,17 @@ void cmVisualStudio10TargetGenerator::WriteClOptions( clOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ", "\n", "CXX"); this->WriteString("<ObjectFileName>$(IntDir)</ObjectFileName>\n", 3); + + // Specify the compiler program database file if configured. + std::string pdb = this->Target->GetCompilePDBPath(configName.c_str()); + if(!pdb.empty()) + { + this->ConvertToWindowsSlash(pdb); + this->WriteString("<ProgramDataBaseFileName>", 3); + *this->BuildFileStream << cmVS10EscapeXML(pdb) + << "</ProgramDataBaseFileName>\n"; + } + this->WriteString("</ClCompile>\n", 2); } @@ -1666,10 +1677,10 @@ cmVisualStudio10TargetGenerator::ComputeLinkOptions(std::string const& config) linkOptions.AddFlag("ImportLibrary", imLib.c_str()); linkOptions.AddFlag("ProgramDataBaseFile", pdb.c_str()); linkOptions.Parse(flags.c_str()); - if(!this->GeneratorTarget->ModuleDefinitionFile.empty()) + std::string def = this->GeneratorTarget->GetModuleDefinitionFile(); + if(!def.empty()) { - linkOptions.AddFlag("ModuleDefinitionFile", - this->GeneratorTarget->ModuleDefinitionFile.c_str()); + linkOptions.AddFlag("ModuleDefinitionFile", def.c_str()); } this->LinkOptions[config] = pOptions.release(); |