diff options
Diffstat (limited to 'Source')
-rw-r--r-- | Source/CMakeVersion.cmake | 2 | ||||
-rw-r--r-- | Source/CPack/cmCPackDebGenerator.cxx | 299 | ||||
-rw-r--r-- | Source/QtDialog/CMakeLists.txt | 16 | ||||
-rw-r--r-- | Source/cmArchiveWrite.cxx | 39 | ||||
-rw-r--r-- | Source/cmArchiveWrite.h | 95 | ||||
-rw-r--r-- | Source/cmCommonTargetGenerator.cxx | 17 | ||||
-rw-r--r-- | Source/cmCommonTargetGenerator.h | 1 | ||||
-rw-r--r-- | Source/cmGeneratedFileStream.h | 4 | ||||
-rw-r--r-- | Source/cmGeneratorTarget.cxx | 14 | ||||
-rw-r--r-- | Source/cmGeneratorTarget.h | 2 | ||||
-rw-r--r-- | Source/cmLocalGenerator.cxx | 7 | ||||
-rw-r--r-- | Source/cmLocalGenerator.h | 1 | ||||
-rw-r--r-- | Source/cmLocalVisualStudio7Generator.cxx | 38 | ||||
-rw-r--r-- | Source/cmMakefileExecutableTargetGenerator.cxx | 4 | ||||
-rw-r--r-- | Source/cmMakefileLibraryTargetGenerator.cxx | 4 | ||||
-rw-r--r-- | Source/cmMakefileTargetGenerator.cxx | 9 | ||||
-rw-r--r-- | Source/cmNinjaNormalTargetGenerator.cxx | 10 | ||||
-rw-r--r-- | Source/cmNinjaTargetGenerator.cxx | 9 | ||||
-rw-r--r-- | Source/cmVisualStudio10TargetGenerator.cxx | 29 | ||||
-rw-r--r-- | Source/cmVisualStudio10TargetGenerator.h | 1 | ||||
-rw-r--r-- | Source/cmcmd.cxx | 416 | ||||
-rw-r--r-- | Source/cmcmd.h | 14 |
22 files changed, 687 insertions, 344 deletions
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index a0d0160..17f8db5 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 3) -set(CMake_VERSION_PATCH 20150917) +set(CMake_VERSION_PATCH 20150921) #set(CMake_VERSION_RC 1) diff --git a/Source/CPack/cmCPackDebGenerator.cxx b/Source/CPack/cmCPackDebGenerator.cxx index 5049a3f..9402689 100644 --- a/Source/CPack/cmCPackDebGenerator.cxx +++ b/Source/CPack/cmCPackDebGenerator.cxx @@ -15,6 +15,7 @@ #include "cmMakefile.h" #include "cmGeneratedFileStream.h" #include "cmCPackLog.h" +#include "cmArchiveWrite.h" #include <cmsys/SystemTools.hxx> #include <cmsys/Glob.hxx> @@ -388,9 +389,9 @@ int cmCPackDebGenerator::createDeb() { std::string dirName = this->GetOption("CPACK_TEMPORARY_DIRECTORY"); dirName += '/'; - for (std::vector<std::string>::const_iterator fileIt = - packageFiles.begin(); - fileIt != packageFiles.end(); ++ fileIt ) + for (std::vector<std::string>::const_iterator fileIt = + packageFiles.begin(); + fileIt != packageFiles.end(); ++ fileIt ) { totalSize += cmSystemTools::FileLength(*fileIt); } @@ -401,8 +402,9 @@ int cmCPackDebGenerator::createDeb() out << std::endl; } - std::string cmd(this->GetOption("GEN_CPACK_DEBIAN_FAKEROOT_EXECUTABLE")); + const std::string strGenWDIR(this->GetOption("GEN_WDIR")); + cmArchiveWrite::Compress tar_compression_type = cmArchiveWrite::CompressGZip; const char* debian_compression_type = this->GetOption("GEN_CPACK_DEBIAN_COMPRESSION_TYPE"); if(!debian_compression_type) @@ -410,102 +412,127 @@ int cmCPackDebGenerator::createDeb() debian_compression_type = "gzip"; } - std::string cmake_tar = " ", compression_modifier = "a", compression_suffix; + std::string compression_suffix; if(!strcmp(debian_compression_type, "lzma")) { compression_suffix = ".lzma"; + tar_compression_type = cmArchiveWrite::CompressLZMA; } else if(!strcmp(debian_compression_type, "xz")) { compression_suffix = ".xz"; + tar_compression_type = cmArchiveWrite::CompressXZ; } else if(!strcmp(debian_compression_type, "bzip2")) { compression_suffix = ".bz2"; - compression_modifier = "j"; - cmake_tar += "\"" + cmSystemTools::GetCMakeCommand() + "\" -E "; + tar_compression_type = cmArchiveWrite::CompressBZip2; } else if(!strcmp(debian_compression_type, "gzip")) { compression_suffix = ".gz"; - compression_modifier = "z"; - cmake_tar += "\"" + cmSystemTools::GetCMakeCommand() + "\" -E "; + tar_compression_type = cmArchiveWrite::CompressGZip; } else if(!strcmp(debian_compression_type, "none")) { compression_suffix = ""; - compression_modifier = ""; - cmake_tar += "\"" + cmSystemTools::GetCMakeCommand() + "\" -E "; + tar_compression_type = cmArchiveWrite::CompressNone; } else { cmCPackLogger(cmCPackLog::LOG_ERROR, "Error unrecognized compression type: " << debian_compression_type << std::endl); } - cmd += cmake_tar + "tar c" + compression_modifier + "f data.tar" - + compression_suffix; - // now add all directories which have to be compressed - // collect all top level install dirs for that - // e.g. /opt/bin/foo, /usr/bin/bar and /usr/bin/baz would give /usr and /opt - size_t topLevelLength = std::string(this->GetOption("GEN_WDIR")).length(); - cmCPackLogger(cmCPackLog::LOG_DEBUG, "WDIR: \"" - << this->GetOption("GEN_WDIR") - << "\", length = " << topLevelLength + std::string filename_data_tar = strGenWDIR + + "/data.tar" + compression_suffix; + + // atomic file generation for data.tar + { + cmGeneratedFileStream fileStream_data_tar; + fileStream_data_tar.Open(filename_data_tar.c_str(), false, true); + if(!fileStream_data_tar) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Error opening the file \"" << filename_data_tar << "\" for writing" << std::endl); - std::set<std::string> installDirs; + return 0; + } + cmArchiveWrite data_tar(fileStream_data_tar, tar_compression_type, "paxr"); + + // uid/gid should be the one of the root user, and this root user has + // always uid/gid equal to 0. + data_tar.SetUIDAndGID(0u, 0u); + data_tar.SetUNAMEAndGNAME("root", "root"); + + // now add all directories which have to be compressed + // collect all top level install dirs for that + // e.g. /opt/bin/foo, /usr/bin/bar and /usr/bin/baz would + // give /usr and /opt + size_t topLevelLength = strGenWDIR.length(); + cmCPackLogger(cmCPackLog::LOG_DEBUG, "WDIR: \"" + << strGenWDIR + << "\", length = " << topLevelLength + << std::endl); + std::set<std::string> orderedFiles; + + // we have to reconstruct the parent folders as well + for (std::vector<std::string>::const_iterator fileIt = - packageFiles.begin(); - fileIt != packageFiles.end(); ++ fileIt ) - { - cmCPackLogger(cmCPackLog::LOG_DEBUG, "FILEIT: \"" << *fileIt << "\"" - << std::endl); - std::string::size_type slashPos = fileIt->find('/', topLevelLength+1); - std::string relativeDir = fileIt->substr(topLevelLength, - slashPos - topLevelLength); - cmCPackLogger(cmCPackLog::LOG_DEBUG, "RELATIVEDIR: \"" << relativeDir - << "\"" << std::endl); - if (installDirs.find(relativeDir) == installDirs.end()) + packageFiles.begin(); + fileIt != packageFiles.end(); ++ fileIt ) { - installDirs.insert(relativeDir); - cmd += " ."; - cmd += relativeDir; + std::string currentPath = *fileIt; + while(currentPath != strGenWDIR) + { + // the last one IS strGenWDIR, but we do not want this one: + // XXX/application/usr/bin/myprogram with GEN_WDIR=XXX/application + // should not add XXX/application + orderedFiles.insert(currentPath); + currentPath = cmSystemTools::CollapseCombinedPath(currentPath, ".."); + } } - } - std::string output; - int retval = -1; - int res = cmSystemTools::RunSingleCommand(cmd.c_str(), &output, &output, - &retval, this->GetOption("GEN_WDIR"), this->GeneratorVerbose, 0); - if ( !res || retval ) - { - std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY"); - tmpFile += "/Deb.log"; - cmGeneratedFileStream ofs(tmpFile.c_str()); - ofs << "# Run command: " << cmd << std::endl - << "# Working directory: " << toplevel << std::endl - << "# Output:" << std::endl - << output << std::endl; - cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running tar command: " - << cmd << std::endl - << "Please check " << tmpFile << " for errors" << std::endl); - return 0; - } + for (std::set<std::string>::const_iterator fileIt = + orderedFiles.begin(); + fileIt != orderedFiles.end(); ++ fileIt ) + { + cmCPackLogger(cmCPackLog::LOG_DEBUG, "FILEIT: \"" << *fileIt << "\"" + << std::endl); + std::string::size_type slashPos = fileIt->find('/', topLevelLength+1); + std::string relativeDir = fileIt->substr(topLevelLength, + slashPos - topLevelLength); + cmCPackLogger(cmCPackLog::LOG_DEBUG, "RELATIVEDIR: \"" << relativeDir + << "\"" << std::endl); - std::string md5filename; - md5filename = this->GetOption("GEN_WDIR"); - md5filename += "/md5sums"; + // do not recurse because the loop will do it + if(!data_tar.Add(*fileIt, topLevelLength, ".", false)) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Problem adding file to tar:" << std::endl + << "#top level directory: " + << strGenWDIR << std::endl + << "#file: " << *fileIt << std::endl + << "#error:" << data_tar.GetError() << std::endl); + return 0; + } + } + } // scope for file generation - { // the scope is needed for cmGeneratedFileStream + + std::string md5filename = strGenWDIR + "/md5sums"; + { + // the scope is needed for cmGeneratedFileStream cmGeneratedFileStream out(md5filename.c_str()); - std::vector<std::string>::const_iterator fileIt; -// std::string topLevelWithTrailingSlash = toplevel; + std::string topLevelWithTrailingSlash = this->GetOption("CPACK_TEMPORARY_DIRECTORY"); topLevelWithTrailingSlash += '/'; - for ( fileIt = packageFiles.begin(); - fileIt != packageFiles.end(); ++ fileIt ) + for (std::vector<std::string>::const_iterator fileIt = + packageFiles.begin(); + fileIt != packageFiles.end(); ++ fileIt ) { - cmd = "\""; + std::string cmd = "\""; cmd += cmSystemTools::GetCMakeCommand(); cmd += "\" -E md5sum \""; cmd += *fileIt; cmd += "\""; - //std::string output; - //int retVal = -1; - res = cmSystemTools::RunSingleCommand(cmd.c_str(), &output, &output, + + std::string output; + int retval = -1; + int res = cmSystemTools::RunSingleCommand(cmd.c_str(), &output, &output, &retval, toplevel.c_str(), this->GeneratorVerbose, 0); if ( !res || retval ) { @@ -521,70 +548,116 @@ int cmCPackDebGenerator::createDeb() } // each line contains a eol. // Do not end the md5sum file with yet another (invalid) - } + } - // set md5sum file permissins to RW-R--R-- so that deb lintian doesn't warn - // about it - cmSystemTools::SetPermissions(md5filename.c_str(), - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - cmd = this->GetOption("GEN_CPACK_DEBIAN_FAKEROOT_EXECUTABLE"); - cmd += cmake_tar + "tar czf control.tar.gz ./control ./md5sums"; + + std::string filename_control_tar = strGenWDIR + "/control.tar.gz"; + // atomic file generation for control.tar + { + cmGeneratedFileStream fileStream_control_tar; + fileStream_control_tar.Open(filename_control_tar.c_str(), false, true); + if(!fileStream_control_tar) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Error opening the file \"" << filename_control_tar + << "\" for writing" << std::endl); + return 0; + } + cmArchiveWrite control_tar(fileStream_control_tar, + tar_compression_type, + "paxr"); + + // sets permissions and uid/gid for the files + control_tar.SetUIDAndGID(0u, 0u); + control_tar.SetUNAMEAndGNAME("root", "root"); + + /* permissions are set according to + https://www.debian.org/doc/debian-policy/ch-files.html#s-permissions-owners + and + https://lintian.debian.org/tags/control-file-has-bad-permissions.html + */ + const mode_t permission644 = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + const mode_t permissionExecute = S_IXUSR | S_IXGRP | S_IXOTH; + const mode_t permission755 = permission644 | permissionExecute; + + // for md5sum and control (that we have generated here), we use 644 + // (RW-R--R--) + // so that deb lintian doesn't warn about it + control_tar.SetPermissions(permission644); + + // adds control and md5sums + if( !control_tar.Add(md5filename, strGenWDIR.length(), ".") + || !control_tar.Add(strGenWDIR + "/control", strGenWDIR.length(), ".")) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Error adding file to tar:" << std::endl + << "#top level directory: " + << strGenWDIR << std::endl + << "#file: \"control\" or \"md5sums\"" << std::endl + << "#error:" << control_tar.GetError() << std::endl); + return 0; + } + + // for the other files, we use + // -either the original permission on the files + // -either a permission strictly defined by the Debian policies const char* controlExtra = this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA"); - if( controlExtra ) - { - std::vector<std::string> controlExtraList; - cmSystemTools::ExpandListArgument(controlExtra, controlExtraList); - for(std::vector<std::string>::iterator i = - controlExtraList.begin(); i != controlExtraList.end(); ++i) + if( controlExtra ) { - std::string filenamename = - cmsys::SystemTools::GetFilenameName(*i); - std::string localcopy = this->GetOption("GEN_WDIR"); - localcopy += "/"; - localcopy += filenamename; - // if we can copy the file, it means it does exist, let's add it: - if( cmsys::SystemTools::CopyFileIfDifferent( - *i, localcopy) ) + // permissions are now controlled by the original file permissions + + const bool permissionStrictPolicy = + this->IsSet("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION"); + + static const char* strictFiles[] = { + "config", "postinst", "postrm", "preinst", "prerm" + }; + std::set<std::string> setStrictFiles( + strictFiles, + strictFiles + sizeof(strictFiles)/sizeof(strictFiles[0])); + + // default + control_tar.ClearPermissions(); + + std::vector<std::string> controlExtraList; + cmSystemTools::ExpandListArgument(controlExtra, controlExtraList); + for(std::vector<std::string>::iterator i = controlExtraList.begin(); + i != controlExtraList.end(); ++i) { - // debian is picky and need relative to ./ path in the tar.* - cmd += " ./"; - cmd += filenamename; + std::string filenamename = + cmsys::SystemTools::GetFilenameName(*i); + std::string localcopy = strGenWDIR + "/" + filenamename; + + if(permissionStrictPolicy) + { + control_tar.SetPermissions(setStrictFiles.count(filenamename) ? + permission755 : permission644); + } + + // if we can copy the file, it means it does exist, let's add it: + if( cmsys::SystemTools::CopyFileIfDifferent(*i, localcopy) ) + { + control_tar.Add(localcopy, strGenWDIR.length(), "."); + } } } - } - res = cmSystemTools::RunSingleCommand(cmd.c_str(), &output, &output, - &retval, this->GetOption("GEN_WDIR"), this->GeneratorVerbose, 0); + } - if ( !res || retval ) - { - std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY"); - tmpFile += "/Deb.log"; - cmGeneratedFileStream ofs(tmpFile.c_str()); - ofs << "# Run command: " << cmd << std::endl - << "# Working directory: " << toplevel << std::endl - << "# Output:" << std::endl - << output << std::endl; - cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running tar command: " - << cmd << std::endl - << "Please check " << tmpFile << " for errors" << std::endl); - return 0; - } // ar -r your-package-name.deb debian-binary control.tar.* data.tar.* // since debian packages require BSD ar (most Linux distros and even // FreeBSD and NetBSD ship GNU ar) we use a copy of OpenBSD ar here. std::vector<std::string> arFiles; - std::string topLevelString = this->GetOption("GEN_WDIR"); - topLevelString += "/"; + std::string topLevelString = strGenWDIR + "/"; arFiles.push_back(topLevelString + "debian-binary"); arFiles.push_back(topLevelString + "control.tar.gz"); arFiles.push_back(topLevelString + "data.tar" + compression_suffix); - std::string outputFileName = this->GetOption("CPACK_TOPLEVEL_DIRECTORY"); - outputFileName += "/"; - outputFileName += this->GetOption("CPACK_OUTPUT_FILE_NAME"); - res = ar_append(outputFileName.c_str(), arFiles); + std::string outputFileName = this->GetOption("CPACK_TOPLEVEL_DIRECTORY"); + outputFileName += "/"; + outputFileName += this->GetOption("CPACK_OUTPUT_FILE_NAME"); + int res = ar_append(outputFileName.c_str(), arFiles); if ( res!=0 ) { std::string tmpFile = this->GetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME"); diff --git a/Source/QtDialog/CMakeLists.txt b/Source/QtDialog/CMakeLists.txt index ad6a7fb..570b537 100644 --- a/Source/QtDialog/CMakeLists.txt +++ b/Source/QtDialog/CMakeLists.txt @@ -78,9 +78,12 @@ if (Qt5Widgets_FOUND) endif() endif() - if(WIN32 AND TARGET Qt5::Core) + if(TARGET Qt5::Core) get_property(_Qt5_Core_LOCATION TARGET Qt5::Core PROPERTY LOCATION) get_filename_component(Qt_BIN_DIR "${_Qt5_Core_LOCATION}" PATH) + if(APPLE) + get_filename_component(Qt_BIN_DIR "${Qt_BIN_DIR}" PATH) + endif() endif() else() set(QT_MIN_VERSION "4.4.0") @@ -94,12 +97,6 @@ else() set(CMake_QT_LIBRARIES ${QT_LIBRARIES}) - if(WIN32 AND EXISTS "${QT_QMAKE_EXECUTABLE}") - get_filename_component(_Qt_BIN_DIR "${QT_QMAKE_EXECUTABLE}" PATH) - if(EXISTS "${_Qt_BIN_DIR}/QtCore4.dll") - set(Qt_BIN_DIR ${_Qt_BIN_DIR}) - endif() - endif() endif() set(SRCS @@ -157,9 +154,6 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) add_executable(cmake-gui WIN32 MACOSX_BUNDLE ${SRCS}) target_link_libraries(cmake-gui CMakeLib ${QT_QTMAIN_LIBRARY} ${CMake_QT_LIBRARIES}) -if(Qt_BIN_DIR) - set_property(TARGET cmake-gui PROPERTY Qt_BIN_DIR ${Qt_BIN_DIR}) -endif() if(APPLE) file(STRINGS "${CMake_SOURCE_DIR}/Copyright.txt" copyright_line @@ -223,7 +217,7 @@ if(CMake_INSTALL_DEPENDENCIES AND (APPLE OR WIN32)) install(CODE " include(\"${CMake_SOURCE_DIR}/Modules/BundleUtilities.cmake\") set(BU_CHMOD_BUNDLE_ITEMS ON) - fixup_bundle(\"${fixup_exe}\" \"${QT_PLUGINS}\" \"${QT_LIBRARY_DIR};${QT_BINARY_DIR}\") + fixup_bundle(\"${fixup_exe}\" \"${QT_PLUGINS}\" \"${Qt_BIN_DIR};${QT_LIBRARY_DIR};${QT_BINARY_DIR}\") " ${COMPONENT}) endif() diff --git a/Source/cmArchiveWrite.cxx b/Source/cmArchiveWrite.cxx index 9f56324..7946950 100644 --- a/Source/cmArchiveWrite.cxx +++ b/Source/cmArchiveWrite.cxx @@ -181,7 +181,10 @@ cmArchiveWrite::~cmArchiveWrite() } //---------------------------------------------------------------------------- -bool cmArchiveWrite::Add(std::string path, size_t skip, const char* prefix) +bool cmArchiveWrite::Add(std::string path, + size_t skip, + const char* prefix, + bool recursive) { if(this->Okay()) { @@ -189,20 +192,21 @@ bool cmArchiveWrite::Add(std::string path, size_t skip, const char* prefix) { path.erase(path.size()-1); } - this->AddPath(path.c_str(), skip, prefix); + this->AddPath(path.c_str(), skip, prefix, recursive); } return this->Okay(); } //---------------------------------------------------------------------------- bool cmArchiveWrite::AddPath(const char* path, - size_t skip, const char* prefix) + size_t skip, const char* prefix, + bool recursive) { if(!this->AddFile(path, skip, prefix)) { return false; } - if(!cmSystemTools::FileIsDirectory(path) || + if((!cmSystemTools::FileIsDirectory(path) || !recursive) || cmSystemTools::FileIsSymlink(path)) { return true; @@ -278,6 +282,33 @@ bool cmArchiveWrite::AddFile(const char* file, } archive_entry_set_mtime(e, t, 0); } + + // manages the uid/guid of the entry (if any) + if (this->Uid.IsSet() && this->Gid.IsSet()) + { + archive_entry_set_uid(e, this->Uid.Get()); + archive_entry_set_gid(e, this->Gid.Get()); + } + + if (this->Uname.size() && this->Gname.size()) + { + archive_entry_set_uname(e, this->Uname.c_str()); + archive_entry_set_gname(e, this->Gname.c_str()); + } + + + // manages the permissions + if (this->Permissions.IsSet()) + { + archive_entry_set_perm(e, this->Permissions.Get()); + } + + if (this->PermissionsMask.IsSet()) + { + mode_t perm = archive_entry_perm(e); + archive_entry_set_perm(e, perm & this->PermissionsMask.Get()); + } + // Clear acl and xattr fields not useful for distribution. archive_entry_acl_clear(e); archive_entry_xattr_clear(e); diff --git a/Source/cmArchiveWrite.h b/Source/cmArchiveWrite.h index e6f515d..8dbbb83 100644 --- a/Source/cmArchiveWrite.h +++ b/Source/cmArchiveWrite.h @@ -18,6 +18,22 @@ # error "cmArchiveWrite not allowed during bootstrap build!" #endif +template<typename T> +class cmArchiveWriteOptional +{ +public: + cmArchiveWriteOptional() {this->Clear();} + explicit cmArchiveWriteOptional(T val) {this->Set(val);} + + void Set(T val) {this->IsValueSet = true; this->Value=val;} + void Clear() {this->IsValueSet = false;} + bool IsSet() const {return this->IsValueSet;} + T Get() const {return Value;} +private: + T Value; + bool IsValueSet; +}; + /** \class cmArchiveWrite * \brief Wrapper around libarchive for writing. * @@ -52,7 +68,10 @@ public: * skip. The remaining part of the input path is appended to the * "prefix" value to construct the final name in the archive. */ - bool Add(std::string path, size_t skip = 0, const char* prefix = 0); + bool Add(std::string path, + size_t skip = 0, + const char* prefix = 0, + bool recursive = true); /** Returns true if there has been no error. */ operator safe_bool() const @@ -69,9 +88,65 @@ public: void SetVerbose(bool v) { this->Verbose = v; } void SetMTime(std::string const& t) { this->MTime = t; } + + //! Sets the permissions of the added files/folders + void SetPermissions(mode_t permissions_) + { + this->Permissions.Set(permissions_); + } + + //! Clears permissions - default is used instead + void ClearPermissions() { this->Permissions.Clear(); } + + //! Sets the permissions mask of files/folders + //! + //! The permissions will be copied from the existing file + //! or folder. The mask will then be applied to unset + //! some of them + void SetPermissionsMask(mode_t permissionsMask_) + { + this->PermissionsMask.Set(permissionsMask_); + } + + //! Clears permissions mask - default is used instead + void ClearPermissionsMask() + { + this->PermissionsMask.Clear(); + } + + //! Sets UID and GID to be used in the tar file + void SetUIDAndGID(int uid_, int gid_) + { + this->Uid.Set(uid_); + this->Gid.Set(gid_); + } + + //! Clears UID and GID to be used in the tar file - default is used instead + void ClearUIDAndGID() + { + this->Uid.Clear(); + this->Gid.Clear(); + } + + //! Sets UNAME and GNAME to be used in the tar file + void SetUNAMEAndGNAME(const std::string& uname_, const std::string& gname_) + { + this->Uname = uname_; + this->Gname = gname_; + } + + //! Clears UNAME and GNAME to be used in the tar file + //! default is used instead + void ClearUNAMEAndGNAME() + { + this->Uname = ""; + this->Gname = ""; + } + private: bool Okay() const { return this->Error.empty(); } - bool AddPath(const char* path, size_t skip, const char* prefix); + bool AddPath(const char* path, size_t skip, const char* prefix, + bool recursive = true); bool AddFile(const char* file, size_t skip, const char* prefix); bool AddData(const char* file, size_t size); @@ -87,6 +162,22 @@ private: std::string Format; std::string Error; std::string MTime; + + //! UID of the user in the tar file + cmArchiveWriteOptional<int> Uid; + + //! GUID of the user in the tar file + cmArchiveWriteOptional<int> Gid; + + //! UNAME/GNAME of the user (does not override UID/GID) + //!@{ + std::string Uname; + std::string Gname; + //!@} + + //! Permissions on files/folders + cmArchiveWriteOptional<mode_t> Permissions; + cmArchiveWriteOptional<mode_t> PermissionsMask; }; #endif diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index 4840e89..252e231 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -412,3 +412,20 @@ cmCommonTargetGenerator::GetLinkedTargetDirectories() const } return dirs; } + +std::string cmCommonTargetGenerator::GetManifests() +{ + std::vector<cmSourceFile const*> manifest_srcs; + this->GeneratorTarget->GetManifests(manifest_srcs, this->ConfigName); + + std::vector<std::string> manifests; + for (std::vector<cmSourceFile const*>::iterator mi = manifest_srcs.begin(); + mi != manifest_srcs.end(); ++mi) + { + manifests.push_back(this->Convert((*mi)->GetFullPath(), + this->WorkingDirectory, + cmOutputConverter::SHELL)); + } + + return cmJoin(manifests, " "); +} diff --git a/Source/cmCommonTargetGenerator.h b/Source/cmCommonTargetGenerator.h index 0a49e12..a4b2c10 100644 --- a/Source/cmCommonTargetGenerator.h +++ b/Source/cmCommonTargetGenerator.h @@ -88,6 +88,7 @@ protected: ByLanguageMap DefinesByLanguage; std::string GetIncludes(std::string const& l); ByLanguageMap IncludesByLanguage; + std::string GetManifests(); std::vector<std::string> GetLinkedTargetDirectories() const; }; diff --git a/Source/cmGeneratedFileStream.h b/Source/cmGeneratedFileStream.h index 2aa6beb..8df3e1a 100644 --- a/Source/cmGeneratedFileStream.h +++ b/Source/cmGeneratedFileStream.h @@ -56,10 +56,10 @@ protected: // Whether the real file stream was valid when it was closed. bool Okay; - // Whether the destionation file is compressed + // Whether the destination file is compressed bool Compress; - // Whether the destionation file is compressed + // Whether the destination file is compressed bool CompressExtraExtension; }; diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 09387b7..fb5805b 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -75,6 +75,7 @@ struct IDLSourcesTag {}; struct ResxTag {}; struct ModuleDefinitionFileTag {}; struct AppManifestTag{}; +struct ManifestsTag{}; struct CertificatesTag{}; struct XamlTag{}; @@ -216,6 +217,10 @@ struct TagVisitor { DoAccept<IsSameTag<Tag, AppManifestTag>::Result>::Do(this->Data, sf); } + else if (ext == "manifest") + { + DoAccept<IsSameTag<Tag, ManifestsTag>::Result>::Do(this->Data, sf); + } else if (ext == "pfx") { DoAccept<IsSameTag<Tag, CertificatesTag>::Result>::Do(this->Data, sf); @@ -626,6 +631,15 @@ cmGeneratorTarget //---------------------------------------------------------------------------- void cmGeneratorTarget +::GetManifests(std::vector<cmSourceFile const*>& data, + const std::string& config) const +{ + IMPLEMENT_VISIT(Manifests); +} + +//---------------------------------------------------------------------------- +void +cmGeneratorTarget ::GetCertificates(std::vector<cmSourceFile const*>& data, const std::string& config) const { diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 06d9a1f..916f281 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -71,6 +71,8 @@ public: const std::string& config) const; void GetAppManifest(std::vector<cmSourceFile const*>&, const std::string& config) const; + void GetManifests(std::vector<cmSourceFile const*>&, + const std::string& config) const; void GetCertificates(std::vector<cmSourceFile const*>&, const std::string& config) const; void GetXamlSources(std::vector<cmSourceFile const*>&, diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 46d5cd8..97a9f1e 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -525,6 +525,13 @@ cmLocalGenerator::ExpandRuleVariable(std::string const& variable, return replaceValues.LinkFlags; } } + if(replaceValues.Manifests) + { + if(variable == "MANIFESTS") + { + return replaceValues.Manifests; + } + } if(replaceValues.Flags) { if(variable == "FLAGS") diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index b051e5d..771131f 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -219,6 +219,7 @@ public: const char* TargetSOName; const char* TargetInstallNameDir; const char* LinkFlags; + const char* Manifests; const char* LanguageCompileFlags; const char* Defines; const char* Includes; diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index cf67251..a4bce8a 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -972,25 +972,43 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout, fout << "\t\t\t\tProxyFileName=\"$(InputName)_p.c\"/>\n"; // end of <Tool Name=VCMIDLTool - // Check if we need the FAT32 workaround. + // Add manifest tool settings. if(targetBuilds && this->GetVersion() >= cmGlobalVisualStudioGenerator::VS8) { + const char* manifestTool = "VCManifestTool"; + if (this->FortranProject) + { + manifestTool = "VFManifestTool"; + } + fout << + "\t\t\t<Tool\n" + "\t\t\t\tName=\"" << manifestTool << "\""; + + std::vector<cmSourceFile const*> manifest_srcs; + gt->GetManifests(manifest_srcs, configName); + if (!manifest_srcs.empty()) + { + fout << "\n\t\t\t\tAdditionalManifestFiles=\""; + for (std::vector<cmSourceFile const*>::const_iterator + mi = manifest_srcs.begin(); mi != manifest_srcs.end(); ++mi) + { + std::string m = (*mi)->GetFullPath(); + fout << this->ConvertToXMLOutputPath(m.c_str()) << ";"; + } + fout << "\""; + } + + // Check if we need the FAT32 workaround. // Check the filesystem type where the target will be written. - if(cmLVS6G_IsFAT(target.GetDirectory(configName).c_str())) + if (cmLVS6G_IsFAT(target.GetDirectory(configName).c_str())) { // Add a flag telling the manifest tool to use a workaround // for FAT32 file systems, which can cause an empty manifest // to be embedded into the resulting executable. See CMake // bug #2617. - const char* manifestTool = "VCManifestTool"; - if(this->FortranProject) - { - manifestTool = "VFManifestTool"; - } - fout << "\t\t\t<Tool\n\t\t\t\tName=\"" << manifestTool << "\"\n" - << "\t\t\t\tUseFAT32Workaround=\"true\"\n" - << "\t\t\t/>\n"; + fout << "\n\t\t\t\tUseFAT32Workaround=\"true\""; } + fout << "/>\n"; } this->OutputTargetRules(fout, configName, target, libName); diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index ccb0974..90f679e 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -353,6 +353,8 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) useResponseFileForObjects, buildObjs, depends, useWatcomQuote); + std::string manifests = this->GetManifests(); + cmLocalGenerator::RuleVariables vars; vars.RuleLauncher = "RULE_LAUNCH_LINK"; vars.CMTarget = this->Target; @@ -391,6 +393,8 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) vars.LinkLibraries = linkLibs.c_str(); vars.Flags = flags.c_str(); vars.LinkFlags = linkFlags.c_str(); + vars.Manifests = manifests.c_str(); + // Expand placeholders in the commands. this->LocalGenerator->TargetImplib = targetOutPathImport; for(std::vector<std::string>::iterator i = real_link_commands.begin(); diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 2f995e8..cd387a0 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -616,6 +616,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules } } + std::string manifests = this->GetManifests(); + cmLocalGenerator::RuleVariables vars; vars.TargetPDB = targetOutPathPDB.c_str(); @@ -660,6 +662,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules } vars.LinkFlags = linkFlags.c_str(); + vars.Manifests = manifests.c_str(); + // Compute the directory portion of the install_name setting. std::string install_name_dir; if(this->Target->GetType() == cmTarget::SHARED_LIBRARY) diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index cf88a74..b278087 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -1493,6 +1493,15 @@ void cmMakefileTargetGenerator depends.push_back(this->ModuleDefinitionFile); } + // Add a dependency on user-specified manifest files, if any. + std::vector<cmSourceFile const*> manifest_srcs; + this->GeneratorTarget->GetManifests(manifest_srcs, this->ConfigName); + for (std::vector<cmSourceFile const*>::iterator mi = manifest_srcs.begin(); + mi != manifest_srcs.end(); ++mi) + { + depends.push_back((*mi)->GetFullPath()); + } + // Add user-specified dependencies. if(const char* linkDepends = this->Target->GetProperty("LINK_DEPENDS")) diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index b855bea..7e7e600 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -237,6 +237,7 @@ cmNinjaNormalTargetGenerator vars.Flags = "$FLAGS"; vars.LinkFlags = "$LINK_FLAGS"; + vars.Manifests = "$MANIFESTS"; std::string langFlags; if (targetType != cmTarget::EXECUTABLE) @@ -509,6 +510,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() vars["LINK_FLAGS"] = cmGlobalNinjaGenerator ::EncodeLiteral(vars["LINK_FLAGS"]); + vars["MANIFESTS"] = this->GetManifests(); + vars["LINK_PATH"] = frameworkPath + linkPath; // Compute architecture specific link flags. Yes, these go into a different @@ -579,11 +582,12 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() vars["TARGET_PDB"] = base + suffix + dbg_suffix; } + const std::string objPath = GetTarget()->GetSupportDirectory(); + vars["OBJECT_DIR"] = ConvertToNinjaPath(objPath); + EnsureDirectoryExists(objPath); + if (this->GetGlobalGenerator()->IsGCCOnWindows()) { - const std::string objPath = GetTarget()->GetSupportDirectory(); - vars["OBJECT_DIR"] = ConvertToNinjaPath(objPath); - EnsureDirectoryExists(objPath); // ar.exe can't handle backslashes in rsp files (implicitly used by gcc) std::string& linkLibraries = vars["LINK_LIBRARIES"]; std::replace(linkLibraries.begin(), linkLibraries.end(), '\\', '/'); diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 81fdde2..752c8a7 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -209,6 +209,15 @@ cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps() const result.push_back(this->ConvertToNinjaPath(this->ModuleDefinitionFile)); } + // Add a dependency on user-specified manifest files, if any. + std::vector<cmSourceFile const*> manifest_srcs; + this->GeneratorTarget->GetManifests(manifest_srcs, this->ConfigName); + for (std::vector<cmSourceFile const*>::iterator mi = manifest_srcs.begin(); + mi != manifest_srcs.end(); ++mi) + { + result.push_back(this->ConvertToNinjaPath((*mi)->GetFullPath())); + } + // Add user-specified dependencies. if (const char* linkDepends = this->Target->GetProperty("LINK_DEPENDS")) { diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 4c380f7..cb5048d 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2203,6 +2203,33 @@ cmVisualStudio10TargetGenerator::WriteLibOptions(std::string const& config) } } +void cmVisualStudio10TargetGenerator::WriteManifestOptions( + std::string const& config) +{ + if (this->Target->GetType() != cmTarget::EXECUTABLE && + this->Target->GetType() != cmTarget::SHARED_LIBRARY && + this->Target->GetType() != cmTarget::MODULE_LIBRARY) + { + return; + } + + std::vector<cmSourceFile const*> manifest_srcs; + this->GeneratorTarget->GetManifests(manifest_srcs, config); + if (!manifest_srcs.empty()) + { + this->WriteString("<Manifest>\n", 2); + this->WriteString("<AdditionalManifestFiles>", 3); + for (std::vector<cmSourceFile const*>::const_iterator + mi = manifest_srcs.begin(); mi != manifest_srcs.end(); ++mi) + { + std::string m = this->ConvertPath((*mi)->GetFullPath(), false); + this->ConvertToWindowsSlash(m); + (*this->BuildFileStream) << m << ";"; + } + (*this->BuildFileStream) << "</AdditionalManifestFiles>\n"; + this->WriteString("</Manifest>\n", 2); + } +} //---------------------------------------------------------------------------- void cmVisualStudio10TargetGenerator::WriteAntBuildOptions( @@ -2740,6 +2767,8 @@ void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups() this->WriteLinkOptions(*i); // output lib flags <Lib></Lib> this->WriteLibOptions(*i); + // output manifest flags <Manifest></Manifest> + this->WriteManifestOptions(*i); if(this->NsightTegra && this->Target->GetType() == cmTarget::EXECUTABLE && this->Target->GetPropertyAsBool("ANDROID_GUI")) diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index 451f8b2..5fadb60 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -111,6 +111,7 @@ private: void AddLibraries(cmComputeLinkInformation& cli, std::vector<std::string>& libVec); void WriteLibOptions(std::string const& config); + void WriteManifestOptions(std::string const& config); void WriteEvents(std::string const& configName); void WriteEvent(const char* name, std::vector<cmCustomCommand> const& commands, diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index aa70aa0..f44c77d 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -1355,6 +1355,35 @@ int cmcmd::WindowsCEEnvironment(const char* version, const std::string& name) return -1; } +class cmVSLink +{ + int Type; + bool Verbose; + bool Incremental; + bool LinkGeneratesManifest; + std::vector<std::string> LinkCommand; + std::vector<std::string> UserManifests; + std::string LinkerManifestFile; + std::string ManifestFile; + std::string ManifestFileRC; + std::string ManifestFileRes; + std::string TargetFile; +public: + cmVSLink(int type, bool verbose) + : Type(type) + , Verbose(verbose) + , Incremental(false) + , LinkGeneratesManifest(true) + {} + bool Parse(std::vector<std::string>::const_iterator argBeg, + std::vector<std::string>::const_iterator argEnd); + int Link(); +private: + int LinkIncremental(); + int LinkNonIncremental(); + int RunMT(std::string const& out, bool notify); +}; + // For visual studio 2005 and newer manifest files need to be embedded into // exe and dll's. This code does that in such a way that incremental linking // still works. @@ -1364,11 +1393,7 @@ int cmcmd::VisualStudioLink(std::vector<std::string>& args, int type) { return -1; } - bool verbose = false; - if(cmSystemTools::GetEnv("VERBOSE")) - { - verbose = true; - } + bool verbose = cmSystemTools::GetEnv("VERBOSE")? true:false; std::vector<std::string> expandedArgs; for(std::vector<std::string>::iterator i = args.begin(); i != args.end(); ++i) @@ -1389,79 +1414,19 @@ int cmcmd::VisualStudioLink(std::vector<std::string>& args, int type) expandedArgs.push_back(*i); } } - bool hasIncremental = false; - bool hasManifest = true; - for(std::vector<std::string>::iterator i = expandedArgs.begin(); - i != expandedArgs.end(); ++i) - { - if(cmSystemTools::Strucmp(i->c_str(), "/INCREMENTAL:YES") == 0) - { - hasIncremental = true; - } - if(cmSystemTools::Strucmp(i->c_str(), "/INCREMENTAL") == 0) - { - hasIncremental = true; - } - if(cmSystemTools::Strucmp(i->c_str(), "/MANIFEST:NO") == 0) - { - hasManifest = false; - } - } - if(hasIncremental && hasManifest) - { - if(verbose) - { - std::cout << "Visual Studio Incremental Link with embedded manifests\n"; - } - return cmcmd::VisualStudioLinkIncremental(expandedArgs, type, verbose); - } - if(verbose) - { - if(!hasIncremental) - { - std::cout << "Visual Studio Non-Incremental Link\n"; - } - else - { - std::cout << "Visual Studio Incremental Link without manifests\n"; - } - } - return cmcmd::VisualStudioLinkNonIncremental(expandedArgs, - type, hasManifest, verbose); -} -int cmcmd::ParseVisualStudioLinkCommand(std::vector<std::string>& args, - std::vector<std::string>& command, - std::string& targetName) -{ - std::vector<std::string>::iterator i = args.begin(); - i++; // skip -E - i++; // skip vs_link_dll or vs_link_exe - command.push_back(*i); - i++; // move past link command - for(; i != args.end(); ++i) - { - command.push_back(*i); - if(i->find("/Fe") == 0) - { - targetName = i->substr(3); - } - if(i->find("/out:") == 0) - { - targetName = i->substr(5); - } - } - if(targetName.empty() || command.empty()) + cmVSLink vsLink(type, verbose); + if (!vsLink.Parse(expandedArgs.begin()+2, expandedArgs.end())) { return -1; } - return 0; + return vsLink.Link(); } -bool cmcmd::RunCommand(const char* comment, +static bool RunCommand(const char* comment, std::vector<std::string>& command, bool verbose, - int* retCodeOut) + int* retCodeOut = 0) { if(verbose) { @@ -1503,8 +1468,134 @@ bool cmcmd::RunCommand(const char* comment, return retCode == 0; } -int cmcmd::VisualStudioLinkIncremental(std::vector<std::string>& args, - int type, bool verbose) +bool cmVSLink::Parse(std::vector<std::string>::const_iterator argBeg, + std::vector<std::string>::const_iterator argEnd) +{ + // Parse our own arguments. + std::string intDir; + std::vector<std::string>::const_iterator arg = argBeg; + while (arg != argEnd && cmHasLiteralPrefix(*arg, "-")) + { + if (*arg == "--") + { + ++arg; + break; + } + else if (*arg == "--manifests") + { + for (++arg; arg != argEnd && !cmHasLiteralPrefix(*arg, "-"); ++arg) + { + this->UserManifests.push_back(*arg); + } + } + else if (cmHasLiteralPrefix(*arg, "--intdir=")) + { + intDir = arg->substr(9); + ++arg; + } + else + { + std::cerr << "unknown argument '" << *arg << "'\n"; + return false; + } + } + if (intDir.empty()) + { + return false; + } + + // The rest of the arguments form the link command. + if (arg == argEnd) + { + return false; + } + this->LinkCommand.insert(this->LinkCommand.begin(), arg, argEnd); + + // Parse the link command to extract information we need. + for (; arg != argEnd; ++arg) + { + if (cmSystemTools::Strucmp(arg->c_str(), "/INCREMENTAL:YES") == 0) + { + this->Incremental = true; + } + else if (cmSystemTools::Strucmp(arg->c_str(), "/INCREMENTAL") == 0) + { + this->Incremental = true; + } + else if (cmSystemTools::Strucmp(arg->c_str(), "/MANIFEST:NO") == 0) + { + this->LinkGeneratesManifest = false; + } + else if (cmHasLiteralPrefix(*arg, "/Fe")) + { + this->TargetFile = arg->substr(3); + } + else if (cmHasLiteralPrefix(*arg, "/out:")) + { + this->TargetFile = arg->substr(5); + } + } + + if (this->TargetFile.empty()) + { + return false; + } + + this->ManifestFile = intDir + "/embed.manifest"; + this->LinkerManifestFile = intDir + "/intermediate.manifest"; + + if (this->Incremental) + { + // We will compile a resource containing the manifest and + // pass it to the link command. + this->ManifestFileRC = intDir + "/manifest.rc"; + this->ManifestFileRes = intDir + "/manifest.res"; + this->LinkCommand.push_back(this->ManifestFileRes); + } + else if (this->UserManifests.empty()) + { + // Prior to support for user-specified manifests CMake placed the + // linker-generated manifest next to the binary (as if it were not to be + // embedded) when not linking incrementally. Preserve this behavior. + this->ManifestFile = this->TargetFile + ".manifest"; + this->LinkerManifestFile = this->ManifestFile; + } + + if (this->LinkGeneratesManifest) + { + this->LinkCommand.push_back("/MANIFEST"); + this->LinkCommand.push_back("/MANIFESTFILE:" + this->LinkerManifestFile); + } + + return true; +} + +int cmVSLink::Link() +{ + if (this->Incremental && + (this->LinkGeneratesManifest || !this->UserManifests.empty())) + { + if (this->Verbose) + { + std::cout << "Visual Studio Incremental Link with embedded manifests\n"; + } + return LinkIncremental(); + } + if (this->Verbose) + { + if (!this->Incremental) + { + std::cout << "Visual Studio Non-Incremental Link\n"; + } + else + { + std::cout << "Visual Studio Incremental Link without manifests\n"; + } + } + return LinkNonIncremental(); +} + +int cmVSLink::LinkIncremental() { // This follows the steps listed here: // http://blogs.msdn.com/zakramer/archive/2006/05/22/603558.aspx @@ -1528,161 +1619,118 @@ int cmcmd::VisualStudioLinkIncremental(std::vector<std::string>& args, // 7. Finally, the Linker does another incremental link, but since the // only thing that has changed is the *.res file that contains the // manifest it is a short link. - std::vector<std::string> linkCommand; - std::string targetName; - if(cmcmd::ParseVisualStudioLinkCommand(args, linkCommand, targetName) == -1) - { - return -1; - } - std::string manifestArg = "/MANIFESTFILE:"; - std::vector<std::string> rcCommand; - rcCommand.push_back(cmSystemTools::FindProgram("rc.exe")); - std::vector<std::string> mtCommand; - mtCommand.push_back(cmSystemTools::FindProgram("mt.exe")); - std::string tempManifest; - tempManifest = targetName; - tempManifest += ".intermediate.manifest"; - std::string resourceInputFile = targetName; - resourceInputFile += ".resource.txt"; - if(verbose) + + // Create a resource file referencing the manifest. + std::string absManifestFile = + cmSystemTools::CollapseFullPath(this->ManifestFile); + if (this->Verbose) { - std::cout << "Create " << resourceInputFile << "\n"; + std::cout << "Create " << this->ManifestFileRC << "\n"; } - // Create input file for rc command - cmsys::ofstream fout(resourceInputFile.c_str()); - if(!fout) + { + cmsys::ofstream fout(this->ManifestFileRC.c_str()); + if (!fout) { return -1; } - std::string manifestFile = targetName; - manifestFile += ".embed.manifest"; - std::string fullPath= cmSystemTools::CollapseFullPath(manifestFile); - fout << type << " /* CREATEPROCESS_MANIFEST_RESOURCE_ID " - "*/ 24 /* RT_MANIFEST */ " << "\"" << fullPath << "\""; - fout.close(); - manifestArg += tempManifest; - // add the manifest arg to the linkCommand - linkCommand.push_back("/MANIFEST"); - linkCommand.push_back(manifestArg); - // if manifestFile is not yet created, create an - // empty one - if(!cmSystemTools::FileExists(manifestFile.c_str())) + fout << this->Type << " /* CREATEPROCESS_MANIFEST_RESOURCE_ID */ " + "24 /* RT_MANIFEST */ \"" << absManifestFile << "\""; + } + + // If we have not previously generated a manifest file, + // generate an empty one so the resource compiler succeeds. + if (!cmSystemTools::FileExists(this->ManifestFile)) { - if(verbose) + if (this->Verbose) { - std::cout << "Create empty: " << manifestFile << "\n"; + std::cout << "Create empty: " << this->ManifestFile << "\n"; } - cmsys::ofstream foutTmp(manifestFile.c_str()); + cmsys::ofstream foutTmp(this->ManifestFile.c_str()); } - std::string resourceFile = manifestFile; - resourceFile += ".res"; - // add the resource file to the end of the link command - linkCommand.push_back(resourceFile); - std::string outputOpt = "/fo"; - outputOpt += resourceFile; - rcCommand.push_back(outputOpt); - rcCommand.push_back(resourceInputFile); - // Run rc command to create resource - if(!cmcmd::RunCommand("RC Pass 1", rcCommand, verbose)) - { - return -1; - } - // Now run the link command to link and create manifest - if(!cmcmd::RunCommand("LINK Pass 1", linkCommand, verbose)) + + // Compile the resource file. + std::vector<std::string> rcCommand; + rcCommand.push_back(cmSystemTools::FindProgram("rc.exe")); + rcCommand.push_back("/fo" + this->ManifestFileRes); + rcCommand.push_back(this->ManifestFileRC); + if (!RunCommand("RC Pass 1", rcCommand, this->Verbose)) { return -1; } - // create mt command - std::string outArg("/out:"); - outArg+= manifestFile; - mtCommand.push_back("/nologo"); - mtCommand.push_back(outArg); - mtCommand.push_back("/notify_update"); - mtCommand.push_back("/manifest"); - mtCommand.push_back(tempManifest); - // now run mt.exe to create the final manifest file - int mtRet =0; - if(!cmcmd::RunCommand("MT", mtCommand, verbose, &mtRet)) + + // Run the link command (possibly generates intermediate manifest). + if (!RunCommand("LINK Pass 1", this->LinkCommand, this->Verbose)) { return -1; } - // if mt returns 0, then the manifest was not changed and - // we do not need to do another link step - if(mtRet == 0) - { - return 0; - } - // check for magic mt return value if mt returns the magic number - // 1090650113 then it means that it updated the manifest file and we need - // to do the final link. If mt has any value other than 0 or 1090650113 - // then there was some problem with the command itself and there was an - // error so return the error code back out of cmake so make can report it. - // (when hosted on a posix system the value is 187) - if(mtRet != 1090650113 && mtRet != 187) + + // Run the manifest tool to create the final manifest. + int mtRet = this->RunMT("/out:" + this->ManifestFile, true); + + // If mt returns 1090650113 (or 187 on a posix host) then it updated the + // manifest file so we need to embed it again. Otherwise we are done. + if (mtRet != 1090650113 && mtRet != 187) { return mtRet; } - // update the resource file with the new manifest from the mt command. - if(!cmcmd::RunCommand("RC Pass 2", rcCommand, verbose)) + + // Compile the resource file again. + if (!RunCommand("RC Pass 2", rcCommand, this->Verbose)) { return -1; } - // Run the final incremental link that will put the new manifest resource - // into the file incrementally. - if(!cmcmd::RunCommand("FINAL LINK", linkCommand, verbose)) + + // Link incrementally again to use the updated resource. + if (!RunCommand("FINAL LINK", this->LinkCommand, this->Verbose)) { return -1; } return 0; } -int cmcmd::VisualStudioLinkNonIncremental(std::vector<std::string>& args, - int type, - bool hasManifest, - bool verbose) +int cmVSLink::LinkNonIncremental() { - std::vector<std::string> linkCommand; - std::string targetName; - if(cmcmd::ParseVisualStudioLinkCommand(args, linkCommand, targetName) == -1) - { - return -1; - } - // Run the link command as given - if (hasManifest) - { - linkCommand.push_back("/MANIFEST"); - } - if(!cmcmd::RunCommand("LINK", linkCommand, verbose)) + // Run the link command (possibly generates intermediate manifest). + if (!RunCommand("LINK", this->LinkCommand, this->Verbose)) { return -1; } - if(!hasManifest) + + // If we have no manifest files we are done. + if (!this->LinkGeneratesManifest && this->UserManifests.empty()) { return 0; } + + // Run the manifest tool to embed the final manifest in the binary. + std::string mtOut = + "/outputresource:" + this->TargetFile + (this->Type == 1? ";#1" : ";#2"); + return this->RunMT(mtOut, false); +} + +int cmVSLink::RunMT(std::string const& out, bool notify) +{ std::vector<std::string> mtCommand; mtCommand.push_back(cmSystemTools::FindProgram("mt.exe")); mtCommand.push_back("/nologo"); mtCommand.push_back("/manifest"); - std::string manifestFile = targetName; - manifestFile += ".manifest"; - mtCommand.push_back(manifestFile); - std::string outresource = "/outputresource:"; - outresource += targetName; - outresource += ";#"; - if(type == 1) + if (this->LinkGeneratesManifest) { - outresource += "1"; + mtCommand.push_back(this->LinkerManifestFile); } - else if(type == 2) + mtCommand.insert(mtCommand.end(), + this->UserManifests.begin(), this->UserManifests.end()); + mtCommand.push_back(out); + if (notify) { - outresource += "2"; + // Add an undocumented option that enables a special return + // code to notify us when the manifest is modified. + mtCommand.push_back("/notify_update"); } - mtCommand.push_back(outresource); - // Now use the mt tool to embed the manifest into the exe or dll - if(!cmcmd::RunCommand("MT", mtCommand, verbose)) + int mtRet = 0; + if (!RunCommand("MT", mtCommand, this->Verbose, &mtRet)) { return -1; } - return 0; + return mtRet; } diff --git a/Source/cmcmd.h b/Source/cmcmd.h index 2bfbae7..64b2406 100644 --- a/Source/cmcmd.h +++ b/Source/cmcmd.h @@ -35,20 +35,6 @@ protected: static int WindowsCEEnvironment(const char* version, const std::string& name); static int VisualStudioLink(std::vector<std::string>& args, int type); - static int VisualStudioLinkIncremental(std::vector<std::string>& args, - int type, - bool verbose); - static int VisualStudioLinkNonIncremental(std::vector<std::string>& args, - int type, - bool hasManifest, - bool verbose); - static int ParseVisualStudioLinkCommand(std::vector<std::string>& args, - std::vector<std::string>& command, - std::string& targetName); - static bool RunCommand(const char* comment, - std::vector<std::string>& command, - bool verbose, - int* retCodeOut = 0); }; #endif |