diff options
Diffstat (limited to 'Source')
192 files changed, 5451 insertions, 3171 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index a4dd918..5611e55 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -216,6 +216,8 @@ set(SRCS cmFileTimeComparison.cxx cmFileTimeComparison.h cmFortranParserImpl.cxx + cmFSPermissions.cxx + cmFSPermissions.h cmGeneratedFileStream.cxx cmGeneratorExpressionContext.cxx cmGeneratorExpressionContext.h @@ -309,11 +311,14 @@ set(SRCS cmPropertyMap.h cmQtAutoGen.cxx cmQtAutoGen.h - cmQtAutoGenDigest.h + cmQtAutoGenerator.cxx + cmQtAutoGenerator.h cmQtAutoGeneratorInitializer.cxx cmQtAutoGeneratorInitializer.h - cmQtAutoGenerators.cxx - cmQtAutoGenerators.h + cmQtAutoGeneratorMocUic.cxx + cmQtAutoGeneratorMocUic.h + cmQtAutoGeneratorRcc.cxx + cmQtAutoGeneratorRcc.h cmRST.cxx cmRST.h cmScriptGenerator.h @@ -343,6 +348,8 @@ set(SRCS cmTestGenerator.cxx cmTestGenerator.h cmUuid.cxx + cmUVHandlePtr.cxx + cmUVHandlePtr.h cmVariableWatch.cxx cmVariableWatch.h cmVersion.cxx @@ -593,6 +600,7 @@ set(SRCS cm_utf8.c cm_codecvt.hxx cm_codecvt.cxx + cm_thread.hxx ) SET_PROPERTY(SOURCE cmProcessOutput.cxx APPEND PROPERTY COMPILE_DEFINITIONS @@ -915,7 +923,7 @@ if(UNIX) # OpenBSD and also Linux and OSX. Look for the header and # the library; it's a warning on FreeBSD if they're not # found, and informational on other platforms. - find_path(FREEBSD_PKG_INCLUDE_DIRS "pkg.h" PATHS /usr/local) + find_path(FREEBSD_PKG_INCLUDE_DIRS "pkg.h") if(FREEBSD_PKG_INCLUDE_DIRS) find_library(FREEBSD_PKG_LIBRARIES pkg @@ -936,8 +944,13 @@ if(UNIX) endif() endif() -if(WIN32) +if(CYGWIN) + find_package(LibUUID) +endif() +if(WIN32 OR (CYGWIN AND LibUUID_FOUND)) set(CPACK_SRCS ${CPACK_SRCS} + CPack/Wix/cmCMakeToWixPath.cxx + CPack/Wix/cmCMakeToWixPath.h CPack/WiX/cmCPackWIXGenerator.cxx CPack/WiX/cmCPackWIXGenerator.h CPack/WiX/cmWIXAccessControlList.cxx @@ -958,7 +971,7 @@ if(WIN32) CPack/WiX/cmWIXShortcut.h CPack/WiX/cmWIXSourceWriter.cxx CPack/WiX/cmWIXSourceWriter.h - ) + ) endif() if(APPLE) @@ -991,6 +1004,11 @@ if(APPLE) "See CMakeFiles/CMakeError.log for details of the failure.") endif() endif() +if(CYGWIN AND LibUUID_FOUND) + target_link_libraries(CPackLib ${LibUUID_LIBRARIES}) + include_directories(CPackLib ${LibUUID_INCLUDE_DIRS}) + set_property(SOURCE CPack/cmCPackGeneratorFactory.cxx PROPERTY COMPILE_DEFINITIONS HAVE_LIBUUID) +endif() if(CPACK_ENABLE_FREEBSD_PKG AND FREEBSD_PKG_INCLUDE_DIRS AND FREEBSD_PKG_LIBRARIES) target_link_libraries(CPackLib ${FREEBSD_PKG_LIBRARIES}) include_directories(${FREEBSD_PKG_INCLUDE_DIRS}) @@ -1047,6 +1065,19 @@ endif() include (${CMake_BINARY_DIR}/Source/LocalUserOptions.cmake OPTIONAL) include (${CMake_SOURCE_DIR}/Source/LocalUserOptions.cmake OPTIONAL) +if(WIN32) + # Add Windows executable version information. + configure_file("CMakeVersion.rc.in" "CMakeVersion.rc" @ONLY) + + # We use a separate object library for this to work around a limitation of + # MinGW's windres tool with spaces in the path to the include directories. + add_library(CMakeVersion OBJECT "${CMAKE_CURRENT_BINARY_DIR}/CMakeVersion.rc") + set_property(TARGET CMakeVersion PROPERTY INCLUDE_DIRECTORIES "") + foreach(_tool ${_tools}) + target_sources(${_tool} PRIVATE $<TARGET_OBJECTS:CMakeVersion>) + endforeach() +endif() + # Install tools foreach(_tool ${_tools}) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 8a93c36..305aa87 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 10) -set(CMake_VERSION_PATCH 0) -#set(CMake_VERSION_RC 0) +set(CMake_VERSION_PATCH 20171201) +#set(CMake_VERSION_RC 1) diff --git a/Source/CMakeVersion.rc.in b/Source/CMakeVersion.rc.in new file mode 100644 index 0000000..60e14e5 --- /dev/null +++ b/Source/CMakeVersion.rc.in @@ -0,0 +1,37 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ + +#define VER_FILEVERSION @CMake_VERSION_MAJOR@,@CMake_VERSION_MINOR@,@CMake_VERSION_PATCH@ +#define VER_FILEVERSION_STR "@CMake_VERSION_MAJOR@.@CMake_VERSION_MINOR@.@CMake_VERSION_PATCH@\0" + +#define VER_PRODUCTVERSION @CMake_VERSION_MAJOR@,@CMake_VERSION_MINOR@,@CMake_VERSION_PATCH@ +#define VER_PRODUCTVERSION_STR "@CMake_VERSION@\0" + +/* Version-information resource identifier. */ +#define VS_VERSION_INFO 1 + +VS_VERSION_INFO VERSIONINFO +FILEVERSION VER_FILEVERSION +PRODUCTVERSION VER_PRODUCTVERSION +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + BEGIN + VALUE "FileVersion", VER_FILEVERSION_STR + VALUE "ProductVersion", VER_PRODUCTVERSION_STR + END + END + + BLOCK "VarFileInfo" + BEGIN + /* The following line should only be modified for localized versions. */ + /* It consists of any number of WORD,WORD pairs, with each pair */ + /* describing a language,codepage combination supported by the file. */ + /* */ + /* For example, a file might have values "0x409,1252" indicating that it */ + /* supports English language (0x409) in the Windows ANSI codepage (1252). */ + + VALUE "Translation", 0x409, 1252 + END +END diff --git a/Source/CPack/WiX/cmCMakeToWixPath.cxx b/Source/CPack/WiX/cmCMakeToWixPath.cxx new file mode 100644 index 0000000..0b0e42a --- /dev/null +++ b/Source/CPack/WiX/cmCMakeToWixPath.cxx @@ -0,0 +1,39 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmCMakeToWixPath.h" + +#include "cmSystemTools.h" + +#include <string> +#include <vector> + +#ifdef __CYGWIN__ +#include <sys/cygwin.h> +std::string CMakeToWixPath(const std::string& cygpath) +{ + std::vector<char> winpath_chars; + ssize_t winpath_size; + + // Get the required buffer size. + winpath_size = + cygwin_conv_path(CCP_POSIX_TO_WIN_A, cygpath.c_str(), nullptr, 0); + if (winpath_size <= 0) { + return cygpath; + } + + winpath_chars.assign(static_cast<size_t>(winpath_size) + 1, '\0'); + + winpath_size = cygwin_conv_path(CCP_POSIX_TO_WIN_A, cygpath.c_str(), + winpath_chars.data(), winpath_size); + if (winpath_size < 0) { + return cygpath; + } + + return cmSystemTools::TrimWhitespace(winpath_chars.data()); +} +#else +std::string CMakeToWixPath(const std::string& path) +{ + return path; +} +#endif diff --git a/Source/CPack/WiX/cmCMakeToWixPath.h b/Source/CPack/WiX/cmCMakeToWixPath.h new file mode 100644 index 0000000..8bb9e04 --- /dev/null +++ b/Source/CPack/WiX/cmCMakeToWixPath.h @@ -0,0 +1,12 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmCMakeToWixPath_h +#define cmCMakeToWixPath_h + +#include "cmConfigure.h" //IWYU pragma: keep + +#include <string> + +std::string CMakeToWixPath(const std::string& cygpath); + +#endif // cmCMakeToWixPath_h diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx index ba07d08..a0bc0ea 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx +++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx @@ -22,7 +22,13 @@ #include "cmsys/FStream.hxx" #include "cmsys/SystemTools.hxx" -#include <rpc.h> // for GUID generation +#ifdef _WIN32 +#include <rpc.h> // for GUID generation (windows only) +#else +#include <uuid/uuid.h> // for GUID generation (libuuid) +#endif + +#include "cmCMakeToWixPath.h" cmCPackWIXGenerator::cmCPackWIXGenerator() : Patch(0) @@ -110,7 +116,7 @@ bool cmCPackWIXGenerator::RunLightCommand(std::string const& objectFiles) std::ostringstream command; command << QuotePath(executable); command << " -nologo"; - command << " -out " << QuotePath(packageFileNames.at(0)); + command << " -out " << QuotePath(CMakeToWixPath(packageFileNames.at(0))); for (std::string const& ext : this->LightExtensions) { command << " -ext " << QuotePath(ext); @@ -270,11 +276,12 @@ bool cmCPackWIXGenerator::PackageFilesImpl() std::string objectFilename = this->CPackTopLevel + "/" + uniqueBaseName + ".wixobj"; - if (!RunCandleCommand(sourceFilename, objectFilename)) { + if (!RunCandleCommand(CMakeToWixPath(sourceFilename), + CMakeToWixPath(objectFilename))) { return false; } - objectFiles << " " << QuotePath(objectFilename); + objectFiles << " " << QuotePath(CMakeToWixPath(objectFilename)); } AppendUserSuppliedExtraObjects(objectFiles); @@ -320,10 +327,10 @@ void cmCPackWIXGenerator::CreateWiXVariablesIncludeFile() CopyDefinition(includeFile, "CPACK_PACKAGE_VENDOR"); CopyDefinition(includeFile, "CPACK_PACKAGE_NAME"); CopyDefinition(includeFile, "CPACK_PACKAGE_VERSION"); - CopyDefinition(includeFile, "CPACK_WIX_LICENSE_RTF"); - CopyDefinition(includeFile, "CPACK_WIX_PRODUCT_ICON"); - CopyDefinition(includeFile, "CPACK_WIX_UI_BANNER"); - CopyDefinition(includeFile, "CPACK_WIX_UI_DIALOG"); + CopyDefinition(includeFile, "CPACK_WIX_LICENSE_RTF", DefinitionType::PATH); + CopyDefinition(includeFile, "CPACK_WIX_PRODUCT_ICON", DefinitionType::PATH); + CopyDefinition(includeFile, "CPACK_WIX_UI_BANNER", DefinitionType::PATH); + CopyDefinition(includeFile, "CPACK_WIX_UI_DIALOG", DefinitionType::PATH); SetOptionIfNotSet("CPACK_WIX_PROGRAM_MENU_FOLDER", GetOption("CPACK_PACKAGE_NAME")); CopyDefinition(includeFile, "CPACK_WIX_PROGRAM_MENU_FOLDER"); @@ -390,11 +397,16 @@ void cmCPackWIXGenerator::CreateWiXProductFragmentIncludeFile() } void cmCPackWIXGenerator::CopyDefinition(cmWIXSourceWriter& source, - std::string const& name) + std::string const& name, + DefinitionType type) { const char* value = GetOption(name.c_str()); if (value) { - AddDefinition(source, name, value); + if (type == DefinitionType::PATH) { + AddDefinition(source, name, CMakeToWixPath(value)); + } else { + AddDefinition(source, name, value); + } } } @@ -966,6 +978,7 @@ std::string cmCPackWIXGenerator::GetArchitecture() const std::string cmCPackWIXGenerator::GenerateGUID() { +#ifdef _WIN32 UUID guid; UuidCreate(&guid); @@ -975,6 +988,14 @@ std::string cmCPackWIXGenerator::GenerateGUID() std::string result = cmsys::Encoding::ToNarrow(reinterpret_cast<wchar_t*>(tmp)); RpcStringFreeW(&tmp); +#else + uuid_t guid; + char guid_ch[37] = { 0 }; + + uuid_generate(guid); + uuid_unparse(guid, guid_ch); + std::string result = guid_ch; +#endif return cmSystemTools::UpperCase(result); } diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.h b/Source/CPack/WiX/cmCPackWIXGenerator.h index b2633a7..128a04d 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.h +++ b/Source/CPack/WiX/cmCPackWIXGenerator.h @@ -48,6 +48,12 @@ private: typedef std::map<std::string, size_t> ambiguity_map_t; typedef std::set<std::string> extension_set_t; + enum class DefinitionType + { + STRING, + PATH + }; + bool InitializeWiXConfiguration(); bool PackageFilesImpl(); @@ -58,7 +64,8 @@ private: void CreateWiXProductFragmentIncludeFile(); - void CopyDefinition(cmWIXSourceWriter& source, std::string const& name); + void CopyDefinition(cmWIXSourceWriter& source, std::string const& name, + DefinitionType type = DefinitionType::STRING); void AddDefinition(cmWIXSourceWriter& source, std::string const& name, std::string const& value); diff --git a/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx b/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx index b4cd1a3..dd3caf9 100644 --- a/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx +++ b/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx @@ -11,6 +11,8 @@ #include "cm_sys_stat.h" +#include "cmCMakeToWixPath.h" + cmWIXFilesSourceWriter::cmWIXFilesSourceWriter(cmCPackLog* logger, std::string const& filename, GuidType componentGuidType) @@ -139,7 +141,7 @@ std::string cmWIXFilesSourceWriter::EmitComponentFile( patch.ApplyFragment(componentId, *this); BeginElement("File"); AddAttribute("Id", fileId); - AddAttribute("Source", filePath); + AddAttribute("Source", CMakeToWixPath(filePath)); AddAttribute("KeyPath", "yes"); mode_t fileMode = 0; diff --git a/Source/CPack/WiX/cmWIXPatchParser.cxx b/Source/CPack/WiX/cmWIXPatchParser.cxx index e6aeed3..c6ca944 100644 --- a/Source/CPack/WiX/cmWIXPatchParser.cxx +++ b/Source/CPack/WiX/cmWIXPatchParser.cxx @@ -90,7 +90,7 @@ void cmWIXPatchParser::StartFragment(const char** attributes) } } - /* add any additional attributes for the fragement */ + /* add any additional attributes for the fragment */ if (!new_element) { ReportValidationError("No 'Id' specified for 'CPackWixFragment' element"); } else { diff --git a/Source/CPack/bills-comments.txt b/Source/CPack/bills-comments.txt index c3b4ee8..1aaf9af 100644 --- a/Source/CPack/bills-comments.txt +++ b/Source/CPack/bills-comments.txt @@ -31,7 +31,7 @@ cmCPackGenericGenerator::ProcessGenerator // DoPackage cmCPackGenericGenerator::InstallProject is used for both source and binary -packages. It is controled based on values set in CPACK_ variables. +packages. It is controlled based on values set in CPACK_ variables. InstallProject diff --git a/Source/CPack/cmCPackDragNDropGenerator.cxx b/Source/CPack/cmCPackDragNDropGenerator.cxx index 1e1543f..bb35623 100644 --- a/Source/CPack/cmCPackDragNDropGenerator.cxx +++ b/Source/CPack/cmCPackDragNDropGenerator.cxx @@ -411,6 +411,7 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir, std::string temp_image = this->GetOption("CPACK_TOPLEVEL_DIRECTORY"); temp_image += "/temp.dmg"; + std::string create_error; std::ostringstream temp_image_command; temp_image_command << this->GetOption("CPACK_COMMAND_HDIUTIL"); temp_image_command << " create"; @@ -421,9 +422,11 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir, temp_image_command << " -format " << temp_image_format; temp_image_command << " \"" << temp_image << "\""; - if (!this->RunCommand(temp_image_command)) { + if (!this->RunCommand(temp_image_command, &create_error)) { cmCPackLogger(cmCPackLog::LOG_ERROR, - "Error generating temporary disk image." << std::endl); + "Error generating temporary disk image." << std::endl + << create_error + << std::endl); return 0; } @@ -464,15 +467,17 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir, // Optionally set the custom icon flag for the image ... if (!had_error && !cpack_package_icon.empty()) { + std::string error; std::ostringstream setfile_command; setfile_command << this->GetOption("CPACK_COMMAND_SETFILE"); setfile_command << " -a C"; setfile_command << " \"" << temp_mount << "\""; - if (!this->RunCommand(setfile_command)) { + if (!this->RunCommand(setfile_command, &error)) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Error assigning custom icon to temporary disk image." - << std::endl); + << std::endl + << error << std::endl); had_error = true; } @@ -717,9 +722,12 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir, final_image_command << " zlib-level=9"; final_image_command << " -o \"" << output_file << "\""; - if (!this->RunCommand(final_image_command)) { + std::string convert_error; + + if (!this->RunCommand(final_image_command, &convert_error)) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Error compressing disk image." - << std::endl); + << std::endl + << convert_error << std::endl); return 0; } diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx index ecb5adb..be75a9f 100644 --- a/Source/CPack/cmCPackGenerator.cxx +++ b/Source/CPack/cmCPackGenerator.cxx @@ -12,6 +12,7 @@ #include "cmCPackComponentGroup.h" #include "cmCPackLog.h" #include "cmCryptoHash.h" +#include "cmFSPermissions.h" #include "cmGeneratedFileStream.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" @@ -201,6 +202,29 @@ int cmCPackGenerator::InstallProject() cmSystemTools::PutEnv("DESTDIR="); } + // prepare default created directory permissions + mode_t default_dir_mode_v = 0; + mode_t* default_dir_mode = nullptr; + const char* default_dir_install_permissions = + this->GetOption("CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS"); + if (default_dir_install_permissions && *default_dir_install_permissions) { + std::vector<std::string> items; + cmSystemTools::ExpandListArgument(default_dir_install_permissions, items); + for (const auto& arg : items) { + if (!cmFSPermissions::stringToModeT(arg, default_dir_mode_v)) { + cmCPackLogger(cmCPackLog::LOG_ERROR, "Invalid permission value '" + << arg + << "'." + " CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS " + "value is invalid." + << std::endl); + return 0; + } + } + + default_dir_mode = &default_dir_mode_v; + } + // If the CPackConfig file sets CPACK_INSTALL_COMMANDS then run them // as listed if (!this->InstallProjectViaInstallCommands(setDestDir, @@ -218,15 +242,15 @@ int cmCPackGenerator::InstallProject() // If the CPackConfig file sets CPACK_INSTALLED_DIRECTORIES // then glob it and copy it to CPACK_TEMPORARY_DIRECTORY // This is used in Source packaging - if (!this->InstallProjectViaInstalledDirectories(setDestDir, - tempInstallDirectory)) { + if (!this->InstallProjectViaInstalledDirectories( + setDestDir, tempInstallDirectory, default_dir_mode)) { return 0; } // If the project is a CMAKE project then run pre-install // and then read the cmake_install script to run it - if (!this->InstallProjectViaInstallCMakeProjects(setDestDir, - bareTempInstallDirectory)) { + if (!this->InstallProjectViaInstallCMakeProjects( + setDestDir, bareTempInstallDirectory, default_dir_mode)) { return 0; } @@ -274,7 +298,8 @@ int cmCPackGenerator::InstallProjectViaInstallCommands( } int cmCPackGenerator::InstallProjectViaInstalledDirectories( - bool setDestDir, const std::string& tempInstallDirectory) + bool setDestDir, const std::string& tempInstallDirectory, + const mode_t* default_dir_mode) { (void)setDestDir; (void)tempInstallDirectory; @@ -385,7 +410,8 @@ int cmCPackGenerator::InstallProjectViaInstalledDirectories( // make sure directory exists for symlink std::string destDir = cmSystemTools::GetFilenamePath(symlinked.second); - if (!destDir.empty() && !cmSystemTools::MakeDirectory(destDir)) { + if (!destDir.empty() && + !cmSystemTools::MakeDirectory(destDir, default_dir_mode)) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot create dir: " << destDir << "\nTrying to create symlink: " << symlinked.second << "--> " << symlinked.first @@ -464,7 +490,8 @@ int cmCPackGenerator::InstallProjectViaInstallScript( } int cmCPackGenerator::InstallProjectViaInstallCMakeProjects( - bool setDestDir, const std::string& baseTempInstallDirectory) + bool setDestDir, const std::string& baseTempInstallDirectory, + const mode_t* default_dir_mode) { const char* cmakeProjects = this->GetOption("CPACK_INSTALL_CMAKE_PROJECTS"); const char* cmakeGenerator = this->GetOption("CPACK_CMAKE_GENERATOR"); @@ -631,6 +658,13 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects( } } + const char* default_dir_inst_permissions = + this->GetOption("CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS"); + if (default_dir_inst_permissions && *default_dir_inst_permissions) { + mf.AddDefinition("CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS", + default_dir_inst_permissions); + } + if (!setDestDir) { tempInstallDirectory += this->GetPackagingInstallPrefix(); } @@ -690,7 +724,7 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects( cmCPackLogger(cmCPackLog::LOG_DEBUG, "- Creating directory: '" << dir << "'" << std::endl); - if (!cmsys::SystemTools::MakeDirectory(dir.c_str())) { + if (!cmsys::SystemTools::MakeDirectory(dir, default_dir_mode)) { cmCPackLogger( cmCPackLog::LOG_ERROR, "Problem creating temporary directory: " << dir << std::endl); @@ -700,8 +734,8 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects( mf.AddDefinition("CMAKE_INSTALL_PREFIX", tempInstallDirectory.c_str()); - if (!cmsys::SystemTools::MakeDirectory( - tempInstallDirectory.c_str())) { + if (!cmsys::SystemTools::MakeDirectory(tempInstallDirectory, + default_dir_mode)) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem creating temporary directory: " << tempInstallDirectory << std::endl); diff --git a/Source/CPack/cmCPackGenerator.h b/Source/CPack/cmCPackGenerator.h index 4e3a6e0..8100b66 100644 --- a/Source/CPack/cmCPackGenerator.h +++ b/Source/CPack/cmCPackGenerator.h @@ -12,6 +12,7 @@ #include "cmCPackComponentGroup.h" #include "cmSystemTools.h" +#include "cm_sys_stat.h" class cmCPackLog; class cmInstalledFile; @@ -168,9 +169,11 @@ protected: virtual int InstallProjectViaInstallScript( bool setDestDir, const std::string& tempInstallDirectory); virtual int InstallProjectViaInstalledDirectories( - bool setDestDir, const std::string& tempInstallDirectory); + bool setDestDir, const std::string& tempInstallDirectory, + const mode_t* default_dir_mode); virtual int InstallProjectViaInstallCMakeProjects( - bool setDestDir, const std::string& tempInstallDirectory); + bool setDestDir, const std::string& tempInstallDirectory, + const mode_t* default_dir_mode); /** * The various level of support of diff --git a/Source/CPack/cmCPackGeneratorFactory.cxx b/Source/CPack/cmCPackGeneratorFactory.cxx index 4b81bbc..47e7527 100644 --- a/Source/CPack/cmCPackGeneratorFactory.cxx +++ b/Source/CPack/cmCPackGeneratorFactory.cxx @@ -40,7 +40,7 @@ #include "cmCPackRPMGenerator.h" #endif -#ifdef _WIN32 +#if defined(_WIN32) || (defined(__CYGWIN__) && defined(HAVE_LIBUUID)) #include "WiX/cmCPackWIXGenerator.h" #endif @@ -87,7 +87,7 @@ cmCPackGeneratorFactory::cmCPackGeneratorFactory() this->RegisterGenerator("7Z", "7-Zip file format", cmCPack7zGenerator::CreateGenerator); } -#ifdef _WIN32 +#if defined(_WIN32) || (defined(__CYGWIN__) && defined(HAVE_LIBUUID)) if (cmCPackWIXGenerator::CanGenerate()) { this->RegisterGenerator("WIX", "MSI file format via WiX tools", cmCPackWIXGenerator::CreateGenerator); diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx index a0d68a0..b603758 100644 --- a/Source/CTest/cmCTestBuildAndTestHandler.cxx +++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx @@ -10,6 +10,7 @@ #include "cmake.h" #include "cmsys/Process.h" +#include <chrono> #include <stdlib.h> cmCTestBuildAndTestHandler::cmCTestBuildAndTestHandler() @@ -192,7 +193,7 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) // we need to honor the timeout specified, the timeout include cmake, build // and test time - double clock_start = cmSystemTools::GetTime(); + auto clock_start = std::chrono::steady_clock::now(); // make sure the binary dir is there out << "Internal cmake changing into directory: " << this->BinaryDir @@ -222,10 +223,12 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) this->BuildTargets.push_back(""); } for (std::string const& tar : this->BuildTargets) { - double remainingTime = 0; + std::chrono::duration<double> remainingTime = std::chrono::seconds(0); if (this->Timeout > 0) { - remainingTime = this->Timeout - cmSystemTools::GetTime() + clock_start; - if (remainingTime <= 0) { + remainingTime = std::chrono::duration<double>(this->Timeout) - + std::chrono::duration_cast<std::chrono::seconds>( + std::chrono::steady_clock::now() - clock_start); + if (remainingTime <= std::chrono::seconds(0)) { if (outstring) { *outstring = "--build-and-test timeout exceeded. "; } @@ -248,7 +251,7 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) int retVal = cm.GetGlobalGenerator()->Build( this->SourceDir, this->BinaryDir, this->BuildProject, tar, output, this->BuildMakeProgram, config, !this->BuildNoClean, false, false, - remainingTime); + remainingTime.count()); out << output; // if the build failed then return if (retVal) { @@ -320,10 +323,12 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) out << "\n"; // how much time is remaining - double remainingTime = 0; + std::chrono::duration<double> remainingTime = std::chrono::seconds(0); if (this->Timeout > 0) { - remainingTime = this->Timeout - cmSystemTools::GetTime() + clock_start; - if (remainingTime <= 0) { + remainingTime = std::chrono::duration<double>(this->Timeout) - + std::chrono::duration_cast<std::chrono::seconds>( + std::chrono::steady_clock::now() - clock_start); + if (remainingTime <= std::chrono::seconds(0)) { if (outstring) { *outstring = "--build-and-test timeout exceeded. "; } @@ -332,7 +337,7 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) } int runTestRes = this->CTest->RunTest(testCommand, &outs, &retval, nullptr, - remainingTime, nullptr); + remainingTime.count(), nullptr); if (runTestRes != cmsysProcess_State_Exited || retval != 0) { out << "Test command failed: " << testCommand[0] << "\n"; diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx index f4fc769..f25c9c3 100644 --- a/Source/CTest/cmCTestBuildHandler.cxx +++ b/Source/CTest/cmCTestBuildHandler.cxx @@ -17,6 +17,7 @@ #include <set> #include <stdlib.h> #include <string.h> +#include <type_traits> static const char* cmCTestErrorMatches[] = { "^[Bb]us [Ee]rror", @@ -327,7 +328,7 @@ int cmCTestBuildHandler::ProcessHandler() // Create a last build log cmGeneratedFileStream ofs; - double elapsed_time_start = cmSystemTools::GetTime(); + auto elapsed_time_start = std::chrono::steady_clock::now(); if (!this->StartLogFile("Build", ofs)) { cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot create build log file" << std::endl); @@ -406,7 +407,7 @@ int cmCTestBuildHandler::ProcessHandler() // Remember start build time this->StartBuild = this->CTest->CurrentTime(); - this->StartBuildTime = cmSystemTools::GetTime(); + this->StartBuildTime = std::chrono::system_clock::now(); int retVal = 0; int res = cmsysProcess_State_Exited; if (!this->CTest->GetShowOnly()) { @@ -420,8 +421,9 @@ int cmCTestBuildHandler::ProcessHandler() // Remember end build time and calculate elapsed time this->EndBuild = this->CTest->CurrentTime(); - this->EndBuildTime = cmSystemTools::GetTime(); - double elapsed_build_time = cmSystemTools::GetTime() - elapsed_time_start; + this->EndBuildTime = std::chrono::system_clock::now(); + auto elapsed_build_time = + std::chrono::steady_clock::now() - elapsed_time_start; // Cleanups strings in the errors and warnings list. if (!this->SimplifySourceDir.empty()) { @@ -486,8 +488,7 @@ void cmCTestBuildHandler::GenerateXMLHeader(cmXMLWriter& xml) this->CTest->GenerateSubprojectsOutput(xml); xml.StartElement("Build"); xml.Element("StartDateTime", this->StartBuild); - xml.Element("StartBuildTime", - static_cast<unsigned int>(this->StartBuildTime)); + xml.Element("StartBuildTime", this->StartBuildTime); xml.Element("BuildCommand", this->GetMakeCommand()); } @@ -633,8 +634,8 @@ void cmCTestBuildHandler::GenerateXMLLogScraped(cmXMLWriter& xml) } } -void cmCTestBuildHandler::GenerateXMLFooter(cmXMLWriter& xml, - double elapsed_build_time) +void cmCTestBuildHandler::GenerateXMLFooter( + cmXMLWriter& xml, std::chrono::duration<double> elapsed_build_time) { xml.StartElement("Log"); xml.Attribute("Encoding", "base64"); @@ -642,9 +643,11 @@ void cmCTestBuildHandler::GenerateXMLFooter(cmXMLWriter& xml, xml.EndElement(); // Log xml.Element("EndDateTime", this->EndBuild); - xml.Element("EndBuildTime", static_cast<unsigned int>(this->EndBuildTime)); - xml.Element("ElapsedMinutes", - static_cast<int>(elapsed_build_time / 6) / 10.0); + xml.Element("EndBuildTime", this->EndBuildTime); + xml.Element( + "ElapsedMinutes", + std::chrono::duration_cast<std::chrono::minutes>(elapsed_build_time) + .count()); xml.EndElement(); // Build this->CTest->EndXML(xml); } diff --git a/Source/CTest/cmCTestBuildHandler.h b/Source/CTest/cmCTestBuildHandler.h index 6e71ad6..d1b9b2e 100644 --- a/Source/CTest/cmCTestBuildHandler.h +++ b/Source/CTest/cmCTestBuildHandler.h @@ -9,6 +9,7 @@ #include "cmProcessOutput.h" #include "cmsys/RegularExpression.hxx" +#include <chrono> #include <deque> #include <iosfwd> #include <stddef.h> @@ -86,14 +87,15 @@ private: void GenerateXMLHeader(cmXMLWriter& xml); void GenerateXMLLaunched(cmXMLWriter& xml); void GenerateXMLLogScraped(cmXMLWriter& xml); - void GenerateXMLFooter(cmXMLWriter& xml, double elapsed_build_time); + void GenerateXMLFooter(cmXMLWriter& xml, + std::chrono::duration<double> elapsed_build_time); bool IsLaunchedErrorFile(const char* fname); bool IsLaunchedWarningFile(const char* fname); std::string StartBuild; std::string EndBuild; - double StartBuildTime; - double EndBuildTime; + std::chrono::system_clock::time_point StartBuildTime; + std::chrono::system_clock::time_point EndBuildTime; std::vector<std::string> CustomErrorMatches; std::vector<std::string> CustomErrorExceptions; diff --git a/Source/CTest/cmCTestConfigureHandler.cxx b/Source/CTest/cmCTestConfigureHandler.cxx index 56a038e..ab77986 100644 --- a/Source/CTest/cmCTestConfigureHandler.cxx +++ b/Source/CTest/cmCTestConfigureHandler.cxx @@ -4,11 +4,12 @@ #include "cmCTest.h" #include "cmGeneratedFileStream.h" -#include "cmSystemTools.h" #include "cmXMLWriter.h" +#include <chrono> #include <ostream> #include <string> +#include <type_traits> cmCTestConfigureHandler::cmCTestConfigureHandler() { @@ -43,7 +44,7 @@ int cmCTestConfigureHandler::ProcessHandler() return -1; } - double elapsed_time_start = cmSystemTools::GetTime(); + auto elapsed_time_start = std::chrono::steady_clock::now(); std::string output; int retVal = 0; int res = 0; @@ -55,8 +56,7 @@ int cmCTestConfigureHandler::ProcessHandler() return 1; } std::string start_time = this->CTest->CurrentTime(); - unsigned int start_time_time = - static_cast<unsigned int>(cmSystemTools::GetTime()); + auto start_time_time = std::chrono::system_clock::now(); cmGeneratedFileStream ofs; this->StartLogFile("Configure", ofs); @@ -82,12 +82,11 @@ int cmCTestConfigureHandler::ProcessHandler() xml.Element("Log", output); xml.Element("ConfigureStatus", retVal); xml.Element("EndDateTime", this->CTest->CurrentTime()); - xml.Element("EndConfigureTime", - static_cast<unsigned int>(cmSystemTools::GetTime())); - xml.Element( - "ElapsedMinutes", - static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start) / 6) / - 10.0); + xml.Element("EndConfigureTime", std::chrono::system_clock::now()); + xml.Element("ElapsedMinutes", + std::chrono::duration_cast<std::chrono::minutes>( + std::chrono::steady_clock::now() - elapsed_time_start) + .count()); xml.EndElement(); // Configure this->CTest->EndXML(xml); } diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx index 56eeceb..bbfe9bd 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -21,11 +21,13 @@ #include "cmsys/Process.h" #include "cmsys/RegularExpression.hxx" #include <algorithm> +#include <chrono> #include <iomanip> #include <iterator> #include <sstream> #include <stdio.h> #include <stdlib.h> +#include <type_traits> #include <utility> class cmMakefile; @@ -173,14 +175,13 @@ void cmCTestCoverageHandler::StartCoverageLogXML(cmXMLWriter& xml) this->CTest->StartXML(xml, this->AppendXML); xml.StartElement("CoverageLog"); xml.Element("StartDateTime", this->CTest->CurrentTime()); - xml.Element("StartTime", - static_cast<unsigned int>(cmSystemTools::GetTime())); + xml.Element("StartTime", std::chrono::system_clock::now()); } void cmCTestCoverageHandler::EndCoverageLogXML(cmXMLWriter& xml) { xml.Element("EndDateTime", this->CTest->CurrentTime()); - xml.Element("EndTime", static_cast<unsigned int>(cmSystemTools::GetTime())); + xml.Element("EndTime", std::chrono::system_clock::now()); xml.EndElement(); // CoverageLog this->CTest->EndXML(xml); } @@ -281,8 +282,7 @@ int cmCTestCoverageHandler::ProcessHandler() } std::string coverage_start_time = this->CTest->CurrentTime(); - unsigned int coverage_start_time_time = - static_cast<unsigned int>(cmSystemTools::GetTime()); + auto coverage_start_time_time = std::chrono::system_clock::now(); std::string sourceDir = this->CTest->GetCTestConfiguration("SourceDirectory"); std::string binaryDir = this->CTest->GetCTestConfiguration("BuildDirectory"); @@ -290,13 +290,14 @@ int cmCTestCoverageHandler::ProcessHandler() this->LoadLabels(); cmGeneratedFileStream ofs; - double elapsed_time_start = cmSystemTools::GetTime(); + auto elapsed_time_start = std::chrono::steady_clock::now(); if (!this->StartLogFile("Coverage", ofs)) { cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot create LastCoverage.log file" << std::endl); } - ofs << "Performing coverage: " << elapsed_time_start << std::endl; + ofs << "Performing coverage: " + << elapsed_time_start.time_since_epoch().count() << std::endl; this->CleanCoverageLogFiles(ofs); cmSystemTools::ConvertToUnixSlashes(sourceDir); @@ -619,12 +620,11 @@ int cmCTestCoverageHandler::ProcessHandler() covSumXML.Element("LOC", total_lines); covSumXML.Element("PercentCoverage", percent_coverage); covSumXML.Element("EndDateTime", end_time); - covSumXML.Element("EndTime", - static_cast<unsigned int>(cmSystemTools::GetTime())); - covSumXML.Element( - "ElapsedMinutes", - static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start) / 6) / - 10.0); + covSumXML.Element("EndTime", std::chrono::system_clock::now()); + covSumXML.Element("ElapsedMinutes", + std::chrono::duration_cast<std::chrono::minutes>( + std::chrono::steady_clock::now() - elapsed_time_start) + .count()); covSumXML.EndElement(); // Coverage this->CTest->EndXML(covSumXML); @@ -1963,12 +1963,11 @@ int cmCTestCoverageHandler::RunBullseyeSourceSummary( return 0; } this->CTest->StartXML(xml, this->AppendXML); - double elapsed_time_start = cmSystemTools::GetTime(); + auto elapsed_time_start = std::chrono::steady_clock::now(); std::string coverage_start_time = this->CTest->CurrentTime(); xml.StartElement("Coverage"); xml.Element("StartDateTime", coverage_start_time); - xml.Element("StartTime", - static_cast<unsigned int>(cmSystemTools::GetTime())); + xml.Element("StartTime", std::chrono::system_clock::now()); std::string stdline; std::string errline; // expected output: @@ -2089,11 +2088,11 @@ int cmCTestCoverageHandler::RunBullseyeSourceSummary( xml.Element("LOC", total_functions); xml.Element("PercentCoverage", SAFEDIV(percent_coverage, number_files)); xml.Element("EndDateTime", end_time); - xml.Element("EndTime", static_cast<unsigned int>(cmSystemTools::GetTime())); - xml.Element( - "ElapsedMinutes", - static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start) / 6) / - 10.0); + xml.Element("EndTime", std::chrono::system_clock::now()); + xml.Element("ElapsedMinutes", + std::chrono::duration_cast<std::chrono::minutes>( + std::chrono::steady_clock::now() - elapsed_time_start) + .count()); xml.EndElement(); // Coverage this->CTest->EndXML(xml); diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx index 3efb039..2e7874d 100644 --- a/Source/CTest/cmCTestMemCheckHandler.cxx +++ b/Source/CTest/cmCTestMemCheckHandler.cxx @@ -10,9 +10,11 @@ #include "cmsys/FStream.hxx" #include "cmsys/Glob.hxx" #include "cmsys/RegularExpression.hxx" +#include <chrono> #include <iostream> #include <sstream> #include <string.h> +#include <type_traits> struct CatToErrorType { @@ -408,8 +410,10 @@ void cmCTestMemCheckHandler::GenerateDartOutput(cmXMLWriter& xml) xml.Element("EndDateTime", this->EndTest); xml.Element("EndTestTime", this->EndTestTime); - xml.Element("ElapsedMinutes", - static_cast<int>(this->ElapsedTestingTime / 6) / 10.0); + xml.Element( + "ElapsedMinutes", + std::chrono::duration_cast<std::chrono::minutes>(this->ElapsedTestingTime) + .count()); xml.EndElement(); // DynamicAnalysis this->CTest->EndXML(xml); @@ -844,7 +848,7 @@ bool cmCTestMemCheckHandler::ProcessMemCheckValgrindOutput( cmsys::RegularExpression vgABR("== .*pthread_mutex_unlock: mutex is " "locked by a different thread"); std::vector<std::string::size_type> nonValGrindOutput; - double sttime = cmSystemTools::GetTime(); + auto sttime = std::chrono::steady_clock::now(); cmCTestOptionalLog(this->CTest, DEBUG, "Start test: " << lines.size() << std::endl, this->Quiet); std::string::size_type totalOutputSize = 0; @@ -918,7 +922,10 @@ bool cmCTestMemCheckHandler::ProcessMemCheckValgrindOutput( } } cmCTestOptionalLog(this->CTest, DEBUG, "End test (elapsed: " - << (cmSystemTools::GetTime() - sttime) << std::endl, + << std::chrono::duration_cast<std::chrono::seconds>( + std::chrono::steady_clock::now() - sttime) + .count() + << "s)" << std::endl, this->Quiet); log = ostr.str(); this->DefectCount += defects; @@ -929,7 +936,7 @@ bool cmCTestMemCheckHandler::ProcessMemCheckBoundsCheckerOutput( const std::string& str, std::string& log, std::vector<int>& results) { log.clear(); - double sttime = cmSystemTools::GetTime(); + auto sttime = std::chrono::steady_clock::now(); std::vector<std::string> lines; cmSystemTools::Split(str.c_str(), lines); cmCTestOptionalLog(this->CTest, DEBUG, @@ -961,7 +968,10 @@ bool cmCTestMemCheckHandler::ProcessMemCheckBoundsCheckerOutput( defects++; } cmCTestOptionalLog(this->CTest, DEBUG, "End test (elapsed: " - << (cmSystemTools::GetTime() - sttime) << std::endl, + << std::chrono::duration_cast<std::chrono::seconds>( + std::chrono::steady_clock::now() - sttime) + .count() + << "s)" << std::endl, this->Quiet); if (defects) { // only put the output of Bounds Checker if there were diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index 6a7bdc0..ae07feb 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/Source/CTest/cmCTestMultiProcessHandler.cxx @@ -326,10 +326,22 @@ void cmCTestMultiProcessHandler::StartNextTests() } if (allTestsFailedTestLoadCheck) { + // Find out whether there are any non RUN_SERIAL tests left, so that the + // correct warning may be displayed. + bool onlyRunSerialTestsLeft = true; + for (auto const& test : copy) { + if (!this->Properties[test]->RunSerial) { + onlyRunSerialTestsLeft = false; + } + } cmCTestLog(this->CTest, HANDLER_OUTPUT, "***** WAITING, "); + if (this->SerialTestRunning) { cmCTestLog(this->CTest, HANDLER_OUTPUT, "Waiting for RUN_SERIAL test to finish."); + } else if (onlyRunSerialTestsLeft) { + cmCTestLog(this->CTest, HANDLER_OUTPUT, + "Only RUN_SERIAL tests remain, awaiting available slot."); } else { /* clang-format off */ cmCTestLog(this->CTest, HANDLER_OUTPUT, diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index abdb643..5443494 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -14,6 +14,7 @@ #include "cmsys/Base64.h" #include "cmsys/Process.h" #include "cmsys/RegularExpression.hxx" +#include <chrono> #include <iomanip> #include <sstream> #include <stdio.h> @@ -46,11 +47,12 @@ cmCTestRunTest::~cmCTestRunTest() bool cmCTestRunTest::CheckOutput() { // Read lines for up to 0.1 seconds of total time. - double timeout = 0.1; - double timeEnd = cmSystemTools::GetTime() + timeout; + std::chrono::duration<double> timeout = std::chrono::milliseconds(100); + auto timeEnd = std::chrono::steady_clock::now() + timeout; std::string line; - while ((timeout = timeEnd - cmSystemTools::GetTime(), timeout > 0)) { - int p = this->TestProcess->GetNextOutputLine(line, timeout); + while ((timeout = timeEnd - std::chrono::steady_clock::now(), + timeout > std::chrono::seconds(0))) { + int p = this->TestProcess->GetNextOutputLine(line, timeout.count()); if (p == cmsysProcess_Pipe_None) { // Process has terminated and all output read. return false; @@ -430,8 +432,6 @@ bool cmCTestRunTest::StartTest(size_t total) return false; } - this->ComputeArguments(); - std::vector<std::string>& args = this->TestProperties->Args; this->TestResult.Properties = this->TestProperties; this->TestResult.ExecutionTime = 0; this->TestResult.CompressOutput = false; @@ -442,6 +442,10 @@ bool cmCTestRunTest::StartTest(size_t total) this->TestResult.Name = this->TestProperties->Name; this->TestResult.Path = this->TestProperties->Directory; + // Check for failed fixture dependencies before we even look at the command + // arguments because if we are not going to run the test, the command and + // its arguments are irrelevant. This matters for the case where a fixture + // dependency might be creating the executable we want to run. if (!this->FailedDependencies.empty()) { this->TestProcess = new cmProcess; std::string msg = "Failed test dependencies:"; @@ -457,6 +461,8 @@ bool cmCTestRunTest::StartTest(size_t total) return false; } + this->ComputeArguments(); + std::vector<std::string>& args = this->TestProperties->Args; if (args.size() >= 2 && args[1] == "NOT_AVAILABLE") { this->TestProcess = new cmProcess; std::string msg; diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx index fdd9622..3bf27a0 100644 --- a/Source/CTest/cmCTestScriptHandler.cxx +++ b/Source/CTest/cmCTestScriptHandler.cxx @@ -5,10 +5,12 @@ #include "cmsys/Directory.hxx" #include "cmsys/Process.h" #include <map> +#include <ratio> #include <sstream> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <type_traits> #include <utility> #include "cmCTest.h" @@ -79,9 +81,9 @@ cmCTestScriptHandler::cmCTestScriptHandler() this->CMake = nullptr; this->GlobalGenerator = nullptr; - this->ScriptStartTime = 0; + this->ScriptStartTime = std::chrono::steady_clock::time_point(); - // the *60 is becuase the settings are in minutes but GetTime is seconds + // the *60 is because the settings are in minutes but GetTime is seconds this->MinimumInterval = 30 * 60; this->ContinuousDuration = -1; } @@ -111,7 +113,7 @@ void cmCTestScriptHandler::Initialize() this->ContinuousDuration = -1; // what time in seconds did this script start running - this->ScriptStartTime = 0; + this->ScriptStartTime = std::chrono::steady_clock::time_point(); delete this->Makefile; this->Makefile = nullptr; @@ -158,11 +160,10 @@ void cmCTestScriptHandler::UpdateElapsedTime() { if (this->Makefile) { // set the current elapsed time - char timeString[20]; - int itime = static_cast<unsigned int>(cmSystemTools::GetTime() - - this->ScriptStartTime); - sprintf(timeString, "%i", itime); - this->Makefile->AddDefinition("CTEST_ELAPSED_TIME", timeString); + auto itime = std::chrono::duration_cast<std::chrono::seconds>( + std::chrono::steady_clock::now() - this->ScriptStartTime); + auto timeString = std::to_string(itime.count()); + this->Makefile->AddDefinition("CTEST_ELAPSED_TIME", timeString.c_str()); } } @@ -507,7 +508,7 @@ int cmCTestScriptHandler::RunConfigurationScript( int result; - this->ScriptStartTime = cmSystemTools::GetTime(); + this->ScriptStartTime = std::chrono::steady_clock::now(); // read in the script if (pscope) { @@ -558,22 +559,27 @@ int cmCTestScriptHandler::RunCurrentScript() // for a continuous, do we ned to run it more than once? if (this->ContinuousDuration >= 0) { this->UpdateElapsedTime(); - double ending_time = cmSystemTools::GetTime() + this->ContinuousDuration; + auto ending_time = std::chrono::steady_clock::now() + + std::chrono::duration<double>(this->ContinuousDuration); if (this->EmptyBinDirOnce) { this->EmptyBinDir = true; } do { - double interval = cmSystemTools::GetTime(); + auto startOfInterval = std::chrono::steady_clock::now(); result = this->RunConfigurationDashboard(); - interval = cmSystemTools::GetTime() - interval; - if (interval < this->MinimumInterval) { - this->SleepInSeconds( - static_cast<unsigned int>(this->MinimumInterval - interval)); + auto interval = std::chrono::steady_clock::now() - startOfInterval; + auto minimumInterval = + std::chrono::duration<double>(this->MinimumInterval); + if (interval < minimumInterval) { + auto sleepTime = std::chrono::duration_cast<std::chrono::seconds>( + minimumInterval - interval) + .count(); + this->SleepInSeconds(static_cast<unsigned int>(sleepTime)); } if (this->EmptyBinDirOnce) { this->EmptyBinDir = false; } - } while (cmSystemTools::GetTime() < ending_time); + } while (std::chrono::steady_clock::now() < ending_time); } // otherwise just run it once else { @@ -830,7 +836,7 @@ int cmCTestScriptHandler::RunConfigurationDashboard() } } - // if all was succesful, delete the backup dirs to free up disk space + // if all was successful, delete the backup dirs to free up disk space if (this->Backup) { cmSystemTools::RemoveADirectory(this->BackupSourceDir); cmSystemTools::RemoveADirectory(this->BackupBinaryDir); @@ -967,7 +973,9 @@ double cmCTestScriptHandler::GetRemainingTimeAllowed() return 1.0e7; } - double timelimit = atof(timelimitS); + auto timelimit = std::chrono::duration<double>(atof(timelimitS)); - return timelimit - cmSystemTools::GetTime() + this->ScriptStartTime; + auto duration = std::chrono::duration_cast<std::chrono::duration<double>>( + std::chrono::steady_clock::now() - this->ScriptStartTime); + return (timelimit - duration).count(); } diff --git a/Source/CTest/cmCTestScriptHandler.h b/Source/CTest/cmCTestScriptHandler.h index b6cd97b..2090d04 100644 --- a/Source/CTest/cmCTestScriptHandler.h +++ b/Source/CTest/cmCTestScriptHandler.h @@ -7,6 +7,7 @@ #include "cmCTestGenericHandler.h" +#include <chrono> #include <string> #include <vector> @@ -104,6 +105,7 @@ public: void CreateCMake(); cmake* GetCMake() { return this->CMake; } + private: // reads in a script int ReadInScript(const std::string& total_script_arg); @@ -156,7 +158,7 @@ private: double ContinuousDuration; // what time in seconds did this script start running - double ScriptStartTime; + std::chrono::steady_clock::time_point ScriptStartTime; cmMakefile* Makefile; cmGlobalGenerator* GlobalGenerator; diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index e51e168..86fee7a 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -6,6 +6,7 @@ #include "cm_jsoncpp_reader.h" #include "cm_jsoncpp_value.h" #include "cmsys/Process.h" +#include <chrono> #include <sstream> #include <stdio.h> #include <stdlib.h> @@ -496,10 +497,11 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const std::string& localprefix, ? "" : this->GetOption("RetryCount"); - int delay = retryDelay.empty() - ? atoi(this->CTest->GetCTestConfiguration("CTestSubmitRetryDelay") - .c_str()) - : atoi(retryDelay.c_str()); + auto delay = std::chrono::duration<double>( + retryDelay.empty() + ? atoi(this->CTest->GetCTestConfiguration("CTestSubmitRetryDelay") + .c_str()) + : atoi(retryDelay.c_str())); int count = retryCount.empty() ? atoi(this->CTest->GetCTestConfiguration("CTestSubmitRetryCount") .c_str()) @@ -507,12 +509,12 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const std::string& localprefix, for (int i = 0; i < count; i++) { cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, - " Submit failed, waiting " << delay + " Submit failed, waiting " << delay.count() << " seconds...\n", this->Quiet); - double stop = cmSystemTools::GetTime() + delay; - while (cmSystemTools::GetTime() < stop) { + auto stop = std::chrono::steady_clock::now() + delay; + while (std::chrono::steady_clock::now() < stop) { cmSystemTools::Delay(100); } @@ -1031,11 +1033,15 @@ int cmCTestSubmitHandler::HandleCDashUploadFile(std::string const& file, std::string retryCountString = this->GetOption("RetryCount") == nullptr ? "" : this->GetOption("RetryCount"); - unsigned long retryDelay = 0; + auto retryDelay = std::chrono::seconds(0); if (!retryDelayString.empty()) { - if (!cmSystemTools::StringToULong(retryDelayString.c_str(), &retryDelay)) { + unsigned long retryDelayValue = 0; + if (!cmSystemTools::StringToULong(retryDelayString.c_str(), + &retryDelayValue)) { cmCTestLog(this->CTest, WARNING, "Invalid value for 'RETRY_DELAY' : " << retryDelayString << std::endl); + } else { + retryDelay = std::chrono::seconds(retryDelayValue); } } unsigned long retryCount = 0; @@ -1063,6 +1069,8 @@ int cmCTestSubmitHandler::HandleCDashUploadFile(std::string const& file, if (subproject) { str << "subproject=" << curl.Escape(subproject) << "&"; } + auto timeNow = + std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); str << "stamp=" << curl.Escape(this->CTest->GetCurrentTag()) << "-" << curl.Escape(this->CTest->GetTestModelString()) << "&" << "model=" << curl.Escape(this->CTest->GetTestModelString()) << "&" @@ -1071,8 +1079,8 @@ int cmCTestSubmitHandler::HandleCDashUploadFile(std::string const& file, << "site=" << curl.Escape(this->CTest->GetCTestConfiguration("Site")) << "&" << "track=" << curl.Escape(this->CTest->GetTestModelString()) << "&" - << "starttime=" << static_cast<int>(cmSystemTools::GetTime()) << "&" - << "endtime=" << static_cast<int>(cmSystemTools::GetTime()) << "&" + << "starttime=" << timeNow << "&" + << "endtime=" << timeNow << "&" << "datafilesmd5[0]=" << md5sum << "&" << "type=" << curl.Escape(typeString); std::string fields = str.str(); @@ -1087,12 +1095,12 @@ int cmCTestSubmitHandler::HandleCDashUploadFile(std::string const& file, // If request failed, wait and retry. for (unsigned long i = 0; i < retryCount; i++) { cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, - " Request failed, waiting " << retryDelay + " Request failed, waiting " << retryDelay.count() << " seconds...\n", this->Quiet); - double stop = cmSystemTools::GetTime() + static_cast<double>(retryDelay); - while (cmSystemTools::GetTime() < stop) { + auto stop = std::chrono::steady_clock::now() + retryDelay; + while (std::chrono::steady_clock::now() < stop) { cmSystemTools::Delay(100); } @@ -1161,12 +1169,12 @@ int cmCTestSubmitHandler::HandleCDashUploadFile(std::string const& file, // If upload failed, wait and retry. for (unsigned long i = 0; i < retryCount; i++) { cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, - " Upload failed, waiting " << retryDelay + " Upload failed, waiting " << retryDelay.count() << " seconds...\n", this->Quiet); - double stop = cmSystemTools::GetTime() + static_cast<double>(retryDelay); - while (cmSystemTools::GetTime() < stop) { + auto stop = std::chrono::steady_clock::now() + retryDelay; + while (std::chrono::steady_clock::now() < stop) { cmSystemTools::Delay(100); } @@ -1521,7 +1529,7 @@ int cmCTestSubmitHandler::ProcessHandler() this->CTest->GetCTestConfiguration("DropLocation"); // change to the build directory so that we can uses a relative path - // on windows since scp dosn't support "c:" a drive in the path + // on windows since scp doesn't support "c:" a drive in the path cmWorkingDirectory workdir(buildDirectory); if (!this->SubmitUsingSCP(this->CTest->GetCTestConfiguration("ScpCommand"), @@ -1540,7 +1548,7 @@ int cmCTestSubmitHandler::ProcessHandler() std::string location = this->CTest->GetCTestConfiguration("DropLocation"); // change to the build directory so that we can uses a relative path - // on windows since scp dosn't support "c:" a drive in the path + // on windows since scp doesn't support "c:" a drive in the path cmWorkingDirectory workdir(buildDirectory); cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Change directory: " << buildDirectory << std::endl, diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index c7ed927..e7c719c 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -2,6 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCTestTestHandler.h" #include <algorithm> +#include <chrono> #include <cmsys/Base64.h> #include <cmsys/Directory.hxx> #include <cmsys/RegularExpression.hxx> @@ -15,6 +16,7 @@ #include <stdlib.h> #include <string.h> #include <time.h> +#include <type_traits> #include "cmAlgorithms.h" #include "cmCTest.h" @@ -346,7 +348,7 @@ void cmCTestTestHandler::Initialize() { this->Superclass::Initialize(); - this->ElapsedTestingTime = -1; + this->ElapsedTestingTime = std::chrono::duration<double>(); this->TestResults.clear(); @@ -484,12 +486,11 @@ int cmCTestTestHandler::ProcessHandler() int total; // start the real time clock - double clock_start, clock_finish; - clock_start = cmSystemTools::GetTime(); + auto clock_start = std::chrono::steady_clock::now(); this->ProcessDirectory(passed, failed); - clock_finish = cmSystemTools::GetTime(); + auto clock_finish = std::chrono::steady_clock::now(); total = int(passed.size()) + int(failed.size()); @@ -540,7 +541,10 @@ int cmCTestTestHandler::ProcessHandler() this->PrintLabelOrSubprojectSummary(false); } char realBuf[1024]; - sprintf(realBuf, "%6.2f sec", clock_finish - clock_start); + auto durationInMs = std::chrono::duration_cast<std::chrono::milliseconds>( + clock_finish - clock_start) + .count(); + sprintf(realBuf, "%6.2f sec", static_cast<double>(durationInMs) / 1000.0); cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "\nTotal Test time (real) = " << realBuf << "\n", this->Quiet); @@ -1200,8 +1204,8 @@ void cmCTestTestHandler::ProcessDirectory(std::vector<std::string>& passed, { this->ComputeTestList(); this->StartTest = this->CTest->CurrentTime(); - this->StartTestTime = static_cast<unsigned int>(cmSystemTools::GetTime()); - double elapsed_time_start = cmSystemTools::GetTime(); + this->StartTestTime = std::chrono::system_clock::now(); + auto elapsed_time_start = std::chrono::steady_clock::now(); cmCTestMultiProcessHandler* parallel = this->CTest->GetBatchJobs() ? new cmCTestBatchTestHandler @@ -1267,8 +1271,9 @@ void cmCTestTestHandler::ProcessDirectory(std::vector<std::string>& passed, } delete parallel; this->EndTest = this->CTest->CurrentTime(); - this->EndTestTime = static_cast<unsigned int>(cmSystemTools::GetTime()); - this->ElapsedTestingTime = cmSystemTools::GetTime() - elapsed_time_start; + this->EndTestTime = std::chrono::system_clock::now(); + this->ElapsedTestingTime = + std::chrono::steady_clock::now() - elapsed_time_start; *this->LogFile << "End testing: " << this->CTest->CurrentTime() << std::endl; } @@ -1373,8 +1378,10 @@ void cmCTestTestHandler::GenerateDartOutput(cmXMLWriter& xml) xml.Element("EndDateTime", this->EndTest); xml.Element("EndTestTime", this->EndTestTime); - xml.Element("ElapsedMinutes", - static_cast<int>(this->ElapsedTestingTime / 6) / 10.0); + xml.Element( + "ElapsedMinutes", + std::chrono::duration_cast<std::chrono::minutes>(this->ElapsedTestingTime) + .count()); xml.EndElement(); // Testing this->CTest->EndXML(xml); } diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h index 394d20e..8572e7b 100644 --- a/Source/CTest/cmCTestTestHandler.h +++ b/Source/CTest/cmCTestTestHandler.h @@ -8,6 +8,7 @@ #include "cmCTestGenericHandler.h" #include "cmsys/RegularExpression.hxx" +#include <chrono> #include <iosfwd> #include <map> #include <set> @@ -39,7 +40,7 @@ public: int ProcessHandler() override; /** - * When both -R and -I are used should te resulting test list be the + * When both -R and -I are used should the resulting test list be the * intersection or the union of the lists. By default it is the * intersection. */ @@ -198,7 +199,7 @@ protected: //! Clean test output to specified length bool CleanTestOutput(std::string& output, size_t length); - double ElapsedTestingTime; + std::chrono::duration<double> ElapsedTestingTime; typedef std::vector<cmCTestTestResult> TestResultsVector; TestResultsVector TestResults; @@ -206,8 +207,8 @@ protected: std::vector<std::string> CustomTestsIgnore; std::string StartTest; std::string EndTest; - unsigned int StartTestTime; - unsigned int EndTestTime; + std::chrono::system_clock::time_point StartTestTime; + std::chrono::system_clock::time_point EndTestTime; bool MemCheck; int CustomMaximumPassedTestOutputSize; int CustomMaximumFailedTestOutputSize; diff --git a/Source/CTest/cmCTestUpdateHandler.cxx b/Source/CTest/cmCTestUpdateHandler.cxx index 786ed5e..f86d4a3 100644 --- a/Source/CTest/cmCTestUpdateHandler.cxx +++ b/Source/CTest/cmCTestUpdateHandler.cxx @@ -17,8 +17,10 @@ #include "cmVersion.h" #include "cmXMLWriter.h" +#include <chrono> #include <memory> // IWYU pragma: keep #include <sstream> +#include <type_traits> static const char* cmCTestUpdateHandlerUpdateStrings[] = { "Unknown", "CVS", "SVN", "BZR", "GIT", "HG", "P4" @@ -175,9 +177,8 @@ int cmCTestUpdateHandler::ProcessHandler() return -1; } std::string start_time = this->CTest->CurrentTime(); - unsigned int start_time_time = - static_cast<unsigned int>(cmSystemTools::GetTime()); - double elapsed_time_start = cmSystemTools::GetTime(); + auto start_time_time = std::chrono::system_clock::now(); + auto elapsed_time_start = std::chrono::steady_clock::now(); bool updated = vc->Update(); std::string buildname = @@ -224,11 +225,11 @@ int cmCTestUpdateHandler::ProcessHandler() cmCTestOptionalLog(this->CTest, DEBUG, "End" << std::endl, this->Quiet); std::string end_time = this->CTest->CurrentTime(); xml.Element("EndDateTime", end_time); - xml.Element("EndTime", static_cast<unsigned int>(cmSystemTools::GetTime())); - xml.Element( - "ElapsedMinutes", - static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start) / 6) / - 10.0); + xml.Element("EndTime", std::chrono::system_clock::now()); + xml.Element("ElapsedMinutes", + std::chrono::duration_cast<std::chrono::minutes>( + std::chrono::steady_clock::now() - elapsed_time_start) + .count()); xml.StartElement("UpdateReturnStatus"); if (localModifications) { diff --git a/Source/CTest/cmParseGTMCoverage.cxx b/Source/CTest/cmParseGTMCoverage.cxx index 9948ede..f965048 100644 --- a/Source/CTest/cmParseGTMCoverage.cxx +++ b/Source/CTest/cmParseGTMCoverage.cxx @@ -93,7 +93,7 @@ bool cmParseGTMCoverage::ReadMCovFile(const char* file) // This section accounts for lines that were previously marked // as non-executable code (-1), if the parser comes back with // a non-zero count, increase the count by 1 to push the line - // into the executable code set in addtion to the count found. + // into the executable code set in addition to the count found. if (coverageVector[lineoffset + linenumber] == -1 && count > 0) { coverageVector[lineoffset + linenumber] += count + 1; } else { diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx index f3c191b..78dd598 100644 --- a/Source/CTest/cmProcess.cxx +++ b/Source/CTest/cmProcess.cxx @@ -3,8 +3,8 @@ #include "cmProcess.h" #include "cmProcessOutput.h" -#include "cmSystemTools.h" #include <iostream> +#include <type_traits> cmProcess::cmProcess() { @@ -13,7 +13,7 @@ cmProcess::cmProcess() this->TotalTime = 0; this->ExitValue = 0; this->Id = 0; - this->StartTime = 0; + this->StartTime = std::chrono::steady_clock::time_point(); } cmProcess::~cmProcess() @@ -35,7 +35,7 @@ bool cmProcess::StartProcess() if (this->Command.empty()) { return false; } - this->StartTime = cmSystemTools::GetTime(); + this->StartTime = std::chrono::steady_clock::now(); this->ProcessArgs.clear(); // put the command as arg0 this->ProcessArgs.push_back(this->Command.c_str()); @@ -143,7 +143,11 @@ int cmProcess::GetNextOutputLine(std::string& line, double timeout) // Record exit information. this->ExitValue = cmsysProcess_GetExitValue(this->Process); - this->TotalTime = cmSystemTools::GetTime() - this->StartTime; + this->TotalTime = + static_cast<double>(std::chrono::duration_cast<std::chrono::milliseconds>( + std::chrono::steady_clock::now() - this->StartTime) + .count()) / + 1000.0; // Because of a processor clock scew the runtime may become slightly // negative. If someone changed the system clock while the process was // running this may be even more. Make sure not to report a negative @@ -231,7 +235,7 @@ void cmProcess::ChangeTimeout(double t) void cmProcess::ResetStartTime() { cmsysProcess_ResetStartTime(this->Process); - this->StartTime = cmSystemTools::GetTime(); + this->StartTime = std::chrono::steady_clock::now(); } int cmProcess::GetExitException() diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h index dfb02fe..ddd69b6 100644 --- a/Source/CTest/cmProcess.h +++ b/Source/CTest/cmProcess.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include "cmsys/Process.h" +#include <chrono> #include <string> #include <vector> @@ -50,7 +51,7 @@ public: private: double Timeout; - double StartTime; + std::chrono::steady_clock::time_point StartTime; double TotalTime; cmsysProcess* Process; class Buffer : public std::vector<char> diff --git a/Source/Checks/cm_cxx_attribute_fallthrough.cxx b/Source/Checks/cm_cxx_attribute_fallthrough.cxx deleted file mode 100644 index 50605b7..0000000 --- a/Source/Checks/cm_cxx_attribute_fallthrough.cxx +++ /dev/null @@ -1,11 +0,0 @@ -int main(int argc, char* []) -{ - int i = 3; - switch (argc) { - case 1: - i = 0; - __attribute__((fallthrough)); - default: - return i; - } -} diff --git a/Source/Checks/cm_cxx_fallthrough.cxx b/Source/Checks/cm_cxx_fallthrough.cxx deleted file mode 100644 index 2825bed..0000000 --- a/Source/Checks/cm_cxx_fallthrough.cxx +++ /dev/null @@ -1,11 +0,0 @@ -int main(int argc, char* []) -{ - int i = 3; - switch (argc) { - case 1: - i = 0; - [[fallthrough]]; - default: - return i; - } -} diff --git a/Source/Checks/cm_cxx_features.cmake b/Source/Checks/cm_cxx_features.cmake index a30a5e6..2704c40 100644 --- a/Source/Checks/cm_cxx_features.cmake +++ b/Source/Checks/cm_cxx_features.cmake @@ -41,13 +41,6 @@ function(cm_check_cxx_feature name) endif() endfunction() -cm_check_cxx_feature(fallthrough) -if(NOT CMake_HAVE_CXX_FALLTHROUGH) - cm_check_cxx_feature(gnu_fallthrough) - if(NOT CMake_HAVE_CXX_GNU_FALLTHROUGH) - cm_check_cxx_feature(attribute_fallthrough) - endif() -endif() cm_check_cxx_feature(make_unique) if(CMake_HAVE_CXX_MAKE_UNIQUE) set(CMake_HAVE_CXX_UNIQUE_PTR 1) diff --git a/Source/Checks/cm_cxx_gnu_fallthrough.cxx b/Source/Checks/cm_cxx_gnu_fallthrough.cxx deleted file mode 100644 index ebc15f4..0000000 --- a/Source/Checks/cm_cxx_gnu_fallthrough.cxx +++ /dev/null @@ -1,11 +0,0 @@ -int main(int argc, char* []) -{ - int i = 3; - switch (argc) { - case 1: - i = 0; - [[gnu::fallthrough]]; - default: - return i; - } -} diff --git a/Source/LexerParser/cmCommandArgumentLexer.cxx b/Source/LexerParser/cmCommandArgumentLexer.cxx index bf6bc2f..6b4fc85 100644 --- a/Source/LexerParser/cmCommandArgumentLexer.cxx +++ b/Source/LexerParser/cmCommandArgumentLexer.cxx @@ -674,6 +674,13 @@ Modify cmCommandArgumentLexer.cxx: /* Include the set of tokens from the parser. */ #include "cmCommandArgumentParserTokens.h" +static const char *DCURLYVariable = "${"; +static const char *RCURLYVariable = "}"; +static const char *ATVariable = "@"; +static const char *DOLLARVariable = "$"; +static const char *LCURLYVariable = "{"; +static const char *BSLASHVariable = "\\"; + /*--------------------------------------------------------------------------*/ #define INITIAL 0 @@ -1011,7 +1018,7 @@ YY_RULE_SETUP { //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl; //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext)); - yylvalp->str = yyextra->DCURLYVariable; + yylvalp->str = DCURLYVariable; return cal_DCURLY; } YY_BREAK @@ -1020,7 +1027,7 @@ YY_RULE_SETUP { //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl; //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext)); - yylvalp->str = yyextra->RCURLYVariable; + yylvalp->str = RCURLYVariable; return cal_RCURLY; } YY_BREAK @@ -1029,7 +1036,7 @@ YY_RULE_SETUP { //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl; //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext)); - yylvalp->str = yyextra->ATVariable; + yylvalp->str = ATVariable; return cal_AT; } YY_BREAK @@ -1064,7 +1071,7 @@ case 10: YY_RULE_SETUP { //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext)); - yylvalp->str = yyextra->DOLLARVariable; + yylvalp->str = DOLLARVariable; return cal_DOLLAR; } YY_BREAK @@ -1072,7 +1079,7 @@ case 11: YY_RULE_SETUP { //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext)); - yylvalp->str = yyextra->LCURLYVariable; + yylvalp->str = LCURLYVariable; return cal_LCURLY; } YY_BREAK @@ -1080,7 +1087,7 @@ case 12: YY_RULE_SETUP { //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext)); - yylvalp->str = yyextra->BSLASHVariable; + yylvalp->str = BSLASHVariable; return cal_BSLASH; } YY_BREAK @@ -1088,7 +1095,7 @@ case 13: YY_RULE_SETUP { //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext)); - yylvalp->str = yyextra->BSLASHVariable; + yylvalp->str = BSLASHVariable; return cal_SYMBOL; } YY_BREAK diff --git a/Source/LexerParser/cmCommandArgumentLexer.in.l b/Source/LexerParser/cmCommandArgumentLexer.in.l index acf18f3..5927b9e 100644 --- a/Source/LexerParser/cmCommandArgumentLexer.in.l +++ b/Source/LexerParser/cmCommandArgumentLexer.in.l @@ -28,6 +28,13 @@ Modify cmCommandArgumentLexer.cxx: /* Include the set of tokens from the parser. */ #include "cmCommandArgumentParserTokens.h" +static const char *DCURLYVariable = "${"; +static const char *RCURLYVariable = "}"; +static const char *ATVariable = "@"; +static const char *DOLLARVariable = "$"; +static const char *LCURLYVariable = "{"; +static const char *BSLASHVariable = "\\"; + /*--------------------------------------------------------------------------*/ %} @@ -63,21 +70,21 @@ Modify cmCommandArgumentLexer.cxx: "${" { //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl; //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext)); - yylvalp->str = yyextra->DCURLYVariable; + yylvalp->str = DCURLYVariable; return cal_DCURLY; } "}" { //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl; //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext)); - yylvalp->str = yyextra->RCURLYVariable; + yylvalp->str = RCURLYVariable; return cal_RCURLY; } "@" { //std::cerr << __LINE__ << " here: [" << yytext << "]" << std::endl; //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext)); - yylvalp->str = yyextra->ATVariable; + yylvalp->str = ATVariable; return cal_AT; } @@ -103,25 +110,25 @@ Modify cmCommandArgumentLexer.cxx: "$" { //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext)); - yylvalp->str = yyextra->DOLLARVariable; + yylvalp->str = DOLLARVariable; return cal_DOLLAR; } "{" { //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext)); - yylvalp->str = yyextra->LCURLYVariable; + yylvalp->str = LCURLYVariable; return cal_LCURLY; } <ESCAPES>"\\" { //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext)); - yylvalp->str = yyextra->BSLASHVariable; + yylvalp->str = BSLASHVariable; return cal_BSLASH; } <NOESCAPES>"\\" { //yyextra->AllocateParserType(yylvalp, yytext, strlen(yytext)); - yylvalp->str = yyextra->BSLASHVariable; + yylvalp->str = BSLASHVariable; return cal_SYMBOL; } diff --git a/Source/Modules/FindLibUUID.cmake b/Source/Modules/FindLibUUID.cmake new file mode 100644 index 0000000..17f11c1 --- /dev/null +++ b/Source/Modules/FindLibUUID.cmake @@ -0,0 +1,85 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +FindLibUUID +------------ + +Find LibUUID include directory and library. + +Imported Targets +^^^^^^^^^^^^^^^^ + +An :ref:`imported target <Imported targets>` named +``LibUUID::LibUUID`` is provided if LibUUID has been found. + +Result Variables +^^^^^^^^^^^^^^^^ + +This module defines the following variables: + +``LibUUID_FOUND`` + True if LibUUID was found, false otherwise. +``LibUUID_INCLUDE_DIRS`` + Include directories needed to include LibUUID headers. +``LibUUID_LIBRARIES`` + Libraries needed to link to LibUUID. + +Cache Variables +^^^^^^^^^^^^^^^ + +This module uses the following cache variables: + +``LibUUID_LIBRARY`` + The location of the LibUUID library file. +``LibUUID_INCLUDE_DIR`` + The location of the LibUUID include directory containing ``uuid/uuid.h``. + +The cache variables should not be used by project code. +They may be set by end users to point at LibUUID components. +#]=======================================================================] + +#----------------------------------------------------------------------------- +if(CYGWIN) + # Note: on current version of Cygwin, linking to libuuid.dll.a doesn't + # import the right symbols sometimes. Fix this by linking directly + # to the DLL that provides the symbols, instead. + set(old_suffixes ${CMAKE_FIND_LIBRARY_SUFFIXES}) + set(CMAKE_FIND_LIBRARY_SUFFIXES .dll) + find_library(LibUUID_LIBRARY + NAMES cyguuid-1.dll + ) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${old_suffixes}) +else() + find_library(LibUUID_LIBRARY + NAMES uuid + ) +endif() +mark_as_advanced(LibUUID_LIBRARY) + +find_path(LibUUID_INCLUDE_DIR + NAMES uuid/uuid.h + ) +mark_as_advanced(LibUUID_INCLUDE_DIR) + +#----------------------------------------------------------------------------- +include(${CMAKE_CURRENT_LIST_DIR}/../../Modules/FindPackageHandleStandardArgs.cmake) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibUUID + FOUND_VAR LibUUID_FOUND + REQUIRED_VARS LibUUID_LIBRARY LibUUID_INCLUDE_DIR + ) +set(LIBUUID_FOUND ${LibUUID_FOUND}) + +#----------------------------------------------------------------------------- +# Provide documented result variables and targets. +if(LibUUID_FOUND) + set(LibUUID_INCLUDE_DIRS ${LibUUID_INCLUDE_DIR}) + set(LibUUID_LIBRARIES ${LibUUID_LIBRARY}) + if(NOT TARGET LibUUID::LibUUID) + add_library(LibUUID::LibUUID UNKNOWN IMPORTED) + set_target_properties(LibUUID::LibUUID PROPERTIES + IMPORTED_LOCATION "${LibUUID_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${LibUUID_INCLUDE_DIRS}" + ) + endif() +endif() diff --git a/Source/Modules/OverrideC.cmake b/Source/Modules/OverrideC.cmake new file mode 100644 index 0000000..f8299ad --- /dev/null +++ b/Source/Modules/OverrideC.cmake @@ -0,0 +1,3 @@ +if("${CMAKE_SYSTEM_NAME};${CMAKE_C_COMPILER_ID}" STREQUAL "AIX;GNU") + string(APPEND CMAKE_C_FLAGS_INIT " -pthread") +endif() diff --git a/Source/Modules/OverrideCXX.cmake b/Source/Modules/OverrideCXX.cmake new file mode 100644 index 0000000..13689e2 --- /dev/null +++ b/Source/Modules/OverrideCXX.cmake @@ -0,0 +1,3 @@ +if("${CMAKE_SYSTEM_NAME};${CMAKE_CXX_COMPILER_ID}" STREQUAL "AIX;GNU") + string(APPEND CMAKE_CXX_FLAGS_INIT " -pthread") +endif() diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx index bbb2395..5be9ec3 100644 --- a/Source/QtDialog/CMakeSetupDialog.cxx +++ b/Source/QtDialog/CMakeSetupDialog.cxx @@ -188,6 +188,9 @@ CMakeSetupDialog::CMakeSetupDialog() connect(this->Output, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(doOutputContextMenu(const QPoint&))); + // disable open project button + this->OpenProjectButton->setDisabled(true); + // start the cmake worker thread this->CMakeThread = new QCMakeThread(this); QObject::connect(this->CMakeThread, SIGNAL(cmakeInitialized()), this, @@ -249,6 +252,10 @@ void CMakeSetupDialog::initialize() SIGNAL(outputMessage(QString)), this, SLOT(message(QString))); + QObject::connect(this->CMakeThread->cmakeInstance(), + SIGNAL(openPossible(bool)), this->OpenProjectButton, + SLOT(setEnabled(bool))); + QObject::connect(this->groupedCheck, SIGNAL(toggled(bool)), this, SLOT(setGroupedView(bool))); QObject::connect(this->advancedCheck, SIGNAL(toggled(bool)), this, @@ -492,24 +499,10 @@ void CMakeSetupDialog::doGenerate() this->ConfigureNeeded = true; } -QString CMakeSetupDialog::getProjectFilename() -{ - QStringList nameFilter; - nameFilter << "*.sln" - << "*.xcodeproj"; - QDir directory(this->BinaryDirectory->currentText()); - QStringList nlnFile = directory.entryList(nameFilter); - - if (nlnFile.count() == 1) { - return this->BinaryDirectory->currentText() + "/" + nlnFile.at(0); - } - - return QString(); -} - void CMakeSetupDialog::doOpenProject() { - QDesktopServices::openUrl(QUrl::fromLocalFile(this->getProjectFilename())); + QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(), "open", + Qt::QueuedConnection); } void CMakeSetupDialog::closeEvent(QCloseEvent* e) @@ -630,11 +623,6 @@ void CMakeSetupDialog::updateBinaryDirectory(const QString& dir) this->BinaryDirectory->setEditText(dir); this->BinaryDirectory->blockSignals(false); } - if (!this->getProjectFilename().isEmpty()) { - this->OpenProjectButton->setEnabled(true); - } else { - this->OpenProjectButton->setEnabled(false); - } } void CMakeSetupDialog::doBinaryBrowse() @@ -1039,9 +1027,6 @@ void CMakeSetupDialog::enterState(CMakeSetupDialog::State s) this->GenerateButton->setEnabled(true); this->GenerateAction->setEnabled(true); this->ConfigureButton->setEnabled(true); - if (!this->getProjectFilename().isEmpty()) { - this->OpenProjectButton->setEnabled(true); - } this->ConfigureButton->setText(tr("&Configure")); this->GenerateButton->setText(tr("&Generate")); } else if (s == ReadyGenerate) { @@ -1049,9 +1034,6 @@ void CMakeSetupDialog::enterState(CMakeSetupDialog::State s) this->GenerateButton->setEnabled(true); this->GenerateAction->setEnabled(true); this->ConfigureButton->setEnabled(true); - if (!this->getProjectFilename().isEmpty()) { - this->OpenProjectButton->setEnabled(true); - } this->ConfigureButton->setText(tr("&Configure")); this->GenerateButton->setText(tr("&Generate")); } diff --git a/Source/QtDialog/CMakeSetupDialog.h b/Source/QtDialog/CMakeSetupDialog.h index 0da28d8..7b767e5 100644 --- a/Source/QtDialog/CMakeSetupDialog.h +++ b/Source/QtDialog/CMakeSetupDialog.h @@ -31,7 +31,6 @@ protected slots: void initialize(); void doConfigure(); void doGenerate(); - QString getProjectFilename(); void doOpenProject(); void doInstallForCommandLine(); void doHelp(); diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx index d473d9b..7e94a27 100644 --- a/Source/QtDialog/QCMake.cxx +++ b/Source/QtDialog/QCMake.cxx @@ -115,6 +115,8 @@ void QCMake::setBinaryDirectory(const QString& _dir) if (toolset) { this->setToolset(QString::fromLocal8Bit(toolset)); } + + checkOpenPossible(); } } @@ -183,6 +185,26 @@ void QCMake::generate() #endif emit this->generateDone(err); + checkOpenPossible(); +} + +void QCMake::open() +{ +#ifdef Q_OS_WIN + UINT lastErrorMode = SetErrorMode(0); +#endif + + InterruptFlag = 0; + cmSystemTools::ResetErrorOccuredFlag(); + + auto successful = this->CMakeInstance->Open( + this->BinaryDirectory.toLocal8Bit().data(), false); + +#ifdef Q_OS_WIN + SetErrorMode(lastErrorMode); +#endif + + emit this->openDone(successful); } void QCMake::setProperties(const QCMakePropertyList& newProps) @@ -450,3 +472,10 @@ void QCMake::setWarnUnusedMode(bool value) { this->WarnUnusedMode = value; } + +void QCMake::checkOpenPossible() +{ + auto data = this->BinaryDirectory.toLocal8Bit().data(); + auto possible = this->CMakeInstance->Open(data, true); + emit openPossible(possible); +} diff --git a/Source/QtDialog/QCMake.h b/Source/QtDialog/QCMake.h index 3b8cea7..6fae7e3 100644 --- a/Source/QtDialog/QCMake.h +++ b/Source/QtDialog/QCMake.h @@ -80,6 +80,8 @@ public slots: void configure(); /// generate the files void generate(); + /// open the project + void open(); /// set the property values void setProperties(const QCMakePropertyList&); /// interrupt the configure or generate process (if connecting, make a direct @@ -111,6 +113,8 @@ public slots: void setWarnUninitializedMode(bool value); /// set whether to run cmake with warnings about unused variables void setWarnUnusedMode(bool value); + /// check if project IDE open is possible and emit openPossible signal + void checkOpenPossible(); public: /// get the list of cache properties @@ -151,6 +155,10 @@ signals: void debugOutputChanged(bool); /// signal when the toolset changes void toolsetChanged(const QString& toolset); + /// signal when open is done + void openDone(bool successful); + /// signal when open is done + void openPossible(bool possible); protected: cmake* CMakeInstance; diff --git a/Source/cmAddCustomTargetCommand.cxx b/Source/cmAddCustomTargetCommand.cxx index a8d5b2e..819c781 100644 --- a/Source/cmAddCustomTargetCommand.cxx +++ b/Source/cmAddCustomTargetCommand.cxx @@ -8,7 +8,7 @@ #include "cmGeneratorExpression.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" -#include "cmPolicies.h" +#include "cmStateTypes.h" #include "cmSystemTools.h" #include "cmTarget.h" #include "cmake.h" @@ -160,35 +160,9 @@ bool cmAddCustomTargetCommand::InitialPass( if (nameOk) { nameOk = targetName.find(':') == std::string::npos; } - if (!nameOk) { - cmake::MessageType messageType = cmake::AUTHOR_WARNING; - std::ostringstream e; - bool issueMessage = false; - switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0037)) { - case cmPolicies::WARN: - e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0037) << "\n"; - issueMessage = true; - case cmPolicies::OLD: - break; - case cmPolicies::NEW: - case cmPolicies::REQUIRED_IF_USED: - case cmPolicies::REQUIRED_ALWAYS: - issueMessage = true; - messageType = cmake::FATAL_ERROR; - } - if (issueMessage) { - /* clang-format off */ - e << "The target name \"" << targetName << - "\" is reserved or not valid for certain " - "CMake features, such as generator expressions, and may result " - "in undefined behavior."; - /* clang-format on */ - this->Makefile->IssueMessage(messageType, e.str()); - - if (messageType == cmake::FATAL_ERROR) { - return false; - } - } + if (!nameOk && + !this->Makefile->CheckCMP0037(targetName, cmStateEnums::UTILITY)) { + return false; } // Store the last command line finished. @@ -235,9 +209,9 @@ bool cmAddCustomTargetCommand::InitialPass( // Add the utility target to the makefile. bool escapeOldStyle = !verbatim; cmTarget* target = this->Makefile->AddUtilityCommand( - targetName, excludeFromAll, working_directory.c_str(), byproducts, depends, - commandLines, escapeOldStyle, comment, uses_terminal, - command_expand_lists); + targetName, cmMakefile::TargetOrigin::Project, excludeFromAll, + working_directory.c_str(), byproducts, depends, commandLines, + escapeOldStyle, comment, uses_terminal, command_expand_lists); // Add additional user-specified source files to the target. target->AddSources(sources); diff --git a/Source/cmAddExecutableCommand.cxx b/Source/cmAddExecutableCommand.cxx index 1d0376f..b9e200a 100644 --- a/Source/cmAddExecutableCommand.cxx +++ b/Source/cmAddExecutableCommand.cxx @@ -7,10 +7,8 @@ #include "cmGeneratorExpression.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" -#include "cmPolicies.h" #include "cmStateTypes.h" #include "cmTarget.h" -#include "cmake.h" class cmExecutionStatus; @@ -18,7 +16,7 @@ class cmExecutionStatus; bool cmAddExecutableCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 2) { + if (args.empty()) { this->SetError("called with incorrect number of arguments"); return false; } @@ -63,35 +61,9 @@ bool cmAddExecutableCommand::InitialPass(std::vector<std::string> const& args, if (nameOk && !importTarget && !isAlias) { nameOk = exename.find(':') == std::string::npos; } - if (!nameOk) { - cmake::MessageType messageType = cmake::AUTHOR_WARNING; - std::ostringstream e; - bool issueMessage = false; - switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0037)) { - case cmPolicies::WARN: - e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0037) << "\n"; - issueMessage = true; - case cmPolicies::OLD: - break; - case cmPolicies::NEW: - case cmPolicies::REQUIRED_IF_USED: - case cmPolicies::REQUIRED_ALWAYS: - issueMessage = true; - messageType = cmake::FATAL_ERROR; - } - if (issueMessage) { - /* clang-format off */ - e << "The target name \"" << exename << - "\" is reserved or not valid for certain " - "CMake features, such as generator expressions, and may result " - "in undefined behavior."; - /* clang-format on */ - this->Makefile->IssueMessage(messageType, e.str()); - - if (messageType == cmake::FATAL_ERROR) { - return false; - } - } + if (!nameOk && + !this->Makefile->CheckCMP0037(exename, cmStateEnums::EXECUTABLE)) { + return false; } // Special modifiers are not allowed with IMPORTED signature. @@ -140,8 +112,7 @@ bool cmAddExecutableCommand::InitialPass(std::vector<std::string> const& args, if (!aliasedTarget) { std::ostringstream e; e << "cannot create ALIAS target \"" << exename << "\" because target \"" - << aliasedName << "\" does not already " - "exist."; + << aliasedName << "\" does not already exist."; this->SetError(e.str()); return false; } @@ -149,15 +120,15 @@ bool cmAddExecutableCommand::InitialPass(std::vector<std::string> const& args, if (type != cmStateEnums::EXECUTABLE) { std::ostringstream e; e << "cannot create ALIAS target \"" << exename << "\" because target \"" - << aliasedName << "\" is not an " - "executable."; + << aliasedName << "\" is not an executable."; this->SetError(e.str()); return false; } - if (aliasedTarget->IsImported()) { + if (aliasedTarget->IsImported() && + !aliasedTarget->IsImportedGloballyVisible()) { std::ostringstream e; e << "cannot create ALIAS target \"" << exename << "\" because target \"" - << aliasedName << "\" is IMPORTED."; + << aliasedName << "\" is imported but not globally visible."; this->SetError(e.str()); return false; } @@ -191,12 +162,6 @@ bool cmAddExecutableCommand::InitialPass(std::vector<std::string> const& args, } } - if (s == args.end()) { - this->SetError( - "called with incorrect number of arguments, no sources provided"); - return false; - } - std::vector<std::string> srclists(s, args.end()); cmTarget* tgt = this->Makefile->AddExecutable(exename.c_str(), srclists, excludeFromAll); diff --git a/Source/cmAddLibraryCommand.cxx b/Source/cmAddLibraryCommand.cxx index ebf1763..0fcffdd 100644 --- a/Source/cmAddLibraryCommand.cxx +++ b/Source/cmAddLibraryCommand.cxx @@ -7,7 +7,6 @@ #include "cmGeneratorExpression.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" -#include "cmPolicies.h" #include "cmState.h" #include "cmStateTypes.h" #include "cmSystemTools.h" @@ -175,35 +174,8 @@ bool cmAddLibraryCommand::InitialPass(std::vector<std::string> const& args, if (nameOk && !importTarget && !isAlias) { nameOk = libName.find(':') == std::string::npos; } - if (!nameOk) { - cmake::MessageType messageType = cmake::AUTHOR_WARNING; - std::ostringstream e; - bool issueMessage = false; - switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0037)) { - case cmPolicies::WARN: - if (type != cmStateEnums::INTERFACE_LIBRARY) { - e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0037) << "\n"; - issueMessage = true; - } - case cmPolicies::OLD: - break; - case cmPolicies::NEW: - case cmPolicies::REQUIRED_IF_USED: - case cmPolicies::REQUIRED_ALWAYS: - issueMessage = true; - messageType = cmake::FATAL_ERROR; - } - if (issueMessage) { - e << "The target name \"" << libName - << "\" is reserved or not valid for certain " - "CMake features, such as generator expressions, and may result " - "in undefined behavior."; - this->Makefile->IssueMessage(messageType, e.str()); - - if (messageType == cmake::FATAL_ERROR) { - return false; - } - } + if (!nameOk && !this->Makefile->CheckCMP0037(libName, type)) { + return false; } if (isAlias) { @@ -256,13 +228,6 @@ bool cmAddLibraryCommand::InitialPass(std::vector<std::string> const& args, this->SetError(e.str()); return false; } - if (aliasedTarget->IsImported()) { - std::ostringstream e; - e << "cannot create ALIAS target \"" << libName << "\" because target \"" - << aliasedName << "\" is IMPORTED."; - this->SetError(e.str()); - return false; - } this->Makefile->AddAlias(libName, aliasedName); return true; } @@ -362,14 +327,6 @@ bool cmAddLibraryCommand::InitialPass(std::vector<std::string> const& args, return true; } - if (s == args.end()) { - std::string msg = "You have called ADD_LIBRARY for library "; - msg += args[0]; - msg += " without any source files. This typically indicates a problem "; - msg += "with your CMakeLists.txt file"; - cmSystemTools::Message(msg.c_str(), "Warning"); - } - srclists.insert(srclists.end(), s, args.end()); this->Makefile->AddLibrary(libName, type, srclists, excludeFromAll); diff --git a/Source/cmAlgorithms.h b/Source/cmAlgorithms.h index 69d0ed6..3380b78 100644 --- a/Source/cmAlgorithms.h +++ b/Source/cmAlgorithms.h @@ -43,22 +43,6 @@ inline bool cmHasLiteralSuffixImpl(const char* str1, const char* str2, } template <typename T, size_t N> -const T* cmArrayBegin(const T (&a)[N]) -{ - return a; -} -template <typename T, size_t N> -const T* cmArrayEnd(const T (&a)[N]) -{ - return a + N; -} -template <typename T, size_t N> -size_t cmArraySize(const T (&)[N]) -{ - return N; -} - -template <typename T, size_t N> bool cmHasLiteralPrefix(const T& str1, const char (&str2)[N]) { return cmHasLiteralPrefixImpl(str1, str2, N - 1); @@ -418,6 +402,67 @@ std::unique_ptr<T> make_unique(Args&&... args) #endif +#if __cplusplus >= 201703L || defined(_MSVC_LANG) && _MSVC_LANG >= 201703L + +using std::size; + +#else + +// std::size backport from C++17. +template <class C> +#if !defined(_MSC_VER) || _MSC_VER >= 1900 +constexpr +#endif + auto + size(C const& c) -> decltype(c.size()) +{ + return c.size(); +} + +template <typename T, size_t N> +#if !defined(_MSC_VER) || _MSC_VER >= 1900 +constexpr +#endif + std::size_t + size(const T (&)[N]) throw() +{ + return N; +} + +#endif + +#if __cplusplus >= 201402L || defined(_MSVC_LANG) && _MSVC_LANG >= 201402L + +using std::cbegin; +using std::cend; + +#else + +// std::c{begin,end} backport from C++14 +template <class C> +#if defined(_MSC_VER) && _MSC_VER < 1900 +auto cbegin(C const& c) +#else +constexpr auto cbegin(C const& c) noexcept(noexcept(std::begin(c))) +#endif + -> decltype(std::begin(c)) +{ + return std::begin(c); +} + +template <class C> +#if defined(_MSC_VER) && _MSC_VER < 1900 +auto cend(C const& c) +#else +constexpr auto cend(C const& c) noexcept(noexcept(std::end(c))) +#endif + -> decltype(std::end(c)) +{ + return std::end(c); +} + +#endif + } // namespace cm #endif diff --git a/Source/cmAuxSourceDirectoryCommand.cxx b/Source/cmAuxSourceDirectoryCommand.cxx index 847a416..fcdc632 100644 --- a/Source/cmAuxSourceDirectoryCommand.cxx +++ b/Source/cmAuxSourceDirectoryCommand.cxx @@ -54,10 +54,8 @@ bool cmAuxSourceDirectoryCommand::InitialPass( std::string ext = file.substr(dotpos + 1); std::string base = file.substr(0, dotpos); // Process only source files - std::vector<std::string> const& srcExts = - this->Makefile->GetCMakeInstance()->GetSourceExtensions(); - if (!base.empty() && - std::find(srcExts.begin(), srcExts.end(), ext) != srcExts.end()) { + auto cm = this->Makefile->GetCMakeInstance(); + if (!base.empty() && cm->IsSourceExtension(ext)) { std::string fullname = templateDirectory; fullname += "/"; fullname += file; diff --git a/Source/cmCMakeHostSystemInformationCommand.cxx b/Source/cmCMakeHostSystemInformationCommand.cxx index 5106f52..662dd74 100644 --- a/Source/cmCMakeHostSystemInformationCommand.cxx +++ b/Source/cmCMakeHostSystemInformationCommand.cxx @@ -8,6 +8,9 @@ #include "cmsys/SystemInformation.hxx" #if defined(_WIN32) +#include "cmAlgorithms.h" +#include "cmGlobalGenerator.h" +#include "cmGlobalVisualStudio15Generator.h" #include "cmSystemTools.h" #include "cmVSSetupHelper.h" #define HAVE_VS_SETUP_HELPER @@ -127,6 +130,17 @@ bool cmCMakeHostSystemInformationCommand::GetValue( value = this->ValueToString(info.GetOSPlatform()); #ifdef HAVE_VS_SETUP_HELPER } else if (key == "VS_15_DIR") { + // If generating for the VS 15 IDE, use the same instance. + cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator(); + if (cmHasLiteralPrefix(gg->GetName(), "Visual Studio 15 ")) { + cmGlobalVisualStudio15Generator* vs15gen = + static_cast<cmGlobalVisualStudio15Generator*>(gg); + if (vs15gen->GetVSInstance(value)) { + return true; + } + } + + // Otherwise, find a VS 15 instance ourselves. cmVSSetupAPIHelper vsSetupAPIHelper; if (vsSetupAPIHelper.GetVSInstanceInfo(value)) { cmSystemTools::ConvertToUnixSlashes(value); diff --git a/Source/cmCMakeHostSystemInformationCommand.h b/Source/cmCMakeHostSystemInformationCommand.h index bfff8f1..b871641 100644 --- a/Source/cmCMakeHostSystemInformationCommand.h +++ b/Source/cmCMakeHostSystemInformationCommand.h @@ -20,7 +20,7 @@ class SystemInformation; * \brief Query host system specific information * * cmCMakeHostSystemInformationCommand queries system information of - * the sytem on which CMake runs. + * the system on which CMake runs. */ class cmCMakeHostSystemInformationCommand : public cmCommand { diff --git a/Source/cmCPluginAPI.cxx b/Source/cmCPluginAPI.cxx index e1e11af..18a1022 100644 --- a/Source/cmCPluginAPI.cxx +++ b/Source/cmCPluginAPI.cxx @@ -218,8 +218,8 @@ void CCONV cmAddUtilityCommand(void* arg, const char* utilityName, } // Pass the call to the makefile instance. - mf->AddUtilityCommand(utilityName, (all ? false : true), nullptr, depends2, - commandLines); + mf->AddUtilityCommand(utilityName, cmMakefile::TargetOrigin::Project, + (all ? false : true), nullptr, depends2, commandLines); } void CCONV cmAddCustomCommand(void* arg, const char* source, const char* command, int numArgs, diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 4ea1493..d358e3d 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -12,6 +12,7 @@ #include "cmsys/String.hxx" #include "cmsys/SystemInformation.hxx" #include <algorithm> +#include <chrono> #include <ctype.h> #include <iostream> #include <map> @@ -281,7 +282,6 @@ cmCTest::cmCTest() this->GlobalTimeout = 0; this->LastStopTimeout = 24 * 60 * 60; this->CompressXMLFiles = false; - this->CTestConfigFile.clear(); this->ScheduleType.clear(); this->StopTime.clear(); this->NextDayStopTime = false; @@ -622,12 +622,9 @@ bool cmCTest::UpdateCTestConfiguration() if (this->SuppressUpdatingCTestConfiguration) { return true; } - std::string fileName = this->CTestConfigFile; - if (fileName.empty()) { - fileName = this->BinaryDir + "/CTestConfiguration.ini"; - if (!cmSystemTools::FileExists(fileName.c_str())) { - fileName = this->BinaryDir + "/DartConfiguration.tcl"; - } + std::string fileName = this->BinaryDir + "/CTestConfiguration.ini"; + if (!cmSystemTools::FileExists(fileName.c_str())) { + fileName = this->BinaryDir + "/DartConfiguration.tcl"; } cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "UpdateCTestConfiguration from :" << fileName << "\n"); @@ -1421,7 +1418,7 @@ int cmCTest::GenerateCTestNotesOutput(cmXMLWriter& xml, std::string note_time = this->CurrentTime(); xml.StartElement("Note"); xml.Attribute("Name", file); - xml.Element("Time", cmSystemTools::GetTime()); + xml.Element("Time", std::chrono::system_clock::now()); xml.Element("DateTime", note_time); xml.StartElement("Text"); cmsys::ifstream ifs(file.c_str()); diff --git a/Source/cmCTest.h b/Source/cmCTest.h index dbd67dc..a2d6fc3 100644 --- a/Source/cmCTest.h +++ b/Source/cmCTest.h @@ -487,7 +487,6 @@ private: /** Map of configuration properties */ typedef std::map<std::string, std::string> CTestConfigurationMap; - std::string CTestConfigFile; // TODO: The ctest configuration should be a hierarchy of // configuration option sources: command-line, script, ini file. // Then the ini file can get re-loaded whenever it changes without diff --git a/Source/cmCacheManager.h b/Source/cmCacheManager.h index e9e6570..28cba85 100644 --- a/Source/cmCacheManager.h +++ b/Source/cmCacheManager.h @@ -107,7 +107,7 @@ public: std::set<std::string>& excludes, std::set<std::string>& includes); - ///! Save cache for given makefile. Saves to ouput path/CMakeCache.txt + ///! Save cache for given makefile. Saves to output path/CMakeCache.txt bool SaveCache(const std::string& path); ///! Delete the cache given diff --git a/Source/cmCommandArgumentParserHelper.cxx b/Source/cmCommandArgumentParserHelper.cxx index 6ae58d6..bf314bd 100644 --- a/Source/cmCommandArgumentParserHelper.cxx +++ b/Source/cmCommandArgumentParserHelper.cxx @@ -21,13 +21,6 @@ cmCommandArgumentParserHelper::cmCommandArgumentParserHelper() this->FileLine = -1; this->FileName = nullptr; this->RemoveEmpty = true; - this->EmptyVariable[0] = 0; - strcpy(this->DCURLYVariable, "${"); - strcpy(this->RCURLYVariable, "}"); - strcpy(this->ATVariable, "@"); - strcpy(this->DOLLARVariable, "$"); - strcpy(this->LCURLYVariable, "{"); - strcpy(this->BSLASHVariable, "\\"); this->NoEscapeMode = false; this->ReplaceAtSyntax = false; @@ -44,10 +37,10 @@ void cmCommandArgumentParserHelper::SetLineFile(long line, const char* file) this->FileName = file; } -char* cmCommandArgumentParserHelper::AddString(const std::string& str) +const char* cmCommandArgumentParserHelper::AddString(const std::string& str) { if (str.empty()) { - return this->EmptyVariable; + return ""; } char* stVal = new char[str.size() + 1]; strcpy(stVal, str.c_str()); @@ -55,14 +48,14 @@ char* cmCommandArgumentParserHelper::AddString(const std::string& str) return stVal; } -char* cmCommandArgumentParserHelper::ExpandSpecialVariable(const char* key, - const char* var) +const char* cmCommandArgumentParserHelper::ExpandSpecialVariable( + const char* key, const char* var) { if (!key) { return this->ExpandVariable(var); } if (!var) { - return this->EmptyVariable; + return ""; } if (strcmp(key, "ENV") == 0) { std::string str; @@ -72,7 +65,7 @@ char* cmCommandArgumentParserHelper::ExpandSpecialVariable(const char* key, } return this->AddString(str); } - return this->EmptyVariable; + return ""; } if (strcmp(key, "CACHE") == 0) { if (const char* c = @@ -82,7 +75,7 @@ char* cmCommandArgumentParserHelper::ExpandSpecialVariable(const char* key, } return this->AddString(c); } - return this->EmptyVariable; + return ""; } std::ostringstream e; e << "Syntax $" << key << "{} is not supported. " @@ -91,7 +84,7 @@ char* cmCommandArgumentParserHelper::ExpandSpecialVariable(const char* key, return nullptr; } -char* cmCommandArgumentParserHelper::ExpandVariable(const char* var) +const char* cmCommandArgumentParserHelper::ExpandVariable(const char* var) { if (!var) { return nullptr; @@ -125,11 +118,11 @@ char* cmCommandArgumentParserHelper::ExpandVariable(const char* var) return this->AddString(value ? value : ""); } -char* cmCommandArgumentParserHelper::ExpandVariableForAt(const char* var) +const char* cmCommandArgumentParserHelper::ExpandVariableForAt(const char* var) { if (this->ReplaceAtSyntax) { // try to expand the variable - char* ret = this->ExpandVariable(var); + const char* ret = this->ExpandVariable(var); // if the return was 0 and we want to replace empty strings // then return an empty string if (!ret && this->RemoveEmpty) { @@ -150,7 +143,8 @@ char* cmCommandArgumentParserHelper::ExpandVariableForAt(const char* var) return this->AddString(ref); } -char* cmCommandArgumentParserHelper::CombineUnions(char* in1, char* in2) +const char* cmCommandArgumentParserHelper::CombineUnions(const char* in1, + const char* in2) { if (!in1) { return in2; @@ -176,10 +170,11 @@ void cmCommandArgumentParserHelper::AllocateParserType( if (len == 0) { return; } - pt->str = new char[len + 1]; - strncpy(pt->str, str, len); - pt->str[len] = 0; - this->Variables.push_back(pt->str); + char* out = new char[len + 1]; + strncpy(out, str, len); + out[len] = 0; + pt->str = out; + this->Variables.push_back(out); } bool cmCommandArgumentParserHelper::HandleEscapeSymbol( diff --git a/Source/cmCommandArgumentParserHelper.h b/Source/cmCommandArgumentParserHelper.h index cb2a390..098c000 100644 --- a/Source/cmCommandArgumentParserHelper.h +++ b/Source/cmCommandArgumentParserHelper.h @@ -17,7 +17,7 @@ class cmCommandArgumentParserHelper public: struct ParserType { - char* str; + const char* str; }; cmCommandArgumentParserHelper(); @@ -35,11 +35,11 @@ public: void Error(const char* str); // For yacc - char* CombineUnions(char* in1, char* in2); + const char* CombineUnions(const char* in1, const char* in2); - char* ExpandSpecialVariable(const char* key, const char* var); - char* ExpandVariable(const char* var); - char* ExpandVariableForAt(const char* var); + const char* ExpandSpecialVariable(const char* key, const char* var); + const char* ExpandVariable(const char* var); + const char* ExpandVariableForAt(const char* var); void SetResult(const char* value); void SetMakefile(const cmMakefile* mf); @@ -53,13 +53,6 @@ public: void SetRemoveEmpty(bool b) { this->RemoveEmpty = b; } const char* GetError() { return this->ErrorString.c_str(); } - char EmptyVariable[1]; - char DCURLYVariable[3]; - char RCURLYVariable[3]; - char ATVariable[3]; - char DOLLARVariable[3]; - char LCURLYVariable[3]; - char BSLASHVariable[3]; private: std::string::size_type InputBufferPos; @@ -69,7 +62,7 @@ private: void Print(const char* place, const char* str); void SafePrintMissing(const char* str, int line, int cnt); - char* AddString(const std::string& str); + const char* AddString(const std::string& str); void CleanupParser(); void SetError(std::string const& msg); diff --git a/Source/cmConfigure.cmake.h.in b/Source/cmConfigure.cmake.h.in index 9a78aca..c80439b 100644 --- a/Source/cmConfigure.cmake.h.in +++ b/Source/cmConfigure.cmake.h.in @@ -19,22 +19,11 @@ #cmakedefine HAVE_UNSETENV #cmakedefine CMAKE_USE_ELF_PARSER #cmakedefine CMAKE_USE_MACH_PARSER -#cmakedefine CMake_HAVE_CXX_FALLTHROUGH -#cmakedefine CMake_HAVE_CXX_GNU_FALLTHROUGH -#cmakedefine CMake_HAVE_CXX_ATTRIBUTE_FALLTHROUGH #cmakedefine CMake_HAVE_CXX_MAKE_UNIQUE #define CMAKE_BIN_DIR "/@CMAKE_BIN_DIR@" #define CMAKE_DATA_DIR "/@CMAKE_DATA_DIR@" -#if defined(CMake_HAVE_CXX_FALLTHROUGH) -#define CM_FALLTHROUGH [[fallthrough]] -#elif defined(CMake_HAVE_CXX_GNU_FALLTHROUGH) -#define CM_FALLTHROUGH [[gnu::fallthrough]] -#elif defined(CMake_HAVE_CXX_ATTRIBUTE_FALLTHROUGH) -#define CM_FALLTHROUGH __attribute__((fallthrough)) -#else -#define CM_FALLTHROUGH -#endif +#define CM_FALLTHROUGH cmsys_FALLTHROUGH #define CM_DISABLE_COPY(Class) \ Class(Class const&) = delete; \ diff --git a/Source/cmConnection.cxx b/Source/cmConnection.cxx index 28ba12c..50e1936 100644 --- a/Source/cmConnection.cxx +++ b/Source/cmConnection.cxx @@ -26,7 +26,7 @@ void cmEventBasedConnection::on_alloc_buffer(uv_handle_t* handle, void cmEventBasedConnection::on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { - auto conn = reinterpret_cast<cmEventBasedConnection*>(stream->data); + auto conn = static_cast<cmEventBasedConnection*>(stream->data); if (conn) { if (nread >= 0) { conn->ReadData(std::string(buf->base, buf->base + nread)); @@ -55,7 +55,7 @@ void cmEventBasedConnection::on_write(uv_write_t* req, int status) void cmEventBasedConnection::on_new_connection(uv_stream_t* stream, int status) { (void)(status); - auto conn = reinterpret_cast<cmEventBasedConnection*>(stream->data); + auto conn = static_cast<cmEventBasedConnection*>(stream->data); if (conn) { conn->Connect(stream); @@ -76,7 +76,7 @@ void cmEventBasedConnection::WriteData(const std::string& _data) #endif auto data = _data; - assert(this->WriteStream); + assert(this->WriteStream.get()); if (BufferStrategy) { data = BufferStrategy->BufferOutMessage(data); } @@ -87,8 +87,7 @@ void cmEventBasedConnection::WriteData(const std::string& _data) req->req.data = this; req->buf = uv_buf_init(new char[ds], static_cast<unsigned int>(ds)); memcpy(req->buf.base, data.c_str(), ds); - uv_write(reinterpret_cast<uv_write_t*>(req), - static_cast<uv_stream_t*>(this->WriteStream), &req->buf, 1, + uv_write(reinterpret_cast<uv_write_t*>(req), this->WriteStream, &req->buf, 1, on_write); } @@ -156,13 +155,11 @@ bool cmConnection::OnServeStart(std::string* errString) bool cmEventBasedConnection::OnConnectionShuttingDown() { - if (this->WriteStream) { + if (this->WriteStream.get()) { this->WriteStream->data = nullptr; } - if (this->ReadStream) { - this->ReadStream->data = nullptr; - } - this->ReadStream = nullptr; - this->WriteStream = nullptr; + + WriteStream.reset(); + return true; } diff --git a/Source/cmConnection.h b/Source/cmConnection.h index ddb7744..ce2d2dc 100644 --- a/Source/cmConnection.h +++ b/Source/cmConnection.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include "cmUVHandlePtr.h" #include "cm_uv.h" #include <cstddef> @@ -107,8 +108,6 @@ public: bool OnConnectionShuttingDown() override; virtual void OnDisconnect(int errorCode); - uv_stream_t* ReadStream = nullptr; - uv_stream_t* WriteStream = nullptr; static void on_close(uv_handle_t* handle); @@ -119,6 +118,8 @@ public: } protected: + cm::uv_stream_ptr WriteStream; + std::string RawReadBuffer; std::unique_ptr<cmConnectionBufferStrategy> BufferStrategy; diff --git a/Source/cmConvertMSBuildXMLToJSON.py b/Source/cmConvertMSBuildXMLToJSON.py index 93ab8a8..92569e7 100644 --- a/Source/cmConvertMSBuildXMLToJSON.py +++ b/Source/cmConvertMSBuildXMLToJSON.py @@ -343,7 +343,7 @@ def __with_argument(node, value): def __preprocess_arguments(root): - """Preprocesses occurrances of Argument within the root. + """Preprocesses occurrences of Argument within the root. Argument XML values reference other values within the document by name. The referenced value does not contain a switch. This function will add the diff --git a/Source/cmCurl.cxx b/Source/cmCurl.cxx index 341b8c0..8ef8bff 100644 --- a/Source/cmCurl.cxx +++ b/Source/cmCurl.cxx @@ -56,3 +56,41 @@ std::string cmCurlSetCAInfo(::CURL* curl, const char* cafile) #endif return e; } + +std::string cmCurlSetNETRCOption(::CURL* curl, const std::string& netrc_level, + const std::string& netrc_file) +{ + std::string e; + CURL_NETRC_OPTION curl_netrc_level = CURL_NETRC_LAST; + ::CURLcode res; + + if (!netrc_level.empty()) { + if (netrc_level == "OPTIONAL") { + curl_netrc_level = CURL_NETRC_OPTIONAL; + } else if (netrc_level == "REQUIRED") { + curl_netrc_level = CURL_NETRC_REQUIRED; + } else if (netrc_level == "IGNORED") { + curl_netrc_level = CURL_NETRC_IGNORED; + } else { + e = "NETRC accepts OPTIONAL, IGNORED or REQUIRED but got: "; + e += netrc_level; + return e; + } + } + + if (curl_netrc_level != CURL_NETRC_LAST && + curl_netrc_level != CURL_NETRC_IGNORED) { + res = ::curl_easy_setopt(curl, CURLOPT_NETRC, curl_netrc_level); + check_curl_result(res, "Unable to set netrc level: "); + if (!e.empty()) { + return e; + } + + // check to see if a .netrc file has been specified + if (!netrc_file.empty()) { + res = ::curl_easy_setopt(curl, CURLOPT_NETRC_FILE, netrc_file.c_str()); + check_curl_result(res, "Unable to set .netrc file path : "); + } + } + return e; +} diff --git a/Source/cmCurl.h b/Source/cmCurl.h index 0688bb2..fe7eb80 100644 --- a/Source/cmCurl.h +++ b/Source/cmCurl.h @@ -9,5 +9,7 @@ #include <string> std::string cmCurlSetCAInfo(::CURL* curl, const char* cafile = nullptr); +std::string cmCurlSetNETRCOption(::CURL* curl, const std::string& netrc_level, + const std::string& netrc_file); #endif diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 7f0cb97..7985d0f 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -591,7 +591,7 @@ void cmExportFileGenerator::ResolveTargetsInGeneratorExpression( std::string::size_type commaPos = input.find(',', nameStartPos); std::string::size_type nextOpenPos = input.find("$<", nameStartPos); if (commaPos == std::string::npos // Implied 'this' target - || closePos == std::string::npos // Imcomplete expression. + || closePos == std::string::npos // Incomplete expression. || closePos < commaPos // Implied 'this' target || nextOpenPos < commaPos) // Non-literal { diff --git a/Source/cmExternalMakefileProjectGenerator.cxx b/Source/cmExternalMakefileProjectGenerator.cxx index 825ec65..fecd821 100644 --- a/Source/cmExternalMakefileProjectGenerator.cxx +++ b/Source/cmExternalMakefileProjectGenerator.cxx @@ -24,6 +24,13 @@ std::string cmExternalMakefileProjectGenerator::CreateFullGeneratorName( return fullName; } +bool cmExternalMakefileProjectGenerator::Open( + const std::string& /*bindir*/, const std::string& /*projectName*/, + bool /*dryRun*/) +{ + return false; +} + cmExternalMakefileProjectGeneratorFactory:: cmExternalMakefileProjectGeneratorFactory(const std::string& n, const std::string& doc) diff --git a/Source/cmExternalMakefileProjectGenerator.h b/Source/cmExternalMakefileProjectGenerator.h index a1734ee..7f332a8 100644 --- a/Source/cmExternalMakefileProjectGenerator.h +++ b/Source/cmExternalMakefileProjectGenerator.h @@ -55,6 +55,9 @@ public: void SetName(const std::string& n) { Name = n; } std::string GetName() const { return Name; } + virtual bool Open(const std::string& bindir, const std::string& projectName, + bool dryRun); + protected: ///! Contains the names of the global generators support by this generator. std::vector<std::string> SupportedGlobalGenerators; diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx index 9c9b75b..edce330 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -345,8 +345,7 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile( all_files_map_t allFiles; std::vector<std::string> cFiles; - std::vector<std::string> const& srcExts = - this->GlobalGenerator->GetCMakeInstance()->GetSourceExtensions(); + auto cm = this->GlobalGenerator->GetCMakeInstance(); for (cmLocalGenerator* lg : lgs) { cmMakefile* makefile = lg->GetMakefile(); @@ -377,12 +376,7 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile( std::string lang = s->GetLanguage(); if (lang == "C" || lang == "CXX") { std::string const& srcext = s->GetExtension(); - for (std::string const& ext : srcExts) { - if (srcext == ext) { - isCFile = true; - break; - } - } + isCFile = cm->IsSourceExtension(srcext); } std::string const& fullPath = s->GetFullPath(); @@ -648,6 +642,13 @@ void cmExtraCodeBlocksGenerator::AppendTarget( // Translate the cmake compiler id into the CodeBlocks compiler id std::string cmExtraCodeBlocksGenerator::GetCBCompilerId(const cmMakefile* mf) { + // allow the user to overwrite the detected compiler + std::string userCompiler = + mf->GetSafeDefinition("CMAKE_CODEBLOCKS_COMPILER_ID"); + if (!userCompiler.empty()) { + return userCompiler; + } + // figure out which language to use // for now care only for C, C++, and Fortran diff --git a/Source/cmExtraCodeLiteGenerator.cxx b/Source/cmExtraCodeLiteGenerator.cxx index 5a02d54..383942b 100644 --- a/Source/cmExtraCodeLiteGenerator.cxx +++ b/Source/cmExtraCodeLiteGenerator.cxx @@ -198,8 +198,7 @@ std::string cmExtraCodeLiteGenerator::CollectSourceFiles( std::map<std::string, cmSourceFile*>& cFiles, std::set<std::string>& otherFiles) { - const std::vector<std::string>& srcExts = - this->GlobalGenerator->GetCMakeInstance()->GetSourceExtensions(); + auto cm = this->GlobalGenerator->GetCMakeInstance(); std::string projectType; switch (gt->GetType()) { @@ -233,12 +232,7 @@ std::string cmExtraCodeLiteGenerator::CollectSourceFiles( std::string lang = s->GetLanguage(); if (lang == "C" || lang == "CXX") { std::string const& srcext = s->GetExtension(); - for (std::string const& ext : srcExts) { - if (srcext == ext) { - isCFile = true; - break; - } - } + isCFile = cm->IsSourceExtension(srcext); } // then put it accordingly into one of the two containers diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx index 73a9c85..3d72ae3 100644 --- a/Source/cmExtraSublimeTextGenerator.cxx +++ b/Source/cmExtraSublimeTextGenerator.cxx @@ -400,3 +400,26 @@ std::string cmExtraSublimeTextGenerator::ComputeDefines( return definesString; } + +bool cmExtraSublimeTextGenerator::Open(const std::string& bindir, + const std::string& projectName, + bool dryRun) +{ + const char* sublExecutable = + this->GlobalGenerator->GetCMakeInstance()->GetCacheDefinition( + "CMAKE_SUBLIMETEXT_EXECUTABLE"); + if (!sublExecutable) { + return false; + } + if (cmSystemTools::IsNOTFOUND(sublExecutable)) { + return false; + } + + std::string filename = bindir + "/" + projectName + ".sublime-project"; + if (dryRun) { + return cmSystemTools::FileExists(filename, true); + } + + return cmSystemTools::RunSingleCommand( + { sublExecutable, "--project", filename }); +} diff --git a/Source/cmExtraSublimeTextGenerator.h b/Source/cmExtraSublimeTextGenerator.h index 7fb304e..57ba1cf 100644 --- a/Source/cmExtraSublimeTextGenerator.h +++ b/Source/cmExtraSublimeTextGenerator.h @@ -65,6 +65,9 @@ private: std::string ComputeDefines(cmSourceFile* source, cmLocalGenerator* lg, cmGeneratorTarget* gtgt); + bool Open(const std::string& bindir, const std::string& projectName, + bool dryRun) override; + bool ExcludeBuildFolder; std::string EnvSettings; }; diff --git a/Source/cmFSPermissions.cxx b/Source/cmFSPermissions.cxx new file mode 100644 index 0000000..4015a51 --- /dev/null +++ b/Source/cmFSPermissions.cxx @@ -0,0 +1,34 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmFSPermissions.h" + +bool cmFSPermissions::stringToModeT(std::string const& arg, + mode_t& permissions) +{ + if (arg == "OWNER_READ") { + permissions |= mode_owner_read; + } else if (arg == "OWNER_WRITE") { + permissions |= mode_owner_write; + } else if (arg == "OWNER_EXECUTE") { + permissions |= mode_owner_execute; + } else if (arg == "GROUP_READ") { + permissions |= mode_group_read; + } else if (arg == "GROUP_WRITE") { + permissions |= mode_group_write; + } else if (arg == "GROUP_EXECUTE") { + permissions |= mode_group_execute; + } else if (arg == "WORLD_READ") { + permissions |= mode_world_read; + } else if (arg == "WORLD_WRITE") { + permissions |= mode_world_write; + } else if (arg == "WORLD_EXECUTE") { + permissions |= mode_world_execute; + } else if (arg == "SETUID") { + permissions |= mode_setuid; + } else if (arg == "SETGID") { + permissions |= mode_setgid; + } else { + return false; + } + return true; +} diff --git a/Source/cmFSPermissions.h b/Source/cmFSPermissions.h new file mode 100644 index 0000000..7a6e708 --- /dev/null +++ b/Source/cmFSPermissions.h @@ -0,0 +1,45 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmFSPermissions_h +#define cmFSPermissions_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include "cm_sys_stat.h" + +#include <string> + +namespace cmFSPermissions { + +// Table of permissions flags. +#if defined(_WIN32) && !defined(__CYGWIN__) +static const mode_t mode_owner_read = S_IREAD; +static const mode_t mode_owner_write = S_IWRITE; +static const mode_t mode_owner_execute = S_IEXEC; +static const mode_t mode_group_read = 040; +static const mode_t mode_group_write = 020; +static const mode_t mode_group_execute = 010; +static const mode_t mode_world_read = 04; +static const mode_t mode_world_write = 02; +static const mode_t mode_world_execute = 01; +static const mode_t mode_setuid = 04000; +static const mode_t mode_setgid = 02000; +#else +static const mode_t mode_owner_read = S_IRUSR; +static const mode_t mode_owner_write = S_IWUSR; +static const mode_t mode_owner_execute = S_IXUSR; +static const mode_t mode_group_read = S_IRGRP; +static const mode_t mode_group_write = S_IWGRP; +static const mode_t mode_group_execute = S_IXGRP; +static const mode_t mode_world_read = S_IROTH; +static const mode_t mode_world_write = S_IWOTH; +static const mode_t mode_world_execute = S_IXOTH; +static const mode_t mode_setuid = S_ISUID; +static const mode_t mode_setgid = S_ISGID; +#endif + +bool stringToModeT(std::string const& arg, mode_t& permissions); + +} // ns + +#endif diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index fdd5f0c..88185bd 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -20,6 +20,7 @@ #include "cmAlgorithms.h" #include "cmCommandArgumentsHelper.h" #include "cmCryptoHash.h" +#include "cmFSPermissions.h" #include "cmFileLockPool.h" #include "cmFileTimeComparison.h" #include "cmGeneratorExpression.h" @@ -50,32 +51,7 @@ class cmSystemToolsFileTime; -// Table of permissions flags. -#if defined(_WIN32) && !defined(__CYGWIN__) -static mode_t mode_owner_read = S_IREAD; -static mode_t mode_owner_write = S_IWRITE; -static mode_t mode_owner_execute = S_IEXEC; -static mode_t mode_group_read = 040; -static mode_t mode_group_write = 020; -static mode_t mode_group_execute = 010; -static mode_t mode_world_read = 04; -static mode_t mode_world_write = 02; -static mode_t mode_world_execute = 01; -static mode_t mode_setuid = 04000; -static mode_t mode_setgid = 02000; -#else -static mode_t mode_owner_read = S_IRUSR; -static mode_t mode_owner_write = S_IWUSR; -static mode_t mode_owner_execute = S_IXUSR; -static mode_t mode_group_read = S_IRGRP; -static mode_t mode_group_write = S_IWGRP; -static mode_t mode_group_execute = S_IXGRP; -static mode_t mode_world_read = S_IROTH; -static mode_t mode_world_write = S_IWOTH; -static mode_t mode_world_execute = S_IXOTH; -static mode_t mode_setuid = S_ISUID; -static mode_t mode_setgid = S_ISGID; -#endif +using namespace cmFSPermissions; #if defined(_WIN32) // libcurl doesn't support file:// urls for unicode filenames on Windows. @@ -1099,29 +1075,7 @@ protected: // Translate an argument to a permissions bit. bool CheckPermissions(std::string const& arg, mode_t& permissions) { - if (arg == "OWNER_READ") { - permissions |= mode_owner_read; - } else if (arg == "OWNER_WRITE") { - permissions |= mode_owner_write; - } else if (arg == "OWNER_EXECUTE") { - permissions |= mode_owner_execute; - } else if (arg == "GROUP_READ") { - permissions |= mode_group_read; - } else if (arg == "GROUP_WRITE") { - permissions |= mode_group_write; - } else if (arg == "GROUP_EXECUTE") { - permissions |= mode_group_execute; - } else if (arg == "WORLD_READ") { - permissions |= mode_world_read; - } else if (arg == "WORLD_WRITE") { - permissions |= mode_world_write; - } else if (arg == "WORLD_EXECUTE") { - permissions |= mode_world_execute; - } else if (arg == "SETUID") { - permissions |= mode_setuid; - } else if (arg == "SETGID") { - permissions |= mode_setgid; - } else { + if (!cmFSPermissions::stringToModeT(arg, permissions)) { std::ostringstream e; e << this->Name << " given invalid permission \"" << arg << "\"."; this->FileCommand->SetError(e.str()); @@ -2015,9 +1969,30 @@ bool cmFileInstaller::HandleInstallDestination() this->DestDirLength = int(sdestdir.size()); } + // check if default dir creation permissions were set + mode_t default_dir_mode_v = 0; + mode_t* default_dir_mode = nullptr; + const char* default_dir_install_permissions = this->Makefile->GetDefinition( + "CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS"); + if (default_dir_install_permissions && *default_dir_install_permissions) { + std::vector<std::string> items; + cmSystemTools::ExpandListArgument(default_dir_install_permissions, items); + for (const auto& arg : items) { + if (!this->CheckPermissions(arg, default_dir_mode_v)) { + std::ostringstream e; + e << this->FileCommand->GetError() + << " Set with CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS variable."; + this->FileCommand->SetError(e.str()); + return false; + } + } + + default_dir_mode = &default_dir_mode_v; + } + if (this->InstallType != cmInstallType_DIRECTORY) { if (!cmSystemTools::FileExists(destination.c_str())) { - if (!cmSystemTools::MakeDirectory(destination.c_str())) { + if (!cmSystemTools::MakeDirectory(destination, default_dir_mode)) { std::string errstring = "cannot create directory: " + destination + ". Maybe need administrative privileges."; this->FileCommand->SetError(errstring); @@ -2626,6 +2601,9 @@ bool cmFileCommand::HandleDownloadCommand(std::vector<std::string> const& args) std::string statusVar; bool tls_verify = this->Makefile->IsOn("CMAKE_TLS_VERIFY"); const char* cainfo = this->Makefile->GetDefinition("CMAKE_TLS_CAINFO"); + std::string netrc_level = this->Makefile->GetSafeDefinition("CMAKE_NETRC"); + std::string netrc_file = + this->Makefile->GetSafeDefinition("CMAKE_NETRC_FILE"); std::string expectedHash; std::string hashMatchMSG; std::unique_ptr<cmCryptoHash> hash; @@ -2681,6 +2659,22 @@ bool cmFileCommand::HandleDownloadCommand(std::vector<std::string> const& args) this->SetError("TLS_CAFILE missing file value."); return false; } + } else if (*i == "NETRC_FILE") { + ++i; + if (i != args.end()) { + netrc_file = *i; + } else { + this->SetError("DOWNLOAD missing file value for NETRC_FILE."); + return false; + } + } else if (*i == "NETRC") { + ++i; + if (i != args.end()) { + netrc_level = *i; + } else { + this->SetError("DOWNLOAD missing level value for NETRC."); + return false; + } } else if (*i == "EXPECTED_MD5") { ++i; if (i == args.end()) { @@ -2822,6 +2816,16 @@ bool cmFileCommand::HandleDownloadCommand(std::vector<std::string> const& args) return false; } + // check to see if netrc parameters have been specified + // local command args takes precedence over CMAKE_NETRC* + netrc_level = cmSystemTools::UpperCase(netrc_level); + std::string const& netrc_option_err = + cmCurlSetNETRCOption(curl, netrc_level, netrc_file); + if (!netrc_option_err.empty()) { + this->SetError(netrc_option_err); + return false; + } + cmFileCommandVectorOfChar chunkDebug; res = ::curl_easy_setopt(curl, CURLOPT_WRITEDATA, &fout); @@ -2964,6 +2968,9 @@ bool cmFileCommand::HandleUploadCommand(std::vector<std::string> const& args) std::string statusVar; bool showProgress = false; std::string userpwd; + std::string netrc_level = this->Makefile->GetSafeDefinition("CMAKE_NETRC"); + std::string netrc_file = + this->Makefile->GetSafeDefinition("CMAKE_NETRC_FILE"); std::vector<std::string> curl_headers; @@ -3000,6 +3007,22 @@ bool cmFileCommand::HandleUploadCommand(std::vector<std::string> const& args) statusVar = *i; } else if (*i == "SHOW_PROGRESS") { showProgress = true; + } else if (*i == "NETRC_FILE") { + ++i; + if (i != args.end()) { + netrc_file = *i; + } else { + this->SetError("UPLOAD missing file value for NETRC_FILE."); + return false; + } + } else if (*i == "NETRC") { + ++i; + if (i != args.end()) { + netrc_level = *i; + } else { + this->SetError("UPLOAD missing level value for NETRC."); + return false; + } } else if (*i == "USERPWD") { ++i; if (i == args.end()) { @@ -3132,6 +3155,16 @@ bool cmFileCommand::HandleUploadCommand(std::vector<std::string> const& args) check_curl_result(res, "UPLOAD cannot set user password: "); } + // check to see if netrc parameters have been specified + // local command args takes precedence over CMAKE_NETRC* + netrc_level = cmSystemTools::UpperCase(netrc_level); + std::string const& netrc_option_err = + cmCurlSetNETRCOption(curl, netrc_level, netrc_file); + if (!netrc_option_err.empty()) { + this->SetError(netrc_option_err); + return false; + } + struct curl_slist* headers = nullptr; for (std::string const& h : curl_headers) { headers = ::curl_slist_append(headers, h.c_str()); diff --git a/Source/cmFilePathChecksum.cxx b/Source/cmFilePathChecksum.cxx index f9afeef..f84360e 100644 --- a/Source/cmFilePathChecksum.cxx +++ b/Source/cmFilePathChecksum.cxx @@ -34,10 +34,10 @@ void cmFilePathChecksum::setupParentDirs(std::string const& currentSrcDir, std::string const& projectSrcDir, std::string const& projectBinDir) { - this->parentDirs[0].first = cmsys::SystemTools::GetRealPath(currentSrcDir); - this->parentDirs[1].first = cmsys::SystemTools::GetRealPath(currentBinDir); - this->parentDirs[2].first = cmsys::SystemTools::GetRealPath(projectSrcDir); - this->parentDirs[3].first = cmsys::SystemTools::GetRealPath(projectBinDir); + this->parentDirs[0].first = cmSystemTools::GetRealPath(currentSrcDir); + this->parentDirs[1].first = cmSystemTools::GetRealPath(currentBinDir); + this->parentDirs[2].first = cmSystemTools::GetRealPath(projectSrcDir); + this->parentDirs[3].first = cmSystemTools::GetRealPath(projectBinDir); this->parentDirs[0].second = "CurrentSource"; this->parentDirs[1].second = "CurrentBinary"; @@ -50,7 +50,7 @@ std::string cmFilePathChecksum::get(std::string const& filePath) const std::string relPath; std::string relSeed; { - std::string const fileReal = cmsys::SystemTools::GetRealPath(filePath); + std::string const fileReal = cmSystemTools::GetRealPath(filePath); std::string parentDir; // Find closest project parent directory for (auto const& pDir : this->parentDirs) { diff --git a/Source/cmFindCommon.cxx b/Source/cmFindCommon.cxx index 8142962..f771150 100644 --- a/Source/cmFindCommon.cxx +++ b/Source/cmFindCommon.cxx @@ -329,7 +329,7 @@ void cmFindCommon::ComputeFinalPaths() std::set<std::string> ignored; this->GetIgnoredPaths(ignored); - // Combine the seperate path types, filtering out ignores + // Combine the separate path types, filtering out ignores this->SearchPaths.clear(); std::vector<PathLabel>& allLabels = this->PathGroupLabelMap[PathGroup::All]; for (PathLabel const& l : allLabels) { diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index 5a72655..103dc5f 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -590,7 +590,7 @@ void cmFindPackageCommand::SetModuleVariables(const std::string& components) this->AddFindDefinition(exact, this->VersionExact ? "1" : "0"); } - // Push on to the pacakge stack + // Push on to the package stack this->Makefile->FindPackageModuleStack.push_back(this->Name); } diff --git a/Source/cmForEachCommand.cxx b/Source/cmForEachCommand.cxx index 542a860..df288bd 100644 --- a/Source/cmForEachCommand.cxx +++ b/Source/cmForEachCommand.cxx @@ -7,6 +7,7 @@ #include <stdio.h> #include <stdlib.h> +#include "cmAlgorithms.h" #include "cmExecutionStatus.h" #include "cmMakefile.h" #include "cmSystemTools.h" @@ -121,7 +122,7 @@ bool cmForEachCommand::InitialPass(std::vector<std::string> const& args, } // create a function blocker - cmForEachFunctionBlocker* f = new cmForEachFunctionBlocker(this->Makefile); + auto f = cm::make_unique<cmForEachFunctionBlocker>(this->Makefile); if (args.size() > 1) { if (args[1] == "RANGE") { int start = 0; @@ -175,7 +176,7 @@ bool cmForEachCommand::InitialPass(std::vector<std::string> const& args, } else { f->Args = args; } - this->Makefile->AddFunctionBlocker(f); + this->Makefile->AddFunctionBlocker(f.release()); return true; } diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index fea20ba..3d311d6 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -828,18 +828,21 @@ static const struct CompileLanguageNode : public cmGeneratorExpressionNode } std::string genName = gg->GetName(); if (genName.find("Visual Studio") != std::string::npos) { - reportError(context, content->GetOriginalExpression(), - "$<COMPILE_LANGUAGE:...> may not be used with Visual Studio " - "generators."); - return std::string(); - } - if (genName.find("Xcode") != std::string::npos) { if (dagChecker && (dagChecker->EvaluatingCompileDefinitions() || dagChecker->EvaluatingIncludeDirectories())) { reportError( context, content->GetOriginalExpression(), - "$<COMPILE_LANGUAGE:...> may only be used with COMPILE_OPTIONS " - "with the Xcode generator."); + "$<COMPILE_LANGUAGE:...> may only be used for COMPILE_OPTIONS " + "and file(GENERATE) with the Visual Studio generator."); + return std::string(); + } + } else if (genName.find("Xcode") != std::string::npos) { + if (dagChecker && (dagChecker->EvaluatingCompileDefinitions() || + dagChecker->EvaluatingIncludeDirectories())) { + reportError( + context, content->GetOriginalExpression(), + "$<COMPILE_LANGUAGE:...> may only be used for COMPILE_OPTIONS " + "and file(GENERATE) with the Xcode generator."); return std::string(); } } else { @@ -1035,7 +1038,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode // No error. We just skip cyclic references. return std::string(); case cmGeneratorExpressionDAGChecker::ALREADY_SEEN: - for (size_t i = 1; i < cmArraySize(targetPropertyTransitiveWhitelist); + for (size_t i = 1; i < cm::size(targetPropertyTransitiveWhitelist); ++i) { if (targetPropertyTransitiveWhitelist[i] == propertyName) { // No error. We're not going to find anything new here. @@ -1443,7 +1446,7 @@ static const struct TargetPolicyNode : public cmGeneratorExpressionNode context->HadContextSensitiveCondition = true; context->HadHeadSensitiveCondition = true; - for (size_t i = 1; i < cmArraySize(targetPolicyWhitelist); ++i) { + for (size_t i = 1; i < cm::size(targetPolicyWhitelist); ++i) { const char* policy = targetPolicyWhitelist[i]; if (parameters.front() == policy) { cmLocalGenerator* lg = context->HeadTarget->GetLocalGenerator(); diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx index a31e415..b3e3393 100644 --- a/Source/cmGhsMultiTargetGenerator.cxx +++ b/Source/cmGhsMultiTargetGenerator.cxx @@ -489,7 +489,7 @@ void cmGhsMultiTargetGenerator::WriteSources( char const* sourceFullPath = (*si)->GetFullPath().c_str(); cmSourceGroup* sourceGroup = this->Makefile->FindSourceGroup(sourceFullPath, sourceGroups); - std::string sgPath(sourceGroup->GetFullName()); + std::string sgPath = sourceGroup->GetFullName(); cmSystemTools::ConvertToUnixSlashes(sgPath); cmGlobalGhsMultiGenerator::AddFilesUpToPath( this->GetFolderBuildStreams(), &this->FolderBuildStreams, @@ -608,7 +608,7 @@ std::string cmGhsMultiTargetGenerator::ComputeLongestObjectDirectory( cmSourceGroup* sourceGroup = localGhsMultiGenerator->GetMakefile()->FindSourceGroup(sourceFullPath, sourceGroups); - std::string const sgPath(sourceGroup->GetFullName()); + std::string const& sgPath = sourceGroup->GetFullName(); dir_max += sgPath; dir_max += "/Objs/libs/"; dir_max += generatorTarget->Target->GetName(); diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 05efff3..6e903fb 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -111,6 +111,26 @@ cmGlobalGenerator::~cmGlobalGenerator() delete this->ExtraGenerator; } +bool cmGlobalGenerator::SetGeneratorInstance(std::string const& i, + cmMakefile* mf) +{ + if (i.empty()) { + return true; + } + + std::ostringstream e; + /* clang-format off */ + e << + "Generator\n" + " " << this->GetName() << "\n" + "does not support instance specification, but instance\n" + " " << i << "\n" + "was specified."; + /* clang-format on */ + mf->IssueMessage(cmake::FATAL_ERROR, e.str()); + return false; +} + bool cmGlobalGenerator::SetGeneratorPlatform(std::string const& p, cmMakefile* mf) { @@ -261,6 +281,43 @@ void cmGlobalGenerator::ForceLinkerLanguages() { } +bool cmGlobalGenerator::CheckTargetsForMissingSources() const +{ + bool failed = false; + for (cmLocalGenerator* localGen : this->LocalGenerators) { + const std::vector<cmGeneratorTarget*>& targets = + localGen->GetGeneratorTargets(); + + for (cmGeneratorTarget* target : targets) { + if (target->GetType() == cmStateEnums::TargetType::GLOBAL_TARGET || + target->GetType() == cmStateEnums::TargetType::INTERFACE_LIBRARY || + target->GetType() == cmStateEnums::TargetType::UTILITY) { + continue; + } + + std::vector<std::string> configs; + target->Makefile->GetConfigurations(configs); + std::vector<cmSourceFile*> srcs; + if (configs.empty()) { + target->GetSourceFiles(srcs, ""); + } else { + for (std::vector<std::string>::const_iterator ci = configs.begin(); + ci != configs.end() && srcs.empty(); ++ci) { + target->GetSourceFiles(srcs, *ci); + } + } + if (srcs.empty()) { + std::ostringstream e; + e << "No SOURCES given to target: " << target->GetName(); + this->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, e.str(), + target->GetBacktrace()); + failed = true; + } + } + } + return failed; +} + bool cmGlobalGenerator::IsExportedTargetsFile( const std::string& filename) const { @@ -491,6 +548,13 @@ void cmGlobalGenerator::EnableLanguage( } if (readCMakeSystem) { + // Tell the generator about the instance, if any. + std::string instance = mf->GetSafeDefinition("CMAKE_GENERATOR_INSTANCE"); + if (!this->SetGeneratorInstance(instance, mf)) { + cmSystemTools::SetFatalErrorOccured(); + return; + } + // Find the native build tool for this generator. if (!this->FindMakeProgram(mf)) { return; @@ -898,7 +962,7 @@ std::string cmGlobalGenerator::GetLanguageOutputExtension( } } else { // if no language is found then check to see if it is already an - // ouput extension for some language. In that case it should be ignored + // output extension for some language. In that case it should be ignored // and in this map, so it will not be compiled but will just be used. std::string const& ext = source.GetExtension(); if (!ext.empty()) { @@ -1250,7 +1314,10 @@ bool cmGlobalGenerator::Compute() #ifdef CMAKE_BUILD_WITH_CMAKE // Iterate through all targets and set up automoc for those which have // the AUTOMOC, AUTOUIC or AUTORCC property set - cmQtAutoGenDigestUPV autogenDigests = this->CreateQtAutoGeneratorsTargets(); + auto autogenInits = this->CreateQtAutoGenInitializers(); + for (auto& autoGen : autogenInits) { + autoGen->InitCustomTargets(); + } #endif // Add generator specific helper commands @@ -1271,10 +1338,11 @@ bool cmGlobalGenerator::Compute() } #ifdef CMAKE_BUILD_WITH_CMAKE - for (cmQtAutoGenDigestUP const& digest : autogenDigests) { - cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget(*digest); + for (auto& autoGen : autogenInits) { + autoGen->SetupCustomTargets(); + autoGen.reset(nullptr); } - autogenDigests.clear(); + autogenInits.clear(); #endif for (cmLocalGenerator* localGen : this->LocalGenerators) { @@ -1292,6 +1360,11 @@ bool cmGlobalGenerator::Compute() localGen->TraceDependencies(); } + // Make sure that all (non-imported) targets have source files added! + if (this->CheckTargetsForMissingSources()) { + return false; + } + this->ForceLinkerLanguages(); // Compute the manifest of main targets generated. @@ -1400,9 +1473,10 @@ bool cmGlobalGenerator::ComputeTargetDepends() return true; } -cmQtAutoGenDigestUPV cmGlobalGenerator::CreateQtAutoGeneratorsTargets() +std::vector<std::unique_ptr<cmQtAutoGeneratorInitializer>> +cmGlobalGenerator::CreateQtAutoGenInitializers() { - cmQtAutoGenDigestUPV autogenDigests; + std::vector<std::unique_ptr<cmQtAutoGeneratorInitializer>> autogenInits; #ifdef CMAKE_BUILD_WITH_CMAKE for (cmLocalGenerator* localGen : this->LocalGenerators) { @@ -1438,25 +1512,12 @@ cmQtAutoGenDigestUPV cmGlobalGenerator::CreateQtAutoGeneratorsTargets() continue; } - { - cmQtAutoGenDigestUP digest(new cmQtAutoGenDigest(target)); - digest->QtVersionMajor = std::move(qtVersionMajor); - digest->QtVersionMinor = - cmQtAutoGeneratorInitializer::GetQtMinorVersion( - target, digest->QtVersionMajor); - digest->MocEnabled = mocEnabled; - digest->UicEnabled = uicEnabled; - digest->RccEnabled = rccEnabled; - autogenDigests.emplace_back(std::move(digest)); - } + autogenInits.emplace_back(new cmQtAutoGeneratorInitializer( + target, mocEnabled, uicEnabled, rccEnabled, qtVersionMajor)); } } - // Initialize autogen targets - for (const cmQtAutoGenDigestUP& digest : autogenDigests) { - cmQtAutoGeneratorInitializer::InitializeAutogenTarget(*digest); - } #endif - return autogenDigests; + return autogenInits; } cmLinkLineComputer* cmGlobalGenerator::CreateLinkLineComputer( @@ -1824,6 +1885,16 @@ int cmGlobalGenerator::Build(const std::string& /*unused*/, return retVal; } +bool cmGlobalGenerator::Open(const std::string& bindir, + const std::string& projectName, bool dryRun) +{ + if (this->ExtraGenerator) { + return this->ExtraGenerator->Open(bindir, projectName, dryRun); + } + + return false; +} + std::string cmGlobalGenerator::GenerateCMakeBuildCommand( const std::string& target, const std::string& config, const std::string& native, bool ignoreErrors) @@ -2141,6 +2212,45 @@ inline std::string removeQuotes(const std::string& s) return s; } +bool cmGlobalGenerator::CheckCMP0037(std::string const& targetName, + std::string const& reason) const +{ + cmTarget* tgt = this->FindTarget(targetName); + if (!tgt) { + return true; + } + cmake::MessageType messageType = cmake::AUTHOR_WARNING; + std::ostringstream e; + bool issueMessage = false; + switch (tgt->GetPolicyStatusCMP0037()) { + case cmPolicies::WARN: + e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0037) << "\n"; + issueMessage = true; + CM_FALLTHROUGH; + case cmPolicies::OLD: + break; + case cmPolicies::NEW: + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + issueMessage = true; + messageType = cmake::FATAL_ERROR; + break; + } + if (issueMessage) { + e << "The target name \"" << targetName << "\" is reserved " << reason + << "."; + if (messageType == cmake::AUTHOR_WARNING) { + e << " It may result in undefined behavior."; + } + this->GetCMakeInstance()->IssueMessage(messageType, e.str(), + tgt->GetBacktrace()); + if (messageType == cmake::FATAL_ERROR) { + return false; + } + } + return true; +} + void cmGlobalGenerator::CreateDefaultGlobalTargets( std::vector<GlobalTargetInfo>& targets) { @@ -2156,6 +2266,20 @@ void cmGlobalGenerator::AddGlobalTarget_Package( std::vector<GlobalTargetInfo>& targets) { cmMakefile* mf = this->Makefiles[0]; + std::string configFile = mf->GetCurrentBinaryDirectory(); + configFile += "/CPackConfig.cmake"; + if (!cmSystemTools::FileExists(configFile.c_str())) { + return; + } + + const char* reservedTargets[] = { "package", "PACKAGE" }; + for (const char* const* tn = cm::cbegin(reservedTargets); + tn != cm::cend(reservedTargets); ++tn) { + if (!this->CheckCMP0037(*tn, "when CPack packaging is enabled")) { + return; + } + } + const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir(); GlobalTargetInfo gti; gti.Name = this->GetPackageTargetName(); @@ -2169,8 +2293,6 @@ void cmGlobalGenerator::AddGlobalTarget_Package( singleLine.push_back(cmakeCfgIntDir); } singleLine.push_back("--config"); - std::string configFile = mf->GetCurrentBinaryDirectory(); - configFile += "/CPackConfig.cmake"; std::string relConfigFile = "./CPackConfig.cmake"; singleLine.push_back(relConfigFile); gti.CommandLines.push_back(singleLine); @@ -2183,61 +2305,81 @@ void cmGlobalGenerator::AddGlobalTarget_Package( gti.Depends.push_back(this->GetAllTargetName()); } } - if (cmSystemTools::FileExists(configFile.c_str())) { - targets.push_back(gti); - } + targets.push_back(gti); } void cmGlobalGenerator::AddGlobalTarget_PackageSource( std::vector<GlobalTargetInfo>& targets) { - cmMakefile* mf = this->Makefiles[0]; const char* packageSourceTargetName = this->GetPackageSourceTargetName(); - if (packageSourceTargetName) { - GlobalTargetInfo gti; - gti.Name = packageSourceTargetName; - gti.Message = "Run CPack packaging tool for source..."; - gti.WorkingDir = mf->GetCurrentBinaryDirectory(); - gti.UsesTerminal = true; - cmCustomCommandLine singleLine; - singleLine.push_back(cmSystemTools::GetCPackCommand()); - singleLine.push_back("--config"); - std::string configFile = mf->GetCurrentBinaryDirectory(); - configFile += "/CPackSourceConfig.cmake"; - std::string relConfigFile = "./CPackSourceConfig.cmake"; - singleLine.push_back(relConfigFile); - if (cmSystemTools::FileExists(configFile.c_str())) { - singleLine.push_back(configFile); - gti.CommandLines.push_back(singleLine); - targets.push_back(gti); + if (!packageSourceTargetName) { + return; + } + + cmMakefile* mf = this->Makefiles[0]; + std::string configFile = mf->GetCurrentBinaryDirectory(); + configFile += "/CPackSourceConfig.cmake"; + if (!cmSystemTools::FileExists(configFile.c_str())) { + return; + } + + const char* reservedTargets[] = { "package_source" }; + for (const char* const* tn = cm::cbegin(reservedTargets); + tn != cm::cend(reservedTargets); ++tn) { + if (!this->CheckCMP0037(*tn, "when CPack source packaging is enabled")) { + return; } } + + GlobalTargetInfo gti; + gti.Name = packageSourceTargetName; + gti.Message = "Run CPack packaging tool for source..."; + gti.WorkingDir = mf->GetCurrentBinaryDirectory(); + gti.UsesTerminal = true; + cmCustomCommandLine singleLine; + singleLine.push_back(cmSystemTools::GetCPackCommand()); + singleLine.push_back("--config"); + std::string relConfigFile = "./CPackSourceConfig.cmake"; + singleLine.push_back(relConfigFile); + singleLine.push_back(configFile); + gti.CommandLines.push_back(singleLine); + targets.push_back(gti); } void cmGlobalGenerator::AddGlobalTarget_Test( std::vector<GlobalTargetInfo>& targets) { cmMakefile* mf = this->Makefiles[0]; - const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir(); - if (mf->IsOn("CMAKE_TESTING_ENABLED")) { - GlobalTargetInfo gti; - gti.Name = this->GetTestTargetName(); - gti.Message = "Running tests..."; - gti.UsesTerminal = true; - cmCustomCommandLine singleLine; - singleLine.push_back(cmSystemTools::GetCTestCommand()); - singleLine.push_back("--force-new-ctest-process"); - if (cmakeCfgIntDir && *cmakeCfgIntDir && cmakeCfgIntDir[0] != '.') { - singleLine.push_back("-C"); - singleLine.push_back(cmakeCfgIntDir); - } else // TODO: This is a hack. Should be something to do with the - // generator - { - singleLine.push_back("$(ARGS)"); + if (!mf->IsOn("CMAKE_TESTING_ENABLED")) { + return; + } + + const char* reservedTargets[] = { "test", "RUN_TESTS" }; + for (const char* const* tn = cm::cbegin(reservedTargets); + tn != cm::cend(reservedTargets); ++tn) { + if (!this->CheckCMP0037(*tn, "when CTest testing is enabled")) { + return; } - gti.CommandLines.push_back(singleLine); - targets.push_back(gti); } + + const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir(); + GlobalTargetInfo gti; + gti.Name = this->GetTestTargetName(); + gti.Message = "Running tests..."; + gti.UsesTerminal = true; + cmCustomCommandLine singleLine; + singleLine.push_back(cmSystemTools::GetCTestCommand()); + singleLine.push_back("--force-new-ctest-process"); + if (cmakeCfgIntDir && *cmakeCfgIntDir && cmakeCfgIntDir[0] != '.') { + singleLine.push_back("-C"); + singleLine.push_back(cmakeCfgIntDir); + } else // TODO: This is a hack. Should be something to do with the + // generator + { + singleLine.push_back("$(ARGS)"); + } + gti.CommandLines.push_back(singleLine); + targets.push_back(gti); } void cmGlobalGenerator::AddGlobalTarget_EditCache( @@ -2503,14 +2645,13 @@ bool cmGlobalGenerator::IsReservedTarget(std::string const& name) // by one or more of the cmake generators. // Adding additional targets to this list will require a policy! - const char* reservedTargets[] = { - "all", "ALL_BUILD", "help", "install", "INSTALL", - "preinstall", "clean", "edit_cache", "rebuild_cache", "test", - "RUN_TESTS", "package", "PACKAGE", "package_source", "ZERO_CHECK" - }; - - return std::find(cmArrayBegin(reservedTargets), cmArrayEnd(reservedTargets), - name) != cmArrayEnd(reservedTargets); + const char* reservedTargets[] = { "all", "ALL_BUILD", "help", + "install", "INSTALL", "preinstall", + "clean", "edit_cache", "rebuild_cache", + "ZERO_CHECK" }; + + return std::find(cm::cbegin(reservedTargets), cm::cend(reservedTargets), + name) != cm::cend(reservedTargets); } void cmGlobalGenerator::SetExternalMakefileProjectGenerator( diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 18ca682..99f33e5 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -15,7 +15,6 @@ #include "cmCustomCommandLines.h" #include "cmExportSetMap.h" -#include "cmQtAutoGenDigest.h" #include "cmStateSnapshot.h" #include "cmSystemTools.h" #include "cmTarget.h" @@ -33,6 +32,7 @@ class cmLinkLineComputer; class cmLocalGenerator; class cmMakefile; class cmOutputConverter; +class cmQtAutoGeneratorInitializer; class cmSourceFile; class cmStateDirectory; class cmake; @@ -70,6 +70,9 @@ public: /** Tell the generator about the target system. */ virtual bool SetSystemName(std::string const&, cmMakefile*) { return true; } + /** Set the generator-specific instance. Returns true if supported. */ + virtual bool SetGeneratorInstance(std::string const& i, cmMakefile* mf); + /** Set the generator-specific platform name. Returns true if platform is supported and false otherwise. */ virtual bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf); @@ -162,6 +165,12 @@ public: std::vector<std::string> const& nativeOptions = std::vector<std::string>()); + /** + * Open a generated IDE project given the following information. + */ + virtual bool Open(const std::string& bindir, const std::string& projectName, + bool dryRun); + virtual void GenerateBuildCommand( std::vector<std::string>& makeCommand, const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, @@ -424,7 +433,8 @@ protected: virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const; // Qt auto generators - cmQtAutoGenDigestUPV CreateQtAutoGeneratorsTargets(); + std::vector<std::unique_ptr<cmQtAutoGeneratorInitializer>> + CreateQtAutoGenInitializers(); std::string SelectMakeProgram(const std::string& makeProgram, const std::string& makeDefault = "") const; @@ -533,6 +543,8 @@ private: virtual void ForceLinkerLanguages(); + bool CheckTargetsForMissingSources() const; + void CreateLocalGenerators(); void CheckCompilerIdCompatibility(cmMakefile* mf, @@ -557,6 +569,9 @@ private: void ClearGeneratorMembers(); + bool CheckCMP0037(std::string const& targetName, + std::string const& reason) const; + void IndexMakefile(cmMakefile* mf); virtual const char* GetBuildIgnoreErrorsFlag() const { return nullptr; } diff --git a/Source/cmGlobalKdevelopGenerator.cxx b/Source/cmGlobalKdevelopGenerator.cxx index b1e630e..80aadb9 100644 --- a/Source/cmGlobalKdevelopGenerator.cxx +++ b/Source/cmGlobalKdevelopGenerator.cxx @@ -110,7 +110,7 @@ bool cmGlobalKdevelopGenerator::CreateFilelistFile( nullptr)) { files.insert(tmp); tmp = cmSystemTools::GetFilenameName(tmp); - // add all files which dont match the default + // add all files which don't match the default // */CMakeLists.txt;*cmake; to the file pattern if ((tmp != "CMakeLists.txt") && (strstr(tmp.c_str(), ".cmake") == nullptr)) { diff --git a/Source/cmGlobalVisualStudio15Generator.cxx b/Source/cmGlobalVisualStudio15Generator.cxx index d2bf7cc..014d93d 100644 --- a/Source/cmGlobalVisualStudio15Generator.cxx +++ b/Source/cmGlobalVisualStudio15Generator.cxx @@ -111,6 +111,53 @@ void cmGlobalVisualStudio15Generator::WriteSLNHeader(std::ostream& fout) } } +bool cmGlobalVisualStudio15Generator::SetGeneratorInstance( + std::string const& i, cmMakefile* mf) +{ + if (!i.empty()) { + if (!this->vsSetupAPIHelper.SetVSInstance(i)) { + std::ostringstream e; + /* clang-format off */ + e << + "Generator\n" + " " << this->GetName() << "\n" + "could not find specified instance of Visual Studio:\n" + " " << i; + /* clang-format on */ + mf->IssueMessage(cmake::FATAL_ERROR, e.str()); + return false; + } + } + + std::string vsInstance; + if (!this->vsSetupAPIHelper.GetVSInstanceInfo(vsInstance)) { + std::ostringstream e; + /* clang-format off */ + e << + "Generator\n" + " " << this->GetName() << "\n" + "could not find any instance of Visual Studio.\n"; + /* clang-format on */ + mf->IssueMessage(cmake::FATAL_ERROR, e.str()); + return false; + } + + // Save the selected instance persistently. + std::string genInstance = mf->GetSafeDefinition("CMAKE_GENERATOR_INSTANCE"); + if (vsInstance != genInstance) { + this->CMakeInstance->AddCacheEntry( + "CMAKE_GENERATOR_INSTANCE", vsInstance.c_str(), + "Generator instance identifier.", cmStateEnums::INTERNAL); + } + + return true; +} + +bool cmGlobalVisualStudio15Generator::GetVSInstance(std::string& dir) const +{ + return vsSetupAPIHelper.GetVSInstanceInfo(dir); +} + bool cmGlobalVisualStudio15Generator::InitializeWindows(cmMakefile* mf) { // If the Win 8.1 SDK is installed then we can select a SDK matching diff --git a/Source/cmGlobalVisualStudio15Generator.h b/Source/cmGlobalVisualStudio15Generator.h index e934882..852a4e7 100644 --- a/Source/cmGlobalVisualStudio15Generator.h +++ b/Source/cmGlobalVisualStudio15Generator.h @@ -27,6 +27,11 @@ public: virtual void WriteSLNHeader(std::ostream& fout); virtual const char* GetToolsVersion() { return "15.0"; } + + bool SetGeneratorInstance(std::string const& i, cmMakefile* mf) override; + + bool GetVSInstance(std::string& dir) const; + protected: bool InitializeWindows(cmMakefile* mf) override; virtual bool SelectWindowsStoreToolset(std::string& toolset) const; diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx index 3b45c90..8a9a3fb 100644 --- a/Source/cmGlobalVisualStudio71Generator.cxx +++ b/Source/cmGlobalVisualStudio71Generator.cxx @@ -222,7 +222,7 @@ void cmGlobalVisualStudio71Generator::WriteProjectConfigurations( } } -// ouput standard header for dsw file +// output standard header for dsw file void cmGlobalVisualStudio71Generator::WriteSLNHeader(std::ostream& fout) { fout << "Microsoft Visual Studio Solution File, Format Version 8.00\n"; diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx index cc1d1a2..1743b18 100644 --- a/Source/cmGlobalVisualStudio8Generator.cxx +++ b/Source/cmGlobalVisualStudio8Generator.cxx @@ -146,7 +146,7 @@ bool cmGlobalVisualStudio8Generator::SetGeneratorPlatform(std::string const& p, } } -// ouput standard header for dsw file +// output standard header for dsw file void cmGlobalVisualStudio8Generator::WriteSLNHeader(std::ostream& fout) { fout << "Microsoft Visual Studio Solution File, Format Version 9.00\n"; @@ -225,9 +225,9 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() } cmCustomCommandLines noCommandLines; - cmTarget* tgt = - mf->AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, false, - no_working_directory, no_depends, noCommandLines); + cmTarget* tgt = mf->AddUtilityCommand( + CMAKE_CHECK_BUILD_SYSTEM_TARGET, cmMakefile::TargetOrigin::Generator, + false, no_working_directory, no_depends, noCommandLines); cmGeneratorTarget* gt = new cmGeneratorTarget(tgt, lg); lg->AddGeneratorTarget(gt); diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index 0651536..c89c2c4 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -4,7 +4,10 @@ #include "cmGlobalVisualStudioGenerator.h" #include "cmsys/Encoding.hxx" +#include <future> #include <iostream> +#include <objbase.h> +#include <shellapi.h> #include <windows.h> #include "cmAlgorithms.h" @@ -66,8 +69,8 @@ void cmGlobalVisualStudioGenerator::AddExtraIDETargets() // Use no actual command lines so that the target itself is not // considered always out of date. cmTarget* allBuild = gen[0]->GetMakefile()->AddUtilityCommand( - "ALL_BUILD", true, no_working_dir, no_depends, no_commands, false, - "Build all projects"); + "ALL_BUILD", cmMakefile::TargetOrigin::Generator, true, no_working_dir, + no_depends, no_commands, false, "Build all projects"); cmGeneratorTarget* gt = new cmGeneratorTarget(allBuild, gen[0]); gen[0]->AddGeneratorTarget(gt); @@ -103,15 +106,6 @@ void cmGlobalVisualStudioGenerator::AddExtraIDETargets() // Configure CMake Visual Studio macros, for this user on this version // of Visual Studio. this->ConfigureCMakeVisualStudioMacros(); - - // Add CMakeLists.txt with custom command to rerun CMake. - for (std::vector<cmLocalGenerator*>::const_iterator lgi = - this->LocalGenerators.begin(); - lgi != this->LocalGenerators.end(); ++lgi) { - cmLocalVisualStudioGenerator* lg = - static_cast<cmLocalVisualStudioGenerator*>(*lgi); - lg->AddCMakeListsRules(); - } } void cmGlobalVisualStudioGenerator::ComputeTargetObjectDirectory( @@ -928,3 +922,33 @@ void cmGlobalVisualStudioGenerator::AddSymbolExportCommand( commandLines, "Auto build dll exports", "."); commands.push_back(command); } + +static bool OpenSolution(std::string sln) +{ + HRESULT comInitialized = + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); + if (FAILED(comInitialized)) { + return false; + } + + HINSTANCE hi = + ShellExecuteA(NULL, "open", sln.c_str(), NULL, NULL, SW_SHOWNORMAL); + + CoUninitialize(); + + return reinterpret_cast<intptr_t>(hi) > 32; +} + +bool cmGlobalVisualStudioGenerator::Open(const std::string& bindir, + const std::string& projectName, + bool dryRun) +{ + std::string buildDir = cmSystemTools::ConvertToOutputPath(bindir.c_str()); + std::string sln = buildDir + "\\" + projectName + ".sln"; + + if (dryRun) { + return cmSystemTools::FileExists(sln, true); + } + + return std::async(std::launch::async, OpenSolution, sln).get(); +} diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h index 62bfd3b..55a6813 100644 --- a/Source/cmGlobalVisualStudioGenerator.h +++ b/Source/cmGlobalVisualStudioGenerator.h @@ -131,6 +131,9 @@ public: std::vector<cmCustomCommand>& commands, std::string const& configName); + bool Open(const std::string& bindir, const std::string& projectName, + bool dryRun) override; + protected: virtual void AddExtraIDETargets(); diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index c79ee47..c376c8d 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -35,6 +35,11 @@ struct cmLinkImplementation; +#if defined(CMAKE_BUILD_WITH_CMAKE) && defined(__APPLE__) +#define HAVE_APPLICATION_SERVICES +#include <ApplicationServices/ApplicationServices.h> +#endif + #if defined(CMAKE_BUILD_WITH_CMAKE) #include "cmXMLParser.h" @@ -287,6 +292,35 @@ void cmGlobalXCodeGenerator::EnableLanguage( this->ComputeArchitectures(mf); } +bool cmGlobalXCodeGenerator::Open(const std::string& bindir, + const std::string& projectName, bool dryRun) +{ + bool ret = false; + +#ifdef HAVE_APPLICATION_SERVICES + std::string url = bindir + "/" + projectName + ".xcodeproj"; + + if (dryRun) { + return cmSystemTools::FileExists(url, false); + } + + CFStringRef cfStr = CFStringCreateWithCString( + kCFAllocatorDefault, url.c_str(), kCFStringEncodingUTF8); + if (cfStr) { + CFURLRef cfUrl = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfStr, + kCFURLPOSIXPathStyle, true); + if (cfUrl) { + OSStatus err = LSOpenCFURLRef(cfUrl, nullptr); + ret = err == noErr; + CFRelease(cfUrl); + } + CFRelease(cfStr); + } +#endif + + return ret; +} + void cmGlobalXCodeGenerator::GenerateBuildCommand( std::vector<std::string>& makeCommand, const std::string& makeProgram, const std::string& projectName, const std::string& /*projectDir*/, @@ -334,14 +368,13 @@ cmLocalGenerator* cmGlobalXCodeGenerator::CreateLocalGenerator(cmMakefile* mf) void cmGlobalXCodeGenerator::AddExtraIDETargets() { - std::map<std::string, std::vector<cmLocalGenerator*>>::iterator it; // make sure extra targets are added before calling // the parent generate which will call trace depends - for (it = this->ProjectMap.begin(); it != this->ProjectMap.end(); ++it) { - cmLocalGenerator* root = it->second[0]; + for (auto keyVal : this->ProjectMap) { + cmLocalGenerator* root = keyVal.second[0]; this->SetGenerationRoot(root); // add ALL_BUILD, INSTALL, etc - this->AddExtraTargets(root, it->second); + this->AddExtraTargets(root, keyVal.second); } } @@ -351,12 +384,22 @@ void cmGlobalXCodeGenerator::Generate() if (cmSystemTools::GetErrorOccuredFlag()) { return; } - std::map<std::string, std::vector<cmLocalGenerator*>>::iterator it; - for (it = this->ProjectMap.begin(); it != this->ProjectMap.end(); ++it) { - cmLocalGenerator* root = it->second[0]; + for (auto keyVal : this->ProjectMap) { + cmLocalGenerator* root = keyVal.second[0]; + + bool generateTopLevelProjectOnly = + root->GetMakefile()->IsOn("CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY"); + + if (generateTopLevelProjectOnly) { + cmStateSnapshot snp = root->GetStateSnapshot(); + if (snp.GetBuildsystemDirectoryParent().IsValid()) { + continue; + } + } + this->SetGenerationRoot(root); // now create the project - this->OutputXCodeProject(root, it->second); + this->OutputXCodeProject(root, keyVal.second); } } @@ -397,19 +440,13 @@ void cmGlobalXCodeGenerator::AddExtraTargets( // Add ALL_BUILD const char* no_working_directory = nullptr; std::vector<std::string> no_depends; - cmTarget* allbuild = - mf->AddUtilityCommand("ALL_BUILD", true, no_depends, no_working_directory, - "echo", "Build all projects"); + cmTarget* allbuild = mf->AddUtilityCommand( + "ALL_BUILD", cmMakefile::TargetOrigin::Generator, true, no_depends, + no_working_directory, "echo", "Build all projects"); cmGeneratorTarget* allBuildGt = new cmGeneratorTarget(allbuild, root); root->AddGeneratorTarget(allBuildGt); - // Refer to the main build configuration file for easy editing. - std::string listfile = root->GetCurrentSourceDirectory(); - listfile += "/"; - listfile += "CMakeLists.txt"; - allBuildGt->AddSource(listfile); - // Add XCODE depend helper std::string dir = root->GetCurrentBinaryDirectory(); cmCustomCommandLine makeHelper; @@ -427,9 +464,9 @@ void cmGlobalXCodeGenerator::AddExtraTargets( std::string file = this->ConvertToRelativeForMake(this->CurrentReRunCMakeMakefile.c_str()); cmSystemTools::ReplaceString(file, "\\ ", " "); - cmTarget* check = - mf->AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, true, no_depends, - no_working_directory, "make", "-f", file.c_str()); + cmTarget* check = mf->AddUtilityCommand( + CMAKE_CHECK_BUILD_SYSTEM_TARGET, cmMakefile::TargetOrigin::Generator, + true, no_depends, no_working_directory, "make", "-f", file.c_str()); cmGeneratorTarget* checkGt = new cmGeneratorTarget(check, root); root->AddGeneratorTarget(checkGt); @@ -442,8 +479,7 @@ void cmGlobalXCodeGenerator::AddExtraTargets( continue; } - const std::vector<cmGeneratorTarget*>& tgts = gen->GetGeneratorTargets(); - for (auto target : tgts) { + for (auto target : gen->GetGeneratorTargets()) { if (target->GetType() == cmStateEnums::GLOBAL_TARGET) { continue; } @@ -479,12 +515,6 @@ void cmGlobalXCodeGenerator::AddExtraTargets( !target->GetPropertyAsBool("EXCLUDE_FROM_ALL")) { allbuild->AddUtility(target->GetName()); } - - // Refer to the build configuration file for easy editing. - listfile = gen->GetCurrentSourceDirectory(); - listfile += "/"; - listfile += "CMakeLists.txt"; - target->AddSource(listfile); } } } @@ -516,10 +546,9 @@ void cmGlobalXCodeGenerator::CreateReRunCMakeFile( makefileStream << "space:= $(empty) $(empty)\n"; makefileStream << "spaceplus:= $(empty)\\ $(empty)\n\n"; - for (std::vector<std::string>::const_iterator i = lfiles.begin(); - i != lfiles.end(); ++i) { + for (const auto& lfile : lfiles) { makefileStream << "TARGETS += $(subst $(space),$(spaceplus),$(wildcard " - << this->ConvertToRelativeForMake(i->c_str()) << "))\n"; + << this->ConvertToRelativeForMake(lfile.c_str()) << "))\n"; } std::string checkCache = root->GetBinaryDirectory(); @@ -728,9 +757,8 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile( cmSystemTools::ExpandListArgument(extraFileAttributes, attributes); // Store the attributes. - for (std::vector<std::string>::const_iterator ai = attributes.begin(); - ai != attributes.end(); ++ai) { - attrs->AddObject(this->CreateString(*ai)); + for (const auto& attribute : attributes) { + attrs->AddObject(this->CreateString(attribute)); } } @@ -925,12 +953,10 @@ bool cmGlobalXCodeGenerator::CreateXCodeTargets( cmLocalGenerator* gen, std::vector<cmXCodeObject*>& targets) { this->SetCurrentLocalGenerator(gen); - const std::vector<cmGeneratorTarget*>& tgts = - this->CurrentLocalGenerator->GetGeneratorTargets(); typedef std::map<std::string, cmGeneratorTarget*, cmCompareTargets> cmSortedTargets; cmSortedTargets sortedTargets; - for (auto tgt : tgts) { + for (auto tgt : this->CurrentLocalGenerator->GetGeneratorTargets()) { sortedTargets[tgt->GetName()] = tgt; } for (auto& sortedTarget : sortedTargets) { @@ -962,6 +988,13 @@ bool cmGlobalXCodeGenerator::CreateXCodeTargets( if (!gtgt->GetConfigCommonSourceFiles(classes)) { return false; } + + // Add CMakeLists.txt file for user convenience. + std::string listfile = + gtgt->GetLocalGenerator()->GetCurrentSourceDirectory(); + listfile += "/CMakeLists.txt"; + classes.push_back(gtgt->Makefile->GetOrCreateSource(listfile)); + std::sort(classes.begin(), classes.end(), cmSourceFilePathCompare()); gtgt->ComputeObjectMapping(); @@ -970,21 +1003,20 @@ bool cmGlobalXCodeGenerator::CreateXCodeTargets( std::vector<cmXCodeObject*> headerFiles; std::vector<cmXCodeObject*> resourceFiles; std::vector<cmXCodeObject*> sourceFiles; - for (std::vector<cmSourceFile*>::const_iterator i = classes.begin(); - i != classes.end(); ++i) { - cmXCodeObject* xsf = - this->CreateXCodeSourceFile(this->CurrentLocalGenerator, *i, gtgt); + for (auto sourceFile : classes) { + cmXCodeObject* xsf = this->CreateXCodeSourceFile( + this->CurrentLocalGenerator, sourceFile, gtgt); cmXCodeObject* fr = xsf->GetObject("fileRef"); cmXCodeObject* filetype = fr->GetObject()->GetObject("explicitFileType"); cmGeneratorTarget::SourceFileFlags tsFlags = - gtgt->GetTargetSourceFileFlags(*i); + gtgt->GetTargetSourceFileFlags(sourceFile); if (filetype && filetype->GetString() == "compiled.mach-o.objfile") { - if ((*i)->GetObjectLibrary().empty()) { + if (sourceFile->GetObjectLibrary().empty()) { externalObjFiles.push_back(xsf); } - } else if (this->IsHeaderFile(*i) || + } else if (this->IsHeaderFile(sourceFile) || (tsFlags.Type == cmGeneratorTarget::SourceFileTypePrivateHeader) || (tsFlags.Type == @@ -992,12 +1024,13 @@ bool cmGlobalXCodeGenerator::CreateXCodeTargets( headerFiles.push_back(xsf); } else if (tsFlags.Type == cmGeneratorTarget::SourceFileTypeResource) { resourceFiles.push_back(xsf); - } else if (!(*i)->GetPropertyAsBool("HEADER_FILE_ONLY")) { + } else if (!sourceFile->GetPropertyAsBool("HEADER_FILE_ONLY")) { // Include this file in the build if it has a known language // and has not been listed as an ignored extension for this // generator. - if (!this->CurrentLocalGenerator->GetSourceFileLanguage(**i).empty() && - !this->IgnoreFile((*i)->GetExtension().c_str())) { + if (!this->CurrentLocalGenerator->GetSourceFileLanguage(*sourceFile) + .empty() && + !this->IgnoreFile(sourceFile->GetExtension().c_str())) { sourceFiles.push_back(xsf); } } @@ -1009,12 +1042,11 @@ bool cmGlobalXCodeGenerator::CreateXCodeTargets( // within the target.) std::vector<cmSourceFile const*> objs; gtgt->GetExternalObjects(objs, ""); - for (std::vector<cmSourceFile const*>::const_iterator oi = objs.begin(); - oi != objs.end(); ++oi) { - if ((*oi)->GetObjectLibrary().empty()) { + for (auto sourceFile : objs) { + if (sourceFile->GetObjectLibrary().empty()) { continue; } - std::string const& obj = (*oi)->GetFullPath(); + std::string const& obj = sourceFile->GetFullPath(); cmXCodeObject* xsf = this->CreateXCodeSourceFileFromPath(obj, gtgt, "", nullptr); externalObjFiles.push_back(xsf); @@ -1087,16 +1119,14 @@ bool cmGlobalXCodeGenerator::CreateXCodeTargets( typedef std::map<std::string, std::vector<cmSourceFile*>> mapOfVectorOfSourceFiles; mapOfVectorOfSourceFiles bundleFiles; - for (std::vector<cmSourceFile*>::const_iterator i = classes.begin(); - i != classes.end(); ++i) { + for (auto sourceFile : classes) { cmGeneratorTarget::SourceFileFlags tsFlags = - gtgt->GetTargetSourceFileFlags(*i); + gtgt->GetTargetSourceFileFlags(sourceFile); if (tsFlags.Type == cmGeneratorTarget::SourceFileTypeMacContent) { - bundleFiles[tsFlags.MacFolder].push_back(*i); + bundleFiles[tsFlags.MacFolder].push_back(sourceFile); } } - mapOfVectorOfSourceFiles::iterator mit; - for (mit = bundleFiles.begin(); mit != bundleFiles.end(); ++mit) { + for (auto keySources : bundleFiles) { cmXCodeObject* copyFilesBuildPhase = this->CreateObject(cmXCodeObject::PBXCopyFilesBuildPhase); copyFilesBuildPhase->SetComment("Copy files"); @@ -1107,13 +1137,13 @@ bool cmGlobalXCodeGenerator::CreateXCodeTargets( std::ostringstream ostr; if (gtgt->IsFrameworkOnApple()) { // dstPath in frameworks is relative to Versions/<version> - ostr << mit->first; - } else if (mit->first != "MacOS") { + ostr << keySources.first; + } else if (keySources.first != "MacOS") { if (gtgt->Target->GetMakefile()->PlatformIsAppleIos()) { - ostr << mit->first; + ostr << keySources.first; } else { // dstPath in bundles is relative to Contents/MacOS - ostr << "../" << mit->first; + ostr << "../" << keySources.first; } } copyFilesBuildPhase->AddAttribute("dstPath", @@ -1122,10 +1152,9 @@ bool cmGlobalXCodeGenerator::CreateXCodeTargets( this->CreateString("0")); buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); copyFilesBuildPhase->AddAttribute("files", buildFiles); - std::vector<cmSourceFile*>::iterator sfIt; - for (sfIt = mit->second.begin(); sfIt != mit->second.end(); ++sfIt) { + for (auto sourceFile : keySources.second) { cmXCodeObject* xsf = this->CreateXCodeSourceFile( - this->CurrentLocalGenerator, *sfIt, gtgt); + this->CurrentLocalGenerator, sourceFile, gtgt); buildFiles->AddObject(xsf); } contentBuildPhases.push_back(copyFilesBuildPhase); @@ -1138,16 +1167,14 @@ bool cmGlobalXCodeGenerator::CreateXCodeTargets( typedef std::map<std::string, std::vector<cmSourceFile*>> mapOfVectorOfSourceFiles; mapOfVectorOfSourceFiles bundleFiles; - for (std::vector<cmSourceFile*>::const_iterator i = classes.begin(); - i != classes.end(); ++i) { + for (auto sourceFile : classes) { cmGeneratorTarget::SourceFileFlags tsFlags = - gtgt->GetTargetSourceFileFlags(*i); + gtgt->GetTargetSourceFileFlags(sourceFile); if (tsFlags.Type == cmGeneratorTarget::SourceFileTypeDeepResource) { - bundleFiles[tsFlags.MacFolder].push_back(*i); + bundleFiles[tsFlags.MacFolder].push_back(sourceFile); } } - mapOfVectorOfSourceFiles::iterator mit; - for (mit = bundleFiles.begin(); mit != bundleFiles.end(); ++mit) { + for (auto keySources : bundleFiles) { cmXCodeObject* copyFilesBuildPhase = this->CreateObject(cmXCodeObject::PBXCopyFilesBuildPhase); copyFilesBuildPhase->SetComment("Copy files"); @@ -1155,16 +1182,15 @@ bool cmGlobalXCodeGenerator::CreateXCodeTargets( this->CreateString("2147483647")); copyFilesBuildPhase->AddAttribute("dstSubfolderSpec", this->CreateString("7")); - copyFilesBuildPhase->AddAttribute("dstPath", - this->CreateString(mit->first)); + copyFilesBuildPhase->AddAttribute( + "dstPath", this->CreateString(keySources.first)); copyFilesBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing", this->CreateString("0")); buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); copyFilesBuildPhase->AddAttribute("files", buildFiles); - std::vector<cmSourceFile*>::iterator sfIt; - for (sfIt = mit->second.begin(); sfIt != mit->second.end(); ++sfIt) { + for (auto sourceFile : keySources.second) { cmXCodeObject* xsf = this->CreateXCodeSourceFile( - this->CurrentLocalGenerator, *sfIt, gtgt); + this->CurrentLocalGenerator, sourceFile, gtgt); buildFiles->AddObject(xsf); } contentBuildPhases.push_back(copyFilesBuildPhase); @@ -1203,11 +1229,9 @@ bool cmGlobalXCodeGenerator::CreateXCodeTargets( void cmGlobalXCodeGenerator::ForceLinkerLanguages() { - for (auto& localGenerator : this->LocalGenerators) { - const std::vector<cmGeneratorTarget*>& tgts = - localGenerator->GetGeneratorTargets(); + for (auto localGenerator : this->LocalGenerators) { // All targets depend on the build-system check target. - for (auto tgt : tgts) { + for (auto tgt : localGenerator->GetGeneratorTargets()) { // This makes sure all targets link using the proper language. this->ForceLinkerLanguage(tgt); } @@ -1229,8 +1253,8 @@ void cmGlobalXCodeGenerator::ForceLinkerLanguage(cmGeneratorTarget* gtgt) } // If the language is compiled as a source trust Xcode to link with it. - cmLinkImplementation const* impl = gtgt->GetLinkImplementation("NOCONFIG"); - for (auto const& Language : impl->Languages) { + for (auto const& Language : + gtgt->GetLinkImplementation("NOCONFIG")->Languages) { if (Language == llang) { return; } @@ -1330,10 +1354,9 @@ void cmGlobalXCodeGenerator::CreateCustomCommands( } // add all the sources std::vector<cmCustomCommand> commands; - for (std::vector<cmSourceFile*>::const_iterator i = classes.begin(); - i != classes.end(); ++i) { - if ((*i)->GetCustomCommand()) { - commands.push_back(*(*i)->GetCustomCommand()); + for (auto sourceFile : classes) { + if (sourceFile->GetCustomCommand()) { + commands.push_back(*sourceFile->GetCustomCommand()); } } // create prebuild phase @@ -1365,10 +1388,8 @@ void cmGlobalXCodeGenerator::CreateCustomCommands( if (resourceBuildPhase) { buildPhases->AddObject(resourceBuildPhase); } - std::vector<cmXCodeObject*>::iterator cit; - for (cit = contentBuildPhases.begin(); cit != contentBuildPhases.end(); - ++cit) { - buildPhases->AddObject(*cit); + for (auto obj : contentBuildPhases) { + buildPhases->AddObject(obj); } if (sourceBuildPhase) { buildPhases->AddObject(sourceBuildPhase); @@ -1491,12 +1512,9 @@ void cmGlobalXCodeGenerator::AddCommandsToBuildPhase( makefile += name; makefile += ".make"; - for (std::vector<std::string>::const_iterator currentConfig = - this->CurrentConfigurationTypes.begin(); - currentConfig != this->CurrentConfigurationTypes.end(); - currentConfig++) { + for (const auto& currentConfig : this->CurrentConfigurationTypes) { this->CreateCustomRulesMakefile(makefile.c_str(), target, commands, - *currentConfig); + currentConfig); } std::string cdir = this->CurrentLocalGenerator->GetCurrentBinaryDirectory(); @@ -1976,8 +1994,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, } // Add framework search paths needed for linking. if (cmComputeLinkInformation* cli = gtgt->GetLinkInformation(configName)) { - std::vector<std::string> const& fwDirs = cli->GetFrameworkPaths(); - for (auto const& fwDir : fwDirs) { + for (auto const& fwDir : cli->GetFrameworkPaths()) { if (emitted.insert(fwDir).second) { std::string incpath = this->XCodeEscapePath(fwDir); if (emitSystemIncludes && @@ -2142,9 +2159,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, // runpath dirs needs to be unique to prevent corruption std::set<std::string> unique_dirs; - for (std::vector<std::string>::const_iterator i = runtimeDirs.begin(); - i != runtimeDirs.end(); ++i) { - std::string runpath = *i; + for (auto runpath : runtimeDirs) { runpath = this->ExpandCFGIntDir(runpath, configName); if (unique_dirs.find(runpath) == unique_dirs.end()) { @@ -2204,8 +2219,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, // put this last so it can override existing settings // Convert "XCODE_ATTRIBUTE_*" properties directly. { - std::vector<std::string> const& props = gtgt->GetPropertyKeys(); - for (auto const& prop : props) { + for (auto const& prop : gtgt->GetPropertyKeys()) { if (prop.find("XCODE_ATTRIBUTE_") == 0) { std::string attribute = prop.substr(16); this->FilterConfigurationAttribute(configName, attribute); @@ -2259,16 +2273,22 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateUtilityTarget( this->XCodeObjectMap[gtgt] = target; // Add source files without build rules for editing convenience. - if (gtgt->GetType() == cmStateEnums::UTILITY) { + if (gtgt->GetType() == cmStateEnums::UTILITY && + gtgt->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) { std::vector<cmSourceFile*> sources; if (!gtgt->GetConfigCommonSourceFiles(sources)) { return nullptr; } - for (std::vector<cmSourceFile*>::const_iterator i = sources.begin(); - i != sources.end(); ++i) { - if (!(*i)->GetPropertyAsBool("GENERATED")) { - this->CreateXCodeFileReference(*i, gtgt); + // Add CMakeLists.txt file for user convenience. + std::string listfile = + gtgt->GetLocalGenerator()->GetCurrentSourceDirectory(); + listfile += "/CMakeLists.txt"; + sources.push_back(gtgt->Makefile->GetOrCreateSource(listfile)); + + for (auto sourceFile : sources) { + if (!sourceFile->GetPropertyAsBool("GENERATED")) { + this->CreateXCodeFileReference(sourceFile, gtgt); } } } @@ -2537,17 +2557,10 @@ void cmGlobalXCodeGenerator::AppendBuildSettingAttribute( target->GetObject("buildConfigurationList")->GetObject(); cmXCodeObject* buildConfigs = configurationList->GetObject("buildConfigurations"); - std::vector<cmXCodeObject*> list = buildConfigs->GetObjectList(); - // each configuration and the target itself has a buildSettings in it - // list.push_back(target); - for (auto& i : list) { - if (!configName.empty()) { - if (i->GetObject("name")->GetString() == configName) { - cmXCodeObject* settings = i->GetObject("buildSettings"); - this->AppendOrAddBuildSetting(settings, attribute, value); - } - } else { - cmXCodeObject* settings = i->GetObject("buildSettings"); + for (auto obj : buildConfigs->GetObjectList()) { + if (configName.empty() || + obj->GetObject("name")->GetString() == configName) { + cmXCodeObject* settings = obj->GetObject("buildSettings"); this->AppendOrAddBuildSetting(settings, attribute, value); } } @@ -2565,8 +2578,7 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) } // Add dependencies on other CMake targets. - TargetDependSet const& deps = this->GetTargetDirectDepends(gt); - for (auto dep : deps) { + for (const auto& dep : this->GetTargetDirectDepends(gt)) { if (cmXCodeObject* dptarget = this->FindXCodeTarget(dep)) { this->AddDependTarget(target, dptarget); } @@ -2581,14 +2593,13 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) const char* sep = ""; std::vector<cmSourceFile const*> objs; gt->GetExternalObjects(objs, configName); - for (std::vector<cmSourceFile const*>::const_iterator oi = objs.begin(); - oi != objs.end(); ++oi) { - if ((*oi)->GetObjectLibrary().empty()) { + for (auto sourceFile : objs) { + if (sourceFile->GetObjectLibrary().empty()) { continue; } linkObjs += sep; sep = " "; - linkObjs += this->XCodeEscapePath((*oi)->GetFullPath()); + linkObjs += this->XCodeEscapePath(sourceFile->GetFullPath()); } this->AppendBuildSettingAttribute( target, this->GetTargetLinkFlagsVar(gt), linkObjs.c_str(), configName); @@ -2608,18 +2619,14 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) cmComputeLinkInformation& cli = *pcli; // Add dependencies directly on library files. - { - std::vector<std::string> const& libDeps = cli.GetDepends(); - for (auto const& libDep : libDeps) { - target->AddDependLibrary(configName, libDep); - } + for (auto const& libDep : cli.GetDepends()) { + target->AddDependLibrary(configName, libDep); } // add the library search paths { - std::vector<std::string> const& libDirs = cli.GetDirectories(); std::string linkDirs; - for (auto const& libDir : libDirs) { + for (auto const& libDir : cli.GetDirectories()) { if (!libDir.empty() && libDir != "/usr/lib") { // Now add the same one but append // $(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) to it: @@ -2638,9 +2645,7 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) { std::string linkLibs; const char* sep = ""; - typedef cmComputeLinkInformation::ItemVector ItemVector; - ItemVector const& libNames = cli.GetItems(); - for (auto const& libName : libNames) { + for (auto const& libName : cli.GetItems()) { linkLibs += sep; sep = " "; if (libName.IsPath) { @@ -2666,11 +2671,9 @@ bool cmGlobalXCodeGenerator::CreateGroups( for (auto& generator : generators) { cmMakefile* mf = generator->GetMakefile(); std::vector<cmSourceGroup> sourceGroups = mf->GetSourceGroups(); - const std::vector<cmGeneratorTarget*>& tgts = - generator->GetGeneratorTargets(); - for (auto gtgt : tgts) { + for (auto gtgt : generator->GetGeneratorTargets()) { // Same skipping logic here as in CreateXCodeTargets so that we do not - // end up with (empty anyhow) ALL_BUILD and XCODE_DEPEND_HELPER source + // end up with (empty anyhow) ZERO_CHECK, install, or test source // groups: // if (gtgt->GetType() == cmStateEnums::GLOBAL_TARGET) { @@ -2679,6 +2682,9 @@ bool cmGlobalXCodeGenerator::CreateGroups( if (gtgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } + if (gtgt->GetName() == CMAKE_CHECK_BUILD_SYSTEM_TARGET) { + continue; + } // add the soon to be generated Info.plist file as a source for a // MACOSX_BUNDLE file @@ -2688,11 +2694,8 @@ bool cmGlobalXCodeGenerator::CreateGroups( gtgt->AddSource(plist); } - std::vector<cmGeneratorTarget::AllConfigSource> const& sources = - gtgt->GetAllConfigSources(); - // Put cmSourceFile instances in proper groups: - for (auto const& si : sources) { + for (auto const& si : gtgt->GetAllConfigSources()) { cmSourceFile const* sf = si.Source; if (this->XcodeVersion >= 50 && !sf->GetObjectLibrary().empty()) { // Object library files go on the link line instead. @@ -2706,6 +2709,20 @@ bool cmGlobalXCodeGenerator::CreateGroups( std::string key = GetGroupMapKeyFromPath(gtgt, source); this->GroupMap[key] = pbxgroup; } + + // Add CMakeLists.txt file for user convenience. + { + std::string listfile = + gtgt->GetLocalGenerator()->GetCurrentSourceDirectory(); + listfile += "/CMakeLists.txt"; + cmSourceFile* sf = gtgt->Makefile->GetOrCreateSource(listfile); + std::string const& source = sf->GetFullPath(); + cmSourceGroup* sourceGroup = + mf->FindSourceGroup(source.c_str(), sourceGroups); + cmXCodeObject* pbxgroup = this->CreateOrGetPBXGroup(gtgt, sourceGroup); + std::string key = GetGroupMapKeyFromPath(gtgt, source); + this->GroupMap[key] = pbxgroup; + } } } return true; @@ -2780,18 +2797,17 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateOrGetPBXGroup( // If it's the default source group (empty name) then put the source file // directly in the tgroup... // - if (std::string(sg->GetFullName()).empty()) { + if (sg->GetFullName().empty()) { this->GroupNameMap[s] = tgroup; return tgroup; } // It's a recursive folder structure, let's find the real parent group - if (std::string(sg->GetFullName()) != std::string(sg->GetName())) { - std::vector<std::string> folders = - cmSystemTools::tokenize(sg->GetFullName(), "\\"); + if (sg->GetFullName() != sg->GetName()) { std::string curr_folder = target; curr_folder += "/"; - for (auto const& folder : folders) { + for (auto const& folder : + cmSystemTools::tokenize(sg->GetFullName(), "\\")) { curr_folder += folder; std::map<std::string, cmXCodeObject*>::iterator i_folder = this->GroupNameMap.find(curr_folder); @@ -2896,10 +2912,9 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( this->CreateObject(cmXCodeObject::OBJECT_LIST); typedef std::vector<std::pair<std::string, cmXCodeObject*>> Configs; Configs configs; - const char* defaultConfigName = "Debug"; - for (unsigned int i = 0; i < this->CurrentConfigurationTypes.size(); ++i) { - const char* name = this->CurrentConfigurationTypes[i].c_str(); - if (0 == i) { + std::string defaultConfigName; + for (const auto& name : this->CurrentConfigurationTypes) { + if (defaultConfigName.empty()) { defaultConfigName = name; } cmXCodeObject* config = @@ -2907,6 +2922,9 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( config->AddAttribute("name", this->CreateString(name)); configs.push_back(std::make_pair(name, config)); } + if (defaultConfigName.empty()) { + defaultConfigName = "Debug"; + } for (auto& config : configs) { buildConfigurations->AddObject(config.second); } @@ -2971,16 +2989,14 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( // Put this last so it can override existing settings // Convert "CMAKE_XCODE_ATTRIBUTE_*" variables directly. - std::vector<std::string> vars = this->CurrentMakefile->GetDefinitions(); - for (std::vector<std::string>::const_iterator d = vars.begin(); - d != vars.end(); ++d) { - if (d->find("CMAKE_XCODE_ATTRIBUTE_") == 0) { - std::string attribute = d->substr(22); + for (const auto& var : this->CurrentMakefile->GetDefinitions()) { + if (var.find("CMAKE_XCODE_ATTRIBUTE_") == 0) { + std::string attribute = var.substr(22); this->FilterConfigurationAttribute(config.first, attribute); if (!attribute.empty()) { cmGeneratorExpression ge; std::string processed = - ge.Parse(this->CurrentMakefile->GetDefinition(*d)) + ge.Parse(this->CurrentMakefile->GetDefinition(var)) ->Evaluate(this->CurrentLocalGenerator, config.first); buildSettingsForCfg->AddAttribute(attribute, this->CreateString(processed)); @@ -3096,10 +3112,7 @@ void cmGlobalXCodeGenerator::CreateXCodeDependHackTarget( "# link. This forces Xcode to relink the targets from scratch. It\n" "# does not seem to check these dependencies itself.\n"; /* clang-format on */ - for (std::vector<std::string>::const_iterator ct = - this->CurrentConfigurationTypes.begin(); - ct != this->CurrentConfigurationTypes.end(); ++ct) { - std::string configName = *ct; + for (const auto& configName : this->CurrentConfigurationTypes) { for (auto target : targets) { cmGeneratorTarget* gt = target->GetTarget(); @@ -3109,7 +3122,7 @@ void cmGlobalXCodeGenerator::CreateXCodeDependHackTarget( gt->GetType() == cmStateEnums::SHARED_LIBRARY || gt->GetType() == cmStateEnums::MODULE_LIBRARY) { // Declare an entry point for the target post-build phase. - makefileStream << this->PostBuildMakeTarget(gt->GetName(), *ct) + makefileStream << this->PostBuildMakeTarget(gt->GetName(), configName) << ":\n"; } @@ -3122,21 +3135,19 @@ void cmGlobalXCodeGenerator::CreateXCodeDependHackTarget( // Add this target to the post-build phases of its dependencies. std::map<std::string, cmXCodeObject::StringVec>::const_iterator y = - target->GetDependTargets().find(*ct); + target->GetDependTargets().find(configName); if (y != target->GetDependTargets().end()) { - std::vector<std::string> const& deptgts = y->second; - for (auto const& deptgt : deptgts) { - makefileStream << this->PostBuildMakeTarget(deptgt, *ct) << ": " - << trel << "\n"; + for (auto const& deptgt : y->second) { + makefileStream << this->PostBuildMakeTarget(deptgt, configName) + << ": " << trel << "\n"; } } std::vector<cmGeneratorTarget*> objlibs; gt->GetObjectLibrariesCMP0026(objlibs); - for (std::vector<cmGeneratorTarget*>::const_iterator it = - objlibs.begin(); - it != objlibs.end(); ++it) { - makefileStream << this->PostBuildMakeTarget((*it)->GetName(), *ct) + for (auto objLib : objlibs) { + makefileStream << this->PostBuildMakeTarget(objLib->GetName(), + configName) << ": " << trel << "\n"; } @@ -3145,23 +3156,20 @@ void cmGlobalXCodeGenerator::CreateXCodeDependHackTarget( // List dependencies if any exist. std::map<std::string, cmXCodeObject::StringVec>::const_iterator x = - target->GetDependLibraries().find(*ct); + target->GetDependLibraries().find(configName); if (x != target->GetDependLibraries().end()) { - std::vector<std::string> const& deplibs = x->second; - for (auto const& deplib : deplibs) { + for (auto const& deplib : x->second) { std::string file = this->ConvertToRelativeForMake(deplib.c_str()); makefileStream << "\\\n\t" << file; dummyRules.insert(file); } } - for (std::vector<cmGeneratorTarget*>::const_iterator it = - objlibs.begin(); - it != objlibs.end(); ++it) { + for (auto objLib : objlibs) { - const std::string objLibName = (*it)->GetName(); + const std::string objLibName = objLib->GetName(); std::string d = this->GetObjectsNormalDirectory(this->CurrentProject, - configName, *it); + configName, objLib); d += "lib"; d += objLibName; d += ".a"; @@ -3181,7 +3189,7 @@ void cmGlobalXCodeGenerator::CreateXCodeDependHackTarget( if (this->Architectures.size() > 1) { std::string universal = this->GetObjectsNormalDirectory( this->CurrentProject, configName, gt); - for (auto& architecture : this->Architectures) { + for (const auto& architecture : this->Architectures) { std::string universalFile = universal; universalFile += architecture; universalFile += "/"; @@ -3212,7 +3220,7 @@ void cmGlobalXCodeGenerator::OutputXCodeProject( return; } // Skip local generators that are excluded from this project. - for (auto& generator : generators) { + for (auto generator : generators) { if (this->IsExcluded(root, generator)) { continue; } @@ -3234,9 +3242,9 @@ void cmGlobalXCodeGenerator::OutputXCodeProject( } this->WriteXCodePBXProj(fout, root, generators); - // Since the lowest available Xcode version for testing was 7.0, + // Since the lowest available Xcode version for testing was 6.4, // I'm setting this as a limit then - if (this->XcodeVersion >= 70) { + if (this->XcodeVersion >= 64) { if (root->GetMakefile()->GetCMakeInstance()->GetIsInTryCompile() || root->GetMakefile()->IsOn("CMAKE_XCODE_GENERATE_SCHEME")) { this->OutputXCodeSharedSchemes(xcodeDir); @@ -3258,10 +3266,7 @@ void cmGlobalXCodeGenerator::OutputXCodeSharedSchemes( // collect all tests for the targets std::map<std::string, cmXCodeScheme::TestObjects> testables; - for (std::vector<cmXCodeObject*>::const_iterator i = - this->XCodeObjects.begin(); - i != this->XCodeObjects.end(); ++i) { - cmXCodeObject* obj = *i; + for (auto obj : this->XCodeObjects) { if (obj->GetType() != cmXCodeObject::OBJECT || obj->GetIsA() != cmXCodeObject::PBXNativeTarget) { continue; @@ -3280,10 +3285,7 @@ void cmGlobalXCodeGenerator::OutputXCodeSharedSchemes( } // generate scheme - for (std::vector<cmXCodeObject*>::const_iterator i = - this->XCodeObjects.begin(); - i != this->XCodeObjects.end(); ++i) { - cmXCodeObject* obj = *i; + for (auto obj : this->XCodeObjects) { if (obj->GetType() == cmXCodeObject::OBJECT && (obj->GetIsA() == cmXCodeObject::PBXNativeTarget || obj->GetIsA() == cmXCodeObject::PBXAggregateTarget)) { @@ -3512,17 +3514,17 @@ void cmGlobalXCodeGenerator::AppendFlag(std::string& flags, } // Flag value with escaped quotes and backslashes. - for (const char* c = flag.c_str(); *c; ++c) { - if (*c == '\'') { + for (auto c : flag) { + if (c == '\'') { if (this->XcodeVersion >= 40) { flags += "'\\''"; } else { flags += "\\'"; } - } else if (*c == '\\') { + } else if (c == '\\') { flags += "\\\\"; } else { - flags += *c; + flags += c; } } diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index e9ca91c..b758e97 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -55,6 +55,13 @@ public: */ void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*, bool optional) override; + + /** + * Open a generated IDE project given the following information. + */ + bool Open(const std::string& bindir, const std::string& projectName, + bool dryRun) override; + /** * Try running cmake and building a file. This is used for dynalically * loaded commands, not as part of the usual build process. diff --git a/Source/cmIncludeDirectoryCommand.cxx b/Source/cmIncludeDirectoryCommand.cxx index 4c30607..7bd6cb9 100644 --- a/Source/cmIncludeDirectoryCommand.cxx +++ b/Source/cmIncludeDirectoryCommand.cxx @@ -77,7 +77,7 @@ static bool StartsWithGeneratorExpression(const std::string& input) // do a lot of cleanup on the arguments because this is one place where folks // sometimes take the output of a program and pass it directly into this // command not thinking that a single argument could be filled with spaces -// and newlines etc liek below: +// and newlines etc like below: // // " /foo/bar // /boo/hoo /dingle/berry " diff --git a/Source/cmLinkedTree.h b/Source/cmLinkedTree.h index 8865e23..975f052 100644 --- a/Source/cmLinkedTree.h +++ b/Source/cmLinkedTree.h @@ -137,7 +137,7 @@ public: iterator Push(iterator it) { return Push_impl(it, T()); } - iterator Push(iterator it, T t) { return Push_impl(it, t); } + iterator Push(iterator it, T t) { return Push_impl(it, std::move(t)); } bool IsLast(iterator it) { return it.Position == this->Data.size(); } @@ -177,12 +177,12 @@ private: T* GetPointer(PositionType pos) { return &this->Data[pos]; } - iterator Push_impl(iterator it, T t) + iterator Push_impl(iterator it, T&& t) { assert(this->UpPositions.size() == this->Data.size()); assert(it.Position <= this->UpPositions.size()); this->UpPositions.push_back(it.Position); - this->Data.push_back(t); + this->Data.push_back(std::move(t)); return iterator(this, this->UpPositions.size()); } diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index 8e8a54d..cbcf200 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -438,6 +438,19 @@ void cmListFileBacktrace::PrintCallStack(std::ostream& out) const } } +size_t cmListFileBacktrace::Depth() const +{ + size_t depth = 0; + if (this->Cur == nullptr) { + return 0; + } + + for (Entry* i = this->Cur->Up; i; i = i->Up) { + depth++; + } + return depth; +} + std::ostream& operator<<(std::ostream& os, cmListFileContext const& lfc) { os << lfc.FilePath; diff --git a/Source/cmListFileCache.h b/Source/cmListFileCache.h index 349ddef..1f9e374 100644 --- a/Source/cmListFileCache.h +++ b/Source/cmListFileCache.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <iosfwd> +#include <stddef.h> #include <string> #include <vector> @@ -138,6 +139,9 @@ public: // Print the call stack below the top of the backtrace. void PrintCallStack(std::ostream& out) const; + // Get the number of 'frames' in this backtrace + size_t Depth() const; + private: struct Entry; diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 1a088ea..c8d94c0 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -135,8 +135,8 @@ cmLocalGenerator::cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile) this->VariableMappings[compilerOptionSysroot] = this->Makefile->GetSafeDefinition(compilerOptionSysroot); - for (const char* const* replaceIter = cmArrayBegin(ruleReplaceVars); - replaceIter != cmArrayEnd(ruleReplaceVars); ++replaceIter) { + for (const char* const* replaceIter = cm::cbegin(ruleReplaceVars); + replaceIter != cm::cend(ruleReplaceVars); ++replaceIter) { std::string actualReplace = *replaceIter; if (actualReplace.find("${LANG}") != std::string::npos) { cmSystemTools::ReplaceString(actualReplace, "${LANG}", lang); @@ -222,7 +222,14 @@ void cmLocalGenerator::TraceDependencies() void cmLocalGenerator::GenerateTestFiles() { + std::string file = this->StateSnapshot.GetDirectory().GetCurrentBinary(); + file += "/"; + file += "CTestTestfile.cmake"; + if (!this->Makefile->IsOn("CMAKE_TESTING_ENABLED")) { + if (cmSystemTools::FileExists(file)) { + cmSystemTools::RemoveFile(file); + } return; } @@ -231,10 +238,6 @@ void cmLocalGenerator::GenerateTestFiles() const std::string& config = this->Makefile->GetConfigurations(configurationTypes, false); - std::string file = this->StateSnapshot.GetDirectory().GetCurrentBinary(); - file += "/"; - file += "CTestTestfile.cmake"; - cmGeneratedFileStream fout(file.c_str()); fout.SetCopyIfDifferent(true); @@ -484,6 +487,20 @@ void cmLocalGenerator::GenerateInstallRules() /* clang-format on */ } + // Write default directory permissions. + if (const char* defaultDirPermissions = this->Makefile->GetDefinition( + "CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS")) { + /* clang-format off */ + fout << + "# Set default install directory permissions.\n" + "if(NOT DEFINED CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS)\n" + " set(CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS \"" + << defaultDirPermissions << "\")\n" + "endif()\n" + "\n"; + /* clang-format on */ + } + // Ask each install generator to write its code. std::vector<cmInstallGenerator*> const& installers = this->Makefile->GetInstallGenerators(); diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index d8030b7..f01ed7a 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -36,6 +36,13 @@ private: cmLocalVisualStudio7Generator* LocalGenerator; }; +class cmLocalVisualStudio7Generator::AllConfigSources +{ +public: + std::vector<cmGeneratorTarget::AllConfigSource> Sources; + std::map<cmSourceFile const*, size_t> Index; +}; + extern cmVS7FlagTable cmLocalVisualStudio7GeneratorFlagTable[]; static void cmConvertToWindowsSlash(std::string& s) @@ -83,29 +90,6 @@ void cmLocalVisualStudio7Generator::Generate() this->WriteStampFiles(); } -void cmLocalVisualStudio7Generator::AddCMakeListsRules() -{ - // Create the regeneration custom rule. - if (!this->Makefile->IsOn("CMAKE_SUPPRESS_REGENERATION")) { - // Create a rule to regenerate the build system when the target - // specification source changes. - if (cmSourceFile* sf = this->CreateVCProjBuildRule()) { - // Add the rule to targets that need it. - const std::vector<cmGeneratorTarget*>& tgts = - this->GetGeneratorTargets(); - for (std::vector<cmGeneratorTarget*>::const_iterator l = tgts.begin(); - l != tgts.end(); ++l) { - if ((*l)->GetType() == cmStateEnums::GLOBAL_TARGET) { - continue; - } - if ((*l)->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) { - (*l)->AddSource(sf->GetFullPath()); - } - } - } - } -} - void cmLocalVisualStudio7Generator::FixGlobalTargets() { // Visual Studio .NET 2003 Service Pack 1 will not run post-build @@ -239,19 +223,29 @@ void cmLocalVisualStudio7Generator::CreateSingleVCProj( cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule() { + if (this->Makefile->IsOn("CMAKE_SUPPRESS_REGENERATION")) { + return nullptr; + } + + std::string makefileIn = this->GetCurrentSourceDirectory(); + makefileIn += "/"; + makefileIn += "CMakeLists.txt"; + makefileIn = cmSystemTools::CollapseFullPath(makefileIn); + if (cmSourceFile* file = this->Makefile->GetSource(makefileIn)) { + if (file->GetCustomCommand()) { + return file; + } + } + if (!cmSystemTools::FileExists(makefileIn)) { + return nullptr; + } + std::string stampName = this->GetCurrentBinaryDirectory(); stampName += "/"; stampName += cmake::GetCMakeFilesDirectoryPostSlash(); stampName += "generate.stamp"; cmCustomCommandLine commandLine; commandLine.push_back(cmSystemTools::GetCMakeCommand()); - std::string makefileIn = this->GetCurrentSourceDirectory(); - makefileIn += "/"; - makefileIn += "CMakeLists.txt"; - makefileIn = cmSystemTools::CollapseFullPath(makefileIn.c_str()); - if (!cmSystemTools::FileExists(makefileIn.c_str())) { - return 0; - } std::string comment = "Building Custom Rule "; comment += makefileIn; std::string args; @@ -275,10 +269,13 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule() fullpathStampName.c_str(), listFiles, makefileIn.c_str(), commandLines, comment.c_str(), no_working_directory, true, false); if (cmSourceFile* file = this->Makefile->GetSource(makefileIn.c_str())) { + // Finalize the source file path now since we're adding this after + // the generator validated all project-named sources. + file->GetFullPath(); return file; } else { cmSystemTools::Error("Error adding rule for ", makefileIn.c_str()); - return 0; + return nullptr; } } @@ -1368,13 +1365,26 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout, // We may be modifying the source groups temporarily, so make a copy. std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups(); - std::vector<cmGeneratorTarget::AllConfigSource> const& sources = - target->GetAllConfigSources(); - std::map<cmSourceFile const*, size_t> sourcesIndex; + AllConfigSources sources; + sources.Sources = target->GetAllConfigSources(); + + // Add CMakeLists.txt file with rule to re-run CMake for user convenience. + if (target->GetType() != cmStateEnums::GLOBAL_TARGET && + target->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) { + if (cmSourceFile const* sf = this->CreateVCProjBuildRule()) { + cmGeneratorTarget::AllConfigSource acs; + acs.Source = sf; + acs.Kind = cmGeneratorTarget::SourceKindCustomCommand; + for (size_t ci = 0; ci < configs.size(); ++ci) { + acs.Configs.push_back(ci); + } + sources.Sources.emplace_back(std::move(acs)); + } + } - for (size_t si = 0; si < sources.size(); ++si) { - cmSourceFile const* sf = sources[si].Source; - sourcesIndex[sf] = si; + for (size_t si = 0; si < sources.Sources.size(); ++si) { + cmSourceFile const* sf = sources.Sources[si].Source; + sources.Index[sf] = si; if (!sf->GetObjectLibrary().empty()) { if (this->FortranProject) { // Intel Fortran does not support per-config source locations @@ -1400,7 +1410,7 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout, // Loop through every source group. for (unsigned int i = 0; i < sourceGroups.size(); ++i) { cmSourceGroup sg = sourceGroups[i]; - this->WriteGroup(&sg, target, fout, libName, configs, sourcesIndex); + this->WriteGroup(&sg, target, fout, libName, configs, sources); } fout << "\t</Files>\n"; @@ -1567,7 +1577,7 @@ std::string cmLocalVisualStudio7Generator::ComputeLongestObjectDirectory( bool cmLocalVisualStudio7Generator::WriteGroup( const cmSourceGroup* sg, cmGeneratorTarget* target, std::ostream& fout, const std::string& libName, std::vector<std::string> const& configs, - std::map<cmSourceFile const*, size_t> const& sourcesIndex) + AllConfigSources const& sources) { cmGlobalVisualStudio7Generator* gg = static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator); @@ -1579,7 +1589,7 @@ bool cmLocalVisualStudio7Generator::WriteGroup( std::ostringstream tmpOut; for (unsigned int i = 0; i < children.size(); ++i) { if (this->WriteGroup(&children[i], target, tmpOut, libName, configs, - sourcesIndex)) { + sources)) { hasChildrenWithSources = true; } } @@ -1590,14 +1600,11 @@ bool cmLocalVisualStudio7Generator::WriteGroup( } // If the group has a name, write the header. - std::string name = sg->GetName(); + std::string const& name = sg->GetName(); if (!name.empty()) { this->WriteVCProjBeginGroup(fout, name.c_str(), ""); } - std::vector<cmGeneratorTarget::AllConfigSource> const& sources = - target->GetAllConfigSources(); - // Loop through each source in the source group. for (std::vector<const cmSourceFile*>::const_iterator sf = sourceFiles.begin(); @@ -1608,10 +1615,11 @@ bool cmLocalVisualStudio7Generator::WriteGroup( target->GetType() == cmStateEnums::GLOBAL_TARGET) { // Look up the source kind and configs. std::map<cmSourceFile const*, size_t>::const_iterator map_it = - sourcesIndex.find(*sf); + sources.Index.find(*sf); // The map entry must exist because we populated it earlier. - assert(map_it != sourcesIndex.end()); - cmGeneratorTarget::AllConfigSource const& acs = sources[map_it->second]; + assert(map_it != sources.Index.end()); + cmGeneratorTarget::AllConfigSource const& acs = + sources.Sources[map_it->second]; FCInfo fcinfo(this, target, acs, configs); diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h index 7a77574..48f2e1a 100644 --- a/Source/cmLocalVisualStudio7Generator.h +++ b/Source/cmLocalVisualStudio7Generator.h @@ -65,7 +65,6 @@ public: virtual void ReadAndStoreExternalGUID(const std::string& name, const char* path); - virtual void AddCMakeListsRules(); protected: void CreateSingleVCProj(const std::string& lname, cmGeneratorTarget* tgt); @@ -117,10 +116,11 @@ private: FCInfo& fcinfo); void WriteTargetVersionAttribute(std::ostream& fout, cmGeneratorTarget* gt); + class AllConfigSources; bool WriteGroup(const cmSourceGroup* sg, cmGeneratorTarget* target, std::ostream& fout, const std::string& libName, std::vector<std::string> const& configs, - std::map<cmSourceFile const*, size_t> const& sourcesIndex); + AllConfigSources const& sources); friend class cmLocalVisualStudio7GeneratorFCInfo; friend class cmLocalVisualStudio7GeneratorInternals; diff --git a/Source/cmLocalVisualStudioGenerator.h b/Source/cmLocalVisualStudioGenerator.h index cba24fe..ace2f89 100644 --- a/Source/cmLocalVisualStudioGenerator.h +++ b/Source/cmLocalVisualStudioGenerator.h @@ -44,8 +44,6 @@ public: virtual std::string ComputeLongestObjectDirectory( cmGeneratorTarget const*) const = 0; - virtual void AddCMakeListsRules() = 0; - virtual void ComputeObjectFilenames( std::map<cmSourceFile const*, std::string>& mapping, cmGeneratorTarget const* = 0); diff --git a/Source/cmLocalXCodeGenerator.cxx b/Source/cmLocalXCodeGenerator.cxx index 853e66c..457d1fd 100644 --- a/Source/cmLocalXCodeGenerator.cxx +++ b/Source/cmLocalXCodeGenerator.cxx @@ -42,8 +42,7 @@ void cmLocalXCodeGenerator::Generate() { cmLocalGenerator::Generate(); - const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets(); - for (auto target : targets) { + for (auto target : this->GetGeneratorTargets()) { target->HasMacOSXRpathInstallNameDir(""); } } @@ -52,8 +51,7 @@ void cmLocalXCodeGenerator::GenerateInstallRules() { cmLocalGenerator::GenerateInstallRules(); - const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets(); - for (auto target : targets) { + for (auto target : this->GetGeneratorTargets()) { target->HasMacOSXRpathInstallNameDir(""); } } diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 5643c97..a9de3f5 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -7,6 +7,7 @@ #include <algorithm> #include <assert.h> #include <ctype.h> +#include <iterator> #include <memory> // IWYU pragma: keep #include <sstream> #include <stdlib.h> @@ -122,6 +123,42 @@ void cmMakefile::IssueMessage(cmake::MessageType t, this->GetCMakeInstance()->IssueMessage(t, text, this->GetBacktrace()); } +bool cmMakefile::CheckCMP0037(std::string const& targetName, + cmStateEnums::TargetType targetType) const +{ + cmake::MessageType messageType = cmake::AUTHOR_WARNING; + std::ostringstream e; + bool issueMessage = false; + switch (this->GetPolicyStatus(cmPolicies::CMP0037)) { + case cmPolicies::WARN: + if (targetType != cmStateEnums::INTERFACE_LIBRARY) { + e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0037) << "\n"; + issueMessage = true; + } + CM_FALLTHROUGH; + case cmPolicies::OLD: + break; + case cmPolicies::NEW: + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + issueMessage = true; + messageType = cmake::FATAL_ERROR; + break; + } + if (issueMessage) { + e << "The target name \"" << targetName + << "\" is reserved or not valid for certain " + "CMake features, such as generator expressions, and may result " + "in undefined behavior."; + this->IssueMessage(messageType, e.str()); + + if (messageType == cmake::FATAL_ERROR) { + return false; + } + } + return true; +} + cmStringRange cmMakefile::GetIncludeDirectoriesEntries() const { return this->StateSnapshot.GetDirectory().GetIncludeDirectoriesEntries(); @@ -562,7 +599,7 @@ void cmMakefile::EnforceDirectoryLevelRules() const << "\"cmake --help-policy CMP0000\"."; switch (this->GetPolicyStatus(cmPolicies::CMP0000)) { case cmPolicies::WARN: - // Warn because the user did not provide a mimimum required + // Warn because the user did not provide a minimum required // version. this->GetCMakeInstance()->IssueMessage(cmake::AUTHOR_WARNING, msg.str(), this->Backtrace); @@ -970,7 +1007,7 @@ void cmMakefile::AddCustomCommandOldStyle( } cmTarget* cmMakefile::AddUtilityCommand( - const std::string& utilityName, bool excludeFromAll, + const std::string& utilityName, TargetOrigin origin, bool excludeFromAll, const std::vector<std::string>& depends, const char* workingDirectory, const char* command, const char* arg1, const char* arg2, const char* arg3, const char* arg4) @@ -994,25 +1031,25 @@ cmTarget* cmMakefile::AddUtilityCommand( commandLines.push_back(commandLine); // Call the real signature of this method. - return this->AddUtilityCommand(utilityName, excludeFromAll, workingDirectory, - depends, commandLines); + return this->AddUtilityCommand(utilityName, origin, excludeFromAll, + workingDirectory, depends, commandLines); } cmTarget* cmMakefile::AddUtilityCommand( - const std::string& utilityName, bool excludeFromAll, + const std::string& utilityName, TargetOrigin origin, bool excludeFromAll, const char* workingDirectory, const std::vector<std::string>& depends, const cmCustomCommandLines& commandLines, bool escapeOldStyle, const char* comment, bool uses_terminal, bool command_expand_lists) { std::vector<std::string> no_byproducts; - return this->AddUtilityCommand(utilityName, excludeFromAll, workingDirectory, - no_byproducts, depends, commandLines, - escapeOldStyle, comment, uses_terminal, - command_expand_lists); + return this->AddUtilityCommand(utilityName, origin, excludeFromAll, + workingDirectory, no_byproducts, depends, + commandLines, escapeOldStyle, comment, + uses_terminal, command_expand_lists); } cmTarget* cmMakefile::AddUtilityCommand( - const std::string& utilityName, bool excludeFromAll, + const std::string& utilityName, TargetOrigin origin, bool excludeFromAll, const char* workingDirectory, const std::vector<std::string>& byproducts, const std::vector<std::string>& depends, const cmCustomCommandLines& commandLines, bool escapeOldStyle, @@ -1020,6 +1057,7 @@ cmTarget* cmMakefile::AddUtilityCommand( { // Create a target instance for this utility. cmTarget* target = this->AddNewTarget(cmStateEnums::UTILITY, utilityName); + target->SetIsGeneratorProvided(origin == TargetOrigin::Generator); if (excludeFromAll) { target->SetProperty("EXCLUDE_FROM_ALL", "TRUE"); } @@ -1913,7 +1951,7 @@ cmSourceGroup* cmMakefile::GetSourceGroup( // first look for source group starting with the same as the one we want for (cmSourceGroup const& srcGroup : this->SourceGroups) { - std::string sgName = srcGroup.GetName(); + std::string const& sgName = srcGroup.GetName(); if (sgName == name[0]) { sg = const_cast<cmSourceGroup*>(&srcGroup); break; @@ -1977,7 +2015,8 @@ void cmMakefile::AddSourceGroup(const std::vector<std::string>& name, } // build the whole source group path for (++i; i <= lastElement; ++i) { - sg->AddChild(cmSourceGroup(name[i].c_str(), nullptr, sg->GetFullName())); + sg->AddChild( + cmSourceGroup(name[i].c_str(), nullptr, sg->GetFullName().c_str())); sg = sg->LookupChild(name[i].c_str()); } @@ -3083,9 +3122,16 @@ void cmMakefile::SetArgcArgv(const std::vector<std::string>& args) cmSourceFile* cmMakefile::GetSource(const std::string& sourceName) const { cmSourceFileLocation sfl(this, sourceName); - for (cmSourceFile* sf : this->SourceFiles) { - if (sf->Matches(sfl)) { - return sf; + auto name = this->GetCMakeInstance()->StripExtension(sfl.GetName()); +#if defined(_WIN32) || defined(__APPLE__) + name = cmSystemTools::LowerCase(name); +#endif + auto sfsi = this->SourceFileSearchIndex.find(name); + if (sfsi != this->SourceFileSearchIndex.end()) { + for (auto sf : sfsi->second) { + if (sf->Matches(sfl)) { + return sf; + } } } return nullptr; @@ -3099,6 +3145,14 @@ cmSourceFile* cmMakefile::CreateSource(const std::string& sourceName, sf->SetProperty("GENERATED", "1"); } this->SourceFiles.push_back(sf); + + auto name = + this->GetCMakeInstance()->StripExtension(sf->GetLocation().GetName()); +#if defined(_WIN32) || defined(__APPLE__) + name = cmSystemTools::LowerCase(name); +#endif + this->SourceFileSearchIndex[name].push_back(sf); + return sf; } @@ -3186,6 +3240,7 @@ int cmMakefile::TryCompile(const std::string& srcdir, // do a configure cm.SetHomeDirectory(srcdir); cm.SetHomeOutputDirectory(bindir); + cm.SetGeneratorInstance(this->GetSafeDefinition("CMAKE_GENERATOR_INSTANCE")); cm.SetGeneratorPlatform(this->GetSafeDefinition("CMAKE_GENERATOR_PLATFORM")); cm.SetGeneratorToolset(this->GetSafeDefinition("CMAKE_GENERATOR_TOOLSET")); cm.LoadCache(); @@ -3616,6 +3671,16 @@ cmTest* cmMakefile::GetTest(const std::string& testName) const return nullptr; } +void cmMakefile::GetTests(const std::string& config, + std::vector<cmTest*>& tests) +{ + for (auto generator : this->GetTestGenerators()) { + if (generator->TestsForConfig(config)) { + tests.push_back(generator->GetTest()); + } + } +} + void cmMakefile::AddCMakeDependFilesFromUser() { std::vector<std::string> deps; @@ -3980,7 +4045,7 @@ bool cmMakefile::SetPolicy(cmPolicies::PolicyID id, // Deprecate old policies, especially those that require a lot // of code to maintain the old behavior. - if (status == cmPolicies::OLD && id <= cmPolicies::CMP0036) { + if (status == cmPolicies::OLD && id <= cmPolicies::CMP0054) { this->IssueMessage(cmake::DEPRECATION_WARNING, cmPolicies::GetPolicyDeprecatedWarning(id)); } @@ -4133,15 +4198,15 @@ bool cmMakefile::CompileFeatureKnown(cmTarget const* target, assert(cmGeneratorExpression::Find(feature) == std::string::npos); bool isCFeature = - std::find_if(cmArrayBegin(C_FEATURES) + 1, cmArrayEnd(C_FEATURES), - cmStrCmp(feature)) != cmArrayEnd(C_FEATURES); + std::find_if(cm::cbegin(C_FEATURES) + 1, cm::cend(C_FEATURES), + cmStrCmp(feature)) != cm::cend(C_FEATURES); if (isCFeature) { lang = "C"; return true; } bool isCxxFeature = - std::find_if(cmArrayBegin(CXX_FEATURES) + 1, cmArrayEnd(CXX_FEATURES), - cmStrCmp(feature)) != cmArrayEnd(CXX_FEATURES); + std::find_if(cm::cbegin(CXX_FEATURES) + 1, cm::cend(CXX_FEATURES), + cmStrCmp(feature)) != cm::cend(CXX_FEATURES); if (isCxxFeature) { lang = "CXX"; return true; @@ -4230,8 +4295,8 @@ bool cmMakefile::HaveCStandardAvailable(cmTarget const* target, // Return true so the caller does not try to lookup the default standard. return true; } - if (std::find_if(cmArrayBegin(C_STANDARDS), cmArrayEnd(C_STANDARDS), - cmStrCmp(defaultCStandard)) == cmArrayEnd(C_STANDARDS)) { + if (std::find_if(cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS), + cmStrCmp(defaultCStandard)) == cm::cend(C_STANDARDS)) { std::ostringstream e; e << "The CMAKE_C_STANDARD_DEFAULT variable contains an " "invalid value: \"" @@ -4251,8 +4316,8 @@ bool cmMakefile::HaveCStandardAvailable(cmTarget const* target, existingCStandard = defaultCStandard; } - if (std::find_if(cmArrayBegin(C_STANDARDS), cmArrayEnd(C_STANDARDS), - cmStrCmp(existingCStandard)) == cmArrayEnd(C_STANDARDS)) { + if (std::find_if(cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS), + cmStrCmp(existingCStandard)) == cm::cend(C_STANDARDS)) { std::ostringstream e; e << "The C_STANDARD property on target \"" << target->GetName() << "\" contained an invalid value: \"" << existingCStandard << "\"."; @@ -4261,23 +4326,23 @@ bool cmMakefile::HaveCStandardAvailable(cmTarget const* target, } const char* const* existingCIt = existingCStandard - ? std::find_if(cmArrayBegin(C_STANDARDS), cmArrayEnd(C_STANDARDS), + ? std::find_if(cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS), cmStrCmp(existingCStandard)) - : cmArrayEnd(C_STANDARDS); + : cm::cend(C_STANDARDS); if (needC11 && existingCStandard && - existingCIt < std::find_if(cmArrayBegin(C_STANDARDS), - cmArrayEnd(C_STANDARDS), cmStrCmp("11"))) { + existingCIt < std::find_if(cm::cbegin(C_STANDARDS), + cm::cend(C_STANDARDS), cmStrCmp("11"))) { return false; } if (needC99 && existingCStandard && - existingCIt < std::find_if(cmArrayBegin(C_STANDARDS), - cmArrayEnd(C_STANDARDS), cmStrCmp("99"))) { + existingCIt < std::find_if(cm::cbegin(C_STANDARDS), + cm::cend(C_STANDARDS), cmStrCmp("99"))) { return false; } if (needC90 && existingCStandard && - existingCIt < std::find_if(cmArrayBegin(C_STANDARDS), - cmArrayEnd(C_STANDARDS), cmStrCmp("90"))) { + existingCIt < std::find_if(cm::cbegin(C_STANDARDS), + cm::cend(C_STANDARDS), cmStrCmp("90"))) { return false; } return true; @@ -4289,16 +4354,16 @@ bool cmMakefile::IsLaterStandard(std::string const& lang, { if (lang == "C") { const char* const* rhsIt = std::find_if( - cmArrayBegin(C_STANDARDS), cmArrayEnd(C_STANDARDS), cmStrCmp(rhs)); + cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS), cmStrCmp(rhs)); - return std::find_if(rhsIt, cmArrayEnd(C_STANDARDS), cmStrCmp(lhs)) != - cmArrayEnd(C_STANDARDS); + return std::find_if(rhsIt, cm::cend(C_STANDARDS), cmStrCmp(lhs)) != + cm::cend(C_STANDARDS); } const char* const* rhsIt = std::find_if( - cmArrayBegin(CXX_STANDARDS), cmArrayEnd(CXX_STANDARDS), cmStrCmp(rhs)); + cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS), cmStrCmp(rhs)); - return std::find_if(rhsIt, cmArrayEnd(CXX_STANDARDS), cmStrCmp(lhs)) != - cmArrayEnd(CXX_STANDARDS); + return std::find_if(rhsIt, cm::cend(CXX_STANDARDS), cmStrCmp(lhs)) != + cm::cend(CXX_STANDARDS); } bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, @@ -4314,9 +4379,8 @@ bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, // Return true so the caller does not try to lookup the default standard. return true; } - if (std::find_if(cmArrayBegin(CXX_STANDARDS), cmArrayEnd(CXX_STANDARDS), - cmStrCmp(defaultCxxStandard)) == - cmArrayEnd(CXX_STANDARDS)) { + if (std::find_if(cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS), + cmStrCmp(defaultCxxStandard)) == cm::cend(CXX_STANDARDS)) { std::ostringstream e; e << "The CMAKE_CXX_STANDARD_DEFAULT variable contains an " "invalid value: \"" @@ -4337,9 +4401,8 @@ bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, existingCxxStandard = defaultCxxStandard; } - if (std::find_if(cmArrayBegin(CXX_STANDARDS), cmArrayEnd(CXX_STANDARDS), - cmStrCmp(existingCxxStandard)) == - cmArrayEnd(CXX_STANDARDS)) { + if (std::find_if(cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS), + cmStrCmp(existingCxxStandard)) == cm::cend(CXX_STANDARDS)) { std::ostringstream e; e << "The CXX_STANDARD property on target \"" << target->GetName() << "\" contained an invalid value: \"" << existingCxxStandard << "\"."; @@ -4348,32 +4411,28 @@ bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, } const char* const* existingCxxIt = existingCxxStandard - ? std::find_if(cmArrayBegin(CXX_STANDARDS), cmArrayEnd(CXX_STANDARDS), + ? std::find_if(cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS), cmStrCmp(existingCxxStandard)) - : cmArrayEnd(CXX_STANDARDS); + : cm::cend(CXX_STANDARDS); if (needCxx17 && - existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS), - cmArrayEnd(CXX_STANDARDS), - cmStrCmp("17"))) { + existingCxxIt < std::find_if(cm::cbegin(CXX_STANDARDS), + cm::cend(CXX_STANDARDS), cmStrCmp("17"))) { return false; } if (needCxx14 && - existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS), - cmArrayEnd(CXX_STANDARDS), - cmStrCmp("14"))) { + existingCxxIt < std::find_if(cm::cbegin(CXX_STANDARDS), + cm::cend(CXX_STANDARDS), cmStrCmp("14"))) { return false; } if (needCxx11 && - existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS), - cmArrayEnd(CXX_STANDARDS), - cmStrCmp("11"))) { + existingCxxIt < std::find_if(cm::cbegin(CXX_STANDARDS), + cm::cend(CXX_STANDARDS), cmStrCmp("11"))) { return false; } if (needCxx98 && - existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS), - cmArrayEnd(CXX_STANDARDS), - cmStrCmp("98"))) { + existingCxxIt < std::find_if(cm::cbegin(CXX_STANDARDS), + cm::cend(CXX_STANDARDS), cmStrCmp("98"))) { return false; } return true; @@ -4423,9 +4482,9 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, const char* existingCxxStandard = target->GetProperty("CXX_STANDARD"); if (existingCxxStandard) { - if (std::find_if(cmArrayBegin(CXX_STANDARDS), cmArrayEnd(CXX_STANDARDS), + if (std::find_if(cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS), cmStrCmp(existingCxxStandard)) == - cmArrayEnd(CXX_STANDARDS)) { + cm::cend(CXX_STANDARDS)) { std::ostringstream e; e << "The CXX_STANDARD property on target \"" << target->GetName() << "\" contained an invalid value: \"" << existingCxxStandard << "\"."; @@ -4439,9 +4498,9 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, } } const char* const* existingCxxIt = existingCxxStandard - ? std::find_if(cmArrayBegin(CXX_STANDARDS), cmArrayEnd(CXX_STANDARDS), + ? std::find_if(cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS), cmStrCmp(existingCxxStandard)) - : cmArrayEnd(CXX_STANDARDS); + : cm::cend(CXX_STANDARDS); bool setCxx98 = needCxx98 && !existingCxxStandard; bool setCxx11 = needCxx11 && !existingCxxStandard; @@ -4449,23 +4508,22 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, bool setCxx17 = needCxx17 && !existingCxxStandard; if (needCxx17 && existingCxxStandard && - existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS), - cmArrayEnd(CXX_STANDARDS), - cmStrCmp("17"))) { + existingCxxIt < std::find_if(cm::cbegin(CXX_STANDARDS), + cm::cend(CXX_STANDARDS), cmStrCmp("17"))) { setCxx17 = true; } else if (needCxx14 && existingCxxStandard && - existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS), - cmArrayEnd(CXX_STANDARDS), + existingCxxIt < std::find_if(cm::cbegin(CXX_STANDARDS), + cm::cend(CXX_STANDARDS), cmStrCmp("14"))) { setCxx14 = true; } else if (needCxx11 && existingCxxStandard && - existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS), - cmArrayEnd(CXX_STANDARDS), + existingCxxIt < std::find_if(cm::cbegin(CXX_STANDARDS), + cm::cend(CXX_STANDARDS), cmStrCmp("11"))) { setCxx11 = true; } else if (needCxx98 && existingCxxStandard && - existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS), - cmArrayEnd(CXX_STANDARDS), + existingCxxIt < std::find_if(cm::cbegin(CXX_STANDARDS), + cm::cend(CXX_STANDARDS), cmStrCmp("98"))) { setCxx98 = true; } @@ -4522,8 +4580,8 @@ bool cmMakefile::AddRequiredTargetCFeature(cmTarget* target, const char* existingCStandard = target->GetProperty("C_STANDARD"); if (existingCStandard) { - if (std::find_if(cmArrayBegin(C_STANDARDS), cmArrayEnd(C_STANDARDS), - cmStrCmp(existingCStandard)) == cmArrayEnd(C_STANDARDS)) { + if (std::find_if(cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS), + cmStrCmp(existingCStandard)) == cm::cend(C_STANDARDS)) { std::ostringstream e; e << "The C_STANDARD property on target \"" << target->GetName() << "\" contained an invalid value: \"" << existingCStandard << "\"."; @@ -4537,26 +4595,26 @@ bool cmMakefile::AddRequiredTargetCFeature(cmTarget* target, } } const char* const* existingCIt = existingCStandard - ? std::find_if(cmArrayBegin(C_STANDARDS), cmArrayEnd(C_STANDARDS), + ? std::find_if(cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS), cmStrCmp(existingCStandard)) - : cmArrayEnd(C_STANDARDS); + : cm::cend(C_STANDARDS); bool setC90 = needC90 && !existingCStandard; bool setC99 = needC99 && !existingCStandard; bool setC11 = needC11 && !existingCStandard; if (needC11 && existingCStandard && - existingCIt < std::find_if(cmArrayBegin(C_STANDARDS), - cmArrayEnd(C_STANDARDS), cmStrCmp("11"))) { + existingCIt < std::find_if(cm::cbegin(C_STANDARDS), + cm::cend(C_STANDARDS), cmStrCmp("11"))) { setC11 = true; } else if (needC99 && existingCStandard && - existingCIt < std::find_if(cmArrayBegin(C_STANDARDS), - cmArrayEnd(C_STANDARDS), + existingCIt < std::find_if(cm::cbegin(C_STANDARDS), + cm::cend(C_STANDARDS), cmStrCmp("99"))) { setC99 = true; } else if (needC90 && existingCStandard && - existingCIt < std::find_if(cmArrayBegin(C_STANDARDS), - cmArrayEnd(C_STANDARDS), + existingCIt < std::find_if(cm::cbegin(C_STANDARDS), + cm::cend(C_STANDARDS), cmStrCmp("90"))) { setC90 = true; } diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 0273f5b..737cab9 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -183,12 +183,19 @@ public: const std::vector<std::string>& srcs, bool excludeFromAll = false); + /** Where the target originated from. */ + enum class TargetOrigin + { + Project, + Generator + }; + /** * Add a utility to the build. A utiltity target is a command that * is run every time the target is built. */ cmTarget* AddUtilityCommand(const std::string& utilityName, - bool excludeFromAll, + TargetOrigin origin, bool excludeFromAll, const std::vector<std::string>& depends, const char* workingDirectory, const char* command, const char* arg1 = nullptr, @@ -196,13 +203,13 @@ public: const char* arg3 = nullptr, const char* arg4 = nullptr); cmTarget* AddUtilityCommand( - const std::string& utilityName, bool excludeFromAll, + const std::string& utilityName, TargetOrigin origin, bool excludeFromAll, const char* workingDirectory, const std::vector<std::string>& depends, const cmCustomCommandLines& commandLines, bool escapeOldStyle = true, const char* comment = nullptr, bool uses_terminal = false, bool command_expand_lists = false); cmTarget* AddUtilityCommand( - const std::string& utilityName, bool excludeFromAll, + const std::string& utilityName, TargetOrigin origin, bool excludeFromAll, const char* workingDirectory, const std::vector<std::string>& byproducts, const std::vector<std::string>& depends, const cmCustomCommandLines& commandLines, bool escapeOldStyle = true, @@ -561,7 +568,7 @@ public: bool atOnly, bool escapeQuotes) const; /** - * Copy file but change lines acording to ConfigureString + * Copy file but change lines according to ConfigureString */ int ConfigureFile(const char* infile, const char* outfile, bool copyonly, bool atOnly, bool escapeQuotes, @@ -639,6 +646,11 @@ public: cmTest* GetTest(const std::string& testName) const; /** + * Get all tests that run under the given configuration. + */ + void GetTests(const std::string& config, std::vector<cmTest*>& tests); + + /** * Return a location of a file in cmake or custom modules directory */ std::string GetModulesFile(const char* name) const; @@ -665,6 +677,10 @@ public: { return this->InstallGenerators; } + const std::vector<cmInstallGenerator*>& GetInstallGenerators() const + { + return this->InstallGenerators; + } void AddTestGenerator(cmTestGenerator* g) { @@ -737,6 +753,9 @@ public: /** Set whether or not to report a CMP0000 violation. */ void SetCheckCMP0000(bool b) { this->CheckCMP0000 = b; } + bool CheckCMP0037(std::string const& targetName, + cmStateEnums::TargetType targetType) const; + cmStringRange GetIncludeDirectoriesEntries() const; cmBacktraceRange GetIncludeDirectoriesBacktraces() const; cmStringRange GetCompileOptionsEntries() const; @@ -793,7 +812,7 @@ public: void RemoveExportBuildFileGeneratorCMP0024(cmExportBuildFileGenerator* gen); void AddExportBuildFileGenerator(cmExportBuildFileGenerator* gen); - // Maintain a stack of pacakge names to determine the depth of find modules + // Maintain a stack of package names to determine the depth of find modules // we are currently being called with std::deque<std::string> FindPackageModuleStack; @@ -809,7 +828,18 @@ protected: // libraries, classes, and executables mutable cmTargets Targets; std::map<std::string, std::string> AliasTargets; - std::vector<cmSourceFile*> SourceFiles; + + typedef std::vector<cmSourceFile*> SourceFileVec; + SourceFileVec SourceFiles; + + // Because cmSourceFile names are compared in a fuzzy way (see + // cmSourceFileLocation::Match()) we can't have a straight mapping from + // filename to cmSourceFile. To make lookups more efficient we store the + // Name portion of the cmSourceFileLocation and then compare on the list of + // cmSourceFiles that might match that name. Note that on platforms which + // have a case-insensitive filesystem we store the key in all lowercase. + typedef std::unordered_map<std::string, SourceFileVec> SourceFileMap; + SourceFileMap SourceFileSearchIndex; // Tests std::map<std::string, cmTest*> Tests; diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 7db010c..dd8a373 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -657,8 +657,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( } // Maybe insert a compiler launcher like ccache or distcc - if (!compileCommands.empty() && - (lang == "C" || lang == "CXX" || lang == "CUDA")) { + if (!compileCommands.empty() && (lang == "C" || lang == "CXX" || + lang == "Fortran" || lang == "CUDA")) { std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER"; const char* clauncher = this->GeneratorTarget->GetProperty(clauncher_prop); diff --git a/Source/cmMessageCommand.cxx b/Source/cmMessageCommand.cxx index 43fb5f5..5a341bd 100644 --- a/Source/cmMessageCommand.cxx +++ b/Source/cmMessageCommand.cxx @@ -63,7 +63,7 @@ bool cmMessageCommand::InitialPass(std::vector<std::string> const& args, std::string message = cmJoin(cmMakeRange(i, args.end()), std::string()); if (type != cmake::MESSAGE) { - // we've overriden the message type, above, so display it directly + // we've overridden the message type, above, so display it directly cmMessenger* m = this->Makefile->GetMessenger(); m->DisplayMessage(type, message, this->Makefile->GetBacktrace()); } else { diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 5805259..0262b3c 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -647,7 +647,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) // Maybe insert a compiler launcher like ccache or distcc if (!compileCmds.empty() && - (lang == "C" || lang == "CXX" || lang == "CUDA")) { + (lang == "C" || lang == "CXX" || lang == "Fortran" || lang == "CUDA")) { std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER"; const char* clauncher = this->GeneratorTarget->GetProperty(clauncher_prop); if (clauncher && *clauncher) { diff --git a/Source/cmPipeConnection.cxx b/Source/cmPipeConnection.cxx index 9e565f6..3dab2f0 100644 --- a/Source/cmPipeConnection.cxx +++ b/Source/cmPipeConnection.cxx @@ -2,6 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmPipeConnection.h" +#include <algorithm> + #include "cmServer.h" cmPipeConnection::cmPipeConnection(const std::string& name, @@ -13,39 +15,33 @@ cmPipeConnection::cmPipeConnection(const std::string& name, void cmPipeConnection::Connect(uv_stream_t* server) { - if (this->ClientPipe) { + if (this->WriteStream.get()) { // Accept and close all pipes but the first: - uv_pipe_t* rejectPipe = new uv_pipe_t(); + cm::uv_pipe_ptr rejectPipe; + + rejectPipe.init(*this->Server->GetLoop(), 0); + uv_accept(server, rejectPipe); - uv_pipe_init(this->Server->GetLoop(), rejectPipe, 0); - uv_accept(server, reinterpret_cast<uv_stream_t*>(rejectPipe)); - uv_close(reinterpret_cast<uv_handle_t*>(rejectPipe), - &on_close_delete<uv_pipe_t>); return; } - this->ClientPipe = new uv_pipe_t(); - uv_pipe_init(this->Server->GetLoop(), this->ClientPipe, 0); - this->ClientPipe->data = static_cast<cmEventBasedConnection*>(this); - auto client = reinterpret_cast<uv_stream_t*>(this->ClientPipe); - if (uv_accept(server, client) != 0) { - uv_close(reinterpret_cast<uv_handle_t*>(client), - &on_close_delete<uv_pipe_t>); - this->ClientPipe = nullptr; + cm::uv_pipe_ptr ClientPipe; + ClientPipe.init(*this->Server->GetLoop(), 0, + static_cast<cmEventBasedConnection*>(this)); + + if (uv_accept(server, ClientPipe) != 0) { return; } - this->ReadStream = client; - this->WriteStream = client; - uv_read_start(this->ReadStream, on_alloc_buffer, on_read); + uv_read_start(ClientPipe, on_alloc_buffer, on_read); + WriteStream = std::move(ClientPipe); Server->OnConnected(this); } bool cmPipeConnection::OnServeStart(std::string* errorMessage) { - this->ServerPipe = new uv_pipe_t(); - uv_pipe_init(this->Server->GetLoop(), this->ServerPipe, 0); - this->ServerPipe->data = static_cast<cmEventBasedConnection*>(this); + this->ServerPipe.init(*this->Server->GetLoop(), 0, + static_cast<cmEventBasedConnection*>(this)); int r; if ((r = uv_pipe_bind(this->ServerPipe, this->PipeName.c_str())) != 0) { @@ -53,8 +49,8 @@ bool cmPipeConnection::OnServeStart(std::string* errorMessage) ": " + uv_err_name(r); return false; } - auto serverStream = reinterpret_cast<uv_stream_t*>(this->ServerPipe); - if ((r = uv_listen(serverStream, 1, on_new_connection)) != 0) { + + if ((r = uv_listen(this->ServerPipe, 1, on_new_connection)) != 0) { *errorMessage = std::string("Internal Error listening on ") + this->PipeName + ": " + uv_err_name(r); return false; @@ -65,18 +61,11 @@ bool cmPipeConnection::OnServeStart(std::string* errorMessage) bool cmPipeConnection::OnConnectionShuttingDown() { - if (this->ClientPipe) { - uv_close(reinterpret_cast<uv_handle_t*>(this->ClientPipe), - &on_close_delete<uv_pipe_t>); + if (this->WriteStream.get()) { this->WriteStream->data = nullptr; } - uv_close(reinterpret_cast<uv_handle_t*>(this->ServerPipe), - &on_close_delete<uv_pipe_t>); - this->ClientPipe = nullptr; - this->ServerPipe = nullptr; - this->WriteStream = nullptr; - this->ReadStream = nullptr; + this->ServerPipe.reset(); return cmEventBasedConnection::OnConnectionShuttingDown(); } diff --git a/Source/cmPipeConnection.h b/Source/cmPipeConnection.h index 7b89842..49f9fdf 100644 --- a/Source/cmPipeConnection.h +++ b/Source/cmPipeConnection.h @@ -4,6 +4,7 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include "cmUVHandlePtr.h" #include <string> #include "cmConnection.h" @@ -23,6 +24,5 @@ public: private: const std::string PipeName; - uv_pipe_t* ServerPipe = nullptr; - uv_pipe_t* ClientPipe = nullptr; + cm::uv_pipe_ptr ServerPipe; }; diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index 6c33e2b..c39f927 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -211,7 +211,10 @@ class cmMakefile; "Define file(GENERATE) behavior for relative paths.", 3, 10, 0, \ cmPolicies::WARN) \ SELECT(POLICY, CMP0071, "Let AUTOMOC and AUTOUIC process GENERATED files.", \ - 3, 10, 0, cmPolicies::WARN) + 3, 10, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0072, \ + "FindOpenGL prefers GLVND by default when available.", 3, 11, 0, \ + cmPolicies::WARN) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) #define CM_FOR_EACH_POLICY_ID(POLICY) \ @@ -225,6 +228,7 @@ class cmMakefile; F(CMP0021) \ F(CMP0022) \ F(CMP0027) \ + F(CMP0037) \ F(CMP0038) \ F(CMP0041) \ F(CMP0042) \ diff --git a/Source/cmQtAutoGen.cxx b/Source/cmQtAutoGen.cxx index 5e89978..b9dd392 100644 --- a/Source/cmQtAutoGen.cxx +++ b/Source/cmQtAutoGen.cxx @@ -9,6 +9,7 @@ #include "cmsys/RegularExpression.hxx" #include <algorithm> +#include <iterator> #include <sstream> #include <stddef.h> @@ -79,16 +80,6 @@ void MergeOptions(std::vector<std::string>& baseOpts, baseOpts.insert(baseOpts.end(), extraOpts.begin(), extraOpts.end()); } -static std::string utilStripCR(std::string const& line) -{ - // Strip CR characters rcc may have printed (possibly more than one!). - std::string::size_type cr = line.find('\r'); - if (cr != std::string::npos) { - return line.substr(0, cr); - } - return line; -} - /// @brief Reads the resource files list from from a .qrc file - Qt4 version /// @return True if the .qrc file was successfully parsed static bool RccListInputsQt4(std::string const& fileName, @@ -106,10 +97,10 @@ static bool RccListInputsQt4(std::string const& fileName, qrcContents = osst.str(); } else { if (errorMessage != nullptr) { - std::ostringstream ost; - ost << "rcc file not readable:\n" - << " " << cmQtAutoGen::Quoted(fileName) << "\n"; - *errorMessage = ost.str(); + std::string& err = *errorMessage; + err = "rcc file not readable:\n "; + err += cmQtAutoGen::Quoted(fileName); + err += "\n"; } allGood = false; } @@ -145,6 +136,7 @@ static bool RccListInputsQt4(std::string const& fileName, /// @brief Reads the resource files list from from a .qrc file - Qt5 version /// @return True if the .qrc file was successfully parsed static bool RccListInputsQt5(std::string const& rccCommand, + std::vector<std::string> const& rccListOptions, std::string const& fileName, std::vector<std::string>& files, std::string* errorMessage) @@ -154,24 +146,6 @@ static bool RccListInputsQt5(std::string const& rccCommand, return false; } - // Read rcc features - bool hasDashDashList = false; - { - std::vector<std::string> command; - command.push_back(rccCommand); - command.push_back("--help"); - std::string rccStdOut; - std::string rccStdErr; - int retVal = 0; - bool result = cmSystemTools::RunSingleCommand( - command, &rccStdOut, &rccStdErr, &retVal, nullptr, - cmSystemTools::OUTPUT_NONE, 0.0, cmProcessOutput::Auto); - if (result && retVal == 0 && - rccStdOut.find("--list") != std::string::npos) { - hasDashDashList = true; - } - } - std::string const fileDir = cmSystemTools::GetFilenamePath(fileName); std::string const fileNameName = cmSystemTools::GetFilenameName(fileName); @@ -183,7 +157,8 @@ static bool RccListInputsQt5(std::string const& rccCommand, { std::vector<std::string> command; command.push_back(rccCommand); - command.push_back(hasDashDashList ? "--list" : "-list"); + command.insert(command.end(), rccListOptions.begin(), + rccListOptions.end()); command.push_back(fileNameName); result = cmSystemTools::RunSingleCommand( command, &rccStdOut, &rccStdErr, &retVal, fileDir.c_str(), @@ -191,22 +166,32 @@ static bool RccListInputsQt5(std::string const& rccCommand, } if (!result || retVal) { if (errorMessage != nullptr) { - std::ostringstream ost; - ost << "rcc list process failed for\n " << cmQtAutoGen::Quoted(fileName) - << "\n" - << rccStdOut << "\n" - << rccStdErr << "\n"; - *errorMessage = ost.str(); + std::string& err = *errorMessage; + err = "rcc list process failed for:\n "; + err += cmQtAutoGen::Quoted(fileName); + err += "\n"; + err += rccStdOut; + err += "\n"; + err += rccStdErr; + err += "\n"; } return false; } + // Lambda to strip CR characters + auto StripCR = [](std::string& line) { + std::string::size_type cr = line.find('\r'); + if (cr != std::string::npos) { + line = line.substr(0, cr); + } + }; + // Parse rcc std output { std::istringstream ostr(rccStdOut); std::string oline; while (std::getline(ostr, oline)) { - oline = utilStripCR(oline); + StripCR(oline); if (!oline.empty()) { files.push_back(oline); } @@ -217,17 +202,17 @@ static bool RccListInputsQt5(std::string const& rccCommand, std::istringstream estr(rccStdErr); std::string eline; while (std::getline(estr, eline)) { - eline = utilStripCR(eline); + StripCR(eline); if (cmHasLiteralPrefix(eline, "RCC: Error in")) { static std::string searchString = "Cannot find file '"; std::string::size_type pos = eline.find(searchString); if (pos == std::string::npos) { if (errorMessage != nullptr) { - std::ostringstream ost; - ost << "rcc lists unparsable output:\n" - << cmQtAutoGen::Quoted(eline) << "\n"; - *errorMessage = ost.str(); + std::string& err = *errorMessage; + err = "rcc lists unparsable output:\n"; + err += cmQtAutoGen::Quoted(eline); + err += "\n"; } return false; } @@ -301,8 +286,7 @@ std::string cmQtAutoGen::Quoted(std::string const& text) "\r", "\\r", "\t", "\\t", "\v", "\\v" }; std::string res = text; - for (const char* const* it = cmArrayBegin(rep); it != cmArrayEnd(rep); - it += 2) { + for (const char* const* it = cm::cbegin(rep); it != cm::cend(rep); it += 2) { cmSystemTools::ReplaceString(res, *it, *(it + 1)); } res = '"' + res; @@ -349,25 +333,26 @@ void cmQtAutoGen::RccMergeOptions(std::vector<std::string>& baseOpts, MergeOptions(baseOpts, newOpts, valueOpts, isQt5); } -bool cmQtAutoGen::RccListInputs(std::string const& qtMajorVersion, - std::string const& rccCommand, +bool cmQtAutoGen::RccListInputs(std::string const& rccCommand, + std::vector<std::string> const& rccListOptions, std::string const& fileName, std::vector<std::string>& files, std::string* errorMessage) { bool allGood = false; if (cmSystemTools::FileExists(fileName.c_str())) { - if (qtMajorVersion == "4") { + if (rccListOptions.empty()) { allGood = RccListInputsQt4(fileName, files, errorMessage); } else { - allGood = RccListInputsQt5(rccCommand, fileName, files, errorMessage); + allGood = RccListInputsQt5(rccCommand, rccListOptions, fileName, files, + errorMessage); } } else { if (errorMessage != nullptr) { - std::ostringstream ost; - ost << "rcc file does not exist:\n" - << " " << cmQtAutoGen::Quoted(fileName) << "\n"; - *errorMessage = ost.str(); + std::string& err = *errorMessage; + err = "rcc resource file does not exist:\n "; + err += cmQtAutoGen::Quoted(fileName); + err += "\n"; } } return allGood; diff --git a/Source/cmQtAutoGen.h b/Source/cmQtAutoGen.h index acc092f..e769e93 100644 --- a/Source/cmQtAutoGen.h +++ b/Source/cmQtAutoGen.h @@ -61,9 +61,9 @@ public: /// @brief Reads the resource files list from from a .qrc file /// @arg fileName Must be the absolute path of the .qrc file - /// @return True if the rcc file was successfully parsed - static bool RccListInputs(std::string const& qtMajorVersion, - std::string const& rccCommand, + /// @return True if the rcc file was successfully read + static bool RccListInputs(std::string const& rccCommand, + std::vector<std::string> const& rccListOptions, std::string const& fileName, std::vector<std::string>& files, std::string* errorMessage = nullptr); diff --git a/Source/cmQtAutoGenDigest.h b/Source/cmQtAutoGenDigest.h deleted file mode 100644 index 677c397..0000000 --- a/Source/cmQtAutoGenDigest.h +++ /dev/null @@ -1,64 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#ifndef cmQtAutoGenDigest_h -#define cmQtAutoGenDigest_h - -#include "cmConfigure.h" // IWYU pragma: keep - -#include <memory> -#include <string> -#include <vector> - -class cmGeneratorTarget; - -class cmQtAutoGenDigestQrc -{ -public: - cmQtAutoGenDigestQrc() - : Generated(false) - , Unique(false) - { - } - -public: - std::string QrcFile; - std::string QrcName; - std::string PathChecksum; - std::string RccFile; - bool Generated; - bool Unique; - std::vector<std::string> Options; - std::vector<std::string> Resources; -}; - -/** \class cmQtAutoGenDigest - * \brief Filtered set of QtAutogen variables for a specific target - */ -class cmQtAutoGenDigest -{ -public: - cmQtAutoGenDigest(cmGeneratorTarget* target) - : Target(target) - , MocEnabled(false) - , UicEnabled(false) - , RccEnabled(false) - { - } - -public: - cmGeneratorTarget* Target; - std::string QtVersionMajor; - std::string QtVersionMinor; - bool MocEnabled; - bool UicEnabled; - bool RccEnabled; - std::vector<std::string> Headers; - std::vector<std::string> Sources; - std::vector<cmQtAutoGenDigestQrc> Qrcs; -}; - -// Utility types -typedef std::unique_ptr<cmQtAutoGenDigest> cmQtAutoGenDigestUP; -typedef std::vector<cmQtAutoGenDigestUP> cmQtAutoGenDigestUPV; - -#endif diff --git a/Source/cmQtAutoGenerator.cxx b/Source/cmQtAutoGenerator.cxx new file mode 100644 index 0000000..52193af --- /dev/null +++ b/Source/cmQtAutoGenerator.cxx @@ -0,0 +1,320 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmQtAutoGen.h" +#include "cmQtAutoGenerator.h" + +#include "cmsys/FStream.hxx" +#include "cmsys/Terminal.h" + +#include "cmAlgorithms.h" +#include "cmGlobalGenerator.h" +#include "cmMakefile.h" +#include "cmStateDirectory.h" +#include "cmStateSnapshot.h" +#include "cmSystemTools.h" +#include "cmake.h" + +// -- Static functions + +static std::string HeadLine(std::string const& title) +{ + std::string head = title; + head += '\n'; + head.append(head.size() - 1, '-'); + head += '\n'; + return head; +} + +static std::string QuotedCommand(std::vector<std::string> const& command) +{ + std::string res; + for (std::string const& item : command) { + if (!res.empty()) { + res.push_back(' '); + } + std::string const cesc = cmQtAutoGen::Quoted(item); + if (item.empty() || (cesc.size() > (item.size() + 2)) || + (cesc.find(' ') != std::string::npos)) { + res += cesc; + } else { + res += item; + } + } + return res; +} + +// -- Class methods + +cmQtAutoGenerator::cmQtAutoGenerator() + : Verbose(cmSystemTools::HasEnv("VERBOSE")) + , ColorOutput(true) +{ + { + std::string colorEnv; + cmSystemTools::GetEnv("COLOR", colorEnv); + if (!colorEnv.empty()) { + this->ColorOutput = cmSystemTools::IsOn(colorEnv.c_str()); + } + } +} + +bool cmQtAutoGenerator::Run(std::string const& infoFile, + std::string const& config) +{ + // Info settings + this->InfoFile = infoFile; + cmSystemTools::ConvertToUnixSlashes(this->InfoFile); + this->InfoDir = cmSystemTools::GetFilenamePath(infoFile); + this->InfoConfig = config; + + cmake cm(cmake::RoleScript); + cm.SetHomeOutputDirectory(this->InfoDir); + cm.SetHomeDirectory(this->InfoDir); + cm.GetCurrentSnapshot().SetDefaultDefinitions(); + cmGlobalGenerator gg(&cm); + + cmStateSnapshot snapshot = cm.GetCurrentSnapshot(); + snapshot.GetDirectory().SetCurrentBinary(this->InfoDir); + snapshot.GetDirectory().SetCurrentSource(this->InfoDir); + + auto makefile = cm::make_unique<cmMakefile>(&gg, snapshot); + gg.SetCurrentMakefile(makefile.get()); + + return this->Process(makefile.get()); +} + +void cmQtAutoGenerator::LogBold(std::string const& message) const +{ + cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue | + cmsysTerminal_Color_ForegroundBold, + message.c_str(), true, this->ColorOutput); +} + +void cmQtAutoGenerator::LogInfo(cmQtAutoGen::Generator genType, + std::string const& message) const +{ + std::string msg = cmQtAutoGen::GeneratorName(genType); + msg += ": "; + msg += message; + if (msg.back() != '\n') { + msg.push_back('\n'); + } + cmSystemTools::Stdout(msg.c_str(), msg.size()); +} + +void cmQtAutoGenerator::LogWarning(cmQtAutoGen::Generator genType, + std::string const& message) const +{ + std::string msg = cmQtAutoGen::GeneratorName(genType); + msg += " warning:"; + if (message.find('\n') == std::string::npos) { + // Single line message + msg.push_back(' '); + } else { + // Multi line message + msg.push_back('\n'); + } + // Message + msg += message; + if (msg.back() != '\n') { + msg.push_back('\n'); + } + msg.push_back('\n'); + cmSystemTools::Stdout(msg.c_str(), msg.size()); +} + +void cmQtAutoGenerator::LogFileWarning(cmQtAutoGen::Generator genType, + std::string const& filename, + std::string const& message) const +{ + std::string msg = " "; + msg += cmQtAutoGen::Quoted(filename); + msg.push_back('\n'); + // Message + msg += message; + this->LogWarning(genType, msg); +} + +void cmQtAutoGenerator::LogError(cmQtAutoGen::Generator genType, + std::string const& message) const +{ + std::string msg; + msg.push_back('\n'); + msg += HeadLine(cmQtAutoGen::GeneratorName(genType) + " error"); + // Message + msg += message; + if (msg.back() != '\n') { + msg.push_back('\n'); + } + msg.push_back('\n'); + cmSystemTools::Stderr(msg.c_str(), msg.size()); +} + +void cmQtAutoGenerator::LogFileError(cmQtAutoGen::Generator genType, + std::string const& filename, + std::string const& message) const +{ + std::string emsg = " "; + emsg += cmQtAutoGen::Quoted(filename); + emsg += '\n'; + // Message + emsg += message; + this->LogError(genType, emsg); +} + +void cmQtAutoGenerator::LogCommandError( + cmQtAutoGen::Generator genType, std::string const& message, + std::vector<std::string> const& command, std::string const& output) const +{ + std::string msg; + msg.push_back('\n'); + msg += HeadLine(cmQtAutoGen::GeneratorName(genType) + " subprocess error"); + msg += message; + if (msg.back() != '\n') { + msg.push_back('\n'); + } + msg.push_back('\n'); + msg += HeadLine("Command"); + msg += QuotedCommand(command); + if (msg.back() != '\n') { + msg.push_back('\n'); + } + msg.push_back('\n'); + msg += HeadLine("Output"); + msg += output; + if (msg.back() != '\n') { + msg.push_back('\n'); + } + msg.push_back('\n'); + cmSystemTools::Stderr(msg.c_str(), msg.size()); +} + +/** + * @brief Generates the parent directory of the given file on demand + * @return True on success + */ +bool cmQtAutoGenerator::MakeParentDirectory(cmQtAutoGen::Generator genType, + std::string const& filename) const +{ + bool success = true; + std::string const dirName = cmSystemTools::GetFilenamePath(filename); + if (!dirName.empty()) { + if (!cmSystemTools::MakeDirectory(dirName)) { + this->LogFileError(genType, filename, + "Could not create parent directory"); + success = false; + } + } + return success; +} + +/** + * @brief Tests if buildFile is older than sourceFile + * @return True if buildFile is older than sourceFile. + * False may indicate an error. + */ +bool cmQtAutoGenerator::FileIsOlderThan(std::string const& buildFile, + std::string const& sourceFile, + std::string* error) +{ + int result = 0; + if (cmSystemTools::FileTimeCompare(buildFile, sourceFile, &result)) { + return (result < 0); + } + if (error != nullptr) { + error->append( + "File modification time comparison failed for the files\n "); + error->append(cmQtAutoGen::Quoted(buildFile)); + error->append("\nand\n "); + error->append(cmQtAutoGen::Quoted(sourceFile)); + } + return false; +} + +bool cmQtAutoGenerator::FileRead(std::string& content, + std::string const& filename, + std::string* error) +{ + bool success = false; + if (cmSystemTools::FileExists(filename)) { + std::size_t const length = cmSystemTools::FileLength(filename); + cmsys::ifstream ifs(filename.c_str(), (std::ios::in | std::ios::binary)); + if (ifs) { + content.resize(length); + ifs.read(&content.front(), content.size()); + if (ifs) { + success = true; + } else { + content.clear(); + if (error != nullptr) { + error->append("Reading from the file failed."); + } + } + } else if (error != nullptr) { + error->append("Opening the file for reading failed."); + } + } else if (error != nullptr) { + error->append("The file does not exist."); + } + return success; +} + +bool cmQtAutoGenerator::FileWrite(cmQtAutoGen::Generator genType, + std::string const& filename, + std::string const& content) +{ + std::string error; + // Make sure the parent directory exists + if (this->MakeParentDirectory(genType, filename)) { + cmsys::ofstream outfile; + outfile.open(filename.c_str(), + (std::ios::out | std::ios::binary | std::ios::trunc)); + if (outfile) { + outfile << content; + // Check for write errors + if (!outfile.good()) { + error = "File writing failed"; + } + } else { + error = "Opening file for writing failed"; + } + } + if (!error.empty()) { + this->LogFileError(genType, filename, error); + return false; + } + return true; +} + +bool cmQtAutoGenerator::FileDiffers(std::string const& filename, + std::string const& content) +{ + bool differs = true; + { + std::string oldContents; + if (this->FileRead(oldContents, filename)) { + differs = (oldContents != content); + } + } + return differs; +} + +/** + * @brief Runs a command and returns true on success + * @return True on success + */ +bool cmQtAutoGenerator::RunCommand(std::vector<std::string> const& command, + std::string& output) const +{ + // Log command + if (this->Verbose) { + std::string qcmd = QuotedCommand(command); + qcmd.push_back('\n'); + cmSystemTools::Stdout(qcmd.c_str(), qcmd.size()); + } + // Execute command + int retVal = 0; + bool res = cmSystemTools::RunSingleCommand( + command, &output, &output, &retVal, nullptr, cmSystemTools::OUTPUT_NONE); + return (res && (retVal == 0)); +} diff --git a/Source/cmQtAutoGenerator.h b/Source/cmQtAutoGenerator.h new file mode 100644 index 0000000..285340d --- /dev/null +++ b/Source/cmQtAutoGenerator.h @@ -0,0 +1,76 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmQtAutoGenerator_h +#define cmQtAutoGenerator_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include "cmQtAutoGen.h" + +#include <string> +#include <vector> + +class cmMakefile; + +class cmQtAutoGenerator +{ + CM_DISABLE_COPY(cmQtAutoGenerator) +public: + cmQtAutoGenerator(); + virtual ~cmQtAutoGenerator() = default; + bool Run(std::string const& infoFile, std::string const& config); + + std::string const& GetInfoFile() const { return InfoFile; } + std::string const& GetInfoDir() const { return InfoDir; } + std::string const& GetInfoConfig() const { return InfoConfig; } + bool GetVerbose() const { return Verbose; } + +protected: + // -- Central processing + virtual bool Process(cmMakefile* makefile) = 0; + + // -- Log info + void LogBold(std::string const& message) const; + void LogInfo(cmQtAutoGen::Generator genType, + std::string const& message) const; + // -- Log warning + void LogWarning(cmQtAutoGen::Generator genType, + std::string const& message) const; + void LogFileWarning(cmQtAutoGen::Generator genType, + std::string const& filename, + std::string const& message) const; + // -- Log error + void LogError(cmQtAutoGen::Generator genType, + std::string const& message) const; + void LogFileError(cmQtAutoGen::Generator genType, + std::string const& filename, + std::string const& message) const; + void LogCommandError(cmQtAutoGen::Generator genType, + std::string const& message, + std::vector<std::string> const& command, + std::string const& output) const; + // -- Utility + bool MakeParentDirectory(cmQtAutoGen::Generator genType, + std::string const& filename) const; + bool FileIsOlderThan(std::string const& buildFile, + std::string const& sourceFile, + std::string* error = nullptr); + bool FileRead(std::string& content, std::string const& filename, + std::string* error = nullptr); + bool FileWrite(cmQtAutoGen::Generator genType, std::string const& filename, + std::string const& content); + bool FileDiffers(std::string const& filename, std::string const& content); + bool RunCommand(std::vector<std::string> const& command, + std::string& output) const; + +private: + // -- Info settings + std::string InfoFile; + std::string InfoDir; + std::string InfoConfig; + // -- Settings + bool Verbose; + bool ColorOutput; +}; + +#endif diff --git a/Source/cmQtAutoGeneratorInitializer.cxx b/Source/cmQtAutoGeneratorInitializer.cxx index c7550e6..bd692a2 100644 --- a/Source/cmQtAutoGeneratorInitializer.cxx +++ b/Source/cmQtAutoGeneratorInitializer.cxx @@ -14,6 +14,7 @@ #include "cmMakefile.h" #include "cmOutputConverter.h" #include "cmPolicies.h" +#include "cmProcessOutput.h" #include "cmSourceFile.h" #include "cmSourceGroup.h" #include "cmState.h" @@ -51,118 +52,6 @@ inline static std::string GetSafeProperty(cmSourceFile const* sf, return std::string(SafeString(sf->GetProperty(key))); } -static cmQtAutoGen::MultiConfig AutogenMultiConfig( - cmGlobalGenerator* globalGen) -{ - if (!globalGen->IsMultiConfig()) { - return cmQtAutoGen::SINGLE; - } - - // FIXME: Xcode does not support per-config sources, yet. - // (EXCLUDED_SOURCE_FILE_NAMES) - // if (globalGen->GetName().find("Xcode") != std::string::npos) { - // return cmQtAutoGen::FULL; - //} - - // FIXME: Visual Studio does not support per-config sources, yet. - // (EXCLUDED_SOURCE_FILE_NAMES) - // if (globalGen->GetName().find("Visual Studio") != std::string::npos) { - // return cmQtAutoGen::FULL; - //} - - return cmQtAutoGen::WRAP; -} - -static std::string GetAutogenTargetName(cmGeneratorTarget const* target) -{ - std::string autogenTargetName = target->GetName(); - autogenTargetName += "_autogen"; - return autogenTargetName; -} - -static std::string GetAutogenTargetFilesDir(cmGeneratorTarget const* target) -{ - cmMakefile* makefile = target->Target->GetMakefile(); - std::string targetDir = makefile->GetCurrentBinaryDirectory(); - targetDir += makefile->GetCMakeInstance()->GetCMakeFilesDirectory(); - targetDir += "/"; - targetDir += GetAutogenTargetName(target); - targetDir += ".dir"; - return targetDir; -} - -static std::string GetAutogenTargetBuildDir(cmGeneratorTarget const* target) -{ - std::string targetDir = GetSafeProperty(target, "AUTOGEN_BUILD_DIR"); - if (targetDir.empty()) { - cmMakefile* makefile = target->Target->GetMakefile(); - targetDir = makefile->GetCurrentBinaryDirectory(); - targetDir += "/"; - targetDir += GetAutogenTargetName(target); - } - return targetDir; -} - -std::string cmQtAutoGeneratorInitializer::GetQtMajorVersion( - cmGeneratorTarget const* target) -{ - cmMakefile* makefile = target->Target->GetMakefile(); - std::string qtMajor = makefile->GetSafeDefinition("QT_VERSION_MAJOR"); - if (qtMajor.empty()) { - qtMajor = makefile->GetSafeDefinition("Qt5Core_VERSION_MAJOR"); - } - const char* targetQtVersion = - target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION", ""); - if (targetQtVersion != nullptr) { - qtMajor = targetQtVersion; - } - return qtMajor; -} - -std::string cmQtAutoGeneratorInitializer::GetQtMinorVersion( - cmGeneratorTarget const* target, std::string const& qtVersionMajor) -{ - cmMakefile* makefile = target->Target->GetMakefile(); - std::string qtMinor; - if (qtVersionMajor == "5") { - qtMinor = makefile->GetSafeDefinition("Qt5Core_VERSION_MINOR"); - } - if (qtMinor.empty()) { - qtMinor = makefile->GetSafeDefinition("QT_VERSION_MINOR"); - } - - const char* targetQtVersion = - target->GetLinkInterfaceDependentStringProperty("QT_MINOR_VERSION", ""); - if (targetQtVersion != nullptr) { - qtMinor = targetQtVersion; - } - return qtMinor; -} - -static bool QtVersionGreaterOrEqual(std::string const& major, - std::string const& minor, - unsigned long requestMajor, - unsigned long requestMinor) -{ - unsigned long majorUL(0); - unsigned long minorUL(0); - if (cmSystemTools::StringToULong(major.c_str(), &majorUL) && - cmSystemTools::StringToULong(minor.c_str(), &minorUL)) { - return (majorUL > requestMajor) || - (majorUL == requestMajor && minorUL >= requestMinor); - } - return false; -} - -static void GetConfigs(cmMakefile* makefile, std::string& configDefault, - std::vector<std::string>& configsList) -{ - configDefault = makefile->GetConfigurations(configsList); - if (configsList.empty()) { - configsList.push_back(configDefault); - } -} - static void AddDefinitionEscaped(cmMakefile* makefile, const char* key, std::string const& value) { @@ -258,48 +147,24 @@ static void AddCleanFile(cmMakefile* makefile, std::string const& fileName) false); } -static std::vector<std::string> AddGeneratedSource( - cmGeneratorTarget* target, std::string const& filename, - cmQtAutoGen::MultiConfig multiConfig, - const std::vector<std::string>& configsList, cmQtAutoGen::Generator genType) +static std::string FileProjectRelativePath(cmMakefile* makefile, + std::string const& fileName) { - std::vector<std::string> genFiles; - // Register source file in makefile and source group - if (multiConfig != cmQtAutoGen::FULL) { - genFiles.push_back(filename); - } else { - for (std::string const& cfg : configsList) { - genFiles.push_back( - cmQtAutoGen::AppendFilenameSuffix(filename, "_" + cfg)); - } - } + std::string res; { - cmMakefile* makefile = target->Target->GetMakefile(); - for (std::string const& genFile : genFiles) { - { - cmSourceFile* gFile = makefile->GetOrCreateSource(genFile, true); - gFile->SetProperty("GENERATED", "1"); - gFile->SetProperty("SKIP_AUTOGEN", "On"); - } - AddToSourceGroup(makefile, genFile, genType); - } - } - - // Add source file to target - if (multiConfig != cmQtAutoGen::FULL) { - target->AddSource(filename); - } else { - for (std::string const& cfg : configsList) { - std::string src = "$<$<CONFIG:"; - src += cfg; - src += ">:"; - src += cmQtAutoGen::AppendFilenameSuffix(filename, "_" + cfg); - src += ">"; - target->AddSource(src); + std::string pSource = cmSystemTools::RelativePath( + makefile->GetCurrentSourceDirectory(), fileName.c_str()); + std::string pBinary = cmSystemTools::RelativePath( + makefile->GetCurrentBinaryDirectory(), fileName.c_str()); + if (pSource.size() < pBinary.size()) { + res = std::move(pSource); + } else if (pBinary.size() < fileName.size()) { + res = std::move(pBinary); + } else { + res = fileName; } } - - return genFiles; + return res; } /* @brief Tests if targetDepend is a STATIC_LIBRARY and if any of its @@ -346,350 +211,123 @@ static bool StaticLibraryCycle(cmGeneratorTarget const* targetOrigin, return cycle; } -struct cmQtAutoGenSetup -{ - std::set<std::string> MocSkip; - std::set<std::string> UicSkip; - - std::map<std::string, std::string> ConfigMocIncludes; - std::map<std::string, std::string> ConfigMocDefines; - std::map<std::string, std::string> ConfigUicOptions; -}; - -static void SetupAcquireSkipFiles(cmQtAutoGenDigest const& digest, - cmQtAutoGenSetup& setup) +cmQtAutoGeneratorInitializer::cmQtAutoGeneratorInitializer( + cmGeneratorTarget* target, bool mocEnabled, bool uicEnabled, bool rccEnabled, + std::string const& qtVersionMajor) + : Target(target) + , MocEnabled(mocEnabled) + , UicEnabled(uicEnabled) + , RccEnabled(rccEnabled) + , QtVersionMajor(qtVersionMajor) + , MultiConfig(cmQtAutoGen::WRAP) { - // Read skip files from makefile sources - { - const std::vector<cmSourceFile*>& allSources = - digest.Target->Makefile->GetSourceFiles(); - for (cmSourceFile* sf : allSources) { - // sf->GetExtension() is only valid after sf->GetFullPath() ... - std::string const& fPath = sf->GetFullPath(); - cmSystemTools::FileFormat const fileType = - cmSystemTools::GetFileFormat(sf->GetExtension().c_str()); - if (!(fileType == cmSystemTools::CXX_FILE_FORMAT) && - !(fileType == cmSystemTools::HEADER_FILE_FORMAT)) { - continue; - } - const bool skipAll = sf->GetPropertyAsBool("SKIP_AUTOGEN"); - const bool mocSkip = digest.MocEnabled && - (skipAll || sf->GetPropertyAsBool("SKIP_AUTOMOC")); - const bool uicSkip = digest.UicEnabled && - (skipAll || sf->GetPropertyAsBool("SKIP_AUTOUIC")); - if (mocSkip || uicSkip) { - std::string const absFile = cmSystemTools::GetRealPath(fPath); - if (mocSkip) { - setup.MocSkip.insert(absFile); - } - if (uicSkip) { - setup.UicSkip.insert(absFile); - } - } - } - } + this->QtVersionMinor = cmQtAutoGeneratorInitializer::GetQtMinorVersion( + target, this->QtVersionMajor); } -static void SetupAutoTargetMoc(cmQtAutoGenDigest const& digest, - std::string const& configDefault, - std::vector<std::string> const& configsList, - cmQtAutoGenSetup& setup) +void cmQtAutoGeneratorInitializer::InitCustomTargets() { - cmGeneratorTarget const* target = digest.Target; - cmLocalGenerator* localGen = target->GetLocalGenerator(); - cmMakefile* makefile = target->Target->GetMakefile(); - - AddDefinitionEscaped(makefile, "_moc_skip", setup.MocSkip); - AddDefinitionEscaped(makefile, "_moc_options", - GetSafeProperty(target, "AUTOMOC_MOC_OPTIONS")); - AddDefinitionEscaped(makefile, "_moc_relaxed_mode", - makefile->IsOn("CMAKE_AUTOMOC_RELAXED_MODE") ? "TRUE" - : "FALSE"); - AddDefinitionEscaped(makefile, "_moc_macro_names", - GetSafeProperty(target, "AUTOMOC_MACRO_NAMES")); - AddDefinitionEscaped(makefile, "_moc_depend_filters", - GetSafeProperty(target, "AUTOMOC_DEPEND_FILTERS")); - - // Compiler predefines - if (target->GetPropertyAsBool("AUTOMOC_COMPILER_PREDEFINES")) { - if (QtVersionGreaterOrEqual(digest.QtVersionMajor, digest.QtVersionMinor, - 5, 8)) { - AddDefinitionEscaped( - makefile, "_moc_predefs_cmd", - makefile->GetSafeDefinition("CMAKE_CXX_COMPILER_PREDEFINES_COMMAND")); - } - } - // Moc includes and compile definitions - { - auto GetIncludeDirs = [target, - localGen](std::string const& cfg) -> std::string { - // Get the include dirs for this target, without stripping the implicit - // include dirs off, see - // https://gitlab.kitware.com/cmake/cmake/issues/13667 - std::vector<std::string> includeDirs; - localGen->GetIncludeDirectories(includeDirs, target, "CXX", cfg, false); - return cmJoin(includeDirs, ";"); - }; - auto GetCompileDefinitions = - [target, localGen](std::string const& cfg) -> std::string { - std::set<std::string> defines; - localGen->AddCompileDefinitions(defines, target, cfg, "CXX"); - return cmJoin(defines, ";"); - }; + cmMakefile* makefile = this->Target->Target->GetMakefile(); + cmLocalGenerator* localGen = this->Target->GetLocalGenerator(); + cmGlobalGenerator* globalGen = localGen->GetGlobalGenerator(); - // Default configuration settings - std::string const includeDirs = GetIncludeDirs(configDefault); - std::string const compileDefs = GetCompileDefinitions(configDefault); - // Other configuration settings - for (std::string const& cfg : configsList) { - { - std::string const configIncludeDirs = GetIncludeDirs(cfg); - if (configIncludeDirs != includeDirs) { - setup.ConfigMocIncludes[cfg] = configIncludeDirs; - } - } - { - std::string const configCompileDefs = GetCompileDefinitions(cfg); - if (configCompileDefs != compileDefs) { - setup.ConfigMocDefines[cfg] = configCompileDefs; - } - } - } - AddDefinitionEscaped(makefile, "_moc_include_dirs", includeDirs); - AddDefinitionEscaped(makefile, "_moc_compile_defs", compileDefs); + // Configurations + this->ConfigDefault = makefile->GetConfigurations(this->ConfigsList); + if (this->ConfigsList.empty()) { + this->ConfigsList.push_back(this->ConfigDefault); } - // Moc executable + // Multi configuration { - std::string mocExec; - std::string err; - - if (digest.QtVersionMajor == "5") { - cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt5::moc"); - if (tgt != nullptr) { - mocExec = SafeString(tgt->ImportedGetLocation("")); - } else { - err = "AUTOMOC: Qt5::moc target not found"; - } - } else if (digest.QtVersionMajor == "4") { - cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt4::moc"); - if (tgt != nullptr) { - mocExec = SafeString(tgt->ImportedGetLocation("")); - } else { - err = "AUTOMOC: Qt4::moc target not found"; - } - } else { - err = "The AUTOMOC feature supports only Qt 4 and Qt 5"; + if (!globalGen->IsMultiConfig()) { + this->MultiConfig = cmQtAutoGen::SINGLE; } - if (err.empty()) { - AddDefinitionEscaped(makefile, "_qt_moc_executable", mocExec); - } else { - err += " (" + target->GetName() + ")"; - cmSystemTools::Error(err.c_str()); - } + // FIXME: Xcode does not support per-config sources, yet. + // (EXCLUDED_SOURCE_FILE_NAMES) + // if (globalGen->GetName().find("Xcode") != std::string::npos) { + // return cmQtAutoGen::FULL; + //} + + // FIXME: Visual Studio does not support per-config sources, yet. + // (EXCLUDED_SOURCE_FILE_NAMES) + // if (globalGen->GetName().find("Visual Studio") != std::string::npos) { + // return cmQtAutoGen::FULL; + //} } -} -static void SetupAutoTargetUic(cmQtAutoGenDigest const& digest, - std::string const& config, - std::vector<std::string> const& configs, - cmQtAutoGenSetup& setup) -{ - cmGeneratorTarget const* target = digest.Target; - cmMakefile* makefile = target->Target->GetMakefile(); + // Autogen target name + this->AutogenTargetName = this->Target->GetName(); + this->AutogenTargetName += "_autogen"; - // Uic search paths + // Autogen directories { - std::vector<std::string> uicSearchPaths; - { - std::string const usp = GetSafeProperty(target, "AUTOUIC_SEARCH_PATHS"); - if (!usp.empty()) { - cmSystemTools::ExpandListArgument(usp, uicSearchPaths); - std::string const srcDir = makefile->GetCurrentSourceDirectory(); - for (std::string& path : uicSearchPaths) { - path = cmSystemTools::CollapseFullPath(path, srcDir); - } - } + // Collapsed current binary directory + std::string const cbd = cmSystemTools::CollapseFullPath( + "", makefile->GetCurrentBinaryDirectory()); + + // Autogen info dir + this->DirInfo = cbd; + this->DirInfo += makefile->GetCMakeInstance()->GetCMakeFilesDirectory(); + this->DirInfo += "/"; + this->DirInfo += this->AutogenTargetName; + this->DirInfo += ".dir"; + cmSystemTools::ConvertToUnixSlashes(this->DirInfo); + + // Autogen build dir + this->DirBuild = GetSafeProperty(this->Target, "AUTOGEN_BUILD_DIR"); + if (this->DirBuild.empty()) { + this->DirBuild = cbd; + this->DirBuild += "/"; + this->DirBuild += this->AutogenTargetName; } - AddDefinitionEscaped(makefile, "_uic_search_paths", uicSearchPaths); - } - // Uic target options - { - auto UicGetOpts = [target](std::string const& cfg) -> std::string { - std::vector<std::string> opts; - target->GetAutoUicOptions(opts, cfg); - return cmJoin(opts, ";"); - }; + cmSystemTools::ConvertToUnixSlashes(this->DirBuild); - // Default settings - std::string const uicOpts = UicGetOpts(config); - AddDefinitionEscaped(makefile, "_uic_target_options", uicOpts); - - // Configuration specific settings - for (std::string const& cfg : configs) { - std::string const configUicOpts = UicGetOpts(cfg); - if (configUicOpts != uicOpts) { - setup.ConfigUicOptions[cfg] = configUicOpts; - } - } - } - // .ui files skip and options - { - std::vector<std::string> uiFileFiles; - std::vector<std::vector<std::string>> uiFileOptions; - { - std::string const uiExt = "ui"; - for (cmSourceFile* sf : makefile->GetSourceFiles()) { - // sf->GetExtension() is only valid after sf->GetFullPath() ... - std::string const& fPath = sf->GetFullPath(); - if (sf->GetExtension() == uiExt) { - std::string const absFile = cmSystemTools::GetRealPath(fPath); - // Check if the file should be skipped - if (sf->GetPropertyAsBool("SKIP_AUTOUIC") || - sf->GetPropertyAsBool("SKIP_AUTOGEN")) { - setup.UicSkip.insert(absFile); - } - // Check if the files has uic options - std::string const uicOpts = GetSafeProperty(sf, "AUTOUIC_OPTIONS"); - if (!uicOpts.empty()) { - // Check if file isn't skipped - if (setup.UicSkip.count(absFile) == 0) { - uiFileFiles.push_back(absFile); - std::vector<std::string> optsVec; - cmSystemTools::ExpandListArgument(uicOpts, optsVec); - uiFileOptions.push_back(std::move(optsVec)); - } - } - } - } - } - AddDefinitionEscaped(makefile, "_qt_uic_options_files", uiFileFiles); - AddDefinitionEscaped(makefile, "_qt_uic_options_options", uiFileOptions); + // Working directory + this->DirWork = cbd; + cmSystemTools::ConvertToUnixSlashes(this->DirWork); } - AddDefinitionEscaped(makefile, "_uic_skip", setup.UicSkip); - - // Uic executable + // Autogen files { - std::string err; - std::string uicExec; + this->AutogenInfoFile = this->DirInfo; + this->AutogenInfoFile += "/AutogenInfo.cmake"; - cmLocalGenerator* localGen = target->GetLocalGenerator(); - if (digest.QtVersionMajor == "5") { - cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt5::uic"); - if (tgt != nullptr) { - uicExec = SafeString(tgt->ImportedGetLocation("")); - } else { - // Project does not use Qt5Widgets, but has AUTOUIC ON anyway - } - } else if (digest.QtVersionMajor == "4") { - cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt4::uic"); - if (tgt != nullptr) { - uicExec = SafeString(tgt->ImportedGetLocation("")); - } else { - err = "AUTOUIC: Qt4::uic target not found"; - } - } else { - err = "The AUTOUIC feature supports only Qt 4 and Qt 5"; - } - - if (err.empty()) { - AddDefinitionEscaped(makefile, "_qt_uic_executable", uicExec); - } else { - err += " (" + target->GetName() + ")"; - cmSystemTools::Error(err.c_str()); - } + this->AutogenSettingsFile = this->DirInfo; + this->AutogenSettingsFile += "/AutogenOldSettings.cmake"; } -} -static std::string RccGetExecutable(cmGeneratorTarget const* target, - std::string const& qtMajorVersion) -{ - std::string rccExec; - std::string err; - - cmLocalGenerator* localGen = target->GetLocalGenerator(); - if (qtMajorVersion == "5") { - cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt5::rcc"); - if (tgt != nullptr) { - rccExec = SafeString(tgt->ImportedGetLocation("")); - } else { - err = "AUTORCC: Qt5::rcc target not found"; + // Autogen target FOLDER property + { + const char* folder = + makefile->GetState()->GetGlobalProperty("AUTOMOC_TARGETS_FOLDER"); + if (folder == nullptr) { + folder = + makefile->GetState()->GetGlobalProperty("AUTOGEN_TARGETS_FOLDER"); } - } else if (qtMajorVersion == "4") { - cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt4::rcc"); - if (tgt != nullptr) { - rccExec = SafeString(tgt->ImportedGetLocation("")); - } else { - err = "AUTORCC: Qt4::rcc target not found"; + // Inherit FOLDER property from target (#13688) + if (folder == nullptr) { + folder = SafeString(this->Target->Target->GetProperty("FOLDER")); + } + if (folder != nullptr) { + this->AutogenFolder = folder; } - } else { - err = "The AUTORCC feature supports only Qt 4 and Qt 5"; - } - - if (!err.empty()) { - err += " (" + target->GetName() + ")"; - cmSystemTools::Error(err.c_str()); - } - return rccExec; -} - -static void SetupAutoTargetRcc(cmQtAutoGenDigest const& digest) -{ - std::vector<std::string> rccFiles; - std::vector<std::string> rccBuilds; - std::vector<std::vector<std::string>> rccOptions; - std::vector<std::vector<std::string>> rccInputs; - - for (cmQtAutoGenDigestQrc const& qrcDigest : digest.Qrcs) { - rccFiles.push_back(qrcDigest.QrcFile); - rccBuilds.push_back(qrcDigest.RccFile); - rccOptions.push_back(qrcDigest.Options); - rccInputs.push_back(qrcDigest.Resources); } - cmMakefile* makefile = digest.Target->Target->GetMakefile(); - AddDefinitionEscaped(makefile, "_qt_rcc_executable", - RccGetExecutable(digest.Target, digest.QtVersionMajor)); - AddDefinitionEscaped(makefile, "_rcc_files", rccFiles); - AddDefinitionEscaped(makefile, "_rcc_builds", rccBuilds); - AddDefinitionEscaped(makefile, "_rcc_options", rccOptions); - AddDefinitionEscaped(makefile, "_rcc_inputs", rccInputs); -} - -void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( - cmQtAutoGenDigest& digest) -{ - cmGeneratorTarget* target = digest.Target; - cmMakefile* makefile = target->Target->GetMakefile(); - cmLocalGenerator* localGen = target->GetLocalGenerator(); - cmGlobalGenerator* globalGen = localGen->GetGlobalGenerator(); - - std::string const autogenTargetName = GetAutogenTargetName(target); - std::string const autogenInfoDir = GetAutogenTargetFilesDir(target); - std::string const autogenBuildDir = GetAutogenTargetBuildDir(target); - std::string const workingDirectory = - cmSystemTools::CollapseFullPath("", makefile->GetCurrentBinaryDirectory()); - - cmQtAutoGen::MultiConfig const multiConfig = AutogenMultiConfig(globalGen); - std::string configDefault; - std::vector<std::string> configsList; - GetConfigs(makefile, configDefault, configsList); - std::set<std::string> autogenDependFiles; std::set<cmTarget*> autogenDependTargets; std::vector<std::string> autogenProvides; // Remove build directories on cleanup - AddCleanFile(makefile, autogenBuildDir); + AddCleanFile(makefile, this->DirBuild); // Remove old settings on cleanup { - std::string base = autogenInfoDir + "/AutogenOldSettings"; - if (multiConfig == cmQtAutoGen::SINGLE) { + std::string base = this->DirInfo; + base += "/AutogenOldSettings"; + if (this->MultiConfig == cmQtAutoGen::SINGLE) { AddCleanFile(makefile, base.append(".cmake")); } else { - for (std::string const& cfg : configsList) { + for (std::string const& cfg : this->ConfigsList) { std::string filename = base; filename += "_"; filename += cfg; @@ -699,62 +337,72 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( } } - // Compose command lines - cmCustomCommandLines commandLines; - { - cmCustomCommandLine currentLine; - currentLine.push_back(cmSystemTools::GetCMakeCommand()); - currentLine.push_back("-E"); - currentLine.push_back("cmake_autogen"); - currentLine.push_back(autogenInfoDir); - currentLine.push_back("$<CONFIGURATION>"); - commandLines.push_back(currentLine); - } - - // Compose target comment - std::string autogenComment; - { - std::vector<std::string> toolNames; - if (digest.MocEnabled) { - toolNames.emplace_back("MOC"); - } - if (digest.UicEnabled) { - toolNames.emplace_back("UIC"); - } - if (digest.RccEnabled) { - toolNames.emplace_back("RCC"); - } - - std::string tools = toolNames.front(); - toolNames.erase(toolNames.begin()); - if (!toolNames.empty()) { - while (toolNames.size() > 1) { - tools += ", "; - tools += toolNames.front(); - toolNames.erase(toolNames.begin()); - } - tools += " and " + toolNames.front(); - } - autogenComment = "Automatic " + tools + " for target " + target->GetName(); - } - // Add moc compilation to generated files list - if (digest.MocEnabled) { - std::string const mocsComp = autogenBuildDir + "/mocs_compilation.cpp"; - auto files = AddGeneratedSource(target, mocsComp, multiConfig, configsList, - cmQtAutoGen::MOC); + if (this->MocEnabled) { + std::string const mocsComp = this->DirBuild + "/mocs_compilation.cpp"; + auto files = this->AddGeneratedSource(mocsComp, cmQtAutoGen::MOC); for (std::string& file : files) { autogenProvides.push_back(std::move(file)); } } // Add autogen includes directory to the origin target INCLUDE_DIRECTORIES - if (digest.MocEnabled || digest.UicEnabled) { - std::string includeDir = autogenBuildDir + "/include"; - if (multiConfig != cmQtAutoGen::SINGLE) { + if (this->MocEnabled || this->UicEnabled) { + std::string includeDir = this->DirBuild + "/include"; + if (this->MultiConfig != cmQtAutoGen::SINGLE) { includeDir += "_$<CONFIG>"; } - target->AddIncludeDirectory(includeDir, true); + this->Target->AddIncludeDirectory(includeDir, true); + } + + // Acquire rcc executable and features + if (this->RccEnabled) { + { + std::string err; + if (this->QtVersionMajor == "5") { + cmGeneratorTarget* tgt = + localGen->FindGeneratorTargetToUse("Qt5::rcc"); + if (tgt != nullptr) { + this->RccExecutable = SafeString(tgt->ImportedGetLocation("")); + } else { + err = "AUTORCC: Qt5::rcc target not found"; + } + } else if (QtVersionMajor == "4") { + cmGeneratorTarget* tgt = + localGen->FindGeneratorTargetToUse("Qt4::rcc"); + if (tgt != nullptr) { + this->RccExecutable = SafeString(tgt->ImportedGetLocation("")); + } else { + err = "AUTORCC: Qt4::rcc target not found"; + } + } else { + err = "The AUTORCC feature supports only Qt 4 and Qt 5"; + } + if (!err.empty()) { + err += " ("; + err += this->Target->GetName(); + err += ")"; + cmSystemTools::Error(err.c_str()); + } + } + // Detect if rcc supports (-)-list + if (!this->RccExecutable.empty() && (this->QtVersionMajor == "5")) { + std::vector<std::string> command; + command.push_back(this->RccExecutable); + command.push_back("--help"); + std::string rccStdOut; + std::string rccStdErr; + int retVal = 0; + bool result = cmSystemTools::RunSingleCommand( + command, &rccStdOut, &rccStdErr, &retVal, nullptr, + cmSystemTools::OUTPUT_NONE, 0.0, cmProcessOutput::Auto); + if (result && retVal == 0 && + rccStdOut.find("--list") != std::string::npos) { + this->RccListOptions.push_back("--list"); + } else { + this->RccListOptions.push_back("-list"); + } + } } // Extract relevant source files @@ -763,7 +411,7 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( { std::string const qrcExt = "qrc"; std::vector<cmSourceFile*> srcFiles; - target->GetConfigCommonSourceFiles(srcFiles); + this->Target->GetConfigCommonSourceFiles(srcFiles); for (cmSourceFile* sf : srcFiles) { if (sf->GetPropertyAsBool("SKIP_AUTOGEN")) { continue; @@ -772,50 +420,50 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( std::string const& fPath = sf->GetFullPath(); std::string const& ext = sf->GetExtension(); // Register generated files that will be scanned by moc or uic - if (digest.MocEnabled || digest.UicEnabled) { + if (this->MocEnabled || this->UicEnabled) { cmSystemTools::FileFormat const fileType = cmSystemTools::GetFileFormat(ext.c_str()); if ((fileType == cmSystemTools::CXX_FILE_FORMAT) || (fileType == cmSystemTools::HEADER_FILE_FORMAT)) { std::string const absPath = cmSystemTools::GetRealPath(fPath); - if ((digest.MocEnabled && !sf->GetPropertyAsBool("SKIP_AUTOMOC")) || - (digest.UicEnabled && !sf->GetPropertyAsBool("SKIP_AUTOUIC"))) { + if ((this->MocEnabled && !sf->GetPropertyAsBool("SKIP_AUTOMOC")) || + (this->UicEnabled && !sf->GetPropertyAsBool("SKIP_AUTOUIC"))) { // Register source const bool generated = sf->GetPropertyAsBool("GENERATED"); if (fileType == cmSystemTools::HEADER_FILE_FORMAT) { if (generated) { generatedHeaders.push_back(absPath); } else { - digest.Headers.push_back(absPath); + this->Headers.push_back(absPath); } } else { if (generated) { generatedSources.push_back(absPath); } else { - digest.Sources.push_back(absPath); + this->Sources.push_back(absPath); } } } } } // Register rcc enabled files - if (digest.RccEnabled && (ext == qrcExt) && + if (this->RccEnabled && (ext == qrcExt) && !sf->GetPropertyAsBool("SKIP_AUTORCC")) { // Register qrc file { - cmQtAutoGenDigestQrc qrcDigest; - qrcDigest.QrcFile = cmSystemTools::GetRealPath(fPath); - qrcDigest.QrcName = - cmSystemTools::GetFilenameWithoutLastExtension(qrcDigest.QrcFile); - qrcDigest.Generated = sf->GetPropertyAsBool("GENERATED"); + Qrc qrc; + qrc.QrcFile = cmSystemTools::GetRealPath(fPath); + qrc.QrcName = + cmSystemTools::GetFilenameWithoutLastExtension(qrc.QrcFile); + qrc.Generated = sf->GetPropertyAsBool("GENERATED"); // RCC options { std::string const opts = GetSafeProperty(sf, "AUTORCC_OPTIONS"); if (!opts.empty()) { - cmSystemTools::ExpandListArgument(opts, qrcDigest.Options); + cmSystemTools::ExpandListArgument(opts, qrc.Options); } } - digest.Qrcs.push_back(std::move(qrcDigest)); + this->Qrcs.push_back(std::move(qrc)); } } } @@ -823,7 +471,35 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( // sources meta data cache. Clear it so that OBJECT library targets that // are AUTOGEN initialized after this target get their added // mocs_compilation.cpp source acknowledged by this target. - target->ClearSourcesCache(); + this->Target->ClearSourcesCache(); + } + // Read skip files from makefile sources + if (this->MocEnabled || this->UicEnabled) { + const std::vector<cmSourceFile*>& allSources = makefile->GetSourceFiles(); + for (cmSourceFile* sf : allSources) { + // sf->GetExtension() is only valid after sf->GetFullPath() ... + std::string const& fPath = sf->GetFullPath(); + cmSystemTools::FileFormat const fileType = + cmSystemTools::GetFileFormat(sf->GetExtension().c_str()); + if (!(fileType == cmSystemTools::CXX_FILE_FORMAT) && + !(fileType == cmSystemTools::HEADER_FILE_FORMAT)) { + continue; + } + const bool skipAll = sf->GetPropertyAsBool("SKIP_AUTOGEN"); + const bool mocSkip = + this->MocEnabled && (skipAll || sf->GetPropertyAsBool("SKIP_AUTOMOC")); + const bool uicSkip = + this->UicEnabled && (skipAll || sf->GetPropertyAsBool("SKIP_AUTOUIC")); + if (mocSkip || uicSkip) { + std::string const absFile = cmSystemTools::GetRealPath(fPath); + if (mocSkip) { + this->MocSkip.insert(absFile); + } + if (uicSkip) { + this->UicSkip.insert(absFile); + } + } + } } // Process GENERATED sources and headers @@ -832,7 +508,7 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( bool policyAccept = false; bool policyWarn = false; cmPolicies::PolicyStatus const CMP0071_status = - target->Makefile->GetPolicyStatus(cmPolicies::CMP0071); + makefile->GetPolicyStatus(cmPolicies::CMP0071); switch (CMP0071_status) { case cmPolicies::WARN: policyWarn = true; @@ -851,11 +527,11 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( if (policyAccept) { // Accept GENERATED sources for (std::string const& absFile : generatedHeaders) { - digest.Headers.push_back(absFile); + this->Headers.push_back(absFile); autogenDependFiles.insert(absFile); } for (std::string const& absFile : generatedSources) { - digest.Sources.push_back(absFile); + this->Sources.push_back(absFile); autogenDependFiles.insert(absFile); } } else { @@ -865,13 +541,13 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( msg += "\n"; std::string tools; std::string property; - if (digest.MocEnabled && digest.UicEnabled) { + if (this->MocEnabled && this->UicEnabled) { tools = "AUTOMOC and AUTOUIC"; property = "SKIP_AUTOGEN"; - } else if (digest.MocEnabled) { + } else if (this->MocEnabled) { tools = "AUTOMOC"; property = "SKIP_AUTOMOC"; - } else if (digest.UicEnabled) { + } else if (this->UicEnabled) { tools = "AUTOUIC"; property = "SKIP_AUTOUIC"; } @@ -896,57 +572,74 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( makefile->IssueMessage(cmake::AUTHOR_WARNING, msg); } } + // Clear lists + generatedSources.clear(); + generatedHeaders.clear(); } // Sort headers and sources - std::sort(digest.Headers.begin(), digest.Headers.end()); - std::sort(digest.Sources.begin(), digest.Sources.end()); + if (this->MocEnabled || this->UicEnabled) { + std::sort(this->Headers.begin(), this->Headers.end()); + std::sort(this->Sources.begin(), this->Sources.end()); + } // Process qrc files - if (!digest.Qrcs.empty()) { - const bool QtV5 = (digest.QtVersionMajor == "5"); - std::string const rcc = RccGetExecutable(target, digest.QtVersionMajor); + if (!this->Qrcs.empty()) { + const bool QtV5 = (this->QtVersionMajor == "5"); // Target rcc options std::vector<std::string> optionsTarget; cmSystemTools::ExpandListArgument( - GetSafeProperty(target, "AUTORCC_OPTIONS"), optionsTarget); + GetSafeProperty(this->Target, "AUTORCC_OPTIONS"), optionsTarget); // Check if file name is unique - for (cmQtAutoGenDigestQrc& qrcDigest : digest.Qrcs) { - qrcDigest.Unique = true; - for (cmQtAutoGenDigestQrc const& qrcDig2 : digest.Qrcs) { - if ((&qrcDigest != &qrcDig2) && - (qrcDigest.QrcName == qrcDig2.QrcName)) { - qrcDigest.Unique = false; + for (Qrc& qrc : this->Qrcs) { + qrc.Unique = true; + for (Qrc const& qrc2 : this->Qrcs) { + if ((&qrc != &qrc2) && (qrc.QrcName == qrc2.QrcName)) { + qrc.Unique = false; break; } } } - // Path checksum + // Path checksum and file names { cmFilePathChecksum const fpathCheckSum(makefile); - for (cmQtAutoGenDigestQrc& qrcDigest : digest.Qrcs) { - qrcDigest.PathChecksum = fpathCheckSum.getPart(qrcDigest.QrcFile); + for (Qrc& qrc : this->Qrcs) { + qrc.PathChecksum = fpathCheckSum.getPart(qrc.QrcFile); // RCC output file name - std::string rccFile = autogenBuildDir + "/"; - rccFile += qrcDigest.PathChecksum; - rccFile += "/qrc_"; - rccFile += qrcDigest.QrcName; - rccFile += ".cpp"; - qrcDigest.RccFile = std::move(rccFile); + { + std::string rccFile = this->DirBuild + "/"; + rccFile += qrc.PathChecksum; + rccFile += "/qrc_"; + rccFile += qrc.QrcName; + rccFile += ".cpp"; + qrc.RccFile = std::move(rccFile); + } + { + std::string base = this->DirInfo; + base += "/RCC"; + base += qrc.QrcName; + if (!qrc.Unique) { + base += qrc.PathChecksum; + } + qrc.InfoFile = base; + qrc.InfoFile += "Info.cmake"; + qrc.SettingsFile = base; + qrc.SettingsFile += "Settings.cmake"; + } } } // RCC options - for (cmQtAutoGenDigestQrc& qrcDigest : digest.Qrcs) { + for (Qrc& qrc : this->Qrcs) { // Target options std::vector<std::string> opts = optionsTarget; // Merge computed "-name XYZ" option { - std::string name = qrcDigest.QrcName; + std::string name = qrc.QrcName; // Replace '-' with '_'. The former is not valid for symbol names. std::replace(name.begin(), name.end(), '-', '_'); - if (!qrcDigest.Unique) { + if (!qrc.Unique) { name += "_"; - name += qrcDigest.PathChecksum; + name += qrc.PathChecksum; } std::vector<std::string> nameOpts; nameOpts.emplace_back("-name"); @@ -954,254 +647,325 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( cmQtAutoGen::RccMergeOptions(opts, nameOpts, QtV5); } // Merge file option - cmQtAutoGen::RccMergeOptions(opts, qrcDigest.Options, QtV5); - qrcDigest.Options = std::move(opts); + cmQtAutoGen::RccMergeOptions(opts, qrc.Options, QtV5); + qrc.Options = std::move(opts); } - for (cmQtAutoGenDigestQrc& qrcDigest : digest.Qrcs) { + for (Qrc& qrc : this->Qrcs) { // Register file at target + std::vector<std::string> const ccOutput = + this->AddGeneratedSource(qrc.RccFile, cmQtAutoGen::RCC); + + cmCustomCommandLines commandLines; { - auto files = AddGeneratedSource(target, qrcDigest.RccFile, multiConfig, - configsList, cmQtAutoGen::RCC); - for (std::string& file : files) { - autogenProvides.push_back(std::move(file)); - } + cmCustomCommandLine currentLine; + currentLine.push_back(cmSystemTools::GetCMakeCommand()); + currentLine.push_back("-E"); + currentLine.push_back("cmake_autorcc"); + currentLine.push_back(qrc.InfoFile); + currentLine.push_back("$<CONFIGURATION>"); + commandLines.push_back(std::move(currentLine)); } - // Dependencies - if (qrcDigest.Generated) { - // Add the GENERATED .qrc file to the dependencies - autogenDependFiles.insert(qrcDigest.QrcFile); + std::string ccComment = "Automatic RCC for "; + ccComment += FileProjectRelativePath(makefile, qrc.QrcFile); + + if (qrc.Generated) { + // Create custom rcc target + std::string ccName; + { + ccName = this->Target->GetName(); + ccName += "_arcc_"; + ccName += qrc.QrcName; + if (!qrc.Unique) { + ccName += "_"; + ccName += qrc.PathChecksum; + } + std::vector<std::string> ccDepends; + // Add the .qrc file to the custom target dependencies + ccDepends.push_back(qrc.QrcFile); + + cmTarget* autoRccTarget = makefile->AddUtilityCommand( + ccName, cmMakefile::TargetOrigin::Generator, true, + this->DirWork.c_str(), ccOutput, ccDepends, commandLines, false, + ccComment.c_str()); + // Create autogen generator target + localGen->AddGeneratorTarget( + new cmGeneratorTarget(autoRccTarget, localGen)); + + // Set FOLDER property in autogen target + if (!this->AutogenFolder.empty()) { + autoRccTarget->SetProperty("FOLDER", this->AutogenFolder.c_str()); + } + } + // Add autogen target to the origin target dependencies + this->Target->Target->AddUtility(ccName, makefile); } else { - // Add the resource files to the dependencies + // Create custom rcc command { - std::string error; - if (cmQtAutoGen::RccListInputs(digest.QtVersionMajor, rcc, - qrcDigest.QrcFile, - qrcDigest.Resources, &error)) { - for (std::string const& fileName : qrcDigest.Resources) { - autogenDependFiles.insert(fileName); + std::vector<std::string> ccByproducts; + std::vector<std::string> ccDepends; + // Add the .qrc file to the custom command dependencies + ccDepends.push_back(qrc.QrcFile); + + // Add the resource files to the dependencies + { + std::string error; + if (cmQtAutoGen::RccListInputs(this->RccExecutable, + this->RccListOptions, qrc.QrcFile, + qrc.Resources, &error)) { + for (std::string const& fileName : qrc.Resources) { + // Add resource file to the custom command dependencies + ccDepends.push_back(fileName); + } + } else { + cmSystemTools::Error(error.c_str()); } - } else { - cmSystemTools::Error(error.c_str()); } + makefile->AddCustomCommandToOutput(ccOutput, ccByproducts, ccDepends, + /*main_dependency*/ std::string(), + commandLines, ccComment.c_str(), + this->DirWork.c_str()); } - // Run cmake again when .qrc file changes - makefile->AddCMakeDependFile(qrcDigest.QrcFile); + // Reconfigure when .qrc file changes + makefile->AddCMakeDependFile(qrc.QrcFile); } } } - // Add user defined autogen target dependencies - { - std::string const deps = GetSafeProperty(target, "AUTOGEN_TARGET_DEPENDS"); - if (!deps.empty()) { - std::vector<std::string> extraDeps; - cmSystemTools::ExpandListArgument(deps, extraDeps); - for (std::string const& depName : extraDeps) { - // Allow target and file dependencies - auto* depTarget = makefile->FindTargetToUse(depName); - if (depTarget != nullptr) { - autogenDependTargets.insert(depTarget); - } else { - autogenDependFiles.insert(depName); + // Create _autogen target + if (this->MocEnabled || this->UicEnabled) { + // Add user defined autogen target dependencies + { + std::string const deps = + GetSafeProperty(this->Target, "AUTOGEN_TARGET_DEPENDS"); + if (!deps.empty()) { + std::vector<std::string> extraDeps; + cmSystemTools::ExpandListArgument(deps, extraDeps); + for (std::string const& depName : extraDeps) { + // Allow target and file dependencies + auto* depTarget = makefile->FindTargetToUse(depName); + if (depTarget != nullptr) { + autogenDependTargets.insert(depTarget); + } else { + autogenDependFiles.insert(depName); + } } } } - } - // Use PRE_BUILD on demand - bool usePRE_BUILD = false; - if (globalGen->GetName().find("Visual Studio") != std::string::npos) { - // Under VS use a PRE_BUILD event instead of a separate target to - // reduce the number of targets loaded into the IDE. - // This also works around a VS 11 bug that may skip updating the target: - // https://connect.microsoft.com/VisualStudio/feedback/details/769495 - usePRE_BUILD = true; - } - // Disable PRE_BUILD in some cases - if (usePRE_BUILD) { - // Cannot use PRE_BUILD with file depends - if (!autogenDependFiles.empty()) { - usePRE_BUILD = false; + // Compose target comment + std::string autogenComment; + { + std::string tools; + if (this->MocEnabled) { + tools += "MOC"; + } + if (this->UicEnabled) { + if (!tools.empty()) { + tools += " and "; + } + tools += "UIC"; + } + autogenComment = "Automatic "; + autogenComment += tools; + autogenComment += " for target "; + autogenComment += this->Target->GetName(); } - } - // Create the autogen target/command - if (usePRE_BUILD) { - // Add additional autogen target dependencies to origin target - for (cmTarget* depTarget : autogenDependTargets) { - target->Target->AddUtility(depTarget->GetName(), makefile); + + // Compose command lines + cmCustomCommandLines commandLines; + { + cmCustomCommandLine currentLine; + currentLine.push_back(cmSystemTools::GetCMakeCommand()); + currentLine.push_back("-E"); + currentLine.push_back("cmake_autogen"); + currentLine.push_back(this->AutogenInfoFile); + currentLine.push_back("$<CONFIGURATION>"); + commandLines.push_back(std::move(currentLine)); } - // Add the pre-build command directly to bypass the OBJECT_LIBRARY - // rejection in cmMakefile::AddCustomCommandToTarget because we know - // PRE_BUILD will work for an OBJECT_LIBRARY in this specific case. - // - // PRE_BUILD does not support file dependencies! - const std::vector<std::string> no_output; - const std::vector<std::string> no_deps; - cmCustomCommand cc(makefile, no_output, autogenProvides, no_deps, - commandLines, autogenComment.c_str(), - workingDirectory.c_str()); - cc.SetEscapeOldStyle(false); - cc.SetEscapeAllowMakeVars(true); - target->Target->AddPreBuildCommand(cc); - } else { + // Use PRE_BUILD on demand + bool usePRE_BUILD = false; + if (globalGen->GetName().find("Visual Studio") != std::string::npos) { + // Under VS use a PRE_BUILD event instead of a separate target to + // reduce the number of targets loaded into the IDE. + // This also works around a VS 11 bug that may skip updating the target: + // https://connect.microsoft.com/VisualStudio/feedback/details/769495 + usePRE_BUILD = true; + } + // Disable PRE_BUILD in some cases + if (usePRE_BUILD) { + // Cannot use PRE_BUILD with file depends + if (!autogenDependFiles.empty()) { + usePRE_BUILD = false; + } + } + // Create the autogen target/command + if (usePRE_BUILD) { + // Add additional autogen target dependencies to origin target + for (cmTarget* depTarget : autogenDependTargets) { + this->Target->Target->AddUtility(depTarget->GetName(), makefile); + } - // Convert file dependencies std::set to std::vector - std::vector<std::string> autogenDepends(autogenDependFiles.begin(), - autogenDependFiles.end()); + // Add the pre-build command directly to bypass the OBJECT_LIBRARY + // rejection in cmMakefile::AddCustomCommandToTarget because we know + // PRE_BUILD will work for an OBJECT_LIBRARY in this specific case. + // + // PRE_BUILD does not support file dependencies! + const std::vector<std::string> no_output; + const std::vector<std::string> no_deps; + cmCustomCommand cc(makefile, no_output, autogenProvides, no_deps, + commandLines, autogenComment.c_str(), + this->DirWork.c_str()); + cc.SetEscapeOldStyle(false); + cc.SetEscapeAllowMakeVars(true); + this->Target->Target->AddPreBuildCommand(cc); + } else { - // Add link library target dependencies to the autogen target dependencies - for (std::string const& config : configsList) { - cmLinkImplementationLibraries const* libs = - target->GetLinkImplementationLibraries(config); - if (libs != nullptr) { - for (cmLinkItem const& item : libs->Libraries) { - cmGeneratorTarget const* libTarget = item.Target; - if ((libTarget != nullptr) && - !StaticLibraryCycle(target, libTarget, config)) { - std::string util; - if (configsList.size() > 1) { - util += "$<$<CONFIG:"; - util += config; - util += ">:"; - } - util += libTarget->GetName(); - if (configsList.size() > 1) { - util += ">"; + // Convert file dependencies std::set to std::vector + std::vector<std::string> autogenDepends(autogenDependFiles.begin(), + autogenDependFiles.end()); + + // Add link library target dependencies to the autogen target + // dependencies + for (std::string const& config : this->ConfigsList) { + cmLinkImplementationLibraries const* libs = + this->Target->GetLinkImplementationLibraries(config); + if (libs != nullptr) { + for (cmLinkItem const& item : libs->Libraries) { + cmGeneratorTarget const* libTarget = item.Target; + if ((libTarget != nullptr) && + !StaticLibraryCycle(this->Target, libTarget, config)) { + std::string util; + if (this->ConfigsList.size() > 1) { + util += "$<$<CONFIG:"; + util += config; + util += ">:"; + } + util += libTarget->GetName(); + if (this->ConfigsList.size() > 1) { + util += ">"; + } + autogenDepends.push_back(util); } - autogenDepends.push_back(util); } } } - } - // Create autogen target - cmTarget* autogenTarget = makefile->AddUtilityCommand( - autogenTargetName, true, workingDirectory.c_str(), - /*byproducts=*/autogenProvides, autogenDepends, commandLines, false, - autogenComment.c_str()); - // Create autogen generator target - localGen->AddGeneratorTarget( - new cmGeneratorTarget(autogenTarget, localGen)); - - // Forward origin utilities to autogen target - for (std::string const& depName : target->Target->GetUtilities()) { - autogenTarget->AddUtility(depName, makefile); - } - // Add additional autogen target dependencies to autogen target - for (cmTarget* depTarget : autogenDependTargets) { - autogenTarget->AddUtility(depTarget->GetName(), makefile); - } - - // Set FOLDER property in autogen target - { - const char* autogenFolder = - makefile->GetState()->GetGlobalProperty("AUTOMOC_TARGETS_FOLDER"); - if (autogenFolder == nullptr) { - autogenFolder = - makefile->GetState()->GetGlobalProperty("AUTOGEN_TARGETS_FOLDER"); + // Create autogen target + cmTarget* autogenTarget = makefile->AddUtilityCommand( + this->AutogenTargetName, cmMakefile::TargetOrigin::Generator, true, + this->DirWork.c_str(), /*byproducts=*/autogenProvides, autogenDepends, + commandLines, false, autogenComment.c_str()); + // Create autogen generator target + localGen->AddGeneratorTarget( + new cmGeneratorTarget(autogenTarget, localGen)); + + // Forward origin utilities to autogen target + for (std::string const& depName : this->Target->Target->GetUtilities()) { + autogenTarget->AddUtility(depName, makefile); } - // Inherit FOLDER property from target (#13688) - if (autogenFolder == nullptr) { - autogenFolder = SafeString(target->Target->GetProperty("FOLDER")); + // Add additional autogen target dependencies to autogen target + for (cmTarget* depTarget : autogenDependTargets) { + autogenTarget->AddUtility(depTarget->GetName(), makefile); } - if ((autogenFolder != nullptr) && (*autogenFolder != '\0')) { - autogenTarget->SetProperty("FOLDER", autogenFolder); + + // Set FOLDER property in autogen target + if (!this->AutogenFolder.empty()) { + autogenTarget->SetProperty("FOLDER", this->AutogenFolder.c_str()); } - } - // Add autogen target to the origin target dependencies - target->Target->AddUtility(autogenTargetName, makefile); + // Add autogen target to the origin target dependencies + this->Target->Target->AddUtility(this->AutogenTargetName, makefile); + } } } -void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget( - cmQtAutoGenDigest const& digest) +void cmQtAutoGeneratorInitializer::SetupCustomTargets() { - cmGeneratorTarget const* target = digest.Target; - cmMakefile* makefile = target->Target->GetMakefile(); - cmQtAutoGen::MultiConfig const multiConfig = - AutogenMultiConfig(target->GetGlobalGenerator()); + cmMakefile* makefile = this->Target->Target->GetMakefile(); // forget the variables added here afterwards again: cmMakefile::ScopePushPop varScope(makefile); static_cast<void>(varScope); - // Configurations - std::string configDefault; - std::vector<std::string> configsList; + // Configuration suffixes std::map<std::string, std::string> configSuffixes; - { - configDefault = makefile->GetConfigurations(configsList); - if (configsList.empty()) { - configsList.push_back(""); - } + for (std::string const& cfg : this->ConfigsList) { + std::string& suffix = configSuffixes[cfg]; + suffix = "_"; + suffix += cfg; } - for (std::string const& cfg : configsList) { - configSuffixes[cfg] = "_" + cfg; - } - - // Configurations settings buffers - cmQtAutoGenSetup setup; // Basic setup AddDefinitionEscaped(makefile, "_multi_config", - cmQtAutoGen::MultiConfigName(multiConfig)); - AddDefinitionEscaped(makefile, "_build_dir", - GetAutogenTargetBuildDir(target)); - AddDefinitionEscaped(makefile, "_sources", digest.Sources); - AddDefinitionEscaped(makefile, "_headers", digest.Headers); - AddDefinitionEscaped(makefile, "_qt_version_major", digest.QtVersionMajor); - AddDefinitionEscaped(makefile, "_qt_version_minor", digest.QtVersionMinor); - { - if (digest.MocEnabled || digest.UicEnabled) { - SetupAcquireSkipFiles(digest, setup); - if (digest.MocEnabled) { - SetupAutoTargetMoc(digest, configDefault, configsList, setup); - } - if (digest.UicEnabled) { - SetupAutoTargetUic(digest, configDefault, configsList, setup); - } + cmQtAutoGen::MultiConfigName(this->MultiConfig)); + AddDefinitionEscaped(makefile, "_build_dir", this->DirBuild); + + if (this->MocEnabled || this->UicEnabled) { + AddDefinitionEscaped(makefile, "_qt_version_major", this->QtVersionMajor); + AddDefinitionEscaped(makefile, "_settings_file", + this->AutogenSettingsFile); + AddDefinitionEscaped(makefile, "_sources", this->Sources); + AddDefinitionEscaped(makefile, "_headers", this->Headers); + + if (this->MocEnabled) { + this->SetupCustomTargetsMoc(); } - if (digest.RccEnabled) { - SetupAutoTargetRcc(digest); + if (this->UicEnabled) { + this->SetupCustomTargetsUic(); } } + if (this->RccEnabled) { + AddDefinitionEscaped(makefile, "_qt_rcc_executable", this->RccExecutable); + AddDefinitionEscaped(makefile, "_qt_rcc_list_options", + this->RccListOptions); + } - // Generate info file - { - std::string const infoDir = GetAutogenTargetFilesDir(target); - if (!cmSystemTools::MakeDirectory(infoDir)) { - std::string emsg = ("Could not create directory: "); - emsg += cmQtAutoGen::Quoted(infoDir); - cmSystemTools::Error(emsg.c_str()); - } - std::string const infoFile = infoDir + "/AutogenInfo.cmake"; - { - std::string infoFileIn = cmSystemTools::GetCMakeRoot(); - infoFileIn += "/Modules/AutogenInfo.cmake.in"; - makefile->ConfigureFile(infoFileIn.c_str(), infoFile.c_str(), false, - true, false); - } - - // Append custom definitions to info file - // -------------------------------------- + // Create info directory on demand + if (!cmSystemTools::MakeDirectory(this->DirInfo)) { + std::string emsg = ("Could not create directory: "); + emsg += cmQtAutoGen::Quoted(this->DirInfo); + cmSystemTools::Error(emsg.c_str()); + } - // Ensure we have write permission in case .in was read-only. + auto ReOpenInfoFile = [](cmsys::ofstream& ofs, + std::string const& fileName) -> bool { + // Ensure we have write permission mode_t perm = 0; #if defined(_WIN32) && !defined(__CYGWIN__) mode_t mode_write = S_IWRITE; #else mode_t mode_write = S_IWUSR; #endif - cmSystemTools::GetPermissions(infoFile, perm); + cmSystemTools::GetPermissions(fileName, perm); if (!(perm & mode_write)) { - cmSystemTools::SetPermissions(infoFile, perm | mode_write); + cmSystemTools::SetPermissions(fileName, perm | mode_write); } - // Open and write file - cmsys::ofstream ofs(infoFile.c_str(), std::ios::app); - if (ofs) { + ofs.open(fileName.c_str(), std::ios::app); + if (!ofs) { + // File open error + std::string error = "Internal CMake error when trying to open file: "; + error += cmQtAutoGen::Quoted(fileName); + error += " for writing."; + cmSystemTools::Error(error.c_str()); + } + return static_cast<bool>(ofs); + }; + + // Generate autogen target info file + if (this->MocEnabled || this->UicEnabled) { + { + std::string infoFileIn = cmSystemTools::GetCMakeRoot(); + infoFileIn += "/Modules/AutogenInfo.cmake.in"; + makefile->ConfigureFile( + infoFileIn.c_str(), this->AutogenInfoFile.c_str(), false, true, false); + } + + // Append custom definitions to info file + // -------------------------------------- + cmsys::ofstream ofs; + if (ReOpenInfoFile(ofs, this->AutogenInfoFile)) { auto OfsWriteMap = [&ofs]( const char* key, std::map<std::string, std::string> const& map) { for (auto const& item : map) { @@ -1211,15 +975,372 @@ void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget( }; ofs << "# Configurations options\n"; OfsWriteMap("AM_CONFIG_SUFFIX", configSuffixes); - OfsWriteMap("AM_MOC_DEFINITIONS", setup.ConfigMocDefines); - OfsWriteMap("AM_MOC_INCLUDES", setup.ConfigMocIncludes); - OfsWriteMap("AM_UIC_TARGET_OPTIONS", setup.ConfigUicOptions); + OfsWriteMap("AM_MOC_DEFINITIONS", this->ConfigMocDefines); + OfsWriteMap("AM_MOC_INCLUDES", this->ConfigMocIncludes); + OfsWriteMap("AM_UIC_TARGET_OPTIONS", this->ConfigUicOptions); + // Settings files (only require for multi configuration generators) + if (this->MultiConfig != cmQtAutoGen::SINGLE) { + std::map<std::string, std::string> settingsFiles; + for (std::string const& cfg : this->ConfigsList) { + settingsFiles[cfg] = cmQtAutoGen::AppendFilenameSuffix( + this->AutogenSettingsFile, "_" + cfg); + } + OfsWriteMap("AM_SETTINGS_FILE", settingsFiles); + } + } + } + + // Generate auto RCC info files + if (this->RccEnabled) { + std::string infoFileIn = cmSystemTools::GetCMakeRoot(); + infoFileIn += "/Modules/AutoRccInfo.cmake.in"; + for (Qrc const& qrc : this->Qrcs) { + // Configure info file + makefile->ConfigureFile(infoFileIn.c_str(), qrc.InfoFile.c_str(), false, + true, false); + + // Append custom definitions to info file + // -------------------------------------- + cmsys::ofstream ofs; + if (ReOpenInfoFile(ofs, qrc.InfoFile)) { + { + ofs << "# Job\n"; + auto OfsWrite = [&ofs](const char* key, std::string const& value) { + ofs << "set(" << key << " " + << cmOutputConverter::EscapeForCMake(value) << ")\n"; + + }; + OfsWrite("ARCC_SETTINGS_FILE", qrc.SettingsFile); + OfsWrite("ARCC_SOURCE", qrc.QrcFile); + OfsWrite("ARCC_OUTPUT", qrc.RccFile); + OfsWrite("ARCC_OPTIONS", cmJoin(qrc.Options, ";")); + OfsWrite("ARCC_INPUTS", cmJoin(qrc.Resources, ";")); + } + { + ofs << "# Configurations options\n"; + auto OfsWriteMap = [&ofs]( + const char* key, std::map<std::string, std::string> const& map) { + for (auto const& item : map) { + ofs << "set(" << key << "_" << item.first << " " + << cmOutputConverter::EscapeForCMake(item.second) << ")\n"; + } + }; + OfsWriteMap("ARCC_CONFIG_SUFFIX", configSuffixes); + + // Settings files (only require for multi configuration generators) + if (this->MultiConfig != cmQtAutoGen::SINGLE) { + std::map<std::string, std::string> settingsFiles; + for (std::string const& cfg : this->ConfigsList) { + settingsFiles[cfg] = + cmQtAutoGen::AppendFilenameSuffix(qrc.SettingsFile, "_" + cfg); + } + OfsWriteMap("ARCC_SETTINGS_FILE", settingsFiles); + } + } + } else { + break; + } + } + } +} + +void cmQtAutoGeneratorInitializer::SetupCustomTargetsMoc() +{ + cmLocalGenerator* localGen = this->Target->GetLocalGenerator(); + cmMakefile* makefile = this->Target->Target->GetMakefile(); + + AddDefinitionEscaped(makefile, "_moc_skip", this->MocSkip); + AddDefinitionEscaped(makefile, "_moc_options", + GetSafeProperty(this->Target, "AUTOMOC_MOC_OPTIONS")); + AddDefinitionEscaped(makefile, "_moc_relaxed_mode", + makefile->IsOn("CMAKE_AUTOMOC_RELAXED_MODE") ? "TRUE" + : "FALSE"); + AddDefinitionEscaped(makefile, "_moc_macro_names", + GetSafeProperty(this->Target, "AUTOMOC_MACRO_NAMES")); + AddDefinitionEscaped( + makefile, "_moc_depend_filters", + GetSafeProperty(this->Target, "AUTOMOC_DEPEND_FILTERS")); + + // Compiler predefines + if (this->Target->GetPropertyAsBool("AUTOMOC_COMPILER_PREDEFINES") && + this->QtVersionGreaterOrEqual(5, 8)) { + AddDefinitionEscaped( + makefile, "_moc_predefs_cmd", + makefile->GetSafeDefinition("CMAKE_CXX_COMPILER_PREDEFINES_COMMAND")); + } + // Moc includes and compile definitions + { + auto GetIncludeDirs = [this, + localGen](std::string const& cfg) -> std::string { + // Get the include dirs for this target, without stripping the implicit + // include dirs off, see + // https://gitlab.kitware.com/cmake/cmake/issues/13667 + std::vector<std::string> includeDirs; + localGen->GetIncludeDirectories(includeDirs, this->Target, "CXX", cfg, + false); + return cmJoin(includeDirs, ";"); + }; + auto GetCompileDefinitions = + [this, localGen](std::string const& cfg) -> std::string { + std::set<std::string> defines; + localGen->AddCompileDefinitions(defines, this->Target, cfg, "CXX"); + return cmJoin(defines, ";"); + }; + + // Default configuration settings + std::string const includeDirs = GetIncludeDirs(this->ConfigDefault); + std::string const compileDefs = GetCompileDefinitions(this->ConfigDefault); + // Other configuration settings + for (std::string const& cfg : this->ConfigsList) { + { + std::string const configIncludeDirs = GetIncludeDirs(cfg); + if (configIncludeDirs != includeDirs) { + this->ConfigMocIncludes[cfg] = configIncludeDirs; + } + } + { + std::string const configCompileDefs = GetCompileDefinitions(cfg); + if (configCompileDefs != compileDefs) { + this->ConfigMocDefines[cfg] = configCompileDefs; + } + } + } + AddDefinitionEscaped(makefile, "_moc_include_dirs", includeDirs); + AddDefinitionEscaped(makefile, "_moc_compile_defs", compileDefs); + } + + // Moc executable + { + std::string mocExec; + std::string err; + + if (this->QtVersionMajor == "5") { + cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt5::moc"); + if (tgt != nullptr) { + mocExec = SafeString(tgt->ImportedGetLocation("")); + } else { + err = "AUTOMOC: Qt5::moc target not found"; + } + } else if (this->QtVersionMajor == "4") { + cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt4::moc"); + if (tgt != nullptr) { + mocExec = SafeString(tgt->ImportedGetLocation("")); + } else { + err = "AUTOMOC: Qt4::moc target not found"; + } } else { - // File open error - std::string error = "Internal CMake error when trying to open file: "; - error += cmQtAutoGen::Quoted(infoFile); - error += " for writing."; - cmSystemTools::Error(error.c_str()); + err = "The AUTOMOC feature supports only Qt 4 and Qt 5"; + } + + if (err.empty()) { + AddDefinitionEscaped(makefile, "_qt_moc_executable", mocExec); + } else { + err += " ("; + err += this->Target->GetName(); + err += ")"; + cmSystemTools::Error(err.c_str()); } } } + +void cmQtAutoGeneratorInitializer::SetupCustomTargetsUic() +{ + cmMakefile* makefile = this->Target->Target->GetMakefile(); + + // Uic search paths + { + std::vector<std::string> uicSearchPaths; + { + std::string const usp = + GetSafeProperty(this->Target, "AUTOUIC_SEARCH_PATHS"); + if (!usp.empty()) { + cmSystemTools::ExpandListArgument(usp, uicSearchPaths); + std::string const srcDir = makefile->GetCurrentSourceDirectory(); + for (std::string& path : uicSearchPaths) { + path = cmSystemTools::CollapseFullPath(path, srcDir); + } + } + } + AddDefinitionEscaped(makefile, "_uic_search_paths", uicSearchPaths); + } + // Uic target options + { + auto UicGetOpts = [this](std::string const& cfg) -> std::string { + std::vector<std::string> opts; + this->Target->GetAutoUicOptions(opts, cfg); + return cmJoin(opts, ";"); + }; + + // Default settings + std::string const uicOpts = UicGetOpts(this->ConfigDefault); + AddDefinitionEscaped(makefile, "_uic_target_options", uicOpts); + + // Configuration specific settings + for (std::string const& cfg : this->ConfigsList) { + std::string const configUicOpts = UicGetOpts(cfg); + if (configUicOpts != uicOpts) { + this->ConfigUicOptions[cfg] = configUicOpts; + } + } + } + // .ui files skip and options + { + std::vector<std::string> uiFileFiles; + std::vector<std::vector<std::string>> uiFileOptions; + { + std::string const uiExt = "ui"; + for (cmSourceFile* sf : makefile->GetSourceFiles()) { + // sf->GetExtension() is only valid after sf->GetFullPath() ... + std::string const& fPath = sf->GetFullPath(); + if (sf->GetExtension() == uiExt) { + std::string const absFile = cmSystemTools::GetRealPath(fPath); + // Check if the .ui file should be skipped + if (sf->GetPropertyAsBool("SKIP_AUTOUIC") || + sf->GetPropertyAsBool("SKIP_AUTOGEN")) { + this->UicSkip.insert(absFile); + } + // Check if the .ui file has uic options + std::string const uicOpts = GetSafeProperty(sf, "AUTOUIC_OPTIONS"); + if (!uicOpts.empty()) { + // Check if file isn't skipped + if (this->UicSkip.count(absFile) == 0) { + uiFileFiles.push_back(absFile); + std::vector<std::string> optsVec; + cmSystemTools::ExpandListArgument(uicOpts, optsVec); + uiFileOptions.push_back(std::move(optsVec)); + } + } + } + } + } + AddDefinitionEscaped(makefile, "_qt_uic_options_files", uiFileFiles); + AddDefinitionEscaped(makefile, "_qt_uic_options_options", uiFileOptions); + } + + AddDefinitionEscaped(makefile, "_uic_skip", this->UicSkip); + + // Uic executable + { + std::string err; + std::string uicExec; + + cmLocalGenerator* localGen = this->Target->GetLocalGenerator(); + if (this->QtVersionMajor == "5") { + cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt5::uic"); + if (tgt != nullptr) { + uicExec = SafeString(tgt->ImportedGetLocation("")); + } else { + // Project does not use Qt5Widgets, but has AUTOUIC ON anyway + } + } else if (this->QtVersionMajor == "4") { + cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt4::uic"); + if (tgt != nullptr) { + uicExec = SafeString(tgt->ImportedGetLocation("")); + } else { + err = "AUTOUIC: Qt4::uic target not found"; + } + } else { + err = "The AUTOUIC feature supports only Qt 4 and Qt 5"; + } + + if (err.empty()) { + AddDefinitionEscaped(makefile, "_qt_uic_executable", uicExec); + } else { + err += " ("; + err += this->Target->GetName(); + err += ")"; + cmSystemTools::Error(err.c_str()); + } + } +} + +std::vector<std::string> cmQtAutoGeneratorInitializer::AddGeneratedSource( + std::string const& filename, cmQtAutoGen::Generator genType) +{ + std::vector<std::string> genFiles; + // Register source file in makefile and source group + if (this->MultiConfig != cmQtAutoGen::FULL) { + genFiles.push_back(filename); + } else { + for (std::string const& cfg : this->ConfigsList) { + genFiles.push_back( + cmQtAutoGen::AppendFilenameSuffix(filename, "_" + cfg)); + } + } + { + cmMakefile* makefile = this->Target->Target->GetMakefile(); + for (std::string const& genFile : genFiles) { + { + cmSourceFile* gFile = makefile->GetOrCreateSource(genFile, true); + gFile->SetProperty("GENERATED", "1"); + gFile->SetProperty("SKIP_AUTOGEN", "On"); + } + AddToSourceGroup(makefile, genFile, genType); + } + } + + // Add source file to target + if (this->MultiConfig != cmQtAutoGen::FULL) { + this->Target->AddSource(filename); + } else { + for (std::string const& cfg : this->ConfigsList) { + std::string src = "$<$<CONFIG:"; + src += cfg; + src += ">:"; + src += cmQtAutoGen::AppendFilenameSuffix(filename, "_" + cfg); + src += ">"; + this->Target->AddSource(src); + } + } + + return genFiles; +} + +std::string cmQtAutoGeneratorInitializer::GetQtMajorVersion( + cmGeneratorTarget const* target) +{ + cmMakefile* makefile = target->Target->GetMakefile(); + std::string qtMajor = makefile->GetSafeDefinition("QT_VERSION_MAJOR"); + if (qtMajor.empty()) { + qtMajor = makefile->GetSafeDefinition("Qt5Core_VERSION_MAJOR"); + } + const char* targetQtVersion = + target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION", ""); + if (targetQtVersion != nullptr) { + qtMajor = targetQtVersion; + } + return qtMajor; +} + +std::string cmQtAutoGeneratorInitializer::GetQtMinorVersion( + cmGeneratorTarget const* target, std::string const& qtVersionMajor) +{ + cmMakefile* makefile = target->Target->GetMakefile(); + std::string qtMinor; + if (qtVersionMajor == "5") { + qtMinor = makefile->GetSafeDefinition("Qt5Core_VERSION_MINOR"); + } + if (qtMinor.empty()) { + qtMinor = makefile->GetSafeDefinition("QT_VERSION_MINOR"); + } + + const char* targetQtVersion = + target->GetLinkInterfaceDependentStringProperty("QT_MINOR_VERSION", ""); + if (targetQtVersion != nullptr) { + qtMinor = targetQtVersion; + } + return qtMinor; +} + +bool cmQtAutoGeneratorInitializer::QtVersionGreaterOrEqual( + unsigned long requestMajor, unsigned long requestMinor) const +{ + unsigned long majorUL(0); + unsigned long minorUL(0); + if (cmSystemTools::StringToULong(this->QtVersionMajor.c_str(), &majorUL) && + cmSystemTools::StringToULong(this->QtVersionMinor.c_str(), &minorUL)) { + return (majorUL > requestMajor) || + (majorUL == requestMajor && minorUL >= requestMinor); + } + return false; +} diff --git a/Source/cmQtAutoGeneratorInitializer.h b/Source/cmQtAutoGeneratorInitializer.h index b8a5ae4..e06e1c4 100644 --- a/Source/cmQtAutoGeneratorInitializer.h +++ b/Source/cmQtAutoGeneratorInitializer.h @@ -4,9 +4,12 @@ #define cmQtAutoGeneratorInitializer_h #include "cmConfigure.h" // IWYU pragma: keep -#include "cmQtAutoGenDigest.h" +#include "cmQtAutoGen.h" +#include <map> +#include <set> #include <string> +#include <vector> class cmGeneratorTarget; @@ -17,8 +20,78 @@ public: static std::string GetQtMinorVersion(cmGeneratorTarget const* target, std::string const& qtVersionMajor); - static void InitializeAutogenTarget(cmQtAutoGenDigest& digest); - static void SetupAutoGenerateTarget(cmQtAutoGenDigest const& digest); + class Qrc + { + public: + Qrc() + : Generated(false) + , Unique(false) + { + } + + public: + std::string QrcFile; + std::string QrcName; + std::string PathChecksum; + std::string InfoFile; + std::string SettingsFile; + std::string RccFile; + bool Generated; + bool Unique; + std::vector<std::string> Options; + std::vector<std::string> Resources; + }; + +public: + cmQtAutoGeneratorInitializer(cmGeneratorTarget* target, bool mocEnabled, + bool uicEnabled, bool rccEnabled, + std::string const& qtVersionMajor); + + void InitCustomTargets(); + void SetupCustomTargets(); + +private: + void SetupCustomTargetsMoc(); + void SetupCustomTargetsUic(); + + std::vector<std::string> AddGeneratedSource(std::string const& filename, + cmQtAutoGen::Generator genType); + + bool QtVersionGreaterOrEqual(unsigned long requestMajor, + unsigned long requestMinor) const; + +private: + cmGeneratorTarget* Target; + bool MocEnabled; + bool UicEnabled; + bool RccEnabled; + // Qt + std::string QtVersionMajor; + std::string QtVersionMinor; + std::string RccExecutable; + std::vector<std::string> RccListOptions; + // Configurations + std::string ConfigDefault; + std::vector<std::string> ConfigsList; + cmQtAutoGen::MultiConfig MultiConfig; + // Names + std::string AutogenTargetName; + std::string AutogenFolder; + std::string AutogenInfoFile; + std::string AutogenSettingsFile; + // Directories + std::string DirInfo; + std::string DirBuild; + std::string DirWork; + // Sources + std::vector<std::string> Headers; + std::vector<std::string> Sources; + std::set<std::string> MocSkip; + std::set<std::string> UicSkip; + std::map<std::string, std::string> ConfigMocIncludes; + std::map<std::string, std::string> ConfigMocDefines; + std::map<std::string, std::string> ConfigUicOptions; + std::vector<Qrc> Qrcs; }; #endif diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGeneratorMocUic.cxx index b329d38..0de02b5 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGeneratorMocUic.cxx @@ -1,10 +1,8 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmQtAutoGen.h" -#include "cmQtAutoGenerators.h" +#include "cmQtAutoGeneratorMocUic.h" -#include "cmsys/FStream.hxx" -#include "cmsys/Terminal.h" #include <algorithm> #include <array> #include <list> @@ -15,12 +13,8 @@ #include "cmAlgorithms.h" #include "cmCryptoHash.h" -#include "cmFilePathChecksum.h" -#include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmOutputConverter.h" -#include "cmStateDirectory.h" -#include "cmStateSnapshot.h" #include "cmSystemTools.h" #include "cmake.h" @@ -32,37 +26,9 @@ static const char* SettingsKeyMoc = "AM_MOC_SETTINGS_HASH"; static const char* SettingsKeyUic = "AM_UIC_SETTINGS_HASH"; -static const char* SettingsKeyRcc = "AM_RCC_SETTINGS_HASH"; // -- Static functions -static std::string HeadLine(std::string const& title) -{ - std::string head = title; - head += '\n'; - head.append(head.size() - 1, '-'); - head += '\n'; - return head; -} - -static std::string QuotedCommand(std::vector<std::string> const& command) -{ - std::string res; - for (std::string const& item : command) { - if (!res.empty()) { - res.push_back(' '); - } - std::string const cesc = cmQtAutoGen::Quoted(item); - if (item.empty() || (cesc.size() > (item.size() + 2)) || - (cesc.find(' ') != std::string::npos)) { - res += cesc; - } else { - res += item; - } - } - return res; -} - static std::string SubDirPrefix(std::string const& fileName) { std::string res(cmSystemTools::GetFilenamePath(fileName)); @@ -72,56 +38,6 @@ static std::string SubDirPrefix(std::string const& fileName) return res; } -static bool ReadFile(std::string& content, std::string const& filename, - std::string* error = nullptr) -{ - bool success = false; - if (cmSystemTools::FileExists(filename)) { - std::size_t const length = cmSystemTools::FileLength(filename); - cmsys::ifstream ifs(filename.c_str(), (std::ios::in | std::ios::binary)); - if (ifs) { - content.resize(length); - ifs.read(&content.front(), content.size()); - if (ifs) { - success = true; - } else { - content.clear(); - if (error != nullptr) { - error->append("Reading from the file failed."); - } - } - } else if (error != nullptr) { - error->append("Opening the file for reading failed."); - } - } else if (error != nullptr) { - error->append("The file does not exist."); - } - return success; -} - -/** - * @brief Tests if buildFile is older than sourceFile - * @return True if buildFile is older than sourceFile. - * False may indicate an error. - */ -static bool FileIsOlderThan(std::string const& buildFile, - std::string const& sourceFile, - std::string* error = nullptr) -{ - int result = 0; - if (cmSystemTools::FileTimeCompare(buildFile, sourceFile, &result)) { - return (result < 0); - } - if (error != nullptr) { - error->append( - "File modification time comparison failed for the files\n "); - error->append(cmQtAutoGen::Quoted(buildFile)); - error->append("\nand\n "); - error->append(cmQtAutoGen::Quoted(sourceFile)); - } - return false; -} - static bool ListContains(std::vector<std::string> const& list, std::string const& entry) { @@ -130,25 +46,15 @@ static bool ListContains(std::vector<std::string> const& list, // -- Class methods -cmQtAutoGenerators::cmQtAutoGenerators() +cmQtAutoGeneratorMocUic::cmQtAutoGeneratorMocUic() : MultiConfig(cmQtAutoGen::WRAP) , IncludeProjectDirsBefore(false) - , Verbose(cmSystemTools::HasEnv("VERBOSE")) - , ColorOutput(true) + , QtVersionMajor(4) , MocSettingsChanged(false) , MocPredefsChanged(false) , MocRelaxedMode(false) , UicSettingsChanged(false) - , RccSettingsChanged(false) { - { - std::string colorEnv; - cmSystemTools::GetEnv("COLOR", colorEnv); - if (!colorEnv.empty()) { - this->ColorOutput = cmSystemTools::IsOn(colorEnv.c_str()); - } - } - // Precompile regular expressions this->MocRegExpInclude.compile( "[\n][ \t]*#[ \t]*include[ \t]+" @@ -157,39 +63,7 @@ cmQtAutoGenerators::cmQtAutoGenerators() "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]"); } -bool cmQtAutoGenerators::Run(std::string const& targetDirectory, - std::string const& config) -{ - cmake cm(cmake::RoleScript); - cm.SetHomeOutputDirectory(targetDirectory); - cm.SetHomeDirectory(targetDirectory); - cm.GetCurrentSnapshot().SetDefaultDefinitions(); - cmGlobalGenerator gg(&cm); - - cmStateSnapshot snapshot = cm.GetCurrentSnapshot(); - snapshot.GetDirectory().SetCurrentBinary(targetDirectory); - snapshot.GetDirectory().SetCurrentSource(targetDirectory); - - auto makefile = cm::make_unique<cmMakefile>(&gg, snapshot); - gg.SetCurrentMakefile(makefile.get()); - - bool success = false; - if (this->InitInfoFile(makefile.get(), targetDirectory, config)) { - // Read latest settings - this->SettingsFileRead(makefile.get()); - if (this->Process()) { - // Write current settings - if (this->SettingsFileWrite()) { - success = true; - } - } - } - return success; -} - -bool cmQtAutoGenerators::InitInfoFile(cmMakefile* makefile, - std::string const& targetDirectory, - std::string const& config) +bool cmQtAutoGeneratorMocUic::InitInfoFile(cmMakefile* makefile) { // -- Meta this->HeaderExtensions = makefile->GetCMakeInstance()->GetHeaderExtensions(); @@ -233,12 +107,12 @@ bool cmQtAutoGenerators::InitInfoFile(cmMakefile* makefile, } return lists; }; - auto InfoGetConfig = [makefile, &config](const char* key) -> std::string { + auto InfoGetConfig = [makefile, this](const char* key) -> std::string { const char* valueConf = nullptr; { std::string keyConf = key; keyConf += '_'; - keyConf += config; + keyConf += this->GetInfoConfig(); valueConf = makefile->GetDefinition(keyConf); } if (valueConf == nullptr) { @@ -254,11 +128,8 @@ bool cmQtAutoGenerators::InitInfoFile(cmMakefile* makefile, }; // -- Read info file - this->InfoFile = cmSystemTools::CollapseFullPath(targetDirectory); - cmSystemTools::ConvertToUnixSlashes(this->InfoFile); - this->InfoFile += "/AutogenInfo.cmake"; - if (!makefile->ReadListFile(this->InfoFile.c_str())) { - this->LogFileError(cmQtAutoGen::GEN, this->InfoFile, + if (!makefile->ReadListFile(this->GetInfoFile().c_str())) { + this->LogFileError(cmQtAutoGen::GEN, this->GetInfoFile(), "File processing failed"); return false; } @@ -268,7 +139,14 @@ bool cmQtAutoGenerators::InitInfoFile(cmMakefile* makefile, this->ConfigSuffix = InfoGetConfig("AM_CONFIG_SUFFIX"); if (this->ConfigSuffix.empty()) { this->ConfigSuffix = "_"; - this->ConfigSuffix += config; + this->ConfigSuffix += this->GetInfoConfig(); + } + + this->SettingsFile = InfoGetConfig("AM_SETTINGS_FILE"); + if (this->SettingsFile.empty()) { + this->LogFileError(cmQtAutoGen::GEN, this->GetInfoFile(), + "Settings file name missing"); + return false; } // - Files and directories @@ -280,25 +158,18 @@ bool cmQtAutoGenerators::InitInfoFile(cmMakefile* makefile, InfoGetBool("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE"); this->AutogenBuildDir = InfoGet("AM_BUILD_DIR"); if (this->AutogenBuildDir.empty()) { - this->LogFileError(cmQtAutoGen::GEN, this->InfoFile, + this->LogFileError(cmQtAutoGen::GEN, this->GetInfoFile(), "Autogen build directory missing"); return false; } // - Qt environment - this->QtMajorVersion = InfoGet("AM_QT_VERSION_MAJOR"); - this->QtMinorVersion = InfoGet("AM_QT_VERSION_MINOR"); + if (!cmSystemTools::StringToULong(InfoGet("AM_QT_VERSION_MAJOR"), + &this->QtVersionMajor)) { + this->QtVersionMajor = 4; + } this->MocExecutable = InfoGet("AM_QT_MOC_EXECUTABLE"); this->UicExecutable = InfoGet("AM_QT_UIC_EXECUTABLE"); - this->RccExecutable = InfoGet("AM_QT_RCC_EXECUTABLE"); - - // Check Qt version - if ((this->QtMajorVersion != "4") && (this->QtMajorVersion != "5")) { - this->LogFileError(cmQtAutoGen::GEN, this->InfoFile, - "Unsupported Qt version: " + - cmQtAutoGen::Quoted(this->QtMajorVersion)); - return false; - } // - Moc if (this->MocEnabled()) { @@ -327,7 +198,7 @@ bool cmQtAutoGenerators::InitInfoFile(cmMakefile* makefile, std::vector<std::string> const mocDependFilters = InfoGetList("AM_MOC_DEPEND_FILTERS"); // Insert Q_PLUGIN_METADATA dependency filter - if (this->QtMajorVersion != "4") { + if (this->QtVersionMajor != 4) { this->MocDependFilterPush("Q_PLUGIN_METADATA", "[\n][ \t]*Q_PLUGIN_METADATA[ \t]*\\(" "[^\\)]*FILE[ \t]*\"([^\"]+)\""); @@ -344,7 +215,7 @@ bool cmQtAutoGenerators::InitInfoFile(cmMakefile* makefile, } } else { this->LogFileError( - cmQtAutoGen::MOC, this->InfoFile, + cmQtAutoGen::MOC, this->GetInfoFile(), "AUTOMOC_DEPEND_FILTERS list size is not a multiple of 2"); return false; } @@ -365,7 +236,7 @@ bool cmQtAutoGenerators::InitInfoFile(cmMakefile* makefile, std::ostringstream ost; ost << "files/options lists sizes missmatch (" << sources.size() << "/" << options.size() << ")"; - this->LogFileError(cmQtAutoGen::UIC, this->InfoFile, ost.str()); + this->LogFileError(cmQtAutoGen::UIC, this->GetInfoFile(), ost.str()); return false; } auto fitEnd = sources.cend(); @@ -379,53 +250,6 @@ bool cmQtAutoGenerators::InitInfoFile(cmMakefile* makefile, } } - // - Rcc - if (this->RccEnabled()) { - // File lists - auto sources = InfoGetList("AM_RCC_SOURCES"); - auto builds = InfoGetList("AM_RCC_BUILDS"); - auto options = InfoGetLists("AM_RCC_OPTIONS"); - auto inputs = InfoGetLists("AM_RCC_INPUTS"); - - if (sources.size() != builds.size()) { - std::ostringstream ost; - ost << "sources, builds lists sizes missmatch (" << sources.size() << "/" - << builds.size() << ")"; - this->LogFileError(cmQtAutoGen::RCC, this->InfoFile, ost.str()); - return false; - } - if (sources.size() != options.size()) { - std::ostringstream ost; - ost << "sources, options lists sizes missmatch (" << sources.size() - << "/" << options.size() << ")"; - this->LogFileError(cmQtAutoGen::RCC, this->InfoFile, ost.str()); - return false; - } - if (sources.size() != inputs.size()) { - std::ostringstream ost; - ost << "sources, inputs lists sizes missmatch (" << sources.size() << "/" - << inputs.size() << ")"; - this->LogFileError(cmQtAutoGen::RCC, this->InfoFile, ost.str()); - return false; - } - { - auto srcItEnd = sources.end(); - auto srcIt = sources.begin(); - auto bldIt = builds.begin(); - auto optIt = options.begin(); - auto inpIt = inputs.begin(); - while (srcIt != srcItEnd) { - this->RccJobs.push_back(RccJob{ std::move(*srcIt), std::move(*bldIt), - std::move(*optIt), - std::move(*inpIt) }); - ++srcIt; - ++bldIt; - ++optIt; - ++inpIt; - } - } - } - // Initialize source file jobs { // Utility lambdas @@ -585,21 +409,10 @@ bool cmQtAutoGenerators::InitInfoFile(cmMakefile* makefile, } } - // - Old settings file - { - this->SettingsFile = cmSystemTools::CollapseFullPath(targetDirectory); - cmSystemTools::ConvertToUnixSlashes(this->SettingsFile); - this->SettingsFile += "/AutogenOldSettings"; - if (this->MultiConfig != cmQtAutoGen::SINGLE) { - this->SettingsFile += this->ConfigSuffix; - } - this->SettingsFile += ".cmake"; - } - return true; } -void cmQtAutoGenerators::SettingsFileRead(cmMakefile* makefile) +void cmQtAutoGeneratorMocUic::SettingsFileRead(cmMakefile* makefile) { // Compose current settings strings { @@ -631,20 +444,6 @@ void cmQtAutoGenerators::SettingsFileRead(cmMakefile* makefile) str += sep; this->SettingsStringUic = crypt.HashString(str); } - if (this->RccEnabled()) { - std::string str; - str += this->RccExecutable; - for (const RccJob& rccJob : this->RccJobs) { - str += sep; - str += rccJob.QrcFile; - str += sep; - str += rccJob.RccFile; - str += sep; - str += cmJoin(rccJob.Options, ";"); - } - str += sep; - this->SettingsStringRcc = crypt.HashString(str); - } } // Read old settings @@ -659,9 +458,6 @@ void cmQtAutoGenerators::SettingsFileRead(cmMakefile* makefile) if (!SMatch(SettingsKeyUic, this->SettingsStringUic)) { this->UicSettingsChanged = true; } - if (!SMatch(SettingsKeyRcc, this->SettingsStringRcc)) { - this->RccSettingsChanged = true; - } } // In case any setting changed remove the old settings file. // This triggers a full rebuild on the next run if the current @@ -673,16 +469,15 @@ void cmQtAutoGenerators::SettingsFileRead(cmMakefile* makefile) // If the file could not be read re-generate everythiung. this->MocSettingsChanged = true; this->UicSettingsChanged = true; - this->RccSettingsChanged = true; } } -bool cmQtAutoGenerators::SettingsFileWrite() +bool cmQtAutoGeneratorMocUic::SettingsFileWrite() { bool success = true; // Only write if any setting changed if (this->SettingsChanged()) { - if (this->Verbose) { + if (this->GetVerbose()) { this->LogInfo(cmQtAutoGen::GEN, "Writing settings file " + cmQtAutoGen::Quoted(this->SettingsFile)); } @@ -699,7 +494,6 @@ bool cmQtAutoGenerators::SettingsFileWrite() }; SettingAppend(SettingsKeyMoc, this->SettingsStringMoc); SettingAppend(SettingsKeyUic, this->SettingsStringUic); - SettingAppend(SettingsKeyRcc, this->SettingsStringRcc); } // Write settings file if (!this->FileWrite(cmQtAutoGen::GEN, this->SettingsFile, settings)) { @@ -713,7 +507,7 @@ bool cmQtAutoGenerators::SettingsFileWrite() return success; } -bool cmQtAutoGenerators::Process() +bool cmQtAutoGeneratorMocUic::Process(cmMakefile* makefile) { // the program goes through all .cpp files to see which moc files are // included. It is not really interesting how the moc file is named, but @@ -723,6 +517,12 @@ bool cmQtAutoGenerators::Process() // moc file is included anywhere a moc_<filename>.cpp file is created and // included in the mocs_compilation.cpp file. + if (!this->InitInfoFile(makefile)) { + return false; + } + // Read latest settings + this->SettingsFileRead(makefile); + // Create AUTOGEN include directory { std::string const incDirAbs = cmSystemTools::CollapseCombinedPath( @@ -758,7 +558,8 @@ bool cmQtAutoGenerators::Process() if (!this->UicGenerateAll()) { return false; } - if (!this->RccGenerateAll()) { + + if (!this->SettingsFileWrite()) { return false; } @@ -768,12 +569,12 @@ bool cmQtAutoGenerators::Process() /** * @return True on success */ -bool cmQtAutoGenerators::ParseSourceFile(std::string const& absFilename, - const SourceJob& job) +bool cmQtAutoGeneratorMocUic::ParseSourceFile(std::string const& absFilename, + const SourceJob& job) { std::string contentText; std::string error; - bool success = ReadFile(contentText, absFilename, &error); + bool success = this->FileRead(contentText, absFilename, &error); if (success) { if (!contentText.empty()) { if (job.Moc) { @@ -796,12 +597,12 @@ bool cmQtAutoGenerators::ParseSourceFile(std::string const& absFilename, /** * @return True on success */ -bool cmQtAutoGenerators::ParseHeaderFile(std::string const& absFilename, - const SourceJob& job) +bool cmQtAutoGeneratorMocUic::ParseHeaderFile(std::string const& absFilename, + const SourceJob& job) { std::string contentText; std::string error; - bool success = ReadFile(contentText, absFilename, &error); + bool success = this->FileRead(contentText, absFilename, &error); if (success) { if (!contentText.empty()) { if (job.Moc) { @@ -824,15 +625,15 @@ bool cmQtAutoGenerators::ParseHeaderFile(std::string const& absFilename, /** * @return True on success */ -bool cmQtAutoGenerators::ParsePostprocess() +bool cmQtAutoGeneratorMocUic::ParsePostprocess() { bool success = true; - // Read missin dependecies + // Read missing dependencies for (auto& item : this->MocJobsIncluded) { if (!item->DependsValid) { std::string content; std::string error; - if (ReadFile(content, item->SourceFile, &error)) { + if (this->FileRead(content, item->SourceFile, &error)) { this->MocFindDepends(item->SourceFile, content, item->Depends); item->DependsValid = true; } else { @@ -855,7 +656,7 @@ bool cmQtAutoGenerators::ParsePostprocess() * @brief Tests if the file should be ignored for moc scanning * @return True if the file should be ignored */ -bool cmQtAutoGenerators::MocSkip(std::string const& absFilename) const +bool cmQtAutoGeneratorMocUic::MocSkip(std::string const& absFilename) const { if (this->MocEnabled()) { // Test if the file name is on the skip list @@ -870,8 +671,8 @@ bool cmQtAutoGenerators::MocSkip(std::string const& absFilename) const * @brief Tests if the C++ content requires moc processing * @return True if moc is required */ -bool cmQtAutoGenerators::MocRequired(std::string const& contentText, - std::string* macroName) +bool cmQtAutoGeneratorMocUic::MocRequired(std::string const& contentText, + std::string* macroName) { for (KeyRegExp& filter : this->MocMacroFilters) { // Run a simple find string operation before the expensive @@ -889,7 +690,7 @@ bool cmQtAutoGenerators::MocRequired(std::string const& contentText, return false; } -std::string cmQtAutoGenerators::MocStringMacros() const +std::string cmQtAutoGeneratorMocUic::MocStringMacros() const { std::string res; const auto itB = this->MocMacroFilters.cbegin(); @@ -911,7 +712,7 @@ std::string cmQtAutoGenerators::MocStringMacros() const return res; } -std::string cmQtAutoGenerators::MocStringHeaders( +std::string cmQtAutoGeneratorMocUic::MocStringHeaders( std::string const& fileBase) const { std::string res = fileBase; @@ -921,7 +722,7 @@ std::string cmQtAutoGenerators::MocStringHeaders( return res; } -std::string cmQtAutoGenerators::MocFindIncludedHeader( +std::string cmQtAutoGeneratorMocUic::MocFindIncludedHeader( std::string const& sourcePath, std::string const& includeBase) const { std::string header; @@ -944,7 +745,7 @@ std::string cmQtAutoGenerators::MocFindIncludedHeader( return header; } -bool cmQtAutoGenerators::MocFindIncludedFile( +bool cmQtAutoGeneratorMocUic::MocFindIncludedFile( std::string& absFile, std::string const& sourcePath, std::string const& includeString) const { @@ -974,8 +775,8 @@ bool cmQtAutoGenerators::MocFindIncludedFile( return success; } -bool cmQtAutoGenerators::MocDependFilterPush(std::string const& key, - std::string const& regExp) +bool cmQtAutoGeneratorMocUic::MocDependFilterPush(std::string const& key, + std::string const& regExp) { std::string error; if (!key.empty()) { @@ -1009,9 +810,9 @@ bool cmQtAutoGenerators::MocDependFilterPush(std::string const& key, return true; } -void cmQtAutoGenerators::MocFindDepends(std::string const& absFilename, - std::string const& contentText, - std::set<std::string>& depends) +void cmQtAutoGeneratorMocUic::MocFindDepends(std::string const& absFilename, + std::string const& contentText, + std::set<std::string>& depends) { if (this->MocDependFilters.empty() && contentText.empty()) { return; @@ -1040,7 +841,7 @@ void cmQtAutoGenerators::MocFindDepends(std::string const& absFilename, std::string incFile; if (this->MocFindIncludedFile(incFile, sourcePath, match)) { depends.insert(incFile); - if (this->Verbose) { + if (this->GetVerbose()) { this->LogInfo(cmQtAutoGen::MOC, "Found dependency:\n " + cmQtAutoGen::Quoted(absFilename) + "\n " + cmQtAutoGen::Quoted(incFile)); @@ -1057,10 +858,10 @@ void cmQtAutoGenerators::MocFindDepends(std::string const& absFilename, /** * @return True on success */ -bool cmQtAutoGenerators::MocParseSourceContent(std::string const& absFilename, - std::string const& contentText) +bool cmQtAutoGeneratorMocUic::MocParseSourceContent( + std::string const& absFilename, std::string const& contentText) { - if (this->Verbose) { + if (this->GetVerbose()) { this->LogInfo(cmQtAutoGen::MOC, "Checking: " + absFilename); } @@ -1296,10 +1097,10 @@ bool cmQtAutoGenerators::MocParseSourceContent(std::string const& absFilename, return true; } -void cmQtAutoGenerators::MocParseHeaderContent(std::string const& absFilename, - std::string const& contentText) +void cmQtAutoGeneratorMocUic::MocParseHeaderContent( + std::string const& absFilename, std::string const& contentText) { - if (this->Verbose) { + if (this->GetVerbose()) { this->LogInfo(cmQtAutoGen::MOC, "Checking: " + absFilename); } @@ -1329,7 +1130,7 @@ void cmQtAutoGenerators::MocParseHeaderContent(std::string const& absFilename, } } -bool cmQtAutoGenerators::MocGenerateAll() +bool cmQtAutoGeneratorMocUic::MocGenerateAll() { if (!this->MocEnabled()) { return true; @@ -1384,7 +1185,7 @@ bool cmQtAutoGenerators::MocGenerateAll() if (!this->MocPredefsCmd.empty()) { if (this->MocSettingsChanged || !cmSystemTools::FileExists(this->MocPredefsFileAbs)) { - if (this->Verbose) { + if (this->GetVerbose()) { this->LogBold("Generating MOC predefs " + this->MocPredefsFileRel); } @@ -1419,7 +1220,7 @@ bool cmQtAutoGenerators::MocGenerateAll() } } else { // Touch to update the time stamp - if (this->Verbose) { + if (this->GetVerbose()) { this->LogInfo(cmQtAutoGen::MOC, "Touching moc_predefs " + this->MocPredefsFileRel); } @@ -1427,7 +1228,7 @@ bool cmQtAutoGenerators::MocGenerateAll() } } - // Add moc_predefs.h to moc file dependecies + // Add moc_predefs.h to moc file dependencies for (auto const& item : this->MocJobsIncluded) { item->Depends.insert(this->MocPredefsFileAbs); } @@ -1470,7 +1271,7 @@ bool cmQtAutoGenerators::MocGenerateAll() if (this->FileDiffers(this->MocCompFileAbs, mocs)) { // Actually write mocs compilation file - if (this->Verbose) { + if (this->GetVerbose()) { this->LogBold("Generating MOC compilation " + this->MocCompFileRel); } if (!this->FileWrite(cmQtAutoGen::MOC, this->MocCompFileAbs, mocs)) { @@ -1480,7 +1281,7 @@ bool cmQtAutoGenerators::MocGenerateAll() } } else if (autoNameGenerated) { // Only touch mocs compilation file - if (this->Verbose) { + if (this->GetVerbose()) { this->LogInfo(cmQtAutoGen::MOC, "Touching mocs compilation " + this->MocCompFileRel); } @@ -1494,8 +1295,8 @@ bool cmQtAutoGenerators::MocGenerateAll() /** * @return True on success */ -bool cmQtAutoGenerators::MocGenerateFile(const MocJobAuto& mocJob, - bool* generated) +bool cmQtAutoGeneratorMocUic::MocGenerateFile(const MocJobAuto& mocJob, + bool* generated) { bool success = true; @@ -1505,7 +1306,7 @@ bool cmQtAutoGenerators::MocGenerateFile(const MocJobAuto& mocJob, bool generate = false; std::string generateReason; if (!generate && !cmSystemTools::FileExists(mocFileAbs.c_str())) { - if (this->Verbose) { + if (this->GetVerbose()) { generateReason = "Generating "; generateReason += cmQtAutoGen::Quoted(mocFileAbs); generateReason += " from its source file "; @@ -1515,7 +1316,7 @@ bool cmQtAutoGenerators::MocGenerateFile(const MocJobAuto& mocJob, generate = true; } if (!generate && this->MocSettingsChanged) { - if (this->Verbose) { + if (this->GetVerbose()) { generateReason = "Generating "; generateReason += cmQtAutoGen::Quoted(mocFileAbs); generateReason += " from "; @@ -1525,7 +1326,7 @@ bool cmQtAutoGenerators::MocGenerateFile(const MocJobAuto& mocJob, generate = true; } if (!generate && this->MocPredefsChanged) { - if (this->Verbose) { + if (this->GetVerbose()) { generateReason = "Generating "; generateReason += cmQtAutoGen::Quoted(mocFileAbs); generateReason += " from "; @@ -1537,7 +1338,7 @@ bool cmQtAutoGenerators::MocGenerateFile(const MocJobAuto& mocJob, if (!generate) { std::string error; if (FileIsOlderThan(mocFileAbs, mocJob.SourceFile, &error)) { - if (this->Verbose) { + if (this->GetVerbose()) { generateReason = "Generating "; generateReason += cmQtAutoGen::Quoted(mocFileAbs); generateReason += " because it's older than its source file "; @@ -1556,7 +1357,7 @@ bool cmQtAutoGenerators::MocGenerateFile(const MocJobAuto& mocJob, std::string error; for (std::string const& depFile : mocJob.Depends) { if (FileIsOlderThan(mocFileAbs, depFile, &error)) { - if (this->Verbose) { + if (this->GetVerbose()) { generateReason = "Generating "; generateReason += cmQtAutoGen::Quoted(mocFileAbs); generateReason += " from "; @@ -1577,7 +1378,7 @@ bool cmQtAutoGenerators::MocGenerateFile(const MocJobAuto& mocJob, if (generate) { // Log - if (this->Verbose) { + if (this->GetVerbose()) { this->LogBold("Generating MOC source " + mocJob.BuildFileRel); this->LogInfo(cmQtAutoGen::MOC, generateReason); } @@ -1627,7 +1428,7 @@ bool cmQtAutoGenerators::MocGenerateFile(const MocJobAuto& mocJob, /** * @brief Tests if the file name is in the skip list */ -bool cmQtAutoGenerators::UicSkip(std::string const& absFilename) const +bool cmQtAutoGeneratorMocUic::UicSkip(std::string const& absFilename) const { if (this->UicEnabled()) { // Test if the file name is on the skip list @@ -1638,10 +1439,10 @@ bool cmQtAutoGenerators::UicSkip(std::string const& absFilename) const return true; } -bool cmQtAutoGenerators::UicParseContent(std::string const& absFilename, - std::string const& contentText) +bool cmQtAutoGeneratorMocUic::UicParseContent(std::string const& absFilename, + std::string const& contentText) { - if (this->Verbose) { + if (this->GetVerbose()) { this->LogInfo(cmQtAutoGen::UIC, "Checking: " + absFilename); } @@ -1689,9 +1490,9 @@ bool cmQtAutoGenerators::UicParseContent(std::string const& absFilename, return true; } -bool cmQtAutoGenerators::UicFindIncludedFile(std::string& absFile, - std::string const& sourceFile, - std::string const& includeString) +bool cmQtAutoGeneratorMocUic::UicFindIncludedFile( + std::string& absFile, std::string const& sourceFile, + std::string const& includeString) { bool success = false; std::string searchFile = @@ -1753,7 +1554,7 @@ bool cmQtAutoGenerators::UicFindIncludedFile(std::string& absFile, return success; } -bool cmQtAutoGenerators::UicGenerateAll() +bool cmQtAutoGeneratorMocUic::UicGenerateAll() { if (!this->UicEnabled()) { return true; @@ -1817,7 +1618,7 @@ bool cmQtAutoGenerators::UicGenerateAll() /** * @return True on success */ -bool cmQtAutoGenerators::UicGenerateFile(const UicJob& uicJob) +bool cmQtAutoGeneratorMocUic::UicGenerateFile(const UicJob& uicJob) { bool success = true; @@ -1827,7 +1628,7 @@ bool cmQtAutoGenerators::UicGenerateFile(const UicJob& uicJob) bool generate = false; std::string generateReason; if (!generate && !cmSystemTools::FileExists(uicFileAbs.c_str())) { - if (this->Verbose) { + if (this->GetVerbose()) { generateReason = "Generating "; generateReason += cmQtAutoGen::Quoted(uicFileAbs); generateReason += " from its source file "; @@ -1837,7 +1638,7 @@ bool cmQtAutoGenerators::UicGenerateFile(const UicJob& uicJob) generate = true; } if (!generate && this->UicSettingsChanged) { - if (this->Verbose) { + if (this->GetVerbose()) { generateReason = "Generating "; generateReason += cmQtAutoGen::Quoted(uicFileAbs); generateReason += " from "; @@ -1849,7 +1650,7 @@ bool cmQtAutoGenerators::UicGenerateFile(const UicJob& uicJob) if (!generate) { std::string error; if (FileIsOlderThan(uicFileAbs, uicJob.SourceFile, &error)) { - if (this->Verbose) { + if (this->GetVerbose()) { generateReason = "Generating "; generateReason += cmQtAutoGen::Quoted(uicFileAbs); generateReason += " because it's older than its source file "; @@ -1865,7 +1666,7 @@ bool cmQtAutoGenerators::UicGenerateFile(const UicJob& uicJob) } if (generate) { // Log - if (this->Verbose) { + if (this->GetVerbose()) { this->LogBold("Generating UIC header " + uicJob.BuildFileRel); this->LogInfo(cmQtAutoGen::UIC, generateReason); } @@ -1880,7 +1681,7 @@ bool cmQtAutoGenerators::UicGenerateFile(const UicJob& uicJob) auto optionIt = this->UicOptions.find(uicJob.SourceFile); if (optionIt != this->UicOptions.end()) { cmQtAutoGen::UicMergeOptions(allOpts, optionIt->second, - (this->QtMajorVersion == "5")); + (this->QtVersionMajor == 5)); } cmd.insert(cmd.end(), allOpts.begin(), allOpts.end()); } @@ -1911,413 +1712,13 @@ bool cmQtAutoGenerators::UicGenerateFile(const UicJob& uicJob) return success; } -bool cmQtAutoGenerators::RccGenerateAll() -{ - if (!this->RccEnabled()) { - return true; - } - - // Generate rcc files - for (const RccJob& rccJob : this->RccJobs) { - if (!this->RccGenerateFile(rccJob)) { - return false; - } - } - return true; -} - -/** - * @return True on success - */ -bool cmQtAutoGenerators::RccGenerateFile(const RccJob& rccJob) -{ - bool success = true; - bool rccGenerated = false; - - std::string rccFileAbs; - { - std::string suffix; - switch (this->MultiConfig) { - case cmQtAutoGen::SINGLE: - break; - case cmQtAutoGen::WRAP: - suffix = "_CMAKE"; - suffix += this->ConfigSuffix; - suffix += "_"; - break; - case cmQtAutoGen::FULL: - suffix = this->ConfigSuffix; - break; - } - rccFileAbs = cmQtAutoGen::AppendFilenameSuffix(rccJob.RccFile, suffix); - } - std::string const rccFileRel = cmSystemTools::RelativePath( - this->AutogenBuildDir.c_str(), rccFileAbs.c_str()); - - // Check if regeneration is required - bool generate = false; - std::string generateReason; - if (!cmSystemTools::FileExists(rccJob.QrcFile)) { - { - std::string error = "Could not find the file\n "; - error += cmQtAutoGen::Quoted(rccJob.QrcFile); - this->LogError(cmQtAutoGen::RCC, error); - } - success = false; - } - if (success && !generate && !cmSystemTools::FileExists(rccFileAbs.c_str())) { - if (this->Verbose) { - generateReason = "Generating "; - generateReason += cmQtAutoGen::Quoted(rccFileAbs); - generateReason += " from its source file "; - generateReason += cmQtAutoGen::Quoted(rccJob.QrcFile); - generateReason += " because it doesn't exist"; - } - generate = true; - } - if (success && !generate && this->RccSettingsChanged) { - if (this->Verbose) { - generateReason = "Generating "; - generateReason += cmQtAutoGen::Quoted(rccFileAbs); - generateReason += " from "; - generateReason += cmQtAutoGen::Quoted(rccJob.QrcFile); - generateReason += " because the RCC settings changed"; - } - generate = true; - } - if (success && !generate) { - std::string error; - if (FileIsOlderThan(rccFileAbs, rccJob.QrcFile, &error)) { - if (this->Verbose) { - generateReason = "Generating "; - generateReason += cmQtAutoGen::Quoted(rccFileAbs); - generateReason += " because it is older than "; - generateReason += cmQtAutoGen::Quoted(rccJob.QrcFile); - } - generate = true; - } else { - if (!error.empty()) { - this->LogError(cmQtAutoGen::RCC, error); - success = false; - } - } - } - if (success && !generate) { - // Acquire input file list - std::vector<std::string> readFiles; - std::vector<std::string> const* files = nullptr; - if (!rccJob.Inputs.empty()) { - files = &rccJob.Inputs; - } else { - // Read input file list from qrc file - std::string error; - if (cmQtAutoGen::RccListInputs(this->QtMajorVersion, this->RccExecutable, - rccJob.QrcFile, readFiles, &error)) { - files = &readFiles; - } else { - this->LogFileError(cmQtAutoGen::RCC, rccJob.QrcFile, error); - success = false; - } - } - // Test if any input file is newer than the build file - if (files != nullptr) { - std::string error; - for (std::string const& resFile : *files) { - if (!cmSystemTools::FileExists(resFile.c_str())) { - error = "Could not find the file\n "; - error += cmQtAutoGen::Quoted(resFile); - error += "\nwhich is listed in\n "; - error += cmQtAutoGen::Quoted(rccJob.QrcFile); - break; - } - if (FileIsOlderThan(rccFileAbs, resFile, &error)) { - if (this->Verbose) { - generateReason = "Generating "; - generateReason += cmQtAutoGen::Quoted(rccFileAbs); - generateReason += " from "; - generateReason += cmQtAutoGen::Quoted(rccJob.QrcFile); - generateReason += " because it is older than "; - generateReason += cmQtAutoGen::Quoted(resFile); - } - generate = true; - break; - } - if (!error.empty()) { - break; - } - } - // Print error - if (!error.empty()) { - this->LogError(cmQtAutoGen::RCC, error); - success = false; - } - } - } - // Regenerate on demand - if (generate) { - // Log - if (this->Verbose) { - this->LogBold("Generating RCC source " + rccFileRel); - this->LogInfo(cmQtAutoGen::RCC, generateReason); - } - - // Make sure the parent directory exists - if (this->MakeParentDirectory(cmQtAutoGen::RCC, rccFileAbs)) { - // Compose rcc command - std::vector<std::string> cmd; - cmd.push_back(this->RccExecutable); - cmd.insert(cmd.end(), rccJob.Options.begin(), rccJob.Options.end()); - cmd.push_back("-o"); - cmd.push_back(rccFileAbs); - cmd.push_back(rccJob.QrcFile); - - std::string output; - if (this->RunCommand(cmd, output)) { - // Success - rccGenerated = true; - } else { - { - std::string emsg = "rcc failed for\n "; - emsg += cmQtAutoGen::Quoted(rccJob.QrcFile); - this->LogCommandError(cmQtAutoGen::RCC, emsg, cmd, output); - } - cmSystemTools::RemoveFile(rccFileAbs); - success = false; - } - } else { - // Parent directory creation failed - success = false; - } - } - - // Generate a wrapper source file on demand - if (success && (this->MultiConfig == cmQtAutoGen::WRAP)) { - // Wrapper file name - std::string const& wrapperFileAbs = rccJob.RccFile; - std::string const wrapperFileRel = cmSystemTools::RelativePath( - this->AutogenBuildDir.c_str(), wrapperFileAbs.c_str()); - // Wrapper file content - std::string content = "// This is an autogenerated configuration " - "wrapper file. Changes will be overwritten.\n" - "#include \""; - content += cmSystemTools::GetFilenameName(rccFileRel); - content += "\"\n"; - // Write content to file - if (this->FileDiffers(wrapperFileAbs, content)) { - // Write new wrapper file - if (this->Verbose) { - this->LogBold("Generating RCC wrapper " + wrapperFileRel); - } - if (!this->FileWrite(cmQtAutoGen::RCC, wrapperFileAbs, content)) { - this->LogFileError(cmQtAutoGen::RCC, wrapperFileAbs, - "rcc wrapper file writing failed"); - success = false; - } - } else if (rccGenerated) { - // Just touch the wrapper file - if (this->Verbose) { - this->LogInfo(cmQtAutoGen::RCC, - "Touching RCC wrapper " + wrapperFileRel); - } - cmSystemTools::Touch(wrapperFileAbs, false); - } - } - - return success; -} - -void cmQtAutoGenerators::LogBold(std::string const& message) const -{ - cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue | - cmsysTerminal_Color_ForegroundBold, - message.c_str(), true, this->ColorOutput); -} - -void cmQtAutoGenerators::LogInfo(cmQtAutoGen::Generator genType, - std::string const& message) const -{ - std::string msg = cmQtAutoGen::GeneratorName(genType); - msg += ": "; - msg += message; - if (msg.back() != '\n') { - msg.push_back('\n'); - } - cmSystemTools::Stdout(msg.c_str(), msg.size()); -} - -void cmQtAutoGenerators::LogWarning(cmQtAutoGen::Generator genType, - std::string const& message) const -{ - std::string msg = cmQtAutoGen::GeneratorName(genType); - msg += " warning:"; - if (message.find('\n') == std::string::npos) { - // Single line message - msg.push_back(' '); - } else { - // Multi line message - msg.push_back('\n'); - } - // Message - msg += message; - if (msg.back() != '\n') { - msg.push_back('\n'); - } - msg.push_back('\n'); - cmSystemTools::Stdout(msg.c_str(), msg.size()); -} - -void cmQtAutoGenerators::LogFileWarning(cmQtAutoGen::Generator genType, - std::string const& filename, - std::string const& message) const -{ - std::string msg = " "; - msg += cmQtAutoGen::Quoted(filename); - msg.push_back('\n'); - // Message - msg += message; - this->LogWarning(genType, msg); -} - -void cmQtAutoGenerators::LogError(cmQtAutoGen::Generator genType, - std::string const& message) const -{ - std::string msg; - msg.push_back('\n'); - msg += HeadLine(cmQtAutoGen::GeneratorName(genType) + " error"); - // Message - msg += message; - if (msg.back() != '\n') { - msg.push_back('\n'); - } - msg.push_back('\n'); - cmSystemTools::Stderr(msg.c_str(), msg.size()); -} - -void cmQtAutoGenerators::LogFileError(cmQtAutoGen::Generator genType, - std::string const& filename, - std::string const& message) const -{ - std::string emsg = " "; - emsg += cmQtAutoGen::Quoted(filename); - emsg += '\n'; - // Message - emsg += message; - this->LogError(genType, emsg); -} - -void cmQtAutoGenerators::LogCommandError( - cmQtAutoGen::Generator genType, std::string const& message, - std::vector<std::string> const& command, std::string const& output) const -{ - std::string msg; - msg.push_back('\n'); - msg += HeadLine(cmQtAutoGen::GeneratorName(genType) + " subprocess error"); - msg += message; - if (msg.back() != '\n') { - msg.push_back('\n'); - } - msg.push_back('\n'); - msg += HeadLine("Command"); - msg += QuotedCommand(command); - if (msg.back() != '\n') { - msg.push_back('\n'); - } - msg.push_back('\n'); - msg += HeadLine("Output"); - msg += output; - if (msg.back() != '\n') { - msg.push_back('\n'); - } - msg.push_back('\n'); - cmSystemTools::Stderr(msg.c_str(), msg.size()); -} - -/** - * @brief Generates the parent directory of the given file on demand - * @return True on success - */ -bool cmQtAutoGenerators::MakeParentDirectory(cmQtAutoGen::Generator genType, - std::string const& filename) const -{ - bool success = true; - std::string const dirName = cmSystemTools::GetFilenamePath(filename); - if (!dirName.empty()) { - if (!cmSystemTools::MakeDirectory(dirName)) { - this->LogFileError(genType, filename, - "Could not create parent directory"); - success = false; - } - } - return success; -} - -bool cmQtAutoGenerators::FileDiffers(std::string const& filename, - std::string const& content) -{ - bool differs = true; - { - std::string oldContents; - if (ReadFile(oldContents, filename)) { - differs = (oldContents != content); - } - } - return differs; -} - -bool cmQtAutoGenerators::FileWrite(cmQtAutoGen::Generator genType, - std::string const& filename, - std::string const& content) -{ - std::string error; - // Make sure the parent directory exists - if (this->MakeParentDirectory(genType, filename)) { - cmsys::ofstream outfile; - outfile.open(filename.c_str(), - (std::ios::out | std::ios::binary | std::ios::trunc)); - if (outfile) { - outfile << content; - // Check for write errors - if (!outfile.good()) { - error = "File writing failed"; - } - } else { - error = "Opening file for writing failed"; - } - } - if (!error.empty()) { - this->LogFileError(genType, filename, error); - return false; - } - return true; -} - -/** - * @brief Runs a command and returns true on success - * @return True on success - */ -bool cmQtAutoGenerators::RunCommand(std::vector<std::string> const& command, - std::string& output) const -{ - // Log command - if (this->Verbose) { - std::string qcmd = QuotedCommand(command); - qcmd.push_back('\n'); - cmSystemTools::Stdout(qcmd.c_str(), qcmd.size()); - } - // Execute command - int retVal = 0; - bool res = cmSystemTools::RunSingleCommand( - command, &output, &output, &retVal, nullptr, cmSystemTools::OUTPUT_NONE); - return (res && (retVal == 0)); -} - /** * @brief Tries to find the header file to the given file base path by * appending different header extensions * @return True on success */ -bool cmQtAutoGenerators::FindHeader(std::string& header, - std::string const& testBasePath) const +bool cmQtAutoGeneratorMocUic::FindHeader(std::string& header, + std::string const& testBasePath) const { for (std::string const& ext : this->HeaderExtensions) { std::string testFilePath(testBasePath); diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGeneratorMocUic.h index a7bb538..d510939 100644 --- a/Source/cmQtAutoGenerators.h +++ b/Source/cmQtAutoGeneratorMocUic.h @@ -1,12 +1,13 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ -#ifndef cmQtAutoGenerators_h -#define cmQtAutoGenerators_h +#ifndef cmQtAutoGeneratorMocUic_h +#define cmQtAutoGeneratorMocUic_h #include "cmConfigure.h" // IWYU pragma: keep #include "cmFilePathChecksum.h" #include "cmQtAutoGen.h" +#include "cmQtAutoGenerator.h" #include "cmsys/RegularExpression.hxx" #include <map> @@ -17,12 +18,11 @@ class cmMakefile; -class cmQtAutoGenerators +class cmQtAutoGeneratorMocUic : public cmQtAutoGenerator { - CM_DISABLE_COPY(cmQtAutoGenerators) + CM_DISABLE_COPY(cmQtAutoGeneratorMocUic) public: - cmQtAutoGenerators(); - bool Run(std::string const& targetDirectory, std::string const& config); + cmQtAutoGeneratorMocUic(); private: // -- Types @@ -80,30 +80,19 @@ private: std::string IncludeString; }; - /// @brief RCC job - struct RccJob - { - std::string QrcFile; - std::string RccFile; - std::vector<std::string> Options; - std::vector<std::string> Inputs; - }; - // -- Initialization - bool InitInfoFile(cmMakefile* makefile, std::string const& targetDirectory, - std::string const& config); + bool InitInfoFile(cmMakefile* makefile); // -- Settings file void SettingsFileRead(cmMakefile* makefile); bool SettingsFileWrite(); bool SettingsChanged() const { - return (this->MocSettingsChanged || this->RccSettingsChanged || - this->UicSettingsChanged); + return (this->MocSettingsChanged || this->UicSettingsChanged); } // -- Central processing - bool Process(); + bool Process(cmMakefile* makefile) override; // -- Source parsing bool ParseSourceFile(std::string const& absFilename, const SourceJob& job); @@ -146,54 +135,17 @@ private: bool UicGenerateAll(); bool UicGenerateFile(const UicJob& uicJob); - // -- Rcc - bool RccEnabled() const { return !this->RccExecutable.empty(); } - bool RccGenerateAll(); - bool RccGenerateFile(const RccJob& rccJob); - - // -- Log info - void LogBold(std::string const& message) const; - void LogInfo(cmQtAutoGen::Generator genType, - std::string const& message) const; - // -- Log warning - void LogWarning(cmQtAutoGen::Generator genType, - std::string const& message) const; - void LogFileWarning(cmQtAutoGen::Generator genType, - std::string const& filename, - std::string const& message) const; - // -- Log error - void LogError(cmQtAutoGen::Generator genType, - std::string const& message) const; - void LogFileError(cmQtAutoGen::Generator genType, - std::string const& filename, - std::string const& message) const; - void LogCommandError(cmQtAutoGen::Generator genType, - std::string const& message, - std::vector<std::string> const& command, - std::string const& output) const; - // -- Utility - bool MakeParentDirectory(cmQtAutoGen::Generator genType, - std::string const& filename) const; - bool FileDiffers(std::string const& filename, std::string const& content); - bool FileWrite(cmQtAutoGen::Generator genType, std::string const& filename, - std::string const& content); bool FindHeader(std::string& header, std::string const& testBasePath) const; - bool RunCommand(std::vector<std::string> const& command, - std::string& output) const; // -- Meta - std::string InfoFile; std::string ConfigSuffix; cmQtAutoGen::MultiConfig MultiConfig; // -- Settings bool IncludeProjectDirsBefore; - bool Verbose; - bool ColorOutput; std::string SettingsFile; std::string SettingsStringMoc; std::string SettingsStringUic; - std::string SettingsStringRcc; // -- Directories std::string ProjectSourceDir; std::string ProjectBinaryDir; @@ -202,11 +154,9 @@ private: std::string AutogenBuildDir; std::string AutogenIncludeDir; // -- Qt environment - std::string QtMajorVersion; - std::string QtMinorVersion; + unsigned long QtVersionMajor; std::string MocExecutable; std::string UicExecutable; - std::string RccExecutable; // -- File lists std::map<std::string, SourceJob> HeaderJobs; std::map<std::string, SourceJob> SourceJobs; @@ -240,9 +190,6 @@ private: std::vector<std::string> UicSearchPaths; cmsys::RegularExpression UicRegExpInclude; std::vector<std::unique_ptr<UicJob>> UicJobs; - // -- Rcc - bool RccSettingsChanged; - std::vector<RccJob> RccJobs; }; #endif diff --git a/Source/cmQtAutoGeneratorRcc.cxx b/Source/cmQtAutoGeneratorRcc.cxx new file mode 100644 index 0000000..3c9f1a8 --- /dev/null +++ b/Source/cmQtAutoGeneratorRcc.cxx @@ -0,0 +1,425 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmQtAutoGen.h" +#include "cmQtAutoGeneratorRcc.h" + +#include "cmAlgorithms.h" +#include "cmCryptoHash.h" +#include "cmMakefile.h" +#include "cmOutputConverter.h" +#include "cmSystemTools.h" + +// -- Static variables + +static const char* SettingsKeyRcc = "ARCC_SETTINGS_HASH"; + +// -- Class methods + +cmQtAutoGeneratorRcc::cmQtAutoGeneratorRcc() + : MultiConfig(cmQtAutoGen::WRAP) + , SettingsChanged(false) +{ +} + +bool cmQtAutoGeneratorRcc::InfoFileRead(cmMakefile* makefile) +{ + // Utility lambdas + auto InfoGet = [makefile](const char* key) { + return makefile->GetSafeDefinition(key); + }; + auto InfoGetList = [makefile](const char* key) -> std::vector<std::string> { + std::vector<std::string> list; + cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition(key), list); + return list; + }; + auto InfoGetConfig = [makefile, this](const char* key) -> std::string { + const char* valueConf = nullptr; + { + std::string keyConf = key; + keyConf += '_'; + keyConf += this->GetInfoConfig(); + valueConf = makefile->GetDefinition(keyConf); + } + if (valueConf == nullptr) { + valueConf = makefile->GetSafeDefinition(key); + } + return std::string(valueConf); + }; + auto InfoGetConfigList = + [&InfoGetConfig](const char* key) -> std::vector<std::string> { + std::vector<std::string> list; + cmSystemTools::ExpandListArgument(InfoGetConfig(key), list); + return list; + }; + + // -- Read info file + if (!makefile->ReadListFile(this->GetInfoFile().c_str())) { + this->LogFileError(cmQtAutoGen::RCC, this->GetInfoFile(), + "File processing failed"); + return false; + } + + // -- Meta + this->MultiConfig = + cmQtAutoGen::MultiConfigType(InfoGet("ARCC_MULTI_CONFIG")); + this->ConfigSuffix = InfoGetConfig("ARCC_CONFIG_SUFFIX"); + if (this->ConfigSuffix.empty()) { + this->ConfigSuffix = "_"; + this->ConfigSuffix += this->GetInfoConfig(); + } + + this->SettingsFile = InfoGetConfig("ARCC_SETTINGS_FILE"); + + // - Files and directories + this->ProjectSourceDir = InfoGet("ARCC_CMAKE_SOURCE_DIR"); + this->ProjectBinaryDir = InfoGet("ARCC_CMAKE_BINARY_DIR"); + this->CurrentSourceDir = InfoGet("ARCC_CMAKE_CURRENT_SOURCE_DIR"); + this->CurrentBinaryDir = InfoGet("ARCC_CMAKE_CURRENT_BINARY_DIR"); + this->AutogenBuildDir = InfoGet("ARCC_BUILD_DIR"); + + // - Qt environment + this->RccExecutable = InfoGet("ARCC_RCC_EXECUTABLE"); + this->RccListOptions = InfoGetList("ARCC_RCC_LIST_OPTIONS"); + + // - Job + this->QrcFile = InfoGet("ARCC_SOURCE"); + this->RccFile = InfoGet("ARCC_OUTPUT"); + this->Options = InfoGetConfigList("ARCC_OPTIONS"); + this->Inputs = InfoGetList("ARCC_INPUTS"); + + // - Validity checks + if (this->SettingsFile.empty()) { + this->LogFileError(cmQtAutoGen::RCC, this->GetInfoFile(), + "Settings file name missing"); + return false; + } + if (this->AutogenBuildDir.empty()) { + this->LogFileError(cmQtAutoGen::RCC, this->GetInfoFile(), + "Autogen build directory missing"); + return false; + } + if (this->RccExecutable.empty()) { + this->LogFileError(cmQtAutoGen::RCC, this->GetInfoFile(), + "rcc executable missing"); + return false; + } + if (this->QrcFile.empty()) { + this->LogFileError(cmQtAutoGen::RCC, this->GetInfoFile(), + "rcc input file missing"); + return false; + } + if (this->RccFile.empty()) { + this->LogFileError(cmQtAutoGen::RCC, this->GetInfoFile(), + "rcc output file missing"); + return false; + } + + // Init derived information + // ------------------------ + + // Init file path checksum generator + this->FilePathChecksum.setupParentDirs( + this->CurrentSourceDir, this->CurrentBinaryDir, this->ProjectSourceDir, + this->ProjectBinaryDir); + + return true; +} + +void cmQtAutoGeneratorRcc::SettingsFileRead(cmMakefile* makefile) +{ + // Compose current settings strings + { + cmCryptoHash crypt(cmCryptoHash::AlgoSHA256); + std::string const sep(" ~~~ "); + { + std::string str; + str += this->RccExecutable; + str += sep; + str += cmJoin(this->RccListOptions, ";"); + str += sep; + str += this->QrcFile; + str += sep; + str += this->RccFile; + str += sep; + str += cmJoin(this->Options, ";"); + str += sep; + str += cmJoin(this->Inputs, ";"); + str += sep; + this->SettingsString = crypt.HashString(str); + } + } + + // Read old settings + if (makefile->ReadListFile(this->SettingsFile.c_str())) { + { + auto SMatch = [makefile](const char* key, std::string const& value) { + return (value == makefile->GetSafeDefinition(key)); + }; + if (!SMatch(SettingsKeyRcc, this->SettingsString)) { + this->SettingsChanged = true; + } + } + // In case any setting changed remove the old settings file. + // This triggers a full rebuild on the next run if the current + // build is aborted before writing the current settings in the end. + if (this->SettingsChanged) { + cmSystemTools::RemoveFile(this->SettingsFile); + } + } else { + // If the file could not be read re-generate everythiung. + this->SettingsChanged = true; + } +} + +bool cmQtAutoGeneratorRcc::SettingsFileWrite() +{ + bool success = true; + // Only write if any setting changed + if (this->SettingsChanged) { + if (this->GetVerbose()) { + this->LogInfo(cmQtAutoGen::RCC, "Writing settings file " + + cmQtAutoGen::Quoted(this->SettingsFile)); + } + // Compose settings file content + std::string settings; + { + auto SettingAppend = [&settings](const char* key, + std::string const& value) { + settings += "set("; + settings += key; + settings += " "; + settings += cmOutputConverter::EscapeForCMake(value); + settings += ")\n"; + }; + SettingAppend(SettingsKeyRcc, this->SettingsString); + } + // Write settings file + if (!this->FileWrite(cmQtAutoGen::RCC, this->SettingsFile, settings)) { + this->LogFileError(cmQtAutoGen::RCC, this->SettingsFile, + "Settings file writing failed"); + // Remove old settings file to trigger a full rebuild on the next run + cmSystemTools::RemoveFile(this->SettingsFile); + success = false; + } + } + return success; +} + +bool cmQtAutoGeneratorRcc::Process(cmMakefile* makefile) +{ + // Read info file + if (!this->InfoFileRead(makefile)) { + return false; + } + // Read latest settings + this->SettingsFileRead(makefile); + // Generate rcc file + if (!this->RccGenerate()) { + return false; + } + // Write latest settings + if (!this->SettingsFileWrite()) { + return false; + } + return true; +} + +/** + * @return True on success + */ +bool cmQtAutoGeneratorRcc::RccGenerate() +{ + bool success = true; + bool rccGenerated = false; + + std::string rccFileAbs; + { + std::string suffix; + switch (this->MultiConfig) { + case cmQtAutoGen::SINGLE: + break; + case cmQtAutoGen::WRAP: + suffix = "_CMAKE"; + suffix += this->ConfigSuffix; + suffix += "_"; + break; + case cmQtAutoGen::FULL: + suffix = this->ConfigSuffix; + break; + } + rccFileAbs = cmQtAutoGen::AppendFilenameSuffix(this->RccFile, suffix); + } + std::string const rccFileRel = cmSystemTools::RelativePath( + this->AutogenBuildDir.c_str(), rccFileAbs.c_str()); + + // Check if regeneration is required + bool generate = false; + std::string generateReason; + if (!cmSystemTools::FileExists(this->QrcFile)) { + { + std::string error = "Could not find the file\n "; + error += cmQtAutoGen::Quoted(this->QrcFile); + this->LogError(cmQtAutoGen::RCC, error); + } + success = false; + } + if (success && !generate && !cmSystemTools::FileExists(rccFileAbs.c_str())) { + if (this->GetVerbose()) { + generateReason = "Generating "; + generateReason += cmQtAutoGen::Quoted(rccFileAbs); + generateReason += " from its source file "; + generateReason += cmQtAutoGen::Quoted(this->QrcFile); + generateReason += " because it doesn't exist"; + } + generate = true; + } + if (success && !generate && this->SettingsChanged) { + if (this->GetVerbose()) { + generateReason = "Generating "; + generateReason += cmQtAutoGen::Quoted(rccFileAbs); + generateReason += " from "; + generateReason += cmQtAutoGen::Quoted(this->QrcFile); + generateReason += " because the RCC settings changed"; + } + generate = true; + } + if (success && !generate) { + std::string error; + if (FileIsOlderThan(rccFileAbs, this->QrcFile, &error)) { + if (this->GetVerbose()) { + generateReason = "Generating "; + generateReason += cmQtAutoGen::Quoted(rccFileAbs); + generateReason += " because it is older than "; + generateReason += cmQtAutoGen::Quoted(this->QrcFile); + } + generate = true; + } else { + if (!error.empty()) { + this->LogError(cmQtAutoGen::RCC, error); + success = false; + } + } + } + if (success && !generate) { + // Acquire input file list + std::vector<std::string> readFiles; + std::vector<std::string> const* files = nullptr; + if (!this->Inputs.empty()) { + files = &this->Inputs; + } else { + // Read input file list from qrc file + std::string error; + if (cmQtAutoGen::RccListInputs(this->RccExecutable, this->RccListOptions, + this->QrcFile, readFiles, &error)) { + files = &readFiles; + } else { + this->LogFileError(cmQtAutoGen::RCC, this->QrcFile, error); + success = false; + } + } + // Test if any input file is newer than the build file + if (files != nullptr) { + std::string error; + for (std::string const& resFile : *files) { + if (!cmSystemTools::FileExists(resFile.c_str())) { + error = "Could not find the file\n "; + error += cmQtAutoGen::Quoted(resFile); + error += "\nwhich is listed in\n "; + error += cmQtAutoGen::Quoted(this->QrcFile); + break; + } + if (FileIsOlderThan(rccFileAbs, resFile, &error)) { + if (this->GetVerbose()) { + generateReason = "Generating "; + generateReason += cmQtAutoGen::Quoted(rccFileAbs); + generateReason += " from "; + generateReason += cmQtAutoGen::Quoted(this->QrcFile); + generateReason += " because it is older than "; + generateReason += cmQtAutoGen::Quoted(resFile); + } + generate = true; + break; + } + if (!error.empty()) { + break; + } + } + // Print error + if (!error.empty()) { + this->LogError(cmQtAutoGen::RCC, error); + success = false; + } + } + } + // Regenerate on demand + if (generate) { + // Log + if (this->GetVerbose()) { + this->LogBold("Generating RCC source " + rccFileRel); + this->LogInfo(cmQtAutoGen::RCC, generateReason); + } + + // Make sure the parent directory exists + if (this->MakeParentDirectory(cmQtAutoGen::RCC, rccFileAbs)) { + // Compose rcc command + std::vector<std::string> cmd; + cmd.push_back(this->RccExecutable); + cmd.insert(cmd.end(), this->Options.begin(), this->Options.end()); + cmd.push_back("-o"); + cmd.push_back(rccFileAbs); + cmd.push_back(this->QrcFile); + + std::string output; + if (this->RunCommand(cmd, output)) { + // Success + rccGenerated = true; + } else { + { + std::string emsg = "rcc failed for\n "; + emsg += cmQtAutoGen::Quoted(this->QrcFile); + this->LogCommandError(cmQtAutoGen::RCC, emsg, cmd, output); + } + cmSystemTools::RemoveFile(rccFileAbs); + success = false; + } + } else { + // Parent directory creation failed + success = false; + } + } + + // Generate a wrapper source file on demand + if (success && (this->MultiConfig == cmQtAutoGen::WRAP)) { + // Wrapper file name + std::string const& wrapperFileAbs = this->RccFile; + std::string const wrapperFileRel = cmSystemTools::RelativePath( + this->AutogenBuildDir.c_str(), wrapperFileAbs.c_str()); + // Wrapper file content + std::string content = "// This is an autogenerated configuration " + "wrapper file. Changes will be overwritten.\n" + "#include \""; + content += cmSystemTools::GetFilenameName(rccFileRel); + content += "\"\n"; + // Write content to file + if (this->FileDiffers(wrapperFileAbs, content)) { + // Write new wrapper file + if (this->GetVerbose()) { + this->LogBold("Generating RCC wrapper " + wrapperFileRel); + } + if (!this->FileWrite(cmQtAutoGen::RCC, wrapperFileAbs, content)) { + this->LogFileError(cmQtAutoGen::RCC, wrapperFileAbs, + "rcc wrapper file writing failed"); + success = false; + } + } else if (rccGenerated) { + // Just touch the wrapper file + if (this->GetVerbose()) { + this->LogInfo(cmQtAutoGen::RCC, + "Touching RCC wrapper " + wrapperFileRel); + } + cmSystemTools::Touch(wrapperFileAbs, false); + } + } + + return success; +} diff --git a/Source/cmQtAutoGeneratorRcc.h b/Source/cmQtAutoGeneratorRcc.h new file mode 100644 index 0000000..0e3f690 --- /dev/null +++ b/Source/cmQtAutoGeneratorRcc.h @@ -0,0 +1,56 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmQtAutoGeneratorRcc_h +#define cmQtAutoGeneratorRcc_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include "cmFilePathChecksum.h" +#include "cmQtAutoGen.h" +#include "cmQtAutoGenerator.h" + +#include <string> +#include <vector> + +class cmMakefile; + +class cmQtAutoGeneratorRcc : public cmQtAutoGenerator +{ + CM_DISABLE_COPY(cmQtAutoGeneratorRcc) +public: + cmQtAutoGeneratorRcc(); + +private: + // -- Initialization & settings + bool InfoFileRead(cmMakefile* makefile); + void SettingsFileRead(cmMakefile* makefile); + bool SettingsFileWrite(); + // -- Central processing + bool Process(cmMakefile* makefile) override; + bool RccGenerate(); + + // -- Config settings + std::string ConfigSuffix; + cmQtAutoGen::MultiConfig MultiConfig; + // -- Settings + bool SettingsChanged; + std::string SettingsFile; + std::string SettingsString; + // -- Directories + std::string ProjectSourceDir; + std::string ProjectBinaryDir; + std::string CurrentSourceDir; + std::string CurrentBinaryDir; + std::string AutogenBuildDir; + cmFilePathChecksum FilePathChecksum; + // -- Qt environment + std::string RccExecutable; + std::vector<std::string> RccListOptions; + // -- Job + std::string QrcFile; + std::string RccFile; + std::vector<std::string> Options; + std::vector<std::string> Inputs; +}; + +#endif diff --git a/Source/cmServer.cxx b/Source/cmServer.cxx index e923c22..ac42fde 100644 --- a/Source/cmServer.cxx +++ b/Source/cmServer.cxx @@ -22,13 +22,14 @@ void on_signal(uv_signal_t* signal, int signum) { - auto conn = reinterpret_cast<cmServerBase*>(signal->data); + auto conn = static_cast<cmServerBase*>(signal->data); conn->OnSignal(signum); } static void on_walk_to_shutdown(uv_handle_t* handle, void* arg) { (void)arg; + assert(uv_is_closing(handle)); if (!uv_is_closing(handle)) { uv_close(handle, &cmEventBasedConnection::on_close); } @@ -58,6 +59,8 @@ cmServer::cmServer(cmConnection* conn, bool supportExperimental) cmServer::~cmServer() { + Close(); + for (cmServerProtocol* p : this->SupportedProtocols) { delete p; } @@ -245,11 +248,10 @@ cmFileMonitor* cmServer::FileMonitor() const void cmServer::WriteJsonObject(const Json::Value& jsonValue, const DebugInfo* debug) const { - uv_rwlock_rdlock(&ConnectionsMutex); + cm::shared_lock<cm::shared_mutex> lock(ConnectionsMutex); for (auto& connection : this->Connections) { WriteJsonObject(connection.get(), jsonValue, debug); } - uv_rwlock_rdunlock(&ConnectionsMutex); } void cmServer::WriteJsonObject(cmConnection* connection, @@ -410,7 +412,7 @@ void cmServer::StartShutDown() static void __start_thread(void* arg) { - auto server = reinterpret_cast<cmServerBase*>(arg); + auto server = static_cast<cmServerBase*>(arg); std::string error; bool success = server->Serve(&error); if (!success || error.empty() == false) { @@ -418,22 +420,19 @@ static void __start_thread(void* arg) } } -static void __shutdownThread(uv_async_t* arg) -{ - auto server = reinterpret_cast<cmServerBase*>(arg->data); - on_walk_to_shutdown(reinterpret_cast<uv_handle_t*>(arg), nullptr); - server->StartShutDown(); -} - bool cmServerBase::StartServeThread() { ServeThreadRunning = true; - uv_async_init(&Loop, &this->ShutdownSignal, __shutdownThread); - this->ShutdownSignal.data = this; uv_thread_create(&ServeThread, __start_thread, this); return true; } +static void __shutdownThread(uv_async_t* arg) +{ + auto server = static_cast<cmServerBase*>(arg->data); + server->StartShutDown(); +} + bool cmServerBase::Serve(std::string* errorMessage) { #ifndef NDEBUG @@ -444,26 +443,23 @@ bool cmServerBase::Serve(std::string* errorMessage) errorMessage->clear(); - uv_signal_init(&Loop, &this->SIGINTHandler); - uv_signal_init(&Loop, &this->SIGHUPHandler); + ShutdownSignal.init(Loop, __shutdownThread, this); - this->SIGINTHandler.data = this; - this->SIGHUPHandler.data = this; + SIGINTHandler.init(Loop, this); + SIGHUPHandler.init(Loop, this); - uv_signal_start(&this->SIGINTHandler, &on_signal, SIGINT); - uv_signal_start(&this->SIGHUPHandler, &on_signal, SIGHUP); + SIGINTHandler.start(&on_signal, SIGINT); + SIGHUPHandler.start(&on_signal, SIGHUP); OnServeStart(); { - uv_rwlock_rdlock(&ConnectionsMutex); + cm::shared_lock<cm::shared_mutex> lock(ConnectionsMutex); for (auto& connection : Connections) { if (!connection->OnServeStart(errorMessage)) { - uv_rwlock_rdunlock(&ConnectionsMutex); return false; } } - uv_rwlock_rdunlock(&ConnectionsMutex); } if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) { @@ -476,7 +472,6 @@ bool cmServerBase::Serve(std::string* errorMessage) return false; } - ServeThreadRunning = false; return true; } @@ -490,23 +485,16 @@ void cmServerBase::OnServeStart() void cmServerBase::StartShutDown() { - if (!uv_is_closing( - reinterpret_cast<const uv_handle_t*>(&this->SIGINTHandler))) { - uv_signal_stop(&this->SIGINTHandler); - } - - if (!uv_is_closing( - reinterpret_cast<const uv_handle_t*>(&this->SIGHUPHandler))) { - uv_signal_stop(&this->SIGHUPHandler); - } + ShutdownSignal.reset(); + SIGINTHandler.reset(); + SIGHUPHandler.reset(); { - uv_rwlock_wrlock(&ConnectionsMutex); + cm::unique_lock<cm::shared_mutex> lock(ConnectionsMutex); for (auto& connection : Connections) { connection->OnConnectionShuttingDown(); } Connections.clear(); - uv_rwlock_wrunlock(&ConnectionsMutex); } uv_walk(&Loop, on_walk_to_shutdown, nullptr); @@ -523,31 +511,35 @@ cmServerBase::cmServerBase(cmConnection* connection) { auto err = uv_loop_init(&Loop); (void)err; - assert(err == 0); - - err = uv_rwlock_init(&ConnectionsMutex); + Loop.data = this; assert(err == 0); AddNewConnection(connection); } -cmServerBase::~cmServerBase() +void cmServerBase::Close() { + if (Loop.data) { + if (ServeThreadRunning) { + this->ShutdownSignal.send(); + uv_thread_join(&ServeThread); + } - if (ServeThreadRunning) { - uv_async_send(&this->ShutdownSignal); - uv_thread_join(&ServeThread); + uv_loop_close(&Loop); + Loop.data = nullptr; } - - uv_loop_close(&Loop); - uv_rwlock_destroy(&ConnectionsMutex); +} +cmServerBase::~cmServerBase() +{ + Close(); } void cmServerBase::AddNewConnection(cmConnection* ownedConnection) { - uv_rwlock_wrlock(&ConnectionsMutex); - Connections.emplace_back(ownedConnection); - uv_rwlock_wrunlock(&ConnectionsMutex); + { + cm::unique_lock<cm::shared_mutex> lock(ConnectionsMutex); + Connections.emplace_back(ownedConnection); + } ownedConnection->SetServer(this); } @@ -561,12 +553,14 @@ void cmServerBase::OnDisconnect(cmConnection* pConnection) auto pred = [pConnection](const std::unique_ptr<cmConnection>& m) { return m.get() == pConnection; }; - uv_rwlock_wrlock(&ConnectionsMutex); - Connections.erase( - std::remove_if(Connections.begin(), Connections.end(), pred), - Connections.end()); - uv_rwlock_wrunlock(&ConnectionsMutex); + { + cm::unique_lock<cm::shared_mutex> lock(ConnectionsMutex); + Connections.erase( + std::remove_if(Connections.begin(), Connections.end(), pred), + Connections.end()); + } + if (Connections.empty()) { - StartShutDown(); + this->ShutdownSignal.send(); } } diff --git a/Source/cmServer.h b/Source/cmServer.h index 15fd2ba..ca37ce2 100644 --- a/Source/cmServer.h +++ b/Source/cmServer.h @@ -5,8 +5,11 @@ #include "cmConfigure.h" // IWYU pragma: keep #include "cm_jsoncpp_value.h" +#include "cm_thread.hxx" #include "cm_uv.h" +#include "cmUVHandlePtr.h" + #include <memory> // IWYU pragma: keep #include <string> #include <vector> @@ -57,16 +60,16 @@ public: virtual bool OnSignal(int signum); uv_loop_t* GetLoop(); - + void Close(); void OnDisconnect(cmConnection* pConnection); protected: - mutable uv_rwlock_t ConnectionsMutex; + mutable cm::shared_mutex ConnectionsMutex; std::vector<std::unique_ptr<cmConnection>> Connections; bool ServeThreadRunning = false; uv_thread_t ServeThread; - uv_async_t ShutdownSignal; + cm::uv_async_ptr ShutdownSignal; #ifndef NDEBUG public: // When the server starts it will mark down it's current thread ID, @@ -79,8 +82,8 @@ protected: uv_loop_t Loop; - uv_signal_t SIGINTHandler; - uv_signal_t SIGHUPHandler; + cm::uv_signal_ptr SIGINTHandler; + cm::uv_signal_ptr SIGHUPHandler; }; class cmServer : public cmServerBase diff --git a/Source/cmServerConnection.cxx b/Source/cmServerConnection.cxx index 44af75f..78c8f06 100644 --- a/Source/cmServerConnection.cxx +++ b/Source/cmServerConnection.cxx @@ -5,6 +5,9 @@ #include "cmConfigure.h" #include "cmServer.h" #include "cmServerDictionary.h" +#include "cm_uv.h" + +#include <algorithm> #ifdef _WIN32 #include "io.h" #else @@ -18,36 +21,34 @@ cmStdIoConnection::cmStdIoConnection( { } -void cmStdIoConnection::SetupStream(uv_stream_t*& stream, int file_id) +cm::uv_stream_ptr cmStdIoConnection::SetupStream(int file_id) { - assert(stream == nullptr); switch (uv_guess_handle(file_id)) { case UV_TTY: { - auto tty = new uv_tty_t(); - uv_tty_init(this->Server->GetLoop(), tty, file_id, file_id == 0); + cm::uv_tty_ptr tty; + tty.init(*this->Server->GetLoop(), file_id, file_id == 0, + static_cast<cmEventBasedConnection*>(this)); uv_tty_set_mode(tty, UV_TTY_MODE_NORMAL); - stream = reinterpret_cast<uv_stream_t*>(tty); - break; + return std::move(tty); } case UV_FILE: if (file_id == 0) { - return; + return nullptr; } // Intentional fallthrough; stdin can _not_ be treated as a named // pipe, however stdout can be. CM_FALLTHROUGH; case UV_NAMED_PIPE: { - auto pipe = new uv_pipe_t(); - uv_pipe_init(this->Server->GetLoop(), pipe, 0); + cm::uv_pipe_ptr pipe; + pipe.init(*this->Server->GetLoop(), 0, + static_cast<cmEventBasedConnection*>(this)); uv_pipe_open(pipe, file_id); - stream = reinterpret_cast<uv_stream_t*>(pipe); - break; + return std::move(pipe); } default: assert(false && "Unable to determine stream type"); - return; + return nullptr; } - stream->data = static_cast<cmEventBasedConnection*>(this); } void cmStdIoConnection::SetServer(cmServerBase* s) @@ -57,14 +58,14 @@ void cmStdIoConnection::SetServer(cmServerBase* s) return; } - SetupStream(this->ReadStream, 0); - SetupStream(this->WriteStream, 1); + this->ReadStream = SetupStream(0); + this->WriteStream = SetupStream(1); } void shutdown_connection(uv_prepare_t* prepare) { cmStdIoConnection* connection = - reinterpret_cast<cmStdIoConnection*>(prepare->data); + static_cast<cmStdIoConnection*>(prepare->data); if (!uv_is_closing(reinterpret_cast<uv_handle_t*>(prepare))) { uv_close(reinterpret_cast<uv_handle_t*>(prepare), @@ -76,7 +77,7 @@ void shutdown_connection(uv_prepare_t* prepare) bool cmStdIoConnection::OnServeStart(std::string* pString) { Server->OnConnected(this); - if (this->ReadStream) { + if (this->ReadStream.get()) { uv_read_start(this->ReadStream, on_alloc_buffer, on_read); } else if (uv_guess_handle(0) == UV_FILE) { char buffer[1024]; @@ -94,44 +95,14 @@ bool cmStdIoConnection::OnServeStart(std::string* pString) return cmConnection::OnServeStart(pString); } -void cmStdIoConnection::ShutdownStream(uv_stream_t*& stream) -{ - if (!stream) { - return; - } - switch (stream->type) { - case UV_TTY: { - assert(!uv_is_closing(reinterpret_cast<uv_handle_t*>(stream))); - if (!uv_is_closing(reinterpret_cast<uv_handle_t*>(stream))) { - uv_close(reinterpret_cast<uv_handle_t*>(stream), - &on_close_delete<uv_tty_t>); - } - break; - } - case UV_FILE: - case UV_NAMED_PIPE: { - assert(!uv_is_closing(reinterpret_cast<uv_handle_t*>(stream))); - if (!uv_is_closing(reinterpret_cast<uv_handle_t*>(stream))) { - uv_close(reinterpret_cast<uv_handle_t*>(stream), - &on_close_delete<uv_pipe_t>); - } - break; - } - default: - assert(false && "Unable to determine stream type"); - } - - stream = nullptr; -} - bool cmStdIoConnection::OnConnectionShuttingDown() { - if (ReadStream) { + if (ReadStream.get()) { uv_read_stop(ReadStream); + ReadStream->data = nullptr; } - ShutdownStream(ReadStream); - ShutdownStream(WriteStream); + this->ReadStream.reset(); cmEventBasedConnection::OnConnectionShuttingDown(); diff --git a/Source/cmServerConnection.h b/Source/cmServerConnection.h index 4ca908d..a70edb4 100644 --- a/Source/cmServerConnection.h +++ b/Source/cmServerConnection.h @@ -8,7 +8,7 @@ #include "cmConnection.h" #include "cmPipeConnection.h" -#include "cm_uv.h" +#include "cmUVHandlePtr.h" class cmServerBase; @@ -46,8 +46,8 @@ public: bool OnServeStart(std::string* pString) override; private: - void SetupStream(uv_stream_t*& stream, int file_id); - void ShutdownStream(uv_stream_t*& stream); + cm::uv_stream_ptr SetupStream(int file_id); + cm::uv_stream_ptr ReadStream; }; /*** diff --git a/Source/cmServerDictionary.h b/Source/cmServerDictionary.h index 405ff6b..62dee11 100644 --- a/Source/cmServerDictionary.h +++ b/Source/cmServerDictionary.h @@ -23,6 +23,7 @@ static const std::string kPROGRESS_TYPE = "progress"; static const std::string kREPLY_TYPE = "reply"; static const std::string kSET_GLOBAL_SETTINGS_TYPE = "setGlobalSettings"; static const std::string kSIGNAL_TYPE = "signal"; +static const std::string kCTEST_INFO_TYPE = "ctestInfo"; static const std::string kARTIFACTS_KEY = "artifacts"; static const std::string kBUILD_DIRECTORY_KEY = "buildDirectory"; @@ -88,6 +89,13 @@ static const std::string kWARN_UNUSED_CLI_KEY = "warnUnusedCli"; static const std::string kWARN_UNUSED_KEY = "warnUnused"; static const std::string kWATCHED_DIRECTORIES_KEY = "watchedDirectories"; static const std::string kWATCHED_FILES_KEY = "watchedFiles"; +static const std::string kHAS_INSTALL_RULE = "hasInstallRule"; +static const std::string kINSTALL_PATHS = "installPaths"; +static const std::string kCTEST_NAME = "ctestName"; +static const std::string kCTEST_COMMAND = "ctestCommand"; +static const std::string kCTEST_INFO = "ctestInfo"; +static const std::string kMINIMUM_CMAKE_VERSION = "minimumCMakeVersion"; +static const std::string kIS_GENERATOR_PROVIDED_KEY = "isGeneratorProvided"; static const std::string kTARGET_CROSS_REFERENCES_KEY = "crossReferences"; static const std::string kLINE_NUMBER_KEY = "line"; diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx index e835b7a..cfac513 100644 --- a/Source/cmServerProtocol.cxx +++ b/Source/cmServerProtocol.cxx @@ -8,10 +8,13 @@ #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" +#include "cmInstallGenerator.h" +#include "cmInstallTargetGenerator.h" #include "cmLinkLineComputer.h" #include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmProperty.h" #include "cmServer.h" #include "cmServerDictionary.h" #include "cmSourceFile.h" @@ -21,6 +24,7 @@ #include "cmStateTypes.h" #include "cmSystemTools.h" #include "cmTarget.h" +#include "cmTest.h" #include "cm_uv.h" #include "cmake.h" @@ -30,6 +34,7 @@ #include <functional> #include <limits> #include <map> +#include <memory> #include <set> #include <string> #include <unordered_map> @@ -252,7 +257,7 @@ bool cmServerProtocol::DoActivate(const cmServerRequest& /*request*/, std::pair<int, int> cmServerProtocol1::ProtocolVersion() const { - return std::make_pair(1, 1); + return std::make_pair(1, 2); } static void setErrorMessage(std::string* errorMessage, const std::string& text) @@ -476,6 +481,9 @@ const cmServerResponse cmServerProtocol1::Process( if (request.Type == kSET_GLOBAL_SETTINGS_TYPE) { return this->ProcessSetGlobalSettings(request); } + if (request.Type == kCTEST_INFO_TYPE) { + return this->ProcessCTests(request); + } return request.ReportError("Unknown command!"); } @@ -763,6 +771,100 @@ static void DumpBacktraceRange(Json::Value& result, const std::string& type, } } +static Json::Value DumpCTestInfo(cmTest* testInfo) +{ + Json::Value result = Json::objectValue; + result[kCTEST_NAME] = testInfo->GetName(); + + // Concat command entries together. After the first should be the arguments + // for the command + std::string command; + for (auto const& cmd : testInfo->GetCommand()) { + command.append(cmd); + command.append(" "); + } + result[kCTEST_COMMAND] = command; + + // Build up the list of properties that may have been specified + Json::Value properties = Json::arrayValue; + for (auto& prop : testInfo->GetProperties()) { + Json::Value entry = Json::objectValue; + entry[kKEY_KEY] = prop.first; + entry[kVALUE_KEY] = prop.second.GetValue(); + properties.append(entry); + } + result[kPROPERTIES_KEY] = properties; + + // Need backtrace to figure out where this test was originally added + result[kBACKTRACE_KEY] = DumpBacktrace(testInfo->GetBacktrace()); + + return result; +} + +static void DumpMakefileTests(cmMakefile* mf, const std::string& config, + Json::Value* result) +{ + std::vector<cmTest*> tests; + mf->GetTests(config, tests); + for (auto test : tests) { + Json::Value tmp = DumpCTestInfo(test); + if (!tmp.isNull()) { + result->append(tmp); + } + } +} + +static Json::Value DumpCTestProjectList(const cmake* cm, + std::string const& config) +{ + Json::Value result = Json::arrayValue; + + auto globalGen = cm->GetGlobalGenerator(); + + for (const auto& projectIt : globalGen->GetProjectMap()) { + Json::Value pObj = Json::objectValue; + pObj[kNAME_KEY] = projectIt.first; + + Json::Value tests = Json::arrayValue; + + // Gather tests for every generator + for (const auto& lg : projectIt.second) { + // Make sure they're generated. + lg->GenerateTestFiles(); + cmMakefile* mf = lg->GetMakefile(); + DumpMakefileTests(mf, config, &tests); + } + + pObj[kCTEST_INFO] = tests; + + result.append(pObj); + } + + return result; +} + +static Json::Value DumpCTestConfiguration(const cmake* cm, + const std::string& config) +{ + Json::Value result = Json::objectValue; + result[kNAME_KEY] = config; + + result[kPROJECTS_KEY] = DumpCTestProjectList(cm, config); + + return result; +} + +static Json::Value DumpCTestConfigurationsList(const cmake* cm) +{ + Json::Value result = Json::arrayValue; + + for (const std::string& c : getConfigurations(cm)) { + result.append(DumpCTestConfiguration(cm, c)); + } + + return result; +} + static Json::Value DumpTarget(cmGeneratorTarget* target, const std::string& config) { @@ -787,6 +889,8 @@ static Json::Value DumpTarget(cmGeneratorTarget* target, Json::Value result = Json::objectValue; result[kNAME_KEY] = target->GetName(); + result[kIS_GENERATOR_PROVIDED_KEY] = + target->Target->GetIsGeneratorProvided(); result[kTYPE_KEY] = typeName; result[kSOURCE_DIRECTORY_KEY] = lg->GetCurrentSourceDirectory(); result[kBUILD_DIRECTORY_KEY] = lg->GetCurrentBinaryDirectory(); @@ -797,6 +901,34 @@ static Json::Value DumpTarget(cmGeneratorTarget* target, result[kFULL_NAME_KEY] = target->GetFullName(config); + if (target->Target->GetHaveInstallRule()) { + result[kHAS_INSTALL_RULE] = true; + + Json::Value installPaths = Json::arrayValue; + auto targetGenerators = target->Makefile->GetInstallGenerators(); + for (auto installGenerator : targetGenerators) { + auto installTargetGenerator = + dynamic_cast<cmInstallTargetGenerator*>(installGenerator); + if (installTargetGenerator != nullptr && + installTargetGenerator->GetTarget()->Target == target->Target) { + auto dest = installTargetGenerator->GetDestination(config); + + std::string installPath; + if (!dest.empty() && cmSystemTools::FileIsFullPath(dest.c_str())) { + installPath = dest; + } else { + std::string installPrefix = + target->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX"); + installPath = installPrefix + '/' + dest; + } + + installPaths.append(installPath); + } + } + + result[kINSTALL_PATHS] = installPaths; + } + Json::Value crossRefs = Json::objectValue; crossRefs[kBACKTRACE_KEY] = DumpBacktrace(target->Target->GetBacktrace()); @@ -933,10 +1065,26 @@ static Json::Value DumpProjectList(const cmake* cm, std::string const& config) // Project structure information: const cmMakefile* mf = lg->GetMakefile(); + pObj[kMINIMUM_CMAKE_VERSION] = + mf->GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION"); pObj[kSOURCE_DIRECTORY_KEY] = mf->GetCurrentSourceDirectory(); pObj[kBUILD_DIRECTORY_KEY] = mf->GetCurrentBinaryDirectory(); pObj[kTARGETS_KEY] = DumpTargetsList(projectIt.second, config); + // For a project-level install rule it might be defined in any of its + // associated generators. + bool hasInstallRule = false; + for (const auto generator : projectIt.second) { + hasInstallRule = + generator->GetMakefile()->GetInstallGenerators().empty() == false; + + if (hasInstallRule) { + break; + } + } + + pObj[kHAS_INSTALL_RULE] = hasInstallRule; + result.append(pObj); } @@ -1190,6 +1338,19 @@ cmServerResponse cmServerProtocol1::ProcessFileSystemWatchers( return request.Reply(result); } +cmServerResponse cmServerProtocol1::ProcessCTests( + const cmServerRequest& request) +{ + if (this->m_State < STATE_COMPUTED) { + return request.ReportError("This instance was not yet computed."); + } + + Json::Value result = Json::objectValue; + result[kCONFIGURATIONS_KEY] = + DumpCTestConfigurationsList(this->CMakeInstance()); + return request.Reply(result); +} + cmServerProtocol1::GeneratorInformation::GeneratorInformation( const std::string& generatorName, const std::string& extraGeneratorName, const std::string& toolset, const std::string& platform, diff --git a/Source/cmServerProtocol.h b/Source/cmServerProtocol.h index 124ac7f..df71cff 100644 --- a/Source/cmServerProtocol.h +++ b/Source/cmServerProtocol.h @@ -123,6 +123,7 @@ private: cmServerResponse ProcessGlobalSettings(const cmServerRequest& request); cmServerResponse ProcessSetGlobalSettings(const cmServerRequest& request); cmServerResponse ProcessFileSystemWatchers(const cmServerRequest& request); + cmServerResponse ProcessCTests(const cmServerRequest& request); enum State { diff --git a/Source/cmSetCommand.cxx b/Source/cmSetCommand.cxx index b32cda3..985aac8 100644 --- a/Source/cmSetCommand.cxx +++ b/Source/cmSetCommand.cxx @@ -2,8 +2,6 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmSetCommand.h" -#include <string.h> - #include "cmAlgorithms.h" #include "cmMakefile.h" #include "cmState.h" @@ -22,19 +20,15 @@ bool cmSetCommand::InitialPass(std::vector<std::string> const& args, } // watch for ENV signatures - const char* variable = args[0].c_str(); // VAR is always first - if (cmHasLiteralPrefix(variable, "ENV{") && strlen(variable) > 5) { + auto const& variable = args[0]; // VAR is always first + if (cmHasLiteralPrefix(variable, "ENV{") && variable.size() > 5) { // what is the variable name - char* varName = new char[strlen(variable)]; - strncpy(varName, variable + 4, strlen(variable) - 5); - varName[strlen(variable) - 5] = '\0'; - std::string putEnvArg = varName; - putEnvArg += "="; + auto const& varName = variable.substr(4, variable.size() - 5); + std::string putEnvArg = varName + "="; // what is the current value if any std::string currValue; const bool currValueSet = cmSystemTools::GetEnv(varName, currValue); - delete[] varName; // will it be set to something, then set it if (args.size() > 1 && !args[1].empty()) { diff --git a/Source/cmSourceFileLocation.cxx b/Source/cmSourceFileLocation.cxx index 4f337f2..6add7b3 100644 --- a/Source/cmSourceFileLocation.cxx +++ b/Source/cmSourceFileLocation.cxx @@ -8,9 +8,7 @@ #include "cmSystemTools.h" #include "cmake.h" -#include <algorithm> #include <assert.h> -#include <vector> cmSourceFileLocation::cmSourceFileLocation() : Makefile(nullptr) @@ -86,13 +84,9 @@ void cmSourceFileLocation::UpdateExtension(const std::string& name) // The global generator checks extensions of enabled languages. cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator(); cmMakefile const* mf = this->Makefile; - const std::vector<std::string>& srcExts = - mf->GetCMakeInstance()->GetSourceExtensions(); - const std::vector<std::string>& hdrExts = - mf->GetCMakeInstance()->GetHeaderExtensions(); + auto cm = mf->GetCMakeInstance(); if (!gg->GetLanguageFromExtension(ext.c_str()).empty() || - std::find(srcExts.begin(), srcExts.end(), ext) != srcExts.end() || - std::find(hdrExts.begin(), hdrExts.end(), ext) != hdrExts.end()) { + cm->IsSourceExtension(ext) || cm->IsHeaderExtension(ext)) { // This is a known extension. Use the given filename with extension. this->Name = cmSystemTools::GetFilenameName(name); this->AmbiguousExtension = false; @@ -149,14 +143,8 @@ bool cmSourceFileLocation::MatchesAmbiguousExtension( // disk. One of these must match if loc refers to this source file. std::string const& ext = this->Name.substr(loc.Name.size() + 1); cmMakefile const* mf = this->Makefile; - const std::vector<std::string>& srcExts = - mf->GetCMakeInstance()->GetSourceExtensions(); - if (std::find(srcExts.begin(), srcExts.end(), ext) != srcExts.end()) { - return true; - } - std::vector<std::string> hdrExts = - mf->GetCMakeInstance()->GetHeaderExtensions(); - return std::find(hdrExts.begin(), hdrExts.end(), ext) != hdrExts.end(); + auto cm = mf->GetCMakeInstance(); + return cm->IsSourceExtension(ext) || cm->IsHeaderExtension(ext); } bool cmSourceFileLocation::Matches(cmSourceFileLocation const& loc) diff --git a/Source/cmSourceGroup.cxx b/Source/cmSourceGroup.cxx index fba4c31..18bcb49 100644 --- a/Source/cmSourceGroup.cxx +++ b/Source/cmSourceGroup.cxx @@ -60,14 +60,14 @@ void cmSourceGroup::AddGroupFile(const std::string& name) this->GroupFiles.insert(name); } -const char* cmSourceGroup::GetName() const +std::string const& cmSourceGroup::GetName() const { - return this->Name.c_str(); + return this->Name; } -const char* cmSourceGroup::GetFullName() const +std::string const& cmSourceGroup::GetFullName() const { - return this->FullName.c_str(); + return this->FullName; } bool cmSourceGroup::MatchesRegex(const char* name) @@ -105,7 +105,7 @@ cmSourceGroup* cmSourceGroup::LookupChild(const char* name) const // st for (; iter != end; ++iter) { - std::string sgName = iter->GetName(); + std::string const& sgName = iter->GetName(); // look if descenened is the one were looking for if (sgName == name) { diff --git a/Source/cmSourceGroup.h b/Source/cmSourceGroup.h index e8bd697..7c7c35f 100644 --- a/Source/cmSourceGroup.h +++ b/Source/cmSourceGroup.h @@ -55,12 +55,12 @@ public: /** * Get the name of this group. */ - const char* GetName() const; + std::string const& GetName() const; /** * Get the full path name for group. */ - const char* GetFullName() const; + std::string const& GetFullName() const; /** * Check if the given name matches this group's regex. diff --git a/Source/cmStandardLexer.h b/Source/cmStandardLexer.h index c9f42e4..b212c7e 100644 --- a/Source/cmStandardLexer.h +++ b/Source/cmStandardLexer.h @@ -3,7 +3,7 @@ #ifndef cmStandardLexer_h #define cmStandardLexer_h -#include "cmConfigure.h" // IWYU pragma: keep +#include "cmsys/Configure.h" // IWYU pragma: keep /* Disable some warnings. */ #if defined(_MSC_VER) diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 63c1452..5d1f5f7 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -50,6 +50,8 @@ #include <windows.h> // include wincrypt.h after windows.h #include <wincrypt.h> + +#include "cm_uv.h" #else #include <sys/time.h> #include <unistd.h> @@ -943,6 +945,39 @@ cmSystemTools::WindowsFileRetry cmSystemTools::GetWindowsFileRetry() } return retry; } + +std::string cmSystemTools::GetRealPath(const std::string& path, + std::string* errorMessage) +{ + // uv_fs_realpath uses Windows Vista API so fallback to kwsys if not found + std::string resolved_path; + uv_fs_t req; + int err = uv_fs_realpath(NULL, &req, path.c_str(), NULL); + if (!err) { + resolved_path = std::string((char*)req.ptr); + cmSystemTools::ConvertToUnixSlashes(resolved_path); + // Normalize to upper-case drive letter as GetActualCaseForPath does. + if (resolved_path.size() > 1 && resolved_path[1] == ':') { + resolved_path[0] = toupper(resolved_path[0]); + } + } else if (err == UV_ENOSYS) { + resolved_path = cmsys::SystemTools::GetRealPath(path, errorMessage); + } else if (errorMessage) { + LPSTR message = NULL; + DWORD size = FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&message, 0, + NULL); + *errorMessage = std::string(message, size); + LocalFree(message); + + resolved_path = ""; + } else { + resolved_path = path; + } + return resolved_path; +} #endif bool cmSystemTools::RenameFile(const char* oldname, const char* newname) diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index e7082e6..2646df9 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -497,6 +497,10 @@ public: unsigned int Delay; }; static WindowsFileRetry GetWindowsFileRetry(); + + /** Get the real path for a given path, removing all symlinks. */ + static std::string GetRealPath(const std::string& path, + std::string* errorMessage = 0); #endif private: static bool s_ForceUnixPaths; diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index c6cd502..de23b08 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -176,6 +176,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, Visibility vis, cmMakefile* mf) { assert(mf); + this->IsGeneratorProvided = false; this->Name = name; this->TargetTypeValue = type; this->Makefile = mf; @@ -238,6 +239,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, this->SetPropertyDefault("COMPILE_PDB_OUTPUT_DIRECTORY", nullptr); this->SetPropertyDefault("Fortran_FORMAT", nullptr); this->SetPropertyDefault("Fortran_MODULE_DIRECTORY", nullptr); + this->SetPropertyDefault("Fortran_COMPILER_LAUNCHER", nullptr); this->SetPropertyDefault("GNUtoMS", nullptr); this->SetPropertyDefault("OSX_ARCHITECTURES", nullptr); this->SetPropertyDefault("IOS_INSTALL_COMBINED", nullptr); @@ -279,6 +281,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, this->SetPropertyDefault("CUDA_STANDARD_REQUIRED", nullptr); this->SetPropertyDefault("CUDA_EXTENSIONS", nullptr); this->SetPropertyDefault("CUDA_COMPILER_LAUNCHER", nullptr); + this->SetPropertyDefault("CUDA_SEPARABLE_COMPILATION", nullptr); this->SetPropertyDefault("LINK_SEARCH_START_STATIC", nullptr); this->SetPropertyDefault("LINK_SEARCH_END_STATIC", nullptr); } @@ -884,6 +887,13 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); return; } + if (prop == "IMPORTED_GLOBAL" && !this->IsImported()) { + std::ostringstream e; + e << "IMPORTED_GLOBAL property can't be set on non-imported targets (\"" + << this->Name << "\")\n"; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); + return; + } if (prop == "INCLUDE_DIRECTORIES") { this->Internal->IncludeDirectoriesEntries.clear(); @@ -933,6 +943,19 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) this->Internal->SourceEntries.push_back(value); this->Internal->SourceBacktraces.push_back(lfbt); } + } else if (prop == "IMPORTED_GLOBAL") { + if (!cmSystemTools::IsOn(value)) { + std::ostringstream e; + e << "IMPORTED_GLOBAL property can't be set to FALSE on targets (\"" + << this->Name << "\")\n"; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); + return; + } + /* no need to change anything if value does not change */ + if (!this->ImportedGloballyVisible) { + this->ImportedGloballyVisible = true; + this->GetGlobalGenerator()->IndexTarget(this); + } } else if (cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME") && !this->CheckImportedLibName(prop, value ? value : "")) { /* error was reported by check method */ @@ -977,6 +1000,14 @@ void cmTarget::AppendProperty(const std::string& prop, const char* value, this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); return; } + if (prop == "IMPORTED_GLOBAL") { + std::ostringstream e; + e << "IMPORTED_GLOBAL property can't be appended, only set on imported " + "targets (\"" + << this->Name << "\")\n"; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); + return; + } if (prop == "INCLUDE_DIRECTORIES") { if (value && *value) { this->Internal->IncludeDirectoriesEntries.push_back(value); @@ -1143,6 +1174,21 @@ static void cmTargetCheckINTERFACE_LINK_LIBRARIES(const char* value, context->IssueMessage(cmake::FATAL_ERROR, e.str()); } +static void cmTargetCheckIMPORTED_GLOBAL(const cmTarget* target, + cmMakefile* context) +{ + std::vector<cmTarget*> targets = context->GetOwnedImportedTargets(); + std::vector<cmTarget*>::const_iterator it = + std::find(targets.begin(), targets.end(), target); + if (it == targets.end()) { + std::ostringstream e; + e << "Attempt to promote imported target \"" << target->GetName() + << "\" to global scope (by setting IMPORTED_GLOBAL) " + "which is not built in this directory."; + context->IssueMessage(cmake::FATAL_ERROR, e.str()); + } +} + void cmTarget::CheckProperty(const std::string& prop, cmMakefile* context) const { @@ -1157,11 +1203,16 @@ void cmTarget::CheckProperty(const std::string& prop, cmTargetCheckLINK_INTERFACE_LIBRARIES(prop, value, context, true); } } - if (cmHasLiteralPrefix(prop, "INTERFACE_LINK_LIBRARIES")) { + if (prop == "INTERFACE_LINK_LIBRARIES") { if (const char* value = this->GetProperty(prop)) { cmTargetCheckINTERFACE_LINK_LIBRARIES(value, context); } } + if (prop == "IMPORTED_GLOBAL") { + if (this->IsImported()) { + cmTargetCheckIMPORTED_GLOBAL(this, context); + } + } } const char* cmTarget::GetComputedProperty( @@ -1182,6 +1233,7 @@ const char* cmTarget::GetProperty(const std::string& prop) const MAKE_STATIC_PROP(COMPILE_OPTIONS); MAKE_STATIC_PROP(COMPILE_DEFINITIONS); MAKE_STATIC_PROP(IMPORTED); + MAKE_STATIC_PROP(IMPORTED_GLOBAL); MAKE_STATIC_PROP(MANUALLY_ADDED_DEPENDENCIES); MAKE_STATIC_PROP(NAME); MAKE_STATIC_PROP(BINARY_DIR); @@ -1196,6 +1248,7 @@ const char* cmTarget::GetProperty(const std::string& prop) const specialProps.insert(propCOMPILE_OPTIONS); specialProps.insert(propCOMPILE_DEFINITIONS); specialProps.insert(propIMPORTED); + specialProps.insert(propIMPORTED_GLOBAL); specialProps.insert(propMANUALLY_ADDED_DEPENDENCIES); specialProps.insert(propNAME); specialProps.insert(propBINARY_DIR); @@ -1264,6 +1317,9 @@ const char* cmTarget::GetProperty(const std::string& prop) const if (prop == propIMPORTED) { return this->IsImported() ? "TRUE" : "FALSE"; } + if (prop == propIMPORTED_GLOBAL) { + return this->IsImportedGloballyVisible() ? "TRUE" : "FALSE"; + } if (prop == propNAME) { return this->GetName().c_str(); } diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 940e26c..56f3e3a 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -180,6 +180,12 @@ public: bool GetHaveInstallRule() const { return this->HaveInstallRule; } void SetHaveInstallRule(bool h) { this->HaveInstallRule = h; } + /** + * Get/Set whether this target was auto-created by a generator. + */ + bool GetIsGeneratorProvided() const { return this->IsGeneratorProvided; } + void SetIsGeneratorProvided(bool igp) { this->IsGeneratorProvided = igp; } + /** Add a utility on which this project depends. A utility is an executable * name as would be specified to the ADD_EXECUTABLE or UTILITY_SOURCE * commands. It is not a full path nor does it have an extension. @@ -284,6 +290,7 @@ private: std::string const& value) const; private: + bool IsGeneratorProvided; cmPropertyMap Properties; std::set<std::string> SystemIncludeDirectories; std::set<std::string> LinkDirectoriesEmmitted; diff --git a/Source/cmTargetCompileDefinitionsCommand.cxx b/Source/cmTargetCompileDefinitionsCommand.cxx index d159d41..bd4121d 100644 --- a/Source/cmTargetCompileDefinitionsCommand.cxx +++ b/Source/cmTargetCompileDefinitionsCommand.cxx @@ -17,15 +17,6 @@ bool cmTargetCompileDefinitionsCommand::InitialPass( return this->HandleArguments(args, "COMPILE_DEFINITIONS"); } -void cmTargetCompileDefinitionsCommand::HandleImportedTarget( - const std::string& tgt) -{ - std::ostringstream e; - e << "Cannot specify compile definitions for imported target \"" << tgt - << "\"."; - this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); -} - void cmTargetCompileDefinitionsCommand::HandleMissingTarget( const std::string& name) { @@ -56,5 +47,5 @@ bool cmTargetCompileDefinitionsCommand::HandleDirectContent( cmTarget* tgt, const std::vector<std::string>& content, bool, bool) { tgt->AppendProperty("COMPILE_DEFINITIONS", this->Join(content).c_str()); - return true; + return true; // Successfully handled. } diff --git a/Source/cmTargetCompileDefinitionsCommand.h b/Source/cmTargetCompileDefinitionsCommand.h index f910452..d41483a 100644 --- a/Source/cmTargetCompileDefinitionsCommand.h +++ b/Source/cmTargetCompileDefinitionsCommand.h @@ -30,7 +30,6 @@ public: cmExecutionStatus& status) override; private: - void HandleImportedTarget(const std::string& tgt) override; void HandleMissingTarget(const std::string& name) override; bool HandleDirectContent(cmTarget* tgt, diff --git a/Source/cmTargetCompileFeaturesCommand.cxx b/Source/cmTargetCompileFeaturesCommand.cxx index 722bbe5..f58e404 100644 --- a/Source/cmTargetCompileFeaturesCommand.cxx +++ b/Source/cmTargetCompileFeaturesCommand.cxx @@ -17,15 +17,6 @@ bool cmTargetCompileFeaturesCommand::InitialPass( return this->HandleArguments(args, "COMPILE_FEATURES", NO_FLAGS); } -void cmTargetCompileFeaturesCommand::HandleImportedTarget( - const std::string& tgt) -{ - std::ostringstream e; - e << "Cannot specify compile features for imported target \"" << tgt - << "\"."; - this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); -} - void cmTargetCompileFeaturesCommand::HandleMissingTarget( const std::string& name) { @@ -49,8 +40,8 @@ bool cmTargetCompileFeaturesCommand::HandleDirectContent( std::string error; if (!this->Makefile->AddRequiredTargetFeature(tgt, it, &error)) { this->SetError(error); - return false; + return false; // Not (successfully) handled. } } - return true; + return true; // Successfully handled. } diff --git a/Source/cmTargetCompileFeaturesCommand.h b/Source/cmTargetCompileFeaturesCommand.h index 444d260..45240a5 100644 --- a/Source/cmTargetCompileFeaturesCommand.h +++ b/Source/cmTargetCompileFeaturesCommand.h @@ -22,7 +22,6 @@ class cmTargetCompileFeaturesCommand : public cmTargetPropCommandBase cmExecutionStatus& status) override; private: - void HandleImportedTarget(const std::string& tgt) override; void HandleMissingTarget(const std::string& name) override; bool HandleDirectContent(cmTarget* tgt, diff --git a/Source/cmTargetCompileOptionsCommand.cxx b/Source/cmTargetCompileOptionsCommand.cxx index 1b4056d..4df3630 100644 --- a/Source/cmTargetCompileOptionsCommand.cxx +++ b/Source/cmTargetCompileOptionsCommand.cxx @@ -18,21 +18,12 @@ bool cmTargetCompileOptionsCommand::InitialPass( return this->HandleArguments(args, "COMPILE_OPTIONS", PROCESS_BEFORE); } -void cmTargetCompileOptionsCommand::HandleImportedTarget( - const std::string& tgt) -{ - std::ostringstream e; - e << "Cannot specify compile options for imported target \"" << tgt << "\"."; - this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); -} - void cmTargetCompileOptionsCommand::HandleMissingTarget( const std::string& name) { std::ostringstream e; e << "Cannot specify compile options for target \"" << name - << "\" " - "which is not built by this project."; + << "\" which is not built by this project."; this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); } @@ -47,5 +38,5 @@ bool cmTargetCompileOptionsCommand::HandleDirectContent( { cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); tgt->InsertCompileOption(this->Join(content), lfbt); - return true; + return true; // Successfully handled. } diff --git a/Source/cmTargetCompileOptionsCommand.h b/Source/cmTargetCompileOptionsCommand.h index 3fab238..6fb151a 100644 --- a/Source/cmTargetCompileOptionsCommand.h +++ b/Source/cmTargetCompileOptionsCommand.h @@ -30,7 +30,6 @@ public: cmExecutionStatus& status) override; private: - void HandleImportedTarget(const std::string& tgt) override; void HandleMissingTarget(const std::string& name) override; bool HandleDirectContent(cmTarget* tgt, diff --git a/Source/cmTargetDepend.h b/Source/cmTargetDepend.h index daa902e..b698db6 100644 --- a/Source/cmTargetDepend.h +++ b/Source/cmTargetDepend.h @@ -16,7 +16,7 @@ class cmTargetDepend cmGeneratorTarget const* Target; // The set order depends only on the Target, so we use - // mutable members to acheive a map with set syntax. + // mutable members to achieve a map with set syntax. mutable bool Link; mutable bool Util; diff --git a/Source/cmTargetIncludeDirectoriesCommand.cxx b/Source/cmTargetIncludeDirectoriesCommand.cxx index 4646c7e..dcec830 100644 --- a/Source/cmTargetIncludeDirectoriesCommand.cxx +++ b/Source/cmTargetIncludeDirectoriesCommand.cxx @@ -21,22 +21,12 @@ bool cmTargetIncludeDirectoriesCommand::InitialPass( ArgumentFlags(PROCESS_BEFORE | PROCESS_SYSTEM)); } -void cmTargetIncludeDirectoriesCommand::HandleImportedTarget( - const std::string& tgt) -{ - std::ostringstream e; - e << "Cannot specify include directories for imported target \"" << tgt - << "\"."; - this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); -} - void cmTargetIncludeDirectoriesCommand::HandleMissingTarget( const std::string& name) { std::ostringstream e; e << "Cannot specify include directories for target \"" << name - << "\" " - "which is not built by this project."; + << "\" which is not built by this project."; this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); } @@ -79,7 +69,7 @@ bool cmTargetIncludeDirectoriesCommand::HandleDirectContent( } tgt->AddSystemIncludeDirectories(sdirs); } - return true; + return true; // Successfully handled. } void cmTargetIncludeDirectoriesCommand::HandleInterfaceContent( diff --git a/Source/cmTargetIncludeDirectoriesCommand.h b/Source/cmTargetIncludeDirectoriesCommand.h index 27a2f43..57bf8fc 100644 --- a/Source/cmTargetIncludeDirectoriesCommand.h +++ b/Source/cmTargetIncludeDirectoriesCommand.h @@ -30,7 +30,6 @@ public: cmExecutionStatus& status) override; private: - void HandleImportedTarget(const std::string& tgt) override; void HandleMissingTarget(const std::string& name) override; bool HandleDirectContent(cmTarget* tgt, diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx index dda0464..97bb0a2 100644 --- a/Source/cmTargetLinkLibrariesCommand.cxx +++ b/Source/cmTargetLinkLibrariesCommand.cxx @@ -25,21 +25,32 @@ const char* cmTargetLinkLibrariesCommand::LinkLibraryTypeNames[3] = { bool cmTargetLinkLibrariesCommand::InitialPass( std::vector<std::string> const& args, cmExecutionStatus&) { - // must have one argument + // Must have at least one argument. if (args.empty()) { this->SetError("called with incorrect number of arguments"); return false; } - + // Alias targets cannot be on the LHS of this command. if (this->Makefile->IsAlias(args[0])) { this->SetError("can not be used on an ALIAS target."); return false; } + // Lookup the target for which libraries are specified. this->Target = this->Makefile->GetCMakeInstance()->GetGlobalGenerator()->FindTarget( args[0]); if (!this->Target) { + const std::vector<cmTarget*>& importedTargets = + this->Makefile->GetOwnedImportedTargets(); + for (cmTarget* importedTarget : importedTargets) { + if (importedTarget->GetName() == args[0]) { + this->Target = importedTarget; + break; + } + } + } + if (!this->Target) { cmake::MessageType t = cmake::FATAL_ERROR; // fail by default std::ostringstream e; e << "Cannot specify link libraries for target \"" << args[0] << "\" " @@ -68,8 +79,7 @@ bool cmTargetLinkLibrariesCommand::InitialPass( break; } } - - // now actually print the message + // Now actually print the message. switch (t) { case cmake::AUTHOR_WARNING: this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, e.str()); @@ -84,6 +94,7 @@ bool cmTargetLinkLibrariesCommand::InitialPass( return true; } + // OBJECT libraries are not allowed on the LHS of the command. if (this->Target->GetType() == cmStateEnums::OBJECT_LIBRARY) { std::ostringstream e; e << "Object library target \"" << args[0] << "\" " @@ -93,6 +104,7 @@ bool cmTargetLinkLibrariesCommand::InitialPass( return true; } + // Having a UTILITY library on the LHS is a bug. if (this->Target->GetType() == cmStateEnums::UTILITY) { std::ostringstream e; const char* modal = nullptr; @@ -119,7 +131,7 @@ bool cmTargetLinkLibrariesCommand::InitialPass( } } - // but we might not have any libs after variable expansion + // But we might not have any libs after variable expansion. if (args.size() < 2) { return true; } @@ -132,8 +144,8 @@ bool cmTargetLinkLibrariesCommand::InitialPass( // specification if the keyword is encountered as the first argument. this->CurrentProcessingState = ProcessingLinkLibraries; - // add libraries, note that there is an optional prefix - // of debug and optimized that can be used + // Add libraries, note that there is an optional prefix + // of debug and optimized that can be used. for (unsigned int i = 1; i < args.size(); ++i) { if (args[i] == "LINK_INTERFACE_LIBRARIES") { this->CurrentProcessingState = ProcessingPlainLinkInterface; @@ -150,8 +162,9 @@ bool cmTargetLinkLibrariesCommand::InitialPass( this->CurrentProcessingState != ProcessingKeywordPublicInterface && this->CurrentProcessingState != ProcessingKeywordLinkInterface) { this->Makefile->IssueMessage( - cmake::FATAL_ERROR, "The INTERFACE option must appear as the second " - "argument, just after the target name."); + cmake::FATAL_ERROR, + "The INTERFACE, PUBLIC or PRIVATE option must appear as the second " + "argument, just after the target name."); return true; } this->CurrentProcessingState = ProcessingKeywordLinkInterface; @@ -173,7 +186,7 @@ bool cmTargetLinkLibrariesCommand::InitialPass( this->CurrentProcessingState != ProcessingKeywordLinkInterface) { this->Makefile->IssueMessage( cmake::FATAL_ERROR, - "The PUBLIC or PRIVATE option must appear as the second " + "The INTERFACE, PUBLIC or PRIVATE option must appear as the second " "argument, just after the target name."); return true; } @@ -196,7 +209,7 @@ bool cmTargetLinkLibrariesCommand::InitialPass( this->CurrentProcessingState != ProcessingKeywordLinkInterface) { this->Makefile->IssueMessage( cmake::FATAL_ERROR, - "The PUBLIC or PRIVATE option must appear as the second " + "The INTERFACE, PUBLIC or PRIVATE option must appear as the second " "argument, just after the target name."); return true; } @@ -228,7 +241,7 @@ bool cmTargetLinkLibrariesCommand::InitialPass( } else { // Lookup old-style cache entry if type is unspecified. So if you // do a target_link_libraries(foo optimized bar) it will stay optimized - // and not use the lookup. As there maybe the case where someone has + // and not use the lookup. As there may be the case where someone has // specifed that a library is both debug and optimized. (this check is // only there for backwards compatibility when mixing projects built // with old versions of CMake and new) @@ -299,6 +312,14 @@ bool cmTargetLinkLibrariesCommand::HandleLibrary(const std::string& lib, "target_link_libraries"); return false; } + if (this->Target->IsImported() && + this->CurrentProcessingState != ProcessingKeywordLinkInterface) { + this->Makefile->IssueMessage( + cmake::FATAL_ERROR, + "IMPORTED library can only be used with the INTERFACE keyword of " + "target_link_libraries"); + return false; + } cmTarget::TLLSignature sig = (this->CurrentProcessingState == ProcessingPlainPrivateInterface || @@ -331,12 +352,11 @@ bool cmTargetLinkLibrariesCommand::HandleLibrary(const std::string& lib, // form must be the plain form. const char* existingSig = (sig == cmTarget::KeywordTLLSignature ? "plain" : "keyword"); - e << "The " << existingSig << " signature for target_link_libraries " - "has already been used with the target \"" - << this->Target->GetName() << "\". All uses of " - "target_link_libraries with a target " - << modal << " be either " - "all-keyword or all-plain.\n"; + e << "The " << existingSig << " signature for target_link_libraries has " + "already been used with the target \"" + << this->Target->GetName() + << "\". All uses of target_link_libraries with a target " << modal + << " be either all-keyword or all-plain.\n"; this->Target->GetTllSignatureTraces(e, sig == cmTarget::KeywordTLLSignature ? cmTarget::PlainTLLSignature @@ -348,104 +368,125 @@ bool cmTargetLinkLibrariesCommand::HandleLibrary(const std::string& lib, } } - // Handle normal case first. + // Handle normal case where the command was called with another keyword than + // INTERFACE / LINK_INTERFACE_LIBRARIES or none at all. (The "LINK_LIBRARIES" + // property of the target on the LHS shall be populated.) if (this->CurrentProcessingState != ProcessingKeywordLinkInterface && this->CurrentProcessingState != ProcessingPlainLinkInterface) { + // Assure that the target on the LHS was created in the current directory. cmTarget* t = this->Makefile->FindLocalNonAliasTarget(this->Target->GetName()); if (!t) { + const std::vector<cmTarget*>& importedTargets = + this->Makefile->GetOwnedImportedTargets(); + for (cmTarget* importedTarget : importedTargets) { + if (importedTarget->GetName() == this->Target->GetName()) { + t = importedTarget; + break; + } + } + } + if (!t) { std::ostringstream e; e << "Attempt to add link library \"" << lib << "\" to target \"" << this->Target->GetName() << "\" which is not built in this directory."; this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); - } else { - - cmTarget* tgt = this->Makefile->GetGlobalGenerator()->FindTarget(lib); + return false; + } - if (tgt && (tgt->GetType() != cmStateEnums::STATIC_LIBRARY) && - (tgt->GetType() != cmStateEnums::SHARED_LIBRARY) && - (tgt->GetType() != cmStateEnums::UNKNOWN_LIBRARY) && - (tgt->GetType() != cmStateEnums::INTERFACE_LIBRARY) && - !tgt->IsExecutableWithExports()) { - std::ostringstream e; - e << "Target \"" << lib << "\" of type " - << cmState::GetTargetTypeName(tgt->GetType()) - << " may not be linked into another target. " - << "One may link only to STATIC or SHARED libraries, or " - << "to executables with the ENABLE_EXPORTS property set."; - this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); - } + cmTarget* tgt = this->Makefile->GetGlobalGenerator()->FindTarget(lib); - this->Target->AddLinkLibrary(*this->Makefile, lib, llt); + if (tgt && (tgt->GetType() != cmStateEnums::STATIC_LIBRARY) && + (tgt->GetType() != cmStateEnums::SHARED_LIBRARY) && + (tgt->GetType() != cmStateEnums::UNKNOWN_LIBRARY) && + (tgt->GetType() != cmStateEnums::INTERFACE_LIBRARY) && + !tgt->IsExecutableWithExports()) { + std::ostringstream e; + e << "Target \"" << lib << "\" of type " + << cmState::GetTargetTypeName(tgt->GetType()) + << " may not be linked into another target. One may link only to " + "INTERFACE, STATIC or SHARED libraries, or to executables with the " + "ENABLE_EXPORTS property set."; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); } - if (this->CurrentProcessingState == ProcessingLinkLibraries) { - this->Target->AppendProperty( - "INTERFACE_LINK_LIBRARIES", - this->Target->GetDebugGeneratorExpressions(lib, llt).c_str()); - return true; - } - if (this->CurrentProcessingState != ProcessingKeywordPublicInterface && - this->CurrentProcessingState != ProcessingPlainPublicInterface) { - if (this->Target->GetType() == cmStateEnums::STATIC_LIBRARY) { - std::string configLib = - this->Target->GetDebugGeneratorExpressions(lib, llt); - if (cmGeneratorExpression::IsValidTargetName(lib) || - cmGeneratorExpression::Find(lib) != std::string::npos) { - configLib = "$<LINK_ONLY:" + configLib + ">"; - } - this->Target->AppendProperty("INTERFACE_LINK_LIBRARIES", - configLib.c_str()); + this->Target->AddLinkLibrary(*this->Makefile, lib, llt); + } + + // Handle (additional) case where the command was called with PRIVATE / + // LINK_PRIVATE and stop its processing. (The "INTERFACE_LINK_LIBRARIES" + // property of the target on the LHS shall only be populated if it is a + // STATIC library.) + if (this->CurrentProcessingState == ProcessingKeywordPrivateInterface || + this->CurrentProcessingState == ProcessingPlainPrivateInterface) { + if (this->Target->GetType() == cmStateEnums::STATIC_LIBRARY) { + std::string configLib = + this->Target->GetDebugGeneratorExpressions(lib, llt); + if (cmGeneratorExpression::IsValidTargetName(lib) || + cmGeneratorExpression::Find(lib) != std::string::npos) { + configLib = "$<LINK_ONLY:" + configLib + ">"; } - // Not a 'public' or 'interface' library. Do not add to interface - // property. - return true; + this->Target->AppendProperty("INTERFACE_LINK_LIBRARIES", + configLib.c_str()); } + return true; } + // Handle general case where the command was called with another keyword than + // PRIVATE / LINK_PRIVATE or none at all. (The "INTERFACE_LINK_LIBRARIES" + // property of the target on the LHS shall be populated.) this->Target->AppendProperty( "INTERFACE_LINK_LIBRARIES", this->Target->GetDebugGeneratorExpressions(lib, llt).c_str()); + // Stop processing if called without any keyword. + if (this->CurrentProcessingState == ProcessingLinkLibraries) { + return true; + } + // Stop processing if policy CMP0022 is set to NEW. const cmPolicies::PolicyStatus policy22Status = this->Target->GetPolicyStatusCMP0022(); - if (policy22Status != cmPolicies::OLD && policy22Status != cmPolicies::WARN) { return true; } - + // Stop processing if called with an INTERFACE library on the LHS. if (this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { return true; } - // Get the list of configurations considered to be DEBUG. - std::vector<std::string> debugConfigs = - this->Makefile->GetCMakeInstance()->GetDebugConfigs(); - std::string prop; - - // Include this library in the link interface for the target. - if (llt == DEBUG_LibraryType || llt == GENERAL_LibraryType) { - // Put in the DEBUG configuration interfaces. - for (std::string const& dc : debugConfigs) { - prop = "LINK_INTERFACE_LIBRARIES_"; - prop += dc; - this->Target->AppendProperty(prop, lib.c_str()); + // Handle (additional) backward-compatibility case where the command was + // called with PUBLIC / INTERFACE / LINK_PUBLIC / LINK_INTERFACE_LIBRARIES. + // (The policy CMP0022 is not set to NEW.) + { + // Get the list of configurations considered to be DEBUG. + std::vector<std::string> debugConfigs = + this->Makefile->GetCMakeInstance()->GetDebugConfigs(); + std::string prop; + + // Include this library in the link interface for the target. + if (llt == DEBUG_LibraryType || llt == GENERAL_LibraryType) { + // Put in the DEBUG configuration interfaces. + for (std::string const& dc : debugConfigs) { + prop = "LINK_INTERFACE_LIBRARIES_"; + prop += dc; + this->Target->AppendProperty(prop, lib.c_str()); + } } - } - if (llt == OPTIMIZED_LibraryType || llt == GENERAL_LibraryType) { - // Put in the non-DEBUG configuration interfaces. - this->Target->AppendProperty("LINK_INTERFACE_LIBRARIES", lib.c_str()); - - // Make sure the DEBUG configuration interfaces exist so that the - // general one will not be used as a fall-back. - for (std::string const& dc : debugConfigs) { - prop = "LINK_INTERFACE_LIBRARIES_"; - prop += dc; - if (!this->Target->GetProperty(prop)) { - this->Target->SetProperty(prop, ""); + if (llt == OPTIMIZED_LibraryType || llt == GENERAL_LibraryType) { + // Put in the non-DEBUG configuration interfaces. + this->Target->AppendProperty("LINK_INTERFACE_LIBRARIES", lib.c_str()); + + // Make sure the DEBUG configuration interfaces exist so that the + // general one will not be used as a fall-back. + for (std::string const& dc : debugConfigs) { + prop = "LINK_INTERFACE_LIBRARIES_"; + prop += dc; + if (!this->Target->GetProperty(prop)) { + this->Target->SetProperty(prop, ""); + } } } } diff --git a/Source/cmTargetLinkLibrariesCommand.h b/Source/cmTargetLinkLibrariesCommand.h index f41af49..a2f3ecd 100644 --- a/Source/cmTargetLinkLibrariesCommand.h +++ b/Source/cmTargetLinkLibrariesCommand.h @@ -20,6 +20,9 @@ class cmTarget; * cmTargetLinkLibrariesCommand is used to specify a list of libraries to link * into executable(s) or shared objects. The names of the libraries * should be those defined by the LIBRARY(library) command(s). + * + * Additionally, it allows to propagate usage-requirements (including link + * libraries) from one target into another. */ class cmTargetLinkLibrariesCommand : public cmCommand { diff --git a/Source/cmTargetPropCommandBase.cxx b/Source/cmTargetPropCommandBase.cxx index 45fe430..9a8fd96 100644 --- a/Source/cmTargetPropCommandBase.cxx +++ b/Source/cmTargetPropCommandBase.cxx @@ -17,11 +17,11 @@ bool cmTargetPropCommandBase::HandleArguments( return false; } - // Lookup the target for which libraries are specified. if (this->Makefile->IsAlias(args[0])) { this->SetError("can not be used on an ALIAS target."); return false; } + // Lookup the target for which property-values are specified. this->Target = this->Makefile->GetCMakeInstance()->GetGlobalGenerator()->FindTarget( args[0]); @@ -84,16 +84,13 @@ bool cmTargetPropCommandBase::ProcessContentArgs( this->SetError("called with invalid arguments"); return false; } - - if (this->Target->IsImported()) { - this->HandleImportedTarget(args[0]); - return false; - } - if (this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY && scope != "INTERFACE") { - this->SetError("may only be set INTERFACE properties on INTERFACE " - "targets"); + this->SetError("may only set INTERFACE properties on INTERFACE targets"); + return false; + } + if (this->Target->IsImported() && scope != "INTERFACE") { + this->SetError("may only set INTERFACE properties on IMPORTED targets"); return false; } diff --git a/Source/cmTargetPropCommandBase.h b/Source/cmTargetPropCommandBase.h index 46a2f6b..3c736fc 100644 --- a/Source/cmTargetPropCommandBase.h +++ b/Source/cmTargetPropCommandBase.h @@ -35,7 +35,6 @@ protected: bool prepend, bool system); private: - virtual void HandleImportedTarget(const std::string& tgt) = 0; virtual void HandleMissingTarget(const std::string& name) = 0; virtual bool HandleDirectContent(cmTarget* tgt, diff --git a/Source/cmTargetPropertyComputer.cxx b/Source/cmTargetPropertyComputer.cxx index 1d2520d..06ce0b1 100644 --- a/Source/cmTargetPropertyComputer.cxx +++ b/Source/cmTargetPropertyComputer.cxx @@ -3,6 +3,7 @@ #include "cmTargetPropertyComputer.h" +#include <cctype> #include <sstream> #include <unordered_set> @@ -49,6 +50,12 @@ bool cmTargetPropertyComputer::WhiteListedInterfaceProperty( if (cmHasLiteralPrefix(prop, "INTERFACE_")) { return true; } + if (cmHasLiteralPrefix(prop, "_")) { + return true; + } + if (std::islower(prop[0])) { + return true; + } static std::unordered_set<std::string> builtIns; if (builtIns.empty()) { builtIns.insert("COMPATIBLE_INTERFACE_BOOL"); @@ -57,6 +64,7 @@ bool cmTargetPropertyComputer::WhiteListedInterfaceProperty( builtIns.insert("COMPATIBLE_INTERFACE_STRING"); builtIns.insert("EXPORT_NAME"); builtIns.insert("IMPORTED"); + builtIns.insert("IMPORTED_GLOBAL"); builtIns.insert("NAME"); builtIns.insert("TYPE"); } diff --git a/Source/cmTargetSourcesCommand.cxx b/Source/cmTargetSourcesCommand.cxx index 058659a..3dd3748 100644 --- a/Source/cmTargetSourcesCommand.cxx +++ b/Source/cmTargetSourcesCommand.cxx @@ -17,13 +17,6 @@ bool cmTargetSourcesCommand::InitialPass(std::vector<std::string> const& args, return this->HandleArguments(args, "SOURCES"); } -void cmTargetSourcesCommand::HandleImportedTarget(const std::string& tgt) -{ - std::ostringstream e; - e << "Cannot specify sources for imported target \"" << tgt << "\"."; - this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); -} - void cmTargetSourcesCommand::HandleMissingTarget(const std::string& name) { std::ostringstream e; @@ -43,5 +36,5 @@ bool cmTargetSourcesCommand::HandleDirectContent( cmTarget* tgt, const std::vector<std::string>& content, bool, bool) { tgt->AppendProperty("SOURCES", this->Join(content).c_str()); - return true; + return true; // Successfully handled. } diff --git a/Source/cmTargetSourcesCommand.h b/Source/cmTargetSourcesCommand.h index 0639e98..ea8776a 100644 --- a/Source/cmTargetSourcesCommand.h +++ b/Source/cmTargetSourcesCommand.h @@ -30,7 +30,6 @@ public: cmExecutionStatus& status) override; private: - void HandleImportedTarget(const std::string& tgt) override; void HandleMissingTarget(const std::string& name) override; bool HandleDirectContent(cmTarget* tgt, diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx index 78ca6bc..b548359 100644 --- a/Source/cmTestGenerator.cxx +++ b/Source/cmTestGenerator.cxx @@ -34,6 +34,16 @@ void cmTestGenerator::Compute(cmLocalGenerator* lg) this->LG = lg; } +bool cmTestGenerator::TestsForConfig(const std::string& config) +{ + return this->GeneratesForConfig(config); +} + +cmTest* cmTestGenerator::GetTest() const +{ + return this->Test; +} + void cmTestGenerator::GenerateScriptConfigs(std::ostream& os, Indent indent) { // Create the tests. diff --git a/Source/cmTestGenerator.h b/Source/cmTestGenerator.h index 1ca61c2..73d05a3 100644 --- a/Source/cmTestGenerator.h +++ b/Source/cmTestGenerator.h @@ -30,6 +30,11 @@ public: void Compute(cmLocalGenerator* lg); + /** Test if this generator installs the test for a given configuration. */ + bool TestsForConfig(const std::string& config); + + cmTest* GetTest() const; + protected: void GenerateScriptConfigs(std::ostream& os, Indent indent) override; void GenerateScriptActions(std::ostream& os, Indent indent) override; diff --git a/Source/cmTimestamp.cxx b/Source/cmTimestamp.cxx index 9fb79d9..f1e9283 100644 --- a/Source/cmTimestamp.cxx +++ b/Source/cmTimestamp.cxx @@ -33,11 +33,13 @@ std::string cmTimestamp::FileModificationTime(const char* path, const std::string& formatString, bool utcFlag) { - if (!cmsys::SystemTools::FileExists(path)) { + std::string real_path = cmSystemTools::GetRealPath(path); + + if (!cmsys::SystemTools::FileExists(real_path)) { return std::string(); } - time_t mtime = cmsys::SystemTools::ModifiedTime(path); + time_t mtime = cmsys::SystemTools::ModifiedTime(real_path); return CreateTimestampFromTimeT(mtime, formatString, utcFlag); } @@ -151,7 +153,7 @@ std::string cmTimestamp::AddTimestampComponent(char flag, if (unixEpoch == -1) { cmSystemTools::Error( "Error generating UNIX epoch in " - "STRING(TIMESTAMP ...). Please, file a bug report aginst CMake"); + "STRING(TIMESTAMP ...). Please, file a bug report against CMake"); return std::string(); } diff --git a/Source/cmTryRunCommand.cxx b/Source/cmTryRunCommand.cxx index dcaa493..932b976 100644 --- a/Source/cmTryRunCommand.cxx +++ b/Source/cmTryRunCommand.cxx @@ -4,7 +4,6 @@ #include "cmsys/FStream.hxx" #include <stdio.h> -#include <string.h> #include "cmMakefile.h" #include "cmState.h" @@ -191,13 +190,15 @@ void cmTryRunCommand::RunExecutable(const std::string& runArgs, finalCommand.c_str(), out, out, &retVal, nullptr, cmSystemTools::OUTPUT_NONE, timeout); // set the run var - char retChar[1000]; + char retChar[16]; + const char* retStr; if (worked) { sprintf(retChar, "%i", retVal); + retStr = retChar; } else { - strcpy(retChar, "FAILED_TO_RUN"); + retStr = "FAILED_TO_RUN"; } - this->Makefile->AddCacheDefinition(this->RunResultVariable, retChar, + this->Makefile->AddCacheDefinition(this->RunResultVariable, retStr, "Result of TRY_RUN", cmStateEnums::INTERNAL); } diff --git a/Source/cmUVHandlePtr.cxx b/Source/cmUVHandlePtr.cxx new file mode 100644 index 0000000..d7e38c3 --- /dev/null +++ b/Source/cmUVHandlePtr.cxx @@ -0,0 +1,227 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#define cmUVHandlePtr_cxx +#include "cmUVHandlePtr.h" + +#include <assert.h> +#include <stdlib.h> + +#include "cm_thread.hxx" +#include "cm_uv.h" + +namespace cm { + +static void close_delete(uv_handle_t* h) +{ + free(h); +} + +template <typename T> +static void default_delete(T* type_handle) +{ + auto handle = reinterpret_cast<uv_handle_t*>(type_handle); + if (handle) { + assert(!uv_is_closing(handle)); + if (!uv_is_closing(handle)) { + uv_close(handle, &close_delete); + } + } +} + +/** + * Encapsulates delete logic for a given handle type T + */ +template <typename T> +struct uv_handle_deleter +{ + void operator()(T* type_handle) const { default_delete(type_handle); } +}; + +template <typename T> +void uv_handle_ptr_base_<T>::allocate(void* data) +{ + reset(); + + /* + We use calloc since we know all these types are c structs + and we just want to 0 init them. New would do the same thing; + but casting from uv_handle_t to certain other types -- namely + uv_timer_t -- triggers a cast_align warning on certain systems. + */ + handle.reset(static_cast<T*>(calloc(1, sizeof(T))), uv_handle_deleter<T>()); + handle->data = data; +} + +template <typename T> +void uv_handle_ptr_base_<T>::reset() +{ + handle.reset(); +} + +template <typename T> +uv_handle_ptr_base_<T>::operator uv_handle_t*() +{ + return reinterpret_cast<uv_handle_t*>(handle.get()); +} + +template <typename T> +T* uv_handle_ptr_base_<T>::operator->() const noexcept +{ + return handle.get(); +} + +template <typename T> +T* uv_handle_ptr_base_<T>::get() const +{ + return handle.get(); +} + +template <typename T> +uv_handle_ptr_<T>::operator T*() const +{ + return this->handle.get(); +} + +#ifdef CMAKE_BUILD_WITH_CMAKE +template <> +struct uv_handle_deleter<uv_async_t> +{ + /*** + * Wile uv_async_send is itself thread-safe, there are + * no strong guarantees that close hasn't already been + * called on the handle; and that it might be deleted + * as the send call goes through. This mutex guards + * against that. + * + * The shared_ptr here is to allow for copy construction + * which is mandated by the standard for Deleter on + * shared_ptrs. + */ + std::shared_ptr<cm::mutex> handleMutex; + + uv_handle_deleter() + : handleMutex(std::make_shared<cm::mutex>()) + { + } + + void operator()(uv_async_t* handle) + { + cm::lock_guard<cm::mutex> lock(*handleMutex); + default_delete(handle); + } +}; + +void uv_async_ptr::send() +{ + auto deleter = std::get_deleter<uv_handle_deleter<uv_async_t>>(this->handle); + assert(deleter); + + cm::lock_guard<cm::mutex> lock(*deleter->handleMutex); + if (this->handle) { + uv_async_send(*this); + } +} + +int uv_async_ptr::init(uv_loop_t& loop, uv_async_cb async_cb, void* data) +{ + allocate(data); + return uv_async_init(&loop, handle.get(), async_cb); +} +#endif + +template <> +struct uv_handle_deleter<uv_signal_t> +{ + void operator()(uv_signal_t* handle) const + { + if (handle) { + uv_signal_stop(handle); + default_delete(handle); + } + } +}; + +int uv_signal_ptr::init(uv_loop_t& loop, void* data) +{ + allocate(data); + return uv_signal_init(&loop, handle.get()); +} + +int uv_signal_ptr::start(uv_signal_cb cb, int signum) +{ + assert(handle); + return uv_signal_start(*this, cb, signum); +} + +void uv_signal_ptr::stop() +{ + if (handle) { + uv_signal_stop(*this); + } +} + +int uv_pipe_ptr::init(uv_loop_t& loop, int ipc, void* data) +{ + allocate(data); + return uv_pipe_init(&loop, *this, ipc); +} + +uv_pipe_ptr::operator uv_stream_t*() const +{ + return reinterpret_cast<uv_stream_t*>(handle.get()); +} + +#ifdef CMAKE_BUILD_WITH_CMAKE +int uv_process_ptr::spawn(uv_loop_t& loop, uv_process_options_t const& options, + void* data) +{ + allocate(data); + return uv_spawn(&loop, *this, &options); +} + +int uv_timer_ptr::init(uv_loop_t& loop, void* data) +{ + allocate(data); + return uv_timer_init(&loop, *this); +} + +int uv_timer_ptr::start(uv_timer_cb cb, uint64_t timeout, uint64_t repeat) +{ + assert(handle); + return uv_timer_start(*this, cb, timeout, repeat); +} + +uv_tty_ptr::operator uv_stream_t*() const +{ + return reinterpret_cast<uv_stream_t*>(handle.get()); +} + +int uv_tty_ptr::init(uv_loop_t& loop, int fd, int readable, void* data) +{ + allocate(data); + return uv_tty_init(&loop, *this, fd, readable); +} +#endif + +template class uv_handle_ptr_base_<uv_handle_t>; + +#define UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(NAME) \ + template class uv_handle_ptr_base_<uv_##NAME##_t>; \ + template class uv_handle_ptr_<uv_##NAME##_t>; + +UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(signal) + +UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(pipe) + +UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(stream) + +#ifdef CMAKE_BUILD_WITH_CMAKE +UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(async) + +UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(process) + +UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(timer) + +UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(tty) +#endif +} diff --git a/Source/cmUVHandlePtr.h b/Source/cmUVHandlePtr.h new file mode 100644 index 0000000..a6ce565 --- /dev/null +++ b/Source/cmUVHandlePtr.h @@ -0,0 +1,222 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once +#include "cmConfigure.h" // IWYU pragma: keep + +#include <algorithm> +#include <cstddef> +#include <cstdint> +#include <memory> +#include <type_traits> + +#include "cm_uv.h" + +#define CM_PERFECT_FWD_CTOR(Class, FwdTo) \ + template <typename... Args> \ + Class(Args&&... args) \ + : FwdTo(std::forward<Args>(args)...) \ + { \ + } + +namespace cm { + +/*** +* RAII class to simplify and insure the safe usage of uv_*_t types. This +* includes making sure resources are properly freed and contains casting +* operators which allow for passing into relevant uv_* functions. +* +*@tparam T actual uv_*_t type represented. +*/ +template <typename T> +class uv_handle_ptr_base_ +{ +protected: + template <typename _T> + friend class uv_handle_ptr_base_; + + /** + * This must be a pointer type since the handle can outlive this class. + * When uv_close is eventually called on the handle, the memory the + * handle inhabits must be valid until the close callback is called + * which can be later on in the loop. + */ + std::shared_ptr<T> handle; + + /** + * Allocate memory for the type and optionally set it's 'data' pointer. + * Protected since this should only be called for an appropriate 'init' + * call. + * + * @param data data pointer to set + */ + void allocate(void* data = nullptr); + +public: + CM_DISABLE_COPY(uv_handle_ptr_base_) + uv_handle_ptr_base_(uv_handle_ptr_base_&&) noexcept; + uv_handle_ptr_base_& operator=(uv_handle_ptr_base_&&) noexcept; + + /** + * This move constructor allows us to move out of a more specialized + * uv type into a less specialized one. The only constraint is that + * the right hand side is castable to T. + * + * This allows you to return uv_handle_ptr or uv_stream_ptr from a function + * that initializes something like uv_pipe_ptr or uv_tcp_ptr and interact + * and clean up after it without caring about the exact type. + */ + template <typename S, typename = typename std::enable_if< + std::is_rvalue_reference<S&&>::value>::type> + uv_handle_ptr_base_(S&& rhs) + { + // This will force a compiler error if rhs doesn't have a casting + // operator to get T* + this->handle = std::shared_ptr<T>(rhs.handle, rhs); + rhs.handle.reset(); + } + + // Dtor and ctor need to be inline defined like this for default ctors and + // dtors to work. + uv_handle_ptr_base_() {} + uv_handle_ptr_base_(std::nullptr_t) {} + ~uv_handle_ptr_base_() { reset(); } + + /** + * Properly close the handle if needed and sets the inner handle to nullptr + */ + void reset(); + + /** + * Allow less verbose calling of uv_handle_* functions + * @return reinterpreted handle + */ + operator uv_handle_t*(); + + T* get() const; + T* operator->() const noexcept; +}; + +template <typename T> +inline uv_handle_ptr_base_<T>::uv_handle_ptr_base_( + uv_handle_ptr_base_<T>&&) noexcept = default; +template <typename T> +inline uv_handle_ptr_base_<T>& uv_handle_ptr_base_<T>::operator=( + uv_handle_ptr_base_<T>&&) noexcept = default; + +/** + * While uv_handle_ptr_base_ only exposes uv_handle_t*, this exposes uv_T_t* + * too. It is broken out like this so we can reuse most of the code for the + * uv_handle_ptr class. + */ +template <typename T> +class uv_handle_ptr_ : public uv_handle_ptr_base_<T> +{ + template <typename _T> + friend class uv_handle_ptr_; + +public: + CM_PERFECT_FWD_CTOR(uv_handle_ptr_, uv_handle_ptr_base_<T>); + + /*** + * Allow less verbose calling of uv_<T> functions + * @return reinterpreted handle + */ + operator T*() const; +}; + +/*** + * This specialization is required to avoid duplicate 'operator uv_handle_t*()' + * declarations + */ +template <> +class uv_handle_ptr_<uv_handle_t> : public uv_handle_ptr_base_<uv_handle_t> +{ +public: + CM_PERFECT_FWD_CTOR(uv_handle_ptr_, uv_handle_ptr_base_<uv_handle_t>); +}; + +class uv_async_ptr : public uv_handle_ptr_<uv_async_t> +{ +public: + CM_PERFECT_FWD_CTOR(uv_async_ptr, uv_handle_ptr_<uv_async_t>); + + int init(uv_loop_t& loop, uv_async_cb async_cb, void* data = nullptr); + + void send(); +}; + +struct uv_signal_ptr : public uv_handle_ptr_<uv_signal_t> +{ + CM_PERFECT_FWD_CTOR(uv_signal_ptr, uv_handle_ptr_<uv_signal_t>); + + int init(uv_loop_t& loop, void* data = nullptr); + + int start(uv_signal_cb cb, int signum); + + void stop(); +}; + +struct uv_pipe_ptr : public uv_handle_ptr_<uv_pipe_t> +{ + CM_PERFECT_FWD_CTOR(uv_pipe_ptr, uv_handle_ptr_<uv_pipe_t>); + + operator uv_stream_t*() const; + + int init(uv_loop_t& loop, int ipc, void* data = nullptr); +}; + +struct uv_process_ptr : public uv_handle_ptr_<uv_process_t> +{ + CM_PERFECT_FWD_CTOR(uv_process_ptr, uv_handle_ptr_<uv_process_t>); + + int spawn(uv_loop_t& loop, uv_process_options_t const& options, + void* data = nullptr); +}; + +struct uv_timer_ptr : public uv_handle_ptr_<uv_timer_t> +{ + CM_PERFECT_FWD_CTOR(uv_timer_ptr, uv_handle_ptr_<uv_timer_t>); + + int init(uv_loop_t& loop, void* data = nullptr); + + int start(uv_timer_cb cb, uint64_t timeout, uint64_t repeat); +}; + +struct uv_tty_ptr : public uv_handle_ptr_<uv_tty_t> +{ + CM_PERFECT_FWD_CTOR(uv_tty_ptr, uv_handle_ptr_<uv_tty_t>); + + operator uv_stream_t*() const; + + int init(uv_loop_t& loop, int fd, int readable, void* data = nullptr); +}; + +typedef uv_handle_ptr_<uv_stream_t> uv_stream_ptr; +typedef uv_handle_ptr_<uv_handle_t> uv_handle_ptr; + +#ifndef cmUVHandlePtr_cxx + +extern template class uv_handle_ptr_base_<uv_handle_t>; + +#define UV_HANDLE_PTR_INSTANTIATE_EXTERN(NAME) \ + extern template class uv_handle_ptr_base_<uv_##NAME##_t>; \ + extern template class uv_handle_ptr_<uv_##NAME##_t>; + +UV_HANDLE_PTR_INSTANTIATE_EXTERN(async) + +UV_HANDLE_PTR_INSTANTIATE_EXTERN(signal) + +UV_HANDLE_PTR_INSTANTIATE_EXTERN(pipe) + +UV_HANDLE_PTR_INSTANTIATE_EXTERN(process) + +UV_HANDLE_PTR_INSTANTIATE_EXTERN(stream) + +UV_HANDLE_PTR_INSTANTIATE_EXTERN(timer) + +UV_HANDLE_PTR_INSTANTIATE_EXTERN(tty) + +#undef UV_HANDLE_PTR_INSTANTIATE_EXTERN + +#endif +} diff --git a/Source/cmUnsetCommand.cxx b/Source/cmUnsetCommand.cxx index 18bbdd7..cfaa1fd2 100644 --- a/Source/cmUnsetCommand.cxx +++ b/Source/cmUnsetCommand.cxx @@ -2,8 +2,6 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmUnsetCommand.h" -#include <string.h> - #include "cmAlgorithms.h" #include "cmMakefile.h" #include "cmSystemTools.h" @@ -19,19 +17,16 @@ bool cmUnsetCommand::InitialPass(std::vector<std::string> const& args, return false; } - const char* variable = args[0].c_str(); + auto const& variable = args[0]; // unset(ENV{VAR}) - if (cmHasLiteralPrefix(variable, "ENV{") && strlen(variable) > 5) { + if (cmHasLiteralPrefix(variable, "ENV{") && variable.size() > 5) { // what is the variable name - char* envVarName = new char[strlen(variable)]; - strncpy(envVarName, variable + 4, strlen(variable) - 5); - envVarName[strlen(variable) - 5] = '\0'; + auto const& envVarName = variable.substr(4, variable.size() - 5); #ifdef CMAKE_BUILD_WITH_CMAKE - cmSystemTools::UnsetEnv(envVarName); + cmSystemTools::UnsetEnv(envVarName.c_str()); #endif - delete[] envVarName; return true; } // unset(VAR) diff --git a/Source/cmUseMangledMesaCommand.cxx b/Source/cmUseMangledMesaCommand.cxx index c04a683..8d4b018 100644 --- a/Source/cmUseMangledMesaCommand.cxx +++ b/Source/cmUseMangledMesaCommand.cxx @@ -13,8 +13,8 @@ bool cmUseMangledMesaCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { // expected two arguments: - // arguement one: the full path to gl_mangle.h - // arguement two : directory for output of edited headers + // argument one: the full path to gl_mangle.h + // argument two : directory for output of edited headers if (args.size() != 2) { this->SetError("called with incorrect number of arguments"); return false; diff --git a/Source/cmVS141CLFlagTable.h b/Source/cmVS141CLFlagTable.h index c780d46..7d3e356 100644 --- a/Source/cmVS141CLFlagTable.h +++ b/Source/cmVS141CLFlagTable.h @@ -1,6 +1,10 @@ static cmVS7FlagTable cmVS141CLFlagTable[] = { // Enum Properties + { "DiagnosticsFormat", "diagnostics:classic", "Classic", "Classic", 0 }, + { "DiagnosticsFormat", "diagnostics:column", "Column", "Column", 0 }, + { "DiagnosticsFormat", "diagnostics:caret", "Caret", "Caret", 0 }, + { "DebugInformationFormat", "", "None", "None", 0 }, { "DebugInformationFormat", "Z7", "C7 compatible", "OldStyle", 0 }, { "DebugInformationFormat", "Zi", "Program Database", "ProgramDatabase", 0 }, diff --git a/Source/cmVSSetupHelper.cxx b/Source/cmVSSetupHelper.cxx index ea13649..c2f8deb 100644 --- a/Source/cmVSSetupHelper.cxx +++ b/Source/cmVSSetupHelper.cxx @@ -80,6 +80,14 @@ cmVSSetupAPIHelper::~cmVSSetupAPIHelper() CoUninitialize(); } +bool cmVSSetupAPIHelper::SetVSInstance(std::string const& vsInstallLocation) +{ + this->SpecifiedVSInstallLocation = vsInstallLocation; + cmSystemTools::ConvertToUnixSlashes(this->SpecifiedVSInstallLocation); + chosenInstanceInfo = VSInstanceInfo(); + return this->EnumerateAndChooseVSInstance(); +} + bool cmVSSetupAPIHelper::IsVS2017Installed() { return this->EnumerateAndChooseVSInstance(); @@ -265,13 +273,6 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() if (cmSystemTools::GetEnv("VS150COMNTOOLS", envVSCommonToolsDir)) { cmSystemTools::ConvertToUnixSlashes(envVSCommonToolsDir); } - // FIXME: If the environment variable value changes between runs - // of CMake within a given build tree the results are not defined. - // Instead we should save a CMAKE_GENERATOR_INSTANCE value in the cache - // (similar to CMAKE_GENERATOR_TOOLSET) to hold it persistently. - // Unfortunately doing so will require refactoring elsewhere in - // order to make sure the value is available in time to create - // the generator. std::vector<VSInstanceInfo> vecVSInstances; SmartCOMPtr<IEnumSetupInstances> enumInstances = NULL; @@ -296,16 +297,29 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() instance = instance2 = NULL; if (isInstalled) { - if (!envVSCommonToolsDir.empty()) { + if (!this->SpecifiedVSInstallLocation.empty()) { + // We are looking for a specific instance. std::string currentVSLocation = instanceInfo.GetInstallLocation(); - currentVSLocation += "/Common7/Tools"; if (cmSystemTools::ComparePath(currentVSLocation, - envVSCommonToolsDir)) { + this->SpecifiedVSInstallLocation)) { chosenInstanceInfo = instanceInfo; return true; } + } else { + // We are not looking for a specific instance. + // If we've been given a hint then use it. + if (!envVSCommonToolsDir.empty()) { + std::string currentVSLocation = instanceInfo.GetInstallLocation(); + currentVSLocation += "/Common7/Tools"; + if (cmSystemTools::ComparePath(currentVSLocation, + envVSCommonToolsDir)) { + chosenInstanceInfo = instanceInfo; + return true; + } + } + // Otherwise, add this to the list of candidates. + vecVSInstances.push_back(instanceInfo); } - vecVSInstances.push_back(instanceInfo); } } diff --git a/Source/cmVSSetupHelper.h b/Source/cmVSSetupHelper.h index 74a7ec0..c07cfaf 100644 --- a/Source/cmVSSetupHelper.h +++ b/Source/cmVSSetupHelper.h @@ -126,6 +126,8 @@ public: cmVSSetupAPIHelper(); ~cmVSSetupAPIHelper(); + bool SetVSInstance(std::string const& vsInstallLocation); + bool IsVS2017Installed(); bool GetVSInstanceInfo(std::string& vsInstallLocation); bool IsWin10SDKInstalled(); @@ -150,6 +152,8 @@ private: HRESULT comInitialized; // current best instance of VS selected VSInstanceInfo chosenInstanceInfo; + + std::string SpecifiedVSInstallLocation; }; #endif diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index c61902a..caeeeb9 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -15,6 +15,7 @@ #include "cmVisualStudioGeneratorOptions.h" #include "windows.h" +#include <iterator> #include <memory> // IWYU pragma: keep static std::string cmVS10EscapeXML(std::string arg) @@ -1174,6 +1175,15 @@ void cmVisualStudio10TargetGenerator::WriteCustomCommands() si != customCommands.end(); ++si) { this->WriteCustomCommand(*si); } + + // Add CMakeLists.txt file with rule to re-run CMake for user convenience. + if (this->GeneratorTarget->GetType() != cmStateEnums::GLOBAL_TARGET && + this->GeneratorTarget->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) { + if (cmSourceFile const* sf = + this->LocalGenerator->CreateVCProjBuildRule()) { + this->WriteCustomCommand(sf); + } + } } void cmVisualStudio10TargetGenerator::WriteCustomCommand( @@ -1459,11 +1469,14 @@ void cmVisualStudio10TargetGenerator::WriteGroups() } this->WriteString("<ItemGroup>\n", 1); - for (std::set<cmSourceGroup*>::iterator g = groupsUsed.begin(); - g != groupsUsed.end(); ++g) { - cmSourceGroup* sg = *g; - const char* name = sg->GetFullName(); - if (strlen(name) != 0) { + std::vector<cmSourceGroup*> groupsVec(groupsUsed.begin(), groupsUsed.end()); + std::sort(groupsVec.begin(), groupsVec.end(), + [](cmSourceGroup* l, cmSourceGroup* r) { + return l->GetFullName() < r->GetFullName(); + }); + for (cmSourceGroup* sg : groupsVec) { + std::string const& name = sg->GetFullName(); + if (!name.empty()) { this->WriteString("<Filter Include=\"", 2); (*this->BuildFileStream) << name << "\">\n"; std::string guidName = "SG_Filter_"; @@ -1548,12 +1561,12 @@ void cmVisualStudio10TargetGenerator::WriteGroupSources( std::string const& source = sf->GetFullPath(); cmSourceGroup* sourceGroup = this->Makefile->FindSourceGroup(source.c_str(), sourceGroups); - const char* filter = sourceGroup->GetFullName(); + std::string const& filter = sourceGroup->GetFullName(); this->WriteString("<", 2); std::string path = this->ConvertPath(source, s->RelativePath); this->ConvertToWindowsSlash(path); (*this->BuildFileStream) << name << " Include=\"" << cmVS10EscapeXML(path); - if (strlen(filter)) { + if (!filter.empty()) { (*this->BuildFileStream) << "\">\n"; this->WriteString("<Filter>", 3); (*this->BuildFileStream) << filter << "</Filter>\n"; @@ -1592,6 +1605,8 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(cmSourceFile const* sf) std::string shaderEntryPoint; std::string shaderModel; std::string shaderAdditionalFlags; + std::string shaderDisableOptimizations; + std::string shaderEnableDebug; std::string outputHeaderFile; std::string variableName; std::string settingsGenerator; @@ -1658,6 +1673,16 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(cmSourceFile const* sf) shaderAdditionalFlags = saf; toolHasSettings = true; } + // Figure out if debug information should be generated + if (const char* sed = sf->GetProperty("VS_SHADER_ENABLE_DEBUG")) { + shaderEnableDebug = cmSystemTools::IsOn(sed) ? "true" : "false"; + toolHasSettings = true; + } + // Figure out if optimizations should be disabled + if (const char* sdo = sf->GetProperty("VS_SHADER_DISABLE_OPTIMIZATIONS")) { + shaderDisableOptimizations = cmSystemTools::IsOn(sdo) ? "true" : "false"; + toolHasSettings = true; + } } else if (ext == "jpg" || ext == "png") { tool = "Image"; } else if (ext == "resw") { @@ -1667,12 +1692,8 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(cmSourceFile const* sf) } else if (ext == "natvis") { tool = "Natvis"; } else if (ext == "settings") { - // remove path to current source dir (if files are in current source dir) - if (!sourceLink.empty()) { - settingsLastGenOutput = sourceLink; - } else { - settingsLastGenOutput = sf->GetFullPath(); - } + settingsLastGenOutput = + cmsys::SystemTools::GetFilenameName(sf->GetFullPath()); std::size_t pos = settingsLastGenOutput.find(".settings"); settingsLastGenOutput.replace(pos, 9, ".Designer.cs"); settingsGenerator = "SettingsSingleFileGenerator"; @@ -1800,6 +1821,16 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(cmSourceFile const* sf) this->WriteString("</VariableName>\n", 0); } } + if (!shaderEnableDebug.empty()) { + this->WriteString("<EnableDebuggingInformation>", 3); + (*this->BuildFileStream) << cmVS10EscapeXML(shaderEnableDebug) + << "</EnableDebuggingInformation>\n"; + } + if (!shaderDisableOptimizations.empty()) { + this->WriteString("<DisableOptimizations>", 3); + (*this->BuildFileStream) << cmVS10EscapeXML(shaderDisableOptimizations) + << "</DisableOptimizations>\n"; + } if (!shaderAdditionalFlags.empty()) { this->WriteString("<AdditionalOptions>", 3); (*this->BuildFileStream) << cmVS10EscapeXML(shaderAdditionalFlags) @@ -2359,14 +2390,14 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( // Choose a language whose flags to use for ClCompile. static const char* clLangs[] = { "CXX", "C", "Fortran", "CSharp" }; std::string langForClCompile; - if (std::find(cmArrayBegin(clLangs), cmArrayEnd(clLangs), linkLanguage) != - cmArrayEnd(clLangs)) { + if (std::find(cm::cbegin(clLangs), cm::cend(clLangs), linkLanguage) != + cm::cend(clLangs)) { langForClCompile = linkLanguage; } else { std::set<std::string> languages; this->GeneratorTarget->GetLanguages(languages, configName); - for (const char* const* l = cmArrayBegin(clLangs); - l != cmArrayEnd(clLangs); ++l) { + for (const char* const* l = cm::cbegin(clLangs); l != cm::cend(clLangs); + ++l) { if (languages.find(*l) != languages.end()) { langForClCompile = *l; break; diff --git a/Source/cmXCodeObject.cxx b/Source/cmXCodeObject.cxx index e54f1f3..1747c9c 100644 --- a/Source/cmXCodeObject.cxx +++ b/Source/cmXCodeObject.cxx @@ -115,16 +115,15 @@ void cmXCodeObject::Print(std::ostream& out) if (separator == "\n") { out << separator; } - std::map<std::string, cmXCodeObject*>::iterator i; cmXCodeObject::Indent(3 * indentFactor, out); out << "isa = " << PBXTypeNames[this->IsA] << ";" << separator; - for (i = this->ObjectAttributes.begin(); i != this->ObjectAttributes.end(); - ++i) { - if (i->first == "isa") { + for (const auto& keyVal : this->ObjectAttributes) { + if (keyVal.first == "isa") { continue; } - PrintAttribute(out, 3, separator, indentFactor, i->first, i->second, this); + PrintAttribute(out, 3, separator, indentFactor, keyVal.first, + keyVal.second, this); } cmXCodeObject::Indent(2 * indentFactor, out); out << "};\n"; @@ -167,11 +166,9 @@ void cmXCodeObject::PrintAttribute(std::ostream& out, int level, if (separator == "\n") { out << separator; } - std::map<std::string, cmXCodeObject*>::const_iterator i; - for (i = object->ObjectAttributes.begin(); - i != object->ObjectAttributes.end(); ++i) { - PrintAttribute(out, (level + 1) * factor, separator, factor, i->first, - i->second, object); + for (const auto& keyVal : object->ObjectAttributes) { + PrintAttribute(out, (level + 1) * factor, separator, factor, + keyVal.first, keyVal.second, object); } cmXCodeObject::Indent(level * factor, out); out << "};" << separator; @@ -221,7 +218,7 @@ void cmXCodeObject::CopyAttributes(cmXCodeObject* copy) this->Object = copy->Object; } -void cmXCodeObject::PrintString(std::ostream& os, std::string String) +void cmXCodeObject::PrintString(std::ostream& os, const std::string& String) { // The string needs to be quoted if it contains any characters // considered special by the Xcode project file parser. @@ -234,13 +231,12 @@ void cmXCodeObject::PrintString(std::ostream& os, std::string String) // Print the string, quoted and escaped as necessary. os << quote; - for (std::string::const_iterator i = String.begin(); i != String.end(); - ++i) { - if (*i == '"' || *i == '\\') { + for (auto c : String) { + if (c == '"' || c == '\\') { // Escape double-quotes and backslashes. os << '\\'; } - os << *i; + os << c; } os << quote; } diff --git a/Source/cmXCodeObject.h b/Source/cmXCodeObject.h index b0f1d31..51e5d36 100644 --- a/Source/cmXCodeObject.h +++ b/Source/cmXCodeObject.h @@ -150,7 +150,7 @@ public: return this->List; } void SetComment(const std::string& c) { this->Comment = c; } - static void PrintString(std::ostream& os, std::string String); + static void PrintString(std::ostream& os, const std::string& String); protected: void PrintString(std::ostream& os) const; diff --git a/Source/cmXMLWriter.h b/Source/cmXMLWriter.h index 981255d..c890acf 100644 --- a/Source/cmXMLWriter.h +++ b/Source/cmXMLWriter.h @@ -7,6 +7,8 @@ #include "cmXMLSafe.h" +#include <chrono> +#include <ctime> #include <ostream> #include <stack> #include <string> @@ -99,6 +101,22 @@ private: return cmXMLSafe(value).Quotes(false); } + /* + * Convert a std::chrono::system::time_point to the number of seconds since + * the UN*X epoch. + * + * It would be tempting to convert a time_point to number of seconds by + * using time_since_epoch(). Unfortunately the C++11 standard does not + * specify what the epoch of the system_clock must be. + * Therefore we must assume it is an arbitary point in time. Instead of this + * method, it is recommended to convert it by means of the to_time_t method. + */ + static std::time_t SafeContent( + std::chrono::system_clock::time_point const& value) + { + return std::chrono::system_clock::to_time_t(value); + } + template <typename T> static T SafeContent(T value) { diff --git a/Source/cm_codecvt.cxx b/Source/cm_codecvt.cxx index cf55741..6705851 100644 --- a/Source/cm_codecvt.cxx +++ b/Source/cm_codecvt.cxx @@ -38,12 +38,14 @@ codecvt::codecvt(Encoding e) } } -codecvt::~codecvt(){}; +codecvt::~codecvt() +{ +} bool codecvt::do_always_noconv() const throw() { return m_noconv; -}; +} std::codecvt_base::result codecvt::do_out(mbstate_t& state, const char* from, const char* from_end, @@ -122,7 +124,7 @@ std::codecvt_base::result codecvt::do_out(mbstate_t& state, const char* from, static_cast<void>(to_next); return std::codecvt_base::noconv; #endif -}; +} std::codecvt_base::result codecvt::do_unshift(mbstate_t& state, char* to, char* to_end, @@ -143,7 +145,7 @@ std::codecvt_base::result codecvt::do_unshift(mbstate_t& state, char* to, static_cast<void>(to_end); return std::codecvt_base::ok; #endif -}; +} #if defined(_WIN32) std::codecvt_base::result codecvt::Decode(mbstate_t& state, int size, @@ -235,9 +237,9 @@ void codecvt::BufferPartial(mbstate_t& state, int size, int codecvt::do_max_length() const throw() { return 4; -}; +} int codecvt::do_encoding() const throw() { return 0; -}; +} diff --git a/Source/cm_thread.hxx b/Source/cm_thread.hxx new file mode 100644 index 0000000..ec5fe1d --- /dev/null +++ b/Source/cm_thread.hxx @@ -0,0 +1,84 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef CM_THREAD_HXX +#define CM_THREAD_HXX + +#include "cmConfigure.h" // IWYU pragma: keep +#include "cm_uv.h" + +namespace cm { +class mutex +{ + CM_DISABLE_COPY(mutex) + uv_mutex_t _M_; + +public: + mutex() { uv_mutex_init(&_M_); } + ~mutex() { uv_mutex_destroy(&_M_); } + + void lock() { uv_mutex_lock(&_M_); } + + void unlock() { uv_mutex_unlock(&_M_); } +}; + +template <typename T> +class lock_guard +{ + T& _mutex; + CM_DISABLE_COPY(lock_guard) + +public: + lock_guard(T& m) + : _mutex(m) + { + _mutex.lock(); + } + ~lock_guard() { _mutex.unlock(); } +}; + +class shared_mutex +{ + uv_rwlock_t _M_; + CM_DISABLE_COPY(shared_mutex) + +public: + shared_mutex() { uv_rwlock_init(&_M_); } + ~shared_mutex() { uv_rwlock_destroy(&_M_); } + + void lock() { uv_rwlock_wrlock(&_M_); } + + void unlock() { uv_rwlock_wrunlock(&_M_); } + + void lock_shared() { uv_rwlock_rdlock(&_M_); } + + void unlock_shared() { uv_rwlock_rdunlock(&_M_); } +}; + +template <typename T> +class shared_lock +{ + T& _mutex; + CM_DISABLE_COPY(shared_lock) + +public: + shared_lock(T& m) + : _mutex(m) + { + _mutex.lock_shared(); + } + ~shared_lock() { _mutex.unlock_shared(); } +}; + +template <typename T> +class unique_lock : public lock_guard<T> +{ + CM_DISABLE_COPY(unique_lock) + +public: + unique_lock(T& m) + : lock_guard<T>(m) + { + } +}; +} +#endif diff --git a/Source/cmake.cxx b/Source/cmake.cxx index fd7151f..2a5bb6c 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -110,6 +110,7 @@ #include "cmsys/RegularExpression.hxx" #include <algorithm> #include <iostream> +#include <iterator> #include <memory> // IWYU pragma: keep #include <sstream> #include <stdio.h> @@ -199,6 +200,11 @@ cmake::cmake(Role role) this->SourceFileExtensions.push_back("M"); this->SourceFileExtensions.push_back("mm"); + std::copy(this->SourceFileExtensions.begin(), + this->SourceFileExtensions.end(), + std::inserter(this->SourceFileExtensionsSet, + this->SourceFileExtensionsSet.end())); + this->HeaderFileExtensions.push_back("h"); this->HeaderFileExtensions.push_back("hh"); this->HeaderFileExtensions.push_back("h++"); @@ -207,6 +213,11 @@ cmake::cmake(Role role) this->HeaderFileExtensions.push_back("hxx"); this->HeaderFileExtensions.push_back("in"); this->HeaderFileExtensions.push_back("txx"); + + std::copy(this->HeaderFileExtensions.begin(), + this->HeaderFileExtensions.end(), + std::inserter(this->HeaderFileExtensionsSet, + this->HeaderFileExtensionsSet.end())); } cmake::~cmake() @@ -1326,6 +1337,25 @@ int cmake::ActualConfigure() cmStateEnums::INTERNAL); } + if (const char* instance = + this->State->GetInitializedCacheValue("CMAKE_GENERATOR_INSTANCE")) { + if (!this->GeneratorInstance.empty() && + this->GeneratorInstance != instance) { + std::string message = "Error: generator instance: "; + message += this->GeneratorInstance; + message += "\nDoes not match the instance used previously: "; + message += instance; + message += "\nEither remove the CMakeCache.txt file and CMakeFiles " + "directory or choose a different binary directory."; + cmSystemTools::Error(message.c_str()); + return -2; + } + } else { + this->AddCacheEntry( + "CMAKE_GENERATOR_INSTANCE", this->GeneratorInstance.c_str(), + "Generator instance identifier.", cmStateEnums::INTERNAL); + } + if (const char* platformName = this->State->GetInitializedCacheValue("CMAKE_GENERATOR_PLATFORM")) { if (!this->GeneratorPlatform.empty() && @@ -1453,12 +1483,12 @@ void cmake::CreateDefaultGlobalGenerator() if (vsSetupAPIHelper.IsVS2017Installed()) { found = "Visual Studio 15 2017"; } else { - for (VSVersionedGenerator const* g = cmArrayBegin(vsGenerators); - found.empty() && g != cmArrayEnd(vsGenerators); ++g) { - for (const char* const* v = cmArrayBegin(vsVariants); - found.empty() && v != cmArrayEnd(vsVariants); ++v) { - for (const char* const* e = cmArrayBegin(vsEntries); - found.empty() && e != cmArrayEnd(vsEntries); ++e) { + for (VSVersionedGenerator const* g = cm::cbegin(vsGenerators); + found.empty() && g != cm::cend(vsGenerators); ++g) { + for (const char* const* v = cm::cbegin(vsVariants); + found.empty() && v != cm::cend(vsVariants); ++v) { + for (const char* const* e = cm::cbegin(vsEntries); + found.empty() && e != cm::cend(vsEntries); ++e) { std::string const reg = vsregBase + *v + g->MSVersion + *e; std::string dir; if (cmSystemTools::ReadRegistryValue(reg, dir, @@ -1627,6 +1657,21 @@ void cmake::AddCacheEntry(const std::string& key, const char* value, this->UnwatchUnusedCli(key); } +std::string cmake::StripExtension(const std::string& file) const +{ + auto dotpos = file.rfind('.'); + if (dotpos != std::string::npos) { + auto ext = file.substr(dotpos + 1); +#if defined(_WIN32) || defined(__APPLE__) + ext = cmSystemTools::LowerCase(ext); +#endif + if (this->IsSourceExtension(ext) || this->IsHeaderExtension(ext)) { + return file.substr(0, dotpos); + } + } + return file; +} + const char* cmake::GetCacheDefinition(const std::string& name) const { return this->State->GetInitializedCacheValue(name); @@ -1716,8 +1761,8 @@ bool cmake::LoadCache(const std::string& path, bool internal, bool result = this->State->LoadCache(path, internal, excludes, includes); static const char* entries[] = { "CMAKE_CACHE_MAJOR_VERSION", "CMAKE_CACHE_MINOR_VERSION" }; - for (const char* const* nameIt = cmArrayBegin(entries); - nameIt != cmArrayEnd(entries); ++nameIt) { + for (const char* const* nameIt = cm::cbegin(entries); + nameIt != cm::cend(entries); ++nameIt) { this->UnwatchUnusedCli(*nameIt); } return result; @@ -1730,8 +1775,8 @@ bool cmake::SaveCache(const std::string& path) "CMAKE_CACHE_MINOR_VERSION", "CMAKE_CACHE_PATCH_VERSION", "CMAKE_CACHEFILE_DIR" }; - for (const char* const* nameIt = cmArrayBegin(entries); - nameIt != cmArrayEnd(entries); ++nameIt) { + for (const char* const* nameIt = cm::cbegin(entries); + nameIt != cm::cend(entries); ++nameIt) { this->UnwatchUnusedCli(*nameIt); } return result; @@ -2360,6 +2405,14 @@ int cmake::Build(const std::string& dir, const std::string& target, << "\"\n"; return 1; } + const char* cachedGeneratorInstance = + this->State->GetCacheEntryValue("CMAKE_GENERATOR_INSTANCE"); + if (cachedGeneratorInstance) { + cmMakefile mf(gen.get(), this->GetCurrentSnapshot()); + if (!gen->SetGeneratorInstance(cachedGeneratorInstance, &mf)) { + return 1; + } + } std::string output; std::string projName; const char* cachedProjectName = @@ -2425,6 +2478,49 @@ int cmake::Build(const std::string& dir, const std::string& target, nativeOptions); } +bool cmake::Open(const std::string& dir, bool dryRun) +{ + this->SetHomeDirectory(""); + this->SetHomeOutputDirectory(""); + if (!cmSystemTools::FileIsDirectory(dir)) { + std::cerr << "Error: " << dir << " is not a directory\n"; + return false; + } + + std::string cachePath = FindCacheFile(dir); + if (!this->LoadCache(cachePath)) { + std::cerr << "Error: could not load cache\n"; + return false; + } + const char* genName = this->State->GetCacheEntryValue("CMAKE_GENERATOR"); + if (!genName) { + std::cerr << "Error: could not find CMAKE_GENERATOR in Cache\n"; + return false; + } + const char* extraGenName = + this->State->GetInitializedCacheValue("CMAKE_EXTRA_GENERATOR"); + std::string fullName = + cmExternalMakefileProjectGenerator::CreateFullGeneratorName( + genName, extraGenName ? extraGenName : ""); + + std::unique_ptr<cmGlobalGenerator> gen( + this->CreateGlobalGenerator(fullName)); + if (!gen.get()) { + std::cerr << "Error: could create CMAKE_GENERATOR \"" << fullName + << "\"\n"; + return false; + } + + const char* cachedProjectName = + this->State->GetCacheEntryValue("CMAKE_PROJECT_NAME"); + if (!cachedProjectName) { + std::cerr << "Error: could not find CMAKE_PROJECT_NAME in Cache\n"; + return false; + } + + return gen->Open(dir, cachedProjectName, dryRun); +} + void cmake::WatchUnusedCli(const std::string& var) { #ifdef CMAKE_BUILD_WITH_CMAKE diff --git a/Source/cmake.h b/Source/cmake.h index b31b6f5..02c6cdb 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -8,6 +8,7 @@ #include <map> #include <set> #include <string> +#include <unordered_set> #include <vector> #include "cmInstalledFile.h" @@ -203,6 +204,12 @@ public: ///! Get the names of the current registered generators void GetRegisteredGenerators(std::vector<GeneratorInfo>& generators) const; + ///! Set the name of the selected generator-specific instance. + void SetGeneratorInstance(std::string const& instance) + { + this->GeneratorInstance = instance; + } + ///! Set the name of the selected generator-specific platform. void SetGeneratorPlatform(std::string const& ts) { @@ -219,11 +226,27 @@ public: { return this->SourceFileExtensions; } + + bool IsSourceExtension(const std::string& ext) const + { + return this->SourceFileExtensionsSet.find(ext) != + this->SourceFileExtensionsSet.end(); + } + const std::vector<std::string>& GetHeaderExtensions() const { return this->HeaderFileExtensions; } + bool IsHeaderExtension(const std::string& ext) const + { + return this->HeaderFileExtensionsSet.find(ext) != + this->HeaderFileExtensionsSet.end(); + } + + // Strips the extension (if present and known) from a filename + std::string StripExtension(const std::string& file) const; + /** * Given a variable name, return its value (as a string). */ @@ -401,6 +424,9 @@ public: const std::string& config, const std::vector<std::string>& nativeOptions, bool clean); + ///! run the --open option + bool Open(const std::string& dir, bool dryRun); + void UnwatchUnusedCli(const std::string& var); void WatchUnusedCli(const std::string& var); @@ -428,6 +454,7 @@ protected: cmGlobalGenerator* GlobalGenerator; std::map<std::string, DiagLevel> DiagLevels; + std::string GeneratorInstance; std::string GeneratorPlatform; std::string GeneratorToolset; @@ -476,7 +503,9 @@ private: std::string CheckStampList; std::string VSSolutionFile; std::vector<std::string> SourceFileExtensions; + std::unordered_set<std::string> SourceFileExtensionsSet; std::vector<std::string> HeaderFileExtensions; + std::unordered_set<std::string> HeaderFileExtensionsSet; bool ClearBuildSystem; bool DebugTryCompile; cmFileTimeComparison* FileComparison; diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index a1dfc3e..59b908a 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -66,6 +66,7 @@ static const char* cmDocumentationOptions[][2] = { { "-E", "CMake command mode." }, { "-L[A][H]", "List non-advanced cached variables." }, { "--build <dir>", "Build a CMake-generated project binary tree." }, + { "--open <dir>", "Open generated project in the associated application." }, { "-N", "View mode only." }, { "-P <file>", "Process script mode." }, { "--find-package", "Run in pkg-config like mode." }, @@ -100,6 +101,7 @@ static int do_command(int ac, char const* const* av) int do_cmake(int ac, char const* const* av); static int do_build(int ac, char const* const* av); +static int do_open(int ac, char const* const* av); static cmMakefile* cmakemainGetMakefile(void* clientdata) { @@ -186,6 +188,9 @@ int main(int ac, char const* const* av) if (strcmp(av[1], "--build") == 0) { return do_build(ac, av); } + if (strcmp(av[1], "--open") == 0) { + return do_open(ac, av); + } if (strcmp(av[1], "-E") == 0) { return do_command(ac, av); } @@ -423,3 +428,41 @@ static int do_build(int ac, char const* const* av) return cm.Build(dir, target, config, nativeOptions, clean); #endif } + +static int do_open(int ac, char const* const* av) +{ +#ifndef CMAKE_BUILD_WITH_CMAKE + std::cerr << "This cmake does not support --open\n"; + return -1; +#else + std::string dir; + + enum Doing + { + DoingNone, + DoingDir, + }; + Doing doing = DoingDir; + for (int i = 2; i < ac; ++i) { + switch (doing) { + case DoingDir: + dir = cmSystemTools::CollapseFullPath(av[i]); + doing = DoingNone; + break; + default: + std::cerr << "Unknown argument " << av[i] << std::endl; + dir.clear(); + break; + } + } + if (dir.empty()) { + std::cerr << "Usage: cmake --open <dir>\n"; + return 1; + } + + cmake cm(cmake::RoleInternal); + cmSystemTools::SetMessageCallback(cmakemainMessageCallback, &cm); + cm.SetProgressCallback(cmakemainProgressCallback, &cm); + return cm.Open(dir, false) ? 0 : 1; +#endif +} diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 69339b4..3d9f65a 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -6,7 +6,8 @@ #include "cmGlobalGenerator.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" -#include "cmQtAutoGenerators.h" +#include "cmQtAutoGeneratorMocUic.h" +#include "cmQtAutoGeneratorRcc.h" #include "cmStateDirectory.h" #include "cmStateSnapshot.h" #include "cmSystemTools.h" @@ -34,6 +35,7 @@ #include "cmsys/Terminal.h" #include <algorithm> #include <iostream> +#include <iterator> #include <memory> // IWYU pragma: keep #include <sstream> #include <stdio.h> @@ -371,8 +373,8 @@ int cmcmd::HandleCoCompileCommands(std::vector<std::string>& args) doing_options = false; } else if (doing_options) { bool optionFound = false; - for (CoCompiler const* cc = cmArrayBegin(CoCompilers); - cc != cmArrayEnd(CoCompilers); ++cc) { + for (CoCompiler const* cc = cm::cbegin(CoCompilers); + cc != cm::cend(CoCompilers); ++cc) { size_t optionLen = strlen(cc->Option); if (arg.compare(0, optionLen, cc->Option) == 0) { optionFound = true; @@ -402,8 +404,8 @@ int cmcmd::HandleCoCompileCommands(std::vector<std::string>& args) if (jobs.empty()) { std::cerr << "__run_co_compile missing command to run. " "Looking for one or more of the following:\n"; - for (CoCompiler const* cc = cmArrayBegin(CoCompilers); - cc != cmArrayEnd(CoCompilers); ++cc) { + for (CoCompiler const* cc = cm::cbegin(CoCompilers); + cc != cm::cend(CoCompilers); ++cc) { std::cerr << cc->Option << "\n"; } return 1; @@ -991,11 +993,20 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args) } #ifdef CMAKE_BUILD_WITH_CMAKE - if (args[1] == "cmake_autogen" && args.size() >= 4) { - cmQtAutoGenerators autogen; + if ((args[1] == "cmake_autogen") && (args.size() >= 4)) { + cmQtAutoGeneratorMocUic autoGen; + std::string const& infoDir = args[2]; std::string const& config = args[3]; - bool autogenSuccess = autogen.Run(args[2], config); - return autogenSuccess ? 0 : 1; + return autoGen.Run(infoDir, config) ? 0 : 1; + } + if ((args[1] == "cmake_autorcc") && (args.size() >= 3)) { + cmQtAutoGeneratorRcc autoGen; + std::string const& infoFile = args[2]; + std::string config; + if (args.size() > 3) { + config = args[3]; + }; + return autoGen.Run(infoFile, config) ? 0 : 1; } #endif @@ -1024,8 +1035,8 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args) } else if (cmHasLiteralPrefix(arg, "--format=")) { format = arg.substr(9); bool isKnown = - std::find(cmArrayBegin(knownFormats), cmArrayEnd(knownFormats), - format) != cmArrayEnd(knownFormats); + std::find(cm::cbegin(knownFormats), cm::cend(knownFormats), + format) != cm::cend(knownFormats); if (!isKnown) { cmSystemTools::Error("Unknown -E tar --format= argument: ", diff --git a/Source/ctest.cxx b/Source/ctest.cxx index f6466fa..ad5fec0 100644 --- a/Source/ctest.cxx +++ b/Source/ctest.cxx @@ -104,8 +104,6 @@ static const char* cmDocumentationOptions[][2] = { { "--test-timeout", "The time limit in seconds, internal use only." }, { "--test-load", "CPU load threshold for starting new parallel tests." }, { "--tomorrow-tag", "Nightly or experimental starts with next day tag." }, - { "--ctest-config", "The configuration file used to initialize CTest state " - "when submitting dashboards." }, { "--overwrite", "Overwrite CTest configuration option." }, { "--extra-submit <file>[;<file>]", "Submit extra files to the dashboard." }, { "--force-new-ctest-process", diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt index 21568bb..64b6484 100644 --- a/Source/kwsys/CMakeLists.txt +++ b/Source/kwsys/CMakeLists.txt @@ -445,8 +445,13 @@ KWSYS_PLATFORM_C_TEST(KWSYS_C_HAS_PTRDIFF_T "Checking whether C compiler has ptrdiff_t in stddef.h" DIRECT) KWSYS_PLATFORM_C_TEST(KWSYS_C_HAS_SSIZE_T "Checking whether C compiler has ssize_t in unistd.h" DIRECT) +IF(KWSYS_USE_Process) + KWSYS_PLATFORM_C_TEST(KWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC + "Checking whether C compiler has clock_gettime" DIRECT) +ENDIF() + SET_SOURCE_FILES_PROPERTIES(ProcessUNIX.c System.c PROPERTIES - COMPILE_FLAGS "-DKWSYS_C_HAS_PTRDIFF_T=${KWSYS_C_HAS_PTRDIFF_T} -DKWSYS_C_HAS_SSIZE_T=${KWSYS_C_HAS_SSIZE_T}" + COMPILE_FLAGS "-DKWSYS_C_HAS_PTRDIFF_T=${KWSYS_C_HAS_PTRDIFF_T} -DKWSYS_C_HAS_SSIZE_T=${KWSYS_C_HAS_SSIZE_T} -DKWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC=${KWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC}" ) IF(DEFINED KWSYS_PROCESS_USE_SELECT) @@ -1028,6 +1033,7 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) ) ENDIF() SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} + testConfigure testSystemTools testCommandLineArguments testCommandLineArguments1 @@ -1142,17 +1148,22 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) SET_TESTS_PROPERTIES(kwsys.testProcess-${n} PROPERTIES TIMEOUT 120) ENDFOREACH() + SET(testProcess_COMPILE_FLAGS "") # Some Apple compilers produce bad optimizations in this source. IF(APPLE AND CMAKE_C_COMPILER_ID MATCHES "^(GNU|LLVM)$") - SET_SOURCE_FILES_PROPERTIES(testProcess.c PROPERTIES COMPILE_FLAGS -O0) + SET(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -O0") ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "XL" AND NOT (CMAKE_SYSTEM MATCHES "Linux.*ppc64le" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS "13.1.1")) # Tell IBM XL not to warn about our test infinite loop # v13.1.1 and newer on Linux ppc64le is clang based and does not accept # the -qsuppress option - SET_PROPERTY(SOURCE testProcess.c PROPERTY COMPILE_FLAGS -qsuppress=1500-010) + SET(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -qsuppress=1500-010") + ENDIF() + IF(CMAKE_C_FLAGS MATCHES "-fsanitize=") + SET(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -DCRASH_USING_ABORT") ENDIF() + SET_PROPERTY(SOURCE testProcess.c PROPERTY COMPILE_FLAGS "${testProcess_COMPILE_FLAGS}") # Test SharedForward CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/testSharedForward.c.in diff --git a/Source/kwsys/CommandLineArguments.cxx b/Source/kwsys/CommandLineArguments.cxx index 5613bd7..5792da9 100644 --- a/Source/kwsys/CommandLineArguments.cxx +++ b/Source/kwsys/CommandLineArguments.cxx @@ -529,10 +529,7 @@ void CommandLineArguments::GenerateHelp() } } - // Create format for that string - char format[80]; - sprintf(format, " %%-%us ", static_cast<unsigned int>(maxlen)); - + CommandLineArguments::Internal::String::size_type maxstrlen = maxlen; maxlen += 4; // For the space before and after the option // Print help for each option @@ -540,27 +537,24 @@ void CommandLineArguments::GenerateHelp() CommandLineArguments::Internal::SetOfStrings::iterator sit; for (sit = mpit->second.begin(); sit != mpit->second.end(); sit++) { str << std::endl; - char argument[100]; - sprintf(argument, "%s", sit->c_str()); + std::string argument = *sit; switch (this->Internals->Callbacks[*sit].ArgumentType) { case CommandLineArguments::NO_ARGUMENT: break; case CommandLineArguments::CONCAT_ARGUMENT: - strcat(argument, "opt"); + argument += "opt"; break; case CommandLineArguments::SPACE_ARGUMENT: - strcat(argument, " opt"); + argument += " opt"; break; case CommandLineArguments::EQUAL_ARGUMENT: - strcat(argument, "=opt"); + argument += "=opt"; break; case CommandLineArguments::MULTI_ARGUMENT: - strcat(argument, " opt opt ..."); + argument += " opt opt ..."; break; } - char buffer[80]; - sprintf(buffer, format, argument); - str << buffer; + str << " " << argument.substr(0, maxstrlen) << " "; } const char* ptr = this->Internals->Callbacks[mpit->first].Help; size_t len = strlen(ptr); @@ -649,10 +643,7 @@ void CommandLineArguments::PopulateVariable(double* variable, void CommandLineArguments::PopulateVariable(char** variable, const std::string& value) { - if (*variable) { - delete[] * variable; - *variable = 0; - } + delete[] * variable; *variable = new char[value.size() + 1]; strcpy(*variable, value.c_str()); } diff --git a/Source/kwsys/Configure.h.in b/Source/kwsys/Configure.h.in index 0afcae7..224047a 100644 --- a/Source/kwsys/Configure.h.in +++ b/Source/kwsys/Configure.h.in @@ -62,9 +62,6 @@ !defined(@KWSYS_NAMESPACE@_LFS_NO_DEFINE_FILE_OFFSET_BITS) #define _FILE_OFFSET_BITS 64 #endif -#if 0 && (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS < 64) -#error "_FILE_OFFSET_BITS must be defined to at least 64" -#endif #endif #endif diff --git a/Source/kwsys/Configure.hxx.in b/Source/kwsys/Configure.hxx.in index 1c07a4e..1e67874 100644 --- a/Source/kwsys/Configure.hxx.in +++ b/Source/kwsys/Configure.hxx.in @@ -12,6 +12,31 @@ #define @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H \ @KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H@ +#if defined(__SUNPRO_CC) && __SUNPRO_CC > 0x5130 && defined(__has_attribute) +#define @KWSYS_NAMESPACE@__has_cpp_attribute(x) __has_attribute(x) +#elif defined(__has_cpp_attribute) +#define @KWSYS_NAMESPACE@__has_cpp_attribute(x) __has_cpp_attribute(x) +#else +#define @KWSYS_NAMESPACE@__has_cpp_attribute(x) 0 +#endif + +#ifndef @KWSYS_NAMESPACE@_FALLTHROUGH +#if __cplusplus >= 201703L && @KWSYS_NAMESPACE@__has_cpp_attribute(fallthrough) +#define @KWSYS_NAMESPACE@_FALLTHROUGH [[fallthrough]] +#elif __cplusplus >= 201103L && \ + @KWSYS_NAMESPACE@__has_cpp_attribute(gnu::fallthrough) +#define @KWSYS_NAMESPACE@_FALLTHROUGH [[gnu::fallthrough]] +#elif __cplusplus >= 201103L && \ + @KWSYS_NAMESPACE@__has_cpp_attribute(clang::fallthrough) +#define @KWSYS_NAMESPACE@_FALLTHROUGH [[clang::fallthrough]] +#endif +#endif +#ifndef @KWSYS_NAMESPACE@_FALLTHROUGH +#define @KWSYS_NAMESPACE@_FALLTHROUGH static_cast<void>(0) +#endif + +#undef @KWSYS_NAMESPACE@__has_cpp_attribute + /* If building a C++ file in kwsys itself, give the source file access to the macros without a configured namespace. */ #if defined(KWSYS_NAMESPACE) @@ -22,6 +47,7 @@ #define KWSYS_STL_HAS_WSTRING @KWSYS_NAMESPACE@_STL_HAS_WSTRING #define KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H \ @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H +#define KWSYS_FALLTHROUGH @KWSYS_NAMESPACE@_FALLTHROUGH #endif #endif diff --git a/Source/kwsys/DynamicLoader.cxx b/Source/kwsys/DynamicLoader.cxx index 1b4596a..664f183 100644 --- a/Source/kwsys/DynamicLoader.cxx +++ b/Source/kwsys/DynamicLoader.cxx @@ -163,17 +163,13 @@ DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( { void* result = 0; // Need to prepend symbols with '_' on Apple-gcc compilers - size_t len = sym.size(); - char* rsym = new char[len + 1 + 1]; - strcpy(rsym, "_"); - strcat(rsym + 1, sym.c_str()); + std::string rsym = '_' + sym; - NSSymbol symbol = NSLookupSymbolInModule(lib, rsym); + NSSymbol symbol = NSLookupSymbolInModule(lib, rsym.c_str()); if (symbol) { result = NSAddressOfSymbol(symbol); } - delete[] rsym; // Hack to cast pointer-to-data to pointer-to-function. return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result); } @@ -237,17 +233,12 @@ DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( void* result; #if defined(__BORLANDC__) || defined(__WATCOMC__) // Need to prepend symbols with '_' - size_t len = sym.size(); - char* rsym = new char[len + 1 + 1]; - strcpy(rsym, "_"); - strcat(rsym, sym.c_str()); + std::string ssym = '_' + sym; + const char* rsym = ssym.c_str(); #else const char* rsym = sym.c_str(); #endif result = (void*)GetProcAddress(lib, rsym); -#if defined(__BORLANDC__) || defined(__WATCOMC__) - delete[] rsym; -#endif // Hack to cast pointer-to-data to pointer-to-function. #ifdef __WATCOMC__ return *(DynamicLoader::SymbolPointer*)(&result); diff --git a/Source/kwsys/DynamicLoader.hxx.in b/Source/kwsys/DynamicLoader.hxx.in index 7e71a45..dc34692 100644 --- a/Source/kwsys/DynamicLoader.hxx.in +++ b/Source/kwsys/DynamicLoader.hxx.in @@ -35,7 +35,7 @@ namespace @KWSYS_NAMESPACE@ { * or absolute) pathname. Otherwise, the dynamic linker searches for the * library as follows : see ld.so(8) for further details): * Whereas this distinction does not exist on Win32. Therefore ideally you - * should be doing full path to garantee to have a consistent way of dealing + * should be doing full path to guarantee to have a consistent way of dealing * with dynamic loading of shared library. * * \warning the Cygwin implementation do not use the Win32 HMODULE. Put extra @@ -72,7 +72,7 @@ public: static LibraryHandle OpenLibrary(const std::string&); /** Attempt to detach a dynamic library from the - * process. A value of true is returned if it is sucessful. */ + * process. A value of true is returned if it is successful. */ static int CloseLibrary(LibraryHandle); /** Find the address of the symbol in the given library. */ diff --git a/Source/kwsys/Process.h.in b/Source/kwsys/Process.h.in index 237001c..daf334a 100644 --- a/Source/kwsys/Process.h.in +++ b/Source/kwsys/Process.h.in @@ -77,6 +77,7 @@ #define kwsysProcess_WaitForExit kwsys_ns(Process_WaitForExit) #define kwsysProcess_Interrupt kwsys_ns(Process_Interrupt) #define kwsysProcess_Kill kwsys_ns(Process_Kill) +#define kwsysProcess_KillPID kwsys_ns(Process_KillPID) #define kwsysProcess_ResetStartTime kwsys_ns(Process_ResetStartTime) #endif @@ -420,7 +421,7 @@ enum kwsysProcess_Pipes_e /** * Block until the child process terminates or the given timeout - * expires. If no process is running, returns immediatly. The + * expires. If no process is running, returns immediately. The * argument is: * * timeout = Specifies the maximum time this call may block. Upon @@ -457,6 +458,13 @@ kwsysEXPORT void kwsysProcess_Interrupt(kwsysProcess* cp); kwsysEXPORT void kwsysProcess_Kill(kwsysProcess* cp); /** + * Same as kwsysProcess_Kill using process ID to locate process to + * terminate. + * @see kwsysProcess_Kill(kwsysProcess* cp) + */ +kwsysEXPORT void kwsysProcess_KillPID(unsigned long); + +/** * Reset the start time of the child process to the current time. */ kwsysEXPORT void kwsysProcess_ResetStartTime(kwsysProcess* cp); diff --git a/Source/kwsys/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c index 3b32ca7..718a1aa 100644 --- a/Source/kwsys/ProcessUNIX.c +++ b/Source/kwsys/ProcessUNIX.c @@ -359,9 +359,7 @@ void kwsysProcess_Delete(kwsysProcess* cp) kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDIN, 0); kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDOUT, 0); kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDERR, 0); - if (cp->CommandExitCodes) { - free(cp->CommandExitCodes); - } + free(cp->CommandExitCodes); free(cp->ProcessResults); free(cp); } @@ -498,11 +496,10 @@ int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir) cp->WorkingDirectory = 0; } if (dir) { - cp->WorkingDirectory = (char*)malloc(strlen(dir) + 1); + cp->WorkingDirectory = strdup(dir); if (!cp->WorkingDirectory) { return 0; } - strcpy(cp->WorkingDirectory, dir); } return 1; } @@ -531,11 +528,10 @@ int kwsysProcess_SetPipeFile(kwsysProcess* cp, int prPipe, const char* file) *pfile = 0; } if (file) { - *pfile = (char*)malloc(strlen(file) + 1); + *pfile = strdup(file); if (!*pfile) { return 0; } - strcpy(*pfile, file); } /* If we are redirecting the pipe, do not share it or use a native @@ -1514,9 +1510,7 @@ static int kwsysProcessInitialize(kwsysProcess* cp) oldForkPIDs = cp->ForkPIDs; cp->ForkPIDs = (volatile pid_t*)malloc(sizeof(volatile pid_t) * (size_t)(cp->NumberOfCommands)); - if (oldForkPIDs) { - kwsysProcessVolatileFree(oldForkPIDs); - } + kwsysProcessVolatileFree(oldForkPIDs); if (!cp->ForkPIDs) { return 0; } @@ -1524,9 +1518,7 @@ static int kwsysProcessInitialize(kwsysProcess* cp) cp->ForkPIDs[i] = 0; /* can't use memset due to volatile */ } - if (cp->CommandExitCodes) { - free(cp->CommandExitCodes); - } + free(cp->CommandExitCodes); cp->CommandExitCodes = (int*)malloc(sizeof(int) * (size_t)(cp->NumberOfCommands)); if (!cp->CommandExitCodes) { @@ -1938,6 +1930,7 @@ static int kwsysProcessSetupOutputPipeFile(int* p, const char* name) /* Set close-on-exec flag on the pipe's end. */ if (fcntl(fout, F_SETFD, FD_CLOEXEC) < 0) { + close(fout); return 0; } @@ -2033,7 +2026,15 @@ static kwsysProcessTime kwsysProcessTimeGetCurrent(void) { kwsysProcessTime current; kwsysProcessTimeNative current_native; +#if KWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC + struct timespec current_timespec; + clock_gettime(CLOCK_MONOTONIC, ¤t_timespec); + + current_native.tv_sec = current_timespec.tv_sec; + current_native.tv_usec = current_timespec.tv_nsec / 1000; +#else gettimeofday(¤t_native, 0); +#endif current.tv_sec = (long)current_native.tv_sec; current.tv_usec = (long)current_native.tv_usec; return current; @@ -2290,6 +2291,7 @@ static void kwsysProcessChildErrorExit(int errorPipe) char buffer[KWSYSPE_PIPE_BUFFER_SIZE]; kwsysProcess_ssize_t result; strncpy(buffer, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE); + buffer[KWSYSPE_PIPE_BUFFER_SIZE - 1] = '\0'; /* Report the error to the parent through the special pipe. */ result = write(errorPipe, buffer, strlen(buffer)); @@ -2483,6 +2485,11 @@ static pid_t kwsysProcessFork(kwsysProcess* cp, #define KWSYSPE_PS_FORMAT "%d %d %*[^\n]\n" #endif +void kwsysProcess_KillPID(unsigned long process_id) +{ + kwsysProcessKill((pid_t)process_id); +} + static void kwsysProcessKill(pid_t process_id) { #if defined(__linux__) || defined(__CYGWIN__) diff --git a/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c index 5183e3d..82fdc74 100644 --- a/Source/kwsys/ProcessWin32.c +++ b/Source/kwsys/ProcessWin32.c @@ -523,9 +523,7 @@ void kwsysProcess_Delete(kwsysProcess* cp) kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDIN, 0); kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDOUT, 0); kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDERR, 0); - if (cp->CommandExitCodes) { - free(cp->CommandExitCodes); - } + free(cp->CommandExitCodes); free(cp->ProcessResults); free(cp); } @@ -713,11 +711,10 @@ int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, const char* file) *pfile = 0; } if (file) { - *pfile = (char*)malloc(strlen(file) + 1); + *pfile = strdup(file); if (!*pfile) { return 0; } - strcpy(*pfile, file); } /* If we are redirecting the pipe, do not share it or use a native @@ -1469,6 +1466,11 @@ void kwsysProcess_Kill(kwsysProcess* cp) for them to exit. */ } +void kwsysProcess_KillPID(unsigned long process_id) +{ + kwsysProcessKillTree((DWORD)process_id); +} + /* Function executed for each pipe's thread. Argument is a pointer to the kwsysProcessPipeData instance for this thread. @@ -1607,9 +1609,7 @@ int kwsysProcessInitialize(kwsysProcess* cp) } ZeroMemory(cp->ProcessInformation, sizeof(PROCESS_INFORMATION) * cp->NumberOfCommands); - if (cp->CommandExitCodes) { - free(cp->CommandExitCodes); - } + free(cp->CommandExitCodes); cp->CommandExitCodes = (DWORD*)malloc(sizeof(DWORD) * cp->NumberOfCommands); if (!cp->CommandExitCodes) { return 0; @@ -2362,9 +2362,7 @@ static int kwsysProcess_List__New_NT4(kwsysProcess_List* self) static void kwsysProcess_List__Delete_NT4(kwsysProcess_List* self) { /* Free the process information buffer. */ - if (self->Buffer) { - free(self->Buffer); - } + free(self->Buffer); } static int kwsysProcess_List__Update_NT4(kwsysProcess_List* self) diff --git a/Source/kwsys/RegularExpression.hxx.in b/Source/kwsys/RegularExpression.hxx.in index 606e3da..763fdab 100644 --- a/Source/kwsys/RegularExpression.hxx.in +++ b/Source/kwsys/RegularExpression.hxx.in @@ -109,12 +109,12 @@ namespace @KWSYS_NAMESPACE@ { * object as an argument and creates an object initialized with the * information from the given RegularExpression object. * - * The find member function finds the first occurence of the regualr + * The find member function finds the first occurrence of the regular * expression of that object in the string given to find as an argument. Find * returns a boolean, and if true, mutates the private data appropriately. * Find sets pointers to the beginning and end of the thing last found, they * are pointers into the actual string that was searched. The start and end - * member functions return indicies into the searched string that correspond + * member functions return indices into the searched string that correspond * to the beginning and end pointers respectively. The compile member * function takes a char* and puts the compiled version of the char* argument * into the object's private data fields. The == and != operators only check diff --git a/Source/kwsys/SystemInformation.cxx b/Source/kwsys/SystemInformation.cxx index 86fdccd..ab1f40a 100644 --- a/Source/kwsys/SystemInformation.cxx +++ b/Source/kwsys/SystemInformation.cxx @@ -1346,7 +1346,7 @@ std::string SymbolProperties::GetBinary() const std::string binary; char buf[1024] = { '\0' }; ssize_t ll = 0; - if ((ll = readlink("/proc/self/exe", buf, 1024)) > 0) { + if ((ll = readlink("/proc/self/exe", buf, 1024)) > 0 && ll < 1024) { buf[ll] = '\0'; binary = buf; } else { @@ -3633,7 +3633,7 @@ SystemInformationImplementation::GetHostMemoryAvailable( // apply resource limits across groups of processes. // this is of use on certain SMP systems (eg. SGI UV) // where the host has a large amount of ram but a given user's - // access to it is severly restricted. The system will + // access to it is severely restricted. The system will // apply a limit across a set of processes. Units are in KiB. if (hostLimitEnvVarName) { const char* hostLimitEnvVarValue = getenv(hostLimitEnvVarName); diff --git a/Source/kwsys/SystemInformation.hxx.in b/Source/kwsys/SystemInformation.hxx.in index 516c505..5678e8a 100644 --- a/Source/kwsys/SystemInformation.hxx.in +++ b/Source/kwsys/SystemInformation.hxx.in @@ -124,7 +124,7 @@ public: // are the processes comprising an mpi program which is running in // parallel. The amount of memory reported may differ from the host // total if a host wide resource limit is applied. Such reource limits - // are reported to us via an applicaiton specified environment variable. + // are reported to us via an application specified environment variable. LongLong GetHostMemoryAvailable(const char* hostLimitEnvVarName = NULL); // Get total system RAM in units of KiB available to this process. diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx index ecfa331..50aa857 100644 --- a/Source/kwsys/SystemTools.cxx +++ b/Source/kwsys/SystemTools.cxx @@ -20,12 +20,14 @@ #include KWSYS_HEADER(SystemTools.hxx) #include KWSYS_HEADER(Directory.hxx) #include KWSYS_HEADER(FStream.hxx) +#include KWSYS_HEADER(Encoding.h) #include KWSYS_HEADER(Encoding.hxx) #include <fstream> #include <iostream> #include <set> #include <sstream> +#include <utility> #include <vector> // Work-around CMake dependency scanning limitation. This must @@ -227,13 +229,17 @@ inline const char* Getcwd(char* buf, unsigned int len) { std::vector<wchar_t> w_buf(len); if (_wgetcwd(&w_buf[0], len)) { - // make sure the drive letter is capital - if (wcslen(&w_buf[0]) > 1 && w_buf[1] == L':') { - w_buf[0] = towupper(w_buf[0]); + size_t nlen = kwsysEncoding_wcstombs(buf, &w_buf[0], len); + if (nlen == static_cast<size_t>(-1)) { + return 0; + } + if (nlen < len) { + // make sure the drive letter is capital + if (nlen > 1 && buf[1] == ':') { + buf[0] = toupper(buf[0]); + } + return buf; } - std::string tmp = KWSYS_NAMESPACE::Encoding::ToNarrow(&w_buf[0]); - strcpy(buf, tmp.c_str()); - return buf; } return 0; } @@ -746,15 +752,15 @@ FILE* SystemTools::Fopen(const std::string& file, const char* mode) #endif } -bool SystemTools::MakeDirectory(const char* path) +bool SystemTools::MakeDirectory(const char* path, const mode_t* mode) { if (!path) { return false; } - return SystemTools::MakeDirectory(std::string(path)); + return SystemTools::MakeDirectory(std::string(path), mode); } -bool SystemTools::MakeDirectory(const std::string& path) +bool SystemTools::MakeDirectory(const std::string& path, const mode_t* mode) { if (SystemTools::PathExists(path)) { return SystemTools::FileIsDirectory(path); @@ -769,8 +775,12 @@ bool SystemTools::MakeDirectory(const std::string& path) std::string topdir; while ((pos = dir.find('/', pos)) != std::string::npos) { topdir = dir.substr(0, pos); - Mkdir(topdir); - pos++; + + if (Mkdir(topdir) == 0 && mode != 0) { + SystemTools::SetPermissions(topdir, *mode); + } + + ++pos; } topdir = dir; if (Mkdir(topdir) != 0) { @@ -785,7 +795,10 @@ bool SystemTools::MakeDirectory(const std::string& path) ) { return false; } + } else if (mode != 0) { + SystemTools::SetPermissions(topdir, *mode); } + return true; } @@ -1679,7 +1692,7 @@ bool SystemTools::StringEndsWith(const std::string& str1, const char* str2) : false; } -// Returns a pointer to the last occurence of str2 in str1 +// Returns a pointer to the last occurrence of str2 in str1 const char* SystemTools::FindLastString(const char* str1, const char* str2) { if (!str1 || !str2) { @@ -3360,7 +3373,7 @@ std::string SystemTools::RelativePath(const std::string& local, } #ifdef _WIN32 -static std::string GetCasePathName(std::string const& pathIn) +static std::pair<std::string, bool> GetCasePathName(std::string const& pathIn) { std::string casePath; std::vector<std::string> path_components; @@ -3369,7 +3382,7 @@ static std::string GetCasePathName(std::string const& pathIn) { // Relative paths cannot be converted. casePath = pathIn; - return casePath; + return std::make_pair(casePath, false); } // Start with root component. @@ -3421,7 +3434,7 @@ static std::string GetCasePathName(std::string const& pathIn) casePath += path_components[idx]; } - return casePath; + return std::make_pair(casePath, converting); } #endif @@ -3436,12 +3449,14 @@ std::string SystemTools::GetActualCaseForPath(const std::string& p) if (i != SystemTools::PathCaseMap->end()) { return i->second; } - std::string casePath = GetCasePathName(p); - if (casePath.size() > MAX_PATH) { - return casePath; + std::pair<std::string, bool> casePath = GetCasePathName(p); + if (casePath.first.size() > MAX_PATH) { + return casePath.first; + } + if (casePath.second) { + (*SystemTools::PathCaseMap)[p] = casePath.first; } - (*SystemTools::PathCaseMap)[p] = casePath; - return casePath; + return casePath.first; #endif } diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in index 35bc1b1..8a02b75 100644 --- a/Source/kwsys/SystemTools.hxx.in +++ b/Source/kwsys/SystemTools.hxx.in @@ -107,7 +107,7 @@ public: } /** - * Replace replace all occurences of the string in the source string. + * Replace replace all occurrences of the string in the source string. */ static void ReplaceString(std::string& source, const char* replace, const char* with); @@ -175,7 +175,7 @@ public: static bool StringEndsWith(const std::string& str1, const char* str2); /** - * Returns a pointer to the last occurence of str2 in str1 + * Returns a pointer to the last occurrence of str2 in str1 */ static const char* FindLastString(const char* str1, const char* str2); @@ -553,13 +553,20 @@ public: */ static FILE* Fopen(const std::string& file, const char* mode); +/** + * Visual C++ does not define mode_t (note that Borland does, however). + */ +#if defined(_MSC_VER) + typedef unsigned short mode_t; +#endif + /** * Make a new directory if it is not there. This function * can make a full path even if none of the directories existed * prior to calling this function. */ - static bool MakeDirectory(const char* path); - static bool MakeDirectory(const std::string& path); + static bool MakeDirectory(const char* path, const mode_t* mode = 0); + static bool MakeDirectory(const std::string& path, const mode_t* mode = 0); /** * Copy the source file to the destination file only @@ -749,13 +756,6 @@ public: */ static long int CreationTime(const std::string& filename); -/** - * Visual C++ does not define mode_t (note that Borland does, however). - */ -#if defined(_MSC_VER) - typedef unsigned short mode_t; -#endif - /** * Get and set permissions of the file. If honor_umask is set, the umask * is queried and applied to the given permissions. Returns false if @@ -905,7 +905,7 @@ public: /** * Delay the execution for a specified amount of time specified - * in miliseconds + * in milliseconds */ static void Delay(unsigned int msec); diff --git a/Source/kwsys/kwsysPlatformTestsC.c b/Source/kwsys/kwsysPlatformTestsC.c index 64a361b..5432633 100644 --- a/Source/kwsys/kwsysPlatformTestsC.c +++ b/Source/kwsys/kwsysPlatformTestsC.c @@ -55,6 +55,21 @@ int KWSYS_PLATFORM_TEST_C_MAIN() } #endif +#ifdef TEST_KWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC +#if defined(__APPLE__) +#include <AvailabilityMacros.h> +#if MAC_OS_X_VERSION_MIN_REQUIRED < 101200 +#error "clock_gettime not available on macOS < 10.12" +#endif +#endif +#include <time.h> +int KWSYS_PLATFORM_TEST_C_MAIN() +{ + struct timespec ts; + return clock_gettime(CLOCK_MONOTONIC, &ts); +} +#endif + #ifdef TEST_KWSYS_C_TYPE_MACROS char* info_macros = #if defined(__SIZEOF_SHORT__) diff --git a/Source/kwsys/kwsysPlatformTestsCXX.cxx b/Source/kwsys/kwsysPlatformTestsCXX.cxx index e67d436..f1f9ed3 100644 --- a/Source/kwsys/kwsysPlatformTestsCXX.cxx +++ b/Source/kwsys/kwsysPlatformTestsCXX.cxx @@ -281,7 +281,7 @@ int main() #ifdef TEST_KWSYS_CXX_HAS_BACKTRACE #if defined(__PATHSCALE__) || defined(__PATHCC__) || \ (defined(__LSB_VERSION__) && (__LSB_VERSION__ < 41)) -backtrace doesnt work with this compiler or os +backtrace does not work with this compiler or os #endif #if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE) #define _GNU_SOURCE diff --git a/Source/kwsys/testConfigure.cxx b/Source/kwsys/testConfigure.cxx new file mode 100644 index 0000000..916dcc1 --- /dev/null +++ b/Source/kwsys/testConfigure.cxx @@ -0,0 +1,30 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying +file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(Configure.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +#include "Configure.hxx.in" +#endif + +static bool testFallthrough(int n) +{ + int r = 0; + switch (n) { + case 1: + ++r; + KWSYS_FALLTHROUGH; + default: + ++r; + } + return r == 2; +} + +int testConfigure(int, char* []) +{ + bool res = true; + res = testFallthrough(1) && res; + return res ? 0 : 1; +} diff --git a/Source/kwsys/testEncoding.cxx b/Source/kwsys/testEncoding.cxx index 2c5ef46..2742fe4 100644 --- a/Source/kwsys/testEncoding.cxx +++ b/Source/kwsys/testEncoding.cxx @@ -75,6 +75,10 @@ static int testRobustEncoding() // test that the conversion functions handle invalid // unicode correctly/gracefully + // we manipulate the format flags of stdout, remember + // the original state here to restore before return + std::ios::fmtflags const& flags = std::cout.flags(); + int ret = 0; char cstr[] = { (char)-1, 0 }; // this conversion could fail @@ -120,6 +124,7 @@ static int testRobustEncoding() ret++; } + std::cout.flags(flags); return ret; } diff --git a/Source/kwsys/testProcess.c b/Source/kwsys/testProcess.c index 092dd03..4b4978d 100644 --- a/Source/kwsys/testProcess.c +++ b/Source/kwsys/testProcess.c @@ -107,6 +107,7 @@ static int test3(int argc, const char* argv[]) static int test4(int argc, const char* argv[]) { +#ifndef CRASH_USING_ABORT /* Prepare a pointer to an invalid address. Don't use null, because dereferencing null is undefined behaviour and compilers are free to do whatever they want. ex: Clang will warn at compile time, or even @@ -114,6 +115,7 @@ static int test4(int argc, const char* argv[]) 'volatile' and a slightly larger address, based on a runtime value. */ volatile int* invalidAddress = 0; invalidAddress += argc ? 1 : 2; +#endif #if defined(_WIN32) /* Avoid error diagnostic popups since we are crashing on purpose. */ @@ -128,9 +130,13 @@ static int test4(int argc, const char* argv[]) fprintf(stderr, "Output before crash on stderr from crash test.\n"); fflush(stdout); fflush(stderr); +#ifdef CRASH_USING_ABORT + abort(); +#else assert(invalidAddress); /* Quiet Clang scan-build. */ /* Provoke deliberate crash by writing to the invalid address. */ *invalidAddress = 0; +#endif fprintf(stdout, "Output after crash on stdout from crash test.\n"); fprintf(stderr, "Output after crash on stderr from crash test.\n"); return 0; @@ -149,7 +155,12 @@ static int test5(int argc, const char* argv[]) fprintf(stderr, "Output on stderr before recursive test.\n"); fflush(stdout); fflush(stderr); - r = runChild(cmd, kwsysProcess_State_Exception, kwsysProcess_Exception_Fault, + r = runChild(cmd, kwsysProcess_State_Exception, +#ifdef CRASH_USING_ABORT + kwsysProcess_Exception_Other, +#else + kwsysProcess_Exception_Fault, +#endif 1, 1, 1, 0, 15, 0, 1, 0, 0, 0); fprintf(stdout, "Output on stdout after recursive test.\n"); fprintf(stderr, "Output on stderr after recursive test.\n"); @@ -628,11 +639,16 @@ int main(int argc, const char* argv[]) kwsysProcess_State_Exception /* Process group test */ }; int exceptions[10] = { - kwsysProcess_Exception_None, kwsysProcess_Exception_None, - kwsysProcess_Exception_None, kwsysProcess_Exception_Fault, - kwsysProcess_Exception_None, kwsysProcess_Exception_None, - kwsysProcess_Exception_None, kwsysProcess_Exception_None, - kwsysProcess_Exception_None, kwsysProcess_Exception_Interrupt + kwsysProcess_Exception_None, kwsysProcess_Exception_None, + kwsysProcess_Exception_None, +#ifdef CRASH_USING_ABORT + kwsysProcess_Exception_Other, +#else + kwsysProcess_Exception_Fault, +#endif + kwsysProcess_Exception_None, kwsysProcess_Exception_None, + kwsysProcess_Exception_None, kwsysProcess_Exception_None, + kwsysProcess_Exception_None, kwsysProcess_Exception_Interrupt }; int values[10] = { 0, 123, 1, 1, 0, 0, 0, 0, 1, 1 }; int shares[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 }; @@ -687,9 +703,7 @@ int main(int argc, const char* argv[]) fflush(stdout); fflush(stderr); #if defined(_WIN32) - if (argv0) { - free(argv0); - } + free(argv0); #endif return r; } else if (argc > 2 && strcmp(argv[1], "0") == 0) { diff --git a/Source/kwsys/testSystemTools.cxx b/Source/kwsys/testSystemTools.cxx index 768eb4d..3b694c9 100644 --- a/Source/kwsys/testSystemTools.cxx +++ b/Source/kwsys/testSystemTools.cxx @@ -254,22 +254,22 @@ static bool CheckFileOperations() } // should work, was created as new file before if (!kwsys::SystemTools::FileExists(testNewFile)) { - std::cerr << "Problem with FileExists for: " << testNewDir << std::endl; + std::cerr << "Problem with FileExists for: " << testNewFile << std::endl; res = false; } if (!kwsys::SystemTools::FileExists(testNewFile.c_str())) { - std::cerr << "Problem with FileExists as C string for: " << testNewDir + std::cerr << "Problem with FileExists as C string for: " << testNewFile << std::endl; res = false; } if (!kwsys::SystemTools::FileExists(testNewFile, true)) { - std::cerr << "Problem with FileExists as file for: " << testNewDir + std::cerr << "Problem with FileExists as file for: " << testNewFile << std::endl; res = false; } if (!kwsys::SystemTools::FileExists(testNewFile.c_str(), true)) { std::cerr << "Problem with FileExists as C string and file for: " - << testNewDir << std::endl; + << testNewFile << std::endl; res = false; } @@ -285,7 +285,7 @@ static bool CheckFileOperations() } // should work, was created as new file before if (!kwsys::SystemTools::PathExists(testNewFile)) { - std::cerr << "Problem with PathExists for: " << testNewDir << std::endl; + std::cerr << "Problem with PathExists for: " << testNewFile << std::endl; res = false; } |